Skip to content

humanplane/updownarena

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UpDown Arena

Paper trading competition for Polymarket 15-minute up/down markets.

Trade BTC, ETH, SOL, XRP with realistic orderbook execution against live Polymarket data.

How it works

  1. Server tracks all trades with realistic orderbook execution
  2. Feed connects to Polymarket CLOB for live orderbook data + Binance for spot prices
  3. Your bot buys/sells shares throughout the 15-min window
  4. PnL is calculated on every trade (buy low, sell high)
  5. Leaderboard shows who's winning

Isolated execution: Each bot trades against the same real Polymarket orderbook, but trades don't affect other bots. This prevents bots from gaming each other.

Quick Start

# Setup
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# Terminal 1: Start server
python server.py

# Terminal 2: Start price feed
python feed.py

# Terminal 3: Run a bot
cd examples
python random_bot.py

SDK Usage

from sdk import UpDownArena

# Register and get API key
arena = UpDownArena.register("my_bot")

# Stream live ticks
async for tick in arena.stream():
    print(f"{tick.asset}: UP={tick.price_up:.3f} | {tick.time_remaining:.0f}s left")

    # Check spread before trading
    if tick.spread_up and tick.spread_up < 0.02:
        # Tight spread, good to trade
        result = arena.buy(tick.asset, "UP", size=50)
        print(f"Bought at {result.price:.3f} (slippage: {result.slippage:.4f})")

# Sell to realize PnL
result = arena.sell("BTC", "UP", size=50)
print(f"PnL: ${result.pnl:.2f}")

# Check positions
for pos in arena.positions():
    print(f"{pos.asset} {pos.side}: {pos.shares:.2f} shares, unrealized: ${pos.unrealized_pnl:.2f}")

Market Data (Tick)

Each tick includes Polymarket orderbook data and Binance spot/futures data:

Polymarket Data

Field Type Range Description
price_up float 0-1 Midpoint price for UP token
price_down float 0-1 Midpoint price for DOWN token
best_bid_up float 0-1 Best bid for UP (sell price)
best_ask_up float 0-1 Best ask for UP (buy price)
best_bid_down float 0-1 Best bid for DOWN (sell price)
best_ask_down float 0-1 Best ask for DOWN (buy price)
spread_up float 0-1 ask - bid for UP token
spread_down float 0-1 ask - bid for DOWN token
time_remaining float 0-900 Seconds until market closes
market_id str - Condition ID for this 15-min window

Orderbook Depth

Full orderbook available via tick.orderbook:

Field Type Description
bids_up list[tuple[float, float]] [(price, size), ...] sorted high→low
asks_up list[tuple[float, float]] [(price, size), ...] sorted low→high
bids_down list[tuple[float, float]] [(price, size), ...] sorted high→low
asks_down list[tuple[float, float]] [(price, size), ...] sorted low→high
  • price: 0-1 (probability)
  • size: shares available at that level
# Walk the UP ask levels
for price, size in tick.orderbook.get("asks_up", []):
    print(f"  {size:.2f} shares @ {price:.3f}")

Binance Data

Field Type Example Description
spot_price float 95420.50 Current USDT spot price
spot_change_1m float -0.12 % change last 1 min
spot_change_5m float 0.35 % change last 5 min
spot_volume_1m float 2500000.0 Volume last 1 min (USDT)
funding_rate float 0.01 Perpetual funding rate (%)
open_interest float 5e9 Open interest (USDT)

Trading

# Buy $50 of UP shares
result = arena.buy("BTC", "UP", size=50)
# result.price = actual fill price (with slippage)
# result.shares = shares received
# result.slippage = difference from midpoint

# Sell shares
result = arena.sell("BTC", "UP", size=50)
# result.pnl = realized profit/loss
# result.proceeds = dollars received

Execution model:

  • All orders walk through the orderbook levels
  • Fill price = volume-weighted average across levels consumed
  • Orders exceeding available depth are rejected (insufficient liquidity)

API Endpoints

Endpoint Method Description
/register POST Register bot, get API key
/markets GET All active markets
/market/<asset> GET Single market (BTC, ETH, SOL, XRP)
/trade POST Execute trade {asset, action, side, size}
/positions GET Your positions with unrealized PnL
/leaderboard GET Rankings by total PnL
/ws WS Real-time tick stream
/ GET Web UI

PnL Calculation

PnL is realized when you sell:

PnL = (sell_price - avg_buy_price) × shares_sold
  • Buy at 0.50, sell at 0.55 → profit
  • Buy at 0.50, sell at 0.45 → loss
  • Leaderboard ranks by total realized PnL

At market resolution: Any remaining positions are auto-liquidated at the final price.

Example Bots

  • examples/random_bot.py - Random baseline
  • examples/momentum_bot.py - Follow price momentum

Bot Ideas

  • Momentum: Buy UP when price_up is rising
  • Mean reversion: Sell when price_up > 0.65, buy when < 0.35
  • Spread trading: Only trade when spread is tight
  • Orderbook imbalance: Use bid/ask depth signals
  • Cross-asset: BTC leads, alts follow
  • Time decay: Prices converge to 0 or 1 near expiry

Architecture

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Polymarket    │◄───│                 │───►│     Binance     │
│   (CLOB WSS)    │    │     feed.py     │    │   (spot data)   │
└─────────────────┘    └────────┬────────┘    └─────────────────┘
                                │
                                ▼
┌─────────────────┐    ┌─────────────────┐
│    Your Bot     │───►│    server.py    │
│   (SDK client)  │◄───│ (orderbook exec)│
└─────────────────┘    └────────┬────────┘
                                │
                                ▼
                       ┌─────────────────┐
                       │   Leaderboard   │
                       │    (Web UI)     │
                       └─────────────────┘

License

MIT

About

trade up down markets with bots and get rewarded

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages