poly-maker

repository·main·Indexed 23 days ago

https://github.com/warproxxx/poly-maker

A maker-only market-making bot for Polymarket (CLOB V2) version 2.0.0, specifically designed for political markets. It features a strategy utilizing fair-value estimation, inventory skew, and regime detection to provide liquidity. The bot includes a CLI for discovering and ranking markets via the Gamma API, a scoring system to evaluate market attractiveness based on reward density and rebate potential, and supports both paper and live trading modes.

Tokens
11K
Snippets
15
Records
81
Agent score
79%

What's inside poly-maker

  1. Understand the economics of liquidity rewards and rebates

    main

    The profitability of the bot relies on two primary components:

    • Liquidity Rewards: A fixed daily pool distributed based on your share of the Qmin. Note that there are diminishing returns; once you control a significant portion of the pool, you are primarily competing against yourself.
    • Maker Rebates: These are typically 20-25% of taker fees. They are volume-driven and uncapped, but they are only earned on filled orders, meaning they are inherently tied to inventory and adverse-selection risk.

    Warning on Fee Rates: Always verify the taker fee rate against the UI. The client library treats the rate (e.g., 0.04) as 4%. If the actual exchange fee is 0.4%, your rebate estimates will be 10x too high.

  2. How the poly-maker strategy works

    main

    The strategy is a maker-only, two-sided quoting system designed to capture edge without crossing the spread. It uses the following components:

    • Fair Value (FV): Calculated using depth-weighted microprice from the live order book, adjusted by an EWMA of signed trade flow.
    • Quote Construction: It calculates a reservation price r = FV − skew(inventory) and a half-spread δ = base + c_vol·σ + c_tox·toxicity. It posts BUY-YES at r − δ and BUY-NO at (1 − r) − δ. Because both legs are bids that sum below 1, a filled pair results in a locked edge.
    • Inventory Skew: Adjusts quotes based on net position. For example, if long YES, it bids YES lower and NO higher to acquire the offsetting leg.
    • Regime Machine: Switches between modes like QUIET (farming rewards), TRENDING (widening spreads), EVENT (pulling quotes during news), REDUCE_ONLY (exiting positions), and HALTED (stale data or kill switch).
    • Risk Management: Enforces per-market notional caps, total exposure caps, and a daily-loss kill switch.
  3. Avoid adverse selection and reward loss

    main

    When trading political markets, follow these risk management patterns to avoid common failure modes:

    1. Managing Thin/Gapped Books

    On markets with sparse order books (large gaps between prices), a single large order can lead to significant adverse selection.

    • Strategy: On thin or manipulable markets, only rest the minimum reward-qualifying size (rewardsMinSize).
    • Goal: Ensure fills are small and disposable rather than building large, unmanageable directional positions.

    2. Ensuring Orders Score Rewards

    To earn liquidity rewards, an order must satisfy two conditions simultaneously:

    • Size: Must be $\ge$ rewardsMinSize shares.
    • Spread: Must be within rewardsMaxSpread of the midpoint.

    Note: rewardsMinSize is dynamic and can change. Ensure the engine refreshes metadata from Gamma at startup and rescans periodically.

    3. Mitigating False Signals

    • False HALT: If a market halts due to inactivity, gate the signal on the WebSocket (WS) connection liveness (which pings every 5s) rather than just 'time since last book update'.
    • False TRENDING: On low-frequency markets, microprice jitter can trigger false trend signals. Increase the trend_vol_ratio threshold on these markets.

    4. Reducing Churn

    Tight reprice/resize thresholds cause frequent cancellations and replacements, leading to lost queue position. Make your strategy sticky by increasing reprice_ticks, resize_frac, and trend thresholds.

  4. Exit positions safely

    main

    Closing positions on thin markets requires caution to avoid excessive slippage and fees:

    • Avoid large positions on thin books: If you cannot exit a size without moving the book, you should not have entered that size.
    • Budget for Taker Fees: While maker (resting) fills pay zero fees, closing a position with a market or marketable order incurs taker fees.
    • Don't dump into the gap: On gapped books, a standard market/FAK sell will fill through the empty price levels. Instead, sell only into near bids and stop before the gap, even if it leaves a small residual position to work off later.
  5. Configure poly-maker environment variables

    main

    Before running the bot, you must set up your environment variables by copying the example file and editing the following two values:

    • PK: The private key of your signer wallet.
    • BROWSER_ADDRESS: Your Polymarket address (found on your profile or developer page).
    cp .env.example .env
  6. Perform wallet and strategy self-tests

    main

    Before going live, use these commands to verify your setup and the execution path:

    • Preflight: Check the wallet status before going live. uv run polymaker doctor

    • Livetest: Places a deep post-only order and cancels it (free, no fill) to test the execution path. uv run polymaker livetest

    • Moneydoctor: Performs a real round-trip test (costs a few cents) involving a limit rest, a market buy, and a market sell, then automatically flattens the position. uv run polymaker moneydoctor

    uv run polymaker doctor
    uv run polymaker livetest
    uv run polymaker moneydoctor
  7. Run poly-maker in paper or live mode

    main

    The bot can be run in different modes depending on your testing stage:

    • Dry Run (Paper Mode): Runs the full pipeline against the live feed, but no orders are actually posted to the exchange. Use this to test the logic without financial risk. uv run polymaker run --paper

    • Live Mode: Executes real market-making orders. uv run polymaker run

    uv run polymaker run --paper
    uv run polymaker run
  8. Run and monitor the polymaker engine

    main

    To start the maker, use uv run polymaker run.

    Critical Safety Rules:

    • Run exactly ONE engine. Running multiple instances on the same wallet causes race conditions and double-ordering. Verify with pgrep -f "polymaker run" and check your log for exactly one engine_started line.
    • Capture logs to a file. Use redirection to ensure you have a persistent record: ... > live.log 2>&1.
    • Watch the stream in real-time. Do not rely on periodic polling. Monitor the log for immediate signals like fill, regime=EVENT/HALTED/REDUCE_ONLY, tox=0.1+, or Traceback/quoter_error/divergence.
    • Perform periodic health probes. A silent log does not guarantee health. Periodically verify:
      1. Open orders on the exchange.
      2. Positions on-chain.
      3. That each order remains within the reward band.
    uv run polymaker run
  9. Use ExecutionGateway for order management

    main

    The ExecutionGateway is the primary component for interacting with the exchange's Central Limit Order Book (CLOB). It wraps the py-clob-client-v2 and offloads blocking network calls to a dedicated thread pool to prevent stalling the asyncio event loop.

    Key features:

    • Maker-only mandate: All quotes are sent as post-only orders.
    • Paper Mode: By initializing with paper=True, the gateway simulates the full pipeline by fabricating order IDs instead of posting real orders to the exchange.
    • Rate Limiting: Uses token buckets to manage POST and DELETE request budgets based on the rate_budget_fraction in your configuration.
  10. Understand market regime priority and decision logic

    main

    The RegimeMachine determines the current trading posture for a market based on a hierarchy of conditions. Regimes are evaluated in a specific priority order (highest to lowest). Once a higher-priority regime is triggered, lower-priority regimes are ignored.

    Regime Priority Order:

    1. Regime.HALTED: Triggered by kill switches, stale data, resolved markets, or if the market is within the halt_before_hours window.
    2. Regime.EVENT: Triggered by active cool-offs, flagged sweeps, or fair-value jumps exceeding event_jump_ticks. This regime initiates a cool-off period defined by event_cooloff_s.
    3. Regime.REDUCE_ONLY: Triggered when inventory reaches the hard cap (inventory_util >= 1.0), risk-based reduce-only flags are set, or the market is within the reduce_only_hours window.
    4. Regime.TRENDING: Triggered by persistent one-sided flow (flow_z exceeding trend_flow_z) or elevated volatility (vol_ratio exceeding trend_vol_ratio).
    5. Regime.QUIET: The default posture for normal farming/liquidity provision.
  11. Monitor heartbeat and connectivity

    main

    The gateway maintains a 'dead-man switch' via heartbeat().

    • Heartbeat: Sends a chained heartbeat to the exchange. The exchange requires each heartbeat to carry the previous heartbeat_id.
    • Failures: If heartbeats fail consecutively, the exchange may auto-cancel all orders. You can monitor heartbeat_failures to detect this state. If failures occur, the engine should stop quoting and resync once the heartbeat recovers.