DEV Community

Cover image for Polymarket Fair Value Trading Bot: Building a Probability Model
Bo$onaX
Bo$onaX

Posted on

Polymarket Fair Value Trading Bot: Building a Probability Model

Learn how to build a Polymarket fair value trading bot that converts probability estimates into executable trading decisions using orderbooks, fees, slippage, and risk controls.

A prediction market gives you something unusually useful: a price that already looks like a probability.

But that does not mean the displayed price is fair value.

A Polymarket fair value trading bot starts with a different question:

“What probability should this outcome have right now, given everything my model knows?”

If the model says 63% while the executable market price is 55%, there may be an edge. If the model says 56% and the ask is 55%, the apparent 1-cent edge may disappear after fees, spread, slippage, and model uncertainty.

That difference—between predicting a probability and actually trading mispricing—is where the interesting engineering begins.

By Bo$onaX

Polymarket trading bots • Quantitative trading • Rust • Web3 infrastructure

GitHub: https://github.com/n9xdev/poly-alpha-lab

Telegram: https://t.me/bosonax

YouTube: https://youtube.com/@bosonax

X: https://x.com/xxniiinxx

Polymarket: https://polymarket.com/@bosona

Fair value is a probability, not a price target

Polymarket documentation describes outcome prices between $0 and $1 as representing the market's implied probability. However, the displayed price is normally the midpoint of the bid and ask; an actual buyer pays the ask rather than the midpoint. :chatgpt-content-reference{index="1"}

Suppose:

Model probability:      0.63
Best bid:               0.54
Best ask:               0.56
Enter fullscreen mode Exit fullscreen mode

A naive strategy sees:

0.63 - 0.56 = +0.07
Enter fullscreen mode Exit fullscreen mode

and buys.

A trading system should not stop there.

For a binary outcome paying $1 if it wins, the simplified expected value of one share bought at price c is:

EV = p_model × $1 - c
Enter fullscreen mode Exit fullscreen mode

So the raw edge is:

edge = p_model - c
Enter fullscreen mode Exit fullscreen mode

But c should represent the effective execution cost, not simply the chart price.

The real decision is closer to:

net_edge =
    model_probability
    - executable_price
    - fees
    - expected_slippage
    - risk_buffer
Enter fullscreen mode Exit fullscreen mode

Only positive net edge should reach the execution layer.

The model is the product

A useful Polymarket probability model does not have to predict every market.

It needs to estimate one well-defined conditional probability.

For a short-horizon crypto market, for example:

P(outcome = Yes | market state, spot price, volatility,
  time remaining, order flow, related markets)
Enter fullscreen mode Exit fullscreen mode

Possible features include:

  • underlying asset price and returns
  • realized volatility
  • momentum
  • volume and order-flow imbalance
  • time remaining
  • Polymarket bid/ask state
  • cross-market probabilities
  • recent model error
  • regime information

The important design decision is to separate prediction from execution.

The probability model answers:

What should the probability be?
Enter fullscreen mode Exit fullscreen mode

The trading engine answers:

Can I buy or sell it at a sufficiently attractive price?
Enter fullscreen mode Exit fullscreen mode

Mixing these responsibilities makes both systems harder to test.

Build around the executable book

Polymarket uses a CLOB, with bids representing prices buyers will pay and asks representing prices sellers will accept. Large orders can also move the market, making orderbook depth relevant to execution. :chatgpt-content-reference{index="2"}

That makes the orderbook a first-class input to a fair-value bot.

A practical architecture looks like:

Market Data
    │
    ├── Polymarket orderbook
    ├── External market data
    └── Market metadata
            │
            ▼
      Feature Engine
            │
            ▼
     Probability Model
            │
            ▼
       Fair Value
            │
            ▼
      Edge Calculator
            │
       ┌────┴────┐
       │         │
    Reject     Trade
                 │
                 ▼
           Risk / Sizing
                 │
                 ▼
             Execution
Enter fullscreen mode Exit fullscreen mode

The current Polymarket real-time market stream can provide book updates, price changes, last-trade information, tick-size changes, and optional best-bid/ask and lifecycle events. :chatgpt-content-reference{index="3"}

That is preferable to repeatedly polling the book when building a latency-sensitive system.

A better signal: fair value versus executable value

Consider a hypothetical market:

Model probability       61.0%
Best ask                57.0%
Enter fullscreen mode Exit fullscreen mode

The theoretical edge is 4 percentage points.

Now introduce costs:

Gross edge               +4.0%
Estimated slippage       -0.8%
Trading fee              -0.4%
Model safety margin      -1.5%
--------------------------------
Remaining edge           +1.3%
Enter fullscreen mode Exit fullscreen mode

The trade may still qualify.

But this calculation should be performed using the actual order size.

Buying $100 worth of liquidity at the best ask is not equivalent to buying $10,000. The orderbook can contain several price levels, so the effective execution price changes with size.

This is why a fair-value bot should calculate size-aware expected execution, not merely compare fair value with the top-of-book price.

Fees can invalidate an apparently good signal

Current Polymarket documentation states that certain markets charge taker fees, while makers are not charged fees. The documented fee formula depends on traded shares, price, and the market's fee rate; the fee is highest around the 50% probability region and declines toward the extremes. :chatgpt-content-reference{index="4"}

That matters for model design.

A signal that repeatedly generates tiny theoretical edges around 50¢ may look excellent before costs and disappear after fees.

Therefore the model should expose at least:

fair_probability
confidence
expected_edge
expected_execution_price
estimated_cost
Enter fullscreen mode Exit fullscreen mode

rather than returning only buy = true.

That makes the system observable and makes post-trade analysis much easier.

Rust makes the boundary explicit

A simplified decision object could look like:

struct FairValue {
    probability: f64,
    confidence: f64,
}

struct Quote {
    best_ask: f64,
    best_bid: f64,
    expected_fill: f64,
    estimated_cost: f64,
}

fn net_edge(fair: &FairValue, quote: &Quote) -> f64 {
    fair.probability
        - quote.expected_fill
        - quote.estimated_cost
}
Enter fullscreen mode Exit fullscreen mode

The production version should avoid floating-point money calculations where exact decimal semantics matter and should attach timestamps to every market-data and model observation.

More importantly, the model output should be immutable for a particular decision event. That gives the system a reproducible record of:

input state → model output → quote → decision → order → fill
Enter fullscreen mode Exit fullscreen mode

Without that chain, debugging a bad trade becomes guesswork.

Resolution belongs inside the risk model

A probability model can be mathematically impressive and still trade the wrong thing.

Polymarket explicitly warns that the market title is not enough: the resolution rules define the actual outcome, including the resolution source, end date, and edge cases. Markets are resolved through the UMA Optimistic Oracle mechanism. :chatgpt-content-reference{index="5"}

A production bot should therefore validate market metadata before treating a probability as tradable.

For automated systems, resolution ambiguity is not documentation trivia. It is model risk.

The hardest part is knowing when not to trade

A fair-value strategy becomes dangerous when every model difference is treated as alpha.

A robust bot should reject trades when:

  • market data is stale
  • orderbook depth is insufficient
  • expected edge is below transaction costs
  • model confidence is low
  • the market definition cannot be validated
  • the estimated fill is materially worse than the top ask
  • external and Polymarket data disagree beyond expected bounds

The objective is not to maximize the number of trades.

It is to make the probability estimate, execution price, and risk assumptions agree closely enough that the trade is worth taking.

Final thought

A Polymarket fair value trading bot is fundamentally a probability-to-execution pipeline.

The model creates an estimate.

The orderbook determines what that estimate is worth in the real market.

Fees, liquidity, slippage, uncertainty, and resolution rules determine whether the difference is actually tradable.

That separation is what turns a probability predictor into a trading system.

Trading-risk note: Fair value is a model estimate, not a guaranteed prediction. Model error, adverse selection, liquidity changes, execution failure, fees, and market-resolution risk can all turn an apparent edge into a loss.

Top comments (0)