This is Part 2 of my trading bot series. Part 1 covered the raw results — 176 trades, three strategies, about $2 profit. This part covers the math that explains why.
If you're building a trading bot for Polymarket, Kalshi, or any binary prediction market, the math in this article is the difference between a bot that prints money and one that bleeds out slowly while showing an 80% win rate.
The Entry Price Trap
Binary markets work like this: you buy a token for some price between $0.01 and $0.99. If your outcome happens, the token pays $1.00. If it doesn't, it pays $0.00.
That means your breakeven win rate is literally your entry price:
Breakeven Win Rate = Entry Price / $1.00
| Entry Price | Breakeven WR | You Need to Win... |
|---|---|---|
| $0.50 | 50% | A coin flip |
| $0.60 | 60% | 3 out of 5 |
| $0.72 | 72% | 7 out of 10 |
| $0.85 | 85% | 17 out of 20 |
| $0.92 | 92% | 23 out of 25 |
| $0.95 | 95% | 19 out of 20 |
Read that table again. At $0.85 entry — a price that looks reasonable, the token is "probably going to win" — you need to be right 85% of the time just to break even. Not to make money. To not lose.
At $0.95 you need 19 out of 20 correct. That's not a trading strategy, that's a prayer.
This is the trap that kills most bots. The backtest says 95% win rate. The live bot enters at $0.85+. The math says you need 85% just to survive. You have 10% of margin at best, and any slippage, any bad fill, any reversion eats it.
Why Backtests Lie in Binary Markets
My backtest showed 95.7% win rate for the momentum strategy. If BTC moved >0.20% in the first 11 minutes of a 15-minute window, the full candle closed in the same direction 95.7% of the time.
That number was accurate. The backtest didn't lie about the signal accuracy.
It lied about the entry price.
Here's what happens in practice:
- BTC moves +0.30% in the first 8 minutes
- My bot sees it at minute 8, confirms the momentum signal
- It queries the Polymarket orderbook for the UP token
- The UP token is already at $0.90
The market moved before my bot could. The signal is right — BTC probably will close up — but the edge is gone because everyone else saw the same move and bought UP already.
My bot's logs were full of this:
SKIP btc-updown-15m-1772810100: UP BTC +0.517% but price $0.9900 > max $0.85
SKIP btc-updown-15m-1772808300: UP BTC +0.332% but price $0.9200 > max $0.85
SKIP sol-updown-15m-1772810100: UP SOL +0.721% but price $0.9500 > max $0.85
See the pattern? By the time BTC has moved enough for the signal to be "obvious" (>0.20%), the token price reflects that. The market isn't stupid. A +0.50% BTC move doesn't leave the UP token sitting at $0.50.
The backtest assumed you could always enter at some fixed price. Reality had the price already at $0.90+ by the time the signal triggered. And at $0.90 entry, you need 90% win rate — which is below the 95.7% signal accuracy, so you'd still be profitable in theory. But the backtest had zero slippage, zero latency, and zero adverse selection. Live trading has all three.
The gap between 95.7% backtest accuracy and ~80% live win rate came from exactly this: the easy signals (big, obvious moves) were priced in before the bot could act. The only signals left were marginal ones — smaller moves, later entries, higher prices.
The Asymmetry Problem
This is where it gets brutal. At $0.85 entry:
- You win: you paid $0.85, you receive $1.00. Profit: $0.15 per share.
- You lose: you paid $0.85, you receive $0.00. Loss: $0.85 per share.
The risk/reward ratio is 1:5.67. Against you.
One loss wipes out 5.67 wins.
From my actual trade data:
WIN: Bought UP at $0.85 × 25 shares = $21.25 cost → $25.00 payout → +$3.75
WIN: Bought UP at $0.82 × 25 shares = $20.50 cost → $25.00 payout → +$4.50
WIN: Bought UP at $0.88 × 25 shares = $22.00 cost → $25.00 payout → +$3.00
WIN: Bought DOWN at $0.80 × 25 shares = $20.00 cost → $25.00 payout → +$5.00
LOSS: Bought UP at $0.85 × 25 shares = $21.25 cost → $0.00 payout → -$21.25
Four wins: +$16.25 total.
One loss: -$21.25.
Net after five trades with 80% win rate: -$5.00.
80% win rate. Losing money. That's the asymmetry problem.
And my real P&L confirmed it. The momentum strategy had some of the biggest individual wins ($2.90, $2.50 per trade) but also the biggest losses ($8.40, $7.70 per trade). A single reversal erased 3-4 winning trades. Over 40+ momentum trades, the strategy was net negative despite winning most of them.
The Edge Formula
Here's the formula that should be tattooed on every bot builder's forearm:
Expected_PnL = WR × (1 - entry_price) - (1 - WR) × entry_price
Let's expand that:
-
WR × (1 - entry_price)= probability of winning × profit per win -
(1 - WR) × entry_price= probability of losing × loss per loss
If Expected_PnL > 0, the trade is positive EV. If it's <= 0, you're burning money.
Here's the same formula, rearranged to show edge:
Edge = Actual_WR - Entry_Price
That's it. Your actual win rate minus the entry price. Positive edge = profitable over time. Negative edge = death by a thousand cuts.
My data, broken down:
| Entry Range | Trades | Win Rate | Edge | Profitable? |
|---|---|---|---|---|
| $0.50-$0.60 | (arb fills) | ~97% | +37% to +47% | Very yes |
| $0.70-$0.78 | 12 | 84.2% | +6.2% to +14.2% | Yes |
| $0.78-$0.85 | 28 | 78.6% | -6.4% to +0.6% | Barely/No |
| $0.85-$0.92 | 31 | 77.4% | -14.6% to -7.6% | No |
| $0.92-$0.97 | 15 | 80.0% | -17% to -12% | No |
The pattern is clear. Below $0.78, edge was consistently positive. Above $0.80, edge was negative regardless of strategy, regardless of signal quality, regardless of how smart the analysis was.
The win rate barely changed across price ranges (77-84%). The edge changed dramatically because the math changed.
This is the code that enforces this in my bot:
# From btc_15m_bot.py — the line that saved me money
MAX_ENTRY_PRICE = 0.85 # Don't buy if winning side already > this
# The skip logic
if ask_price > MAX_ENTRY_PRICE:
log.info(
f"SKIP {slug}: {side} {asset} {move:+.3f}% "
f"but price ${ask_price:.4f} > max ${MAX_ENTRY_PRICE}"
)
continue
After tightening this from $0.85 to $0.72 — combined with other risk fixes — the bot went from bleeding money on momentum trades to only taking trades with positive expected value.
The Market Efficiency Paradox
Here's the paradox that makes binary prediction markets so hard to trade with a bot:
The signal accuracy and the entry price are inversely correlated.
When your signal is strongest (BTC clearly moving in one direction), the entry price is highest (the market already priced in the move). When the entry price is low (tokens near $0.50), the signal is weakest (nobody knows which way it'll go).
This is the efficient market hypothesis playing out in real-time on a 15-minute timescale.
My backtest showed this clearly:
Signal at minute 3: WR 65%, entry ~$0.55 → Edge: +10% → PROFITABLE
Signal at minute 7: WR 82%, entry ~$0.75 → Edge: +7% → PROFITABLE
Signal at minute 11: WR 96%, entry ~$0.92 → Edge: +4% → BARELY
Signal at minute 13: WR 99%, entry ~$0.97 → Edge: +2% → DUST
The later you wait, the more accurate you are but the less money you make. The earlier you act, the cheaper the entry but the less certain the outcome.
There's no free lunch at any point on this curve. The market is pricing in the information faster than your bot can exploit it.
The Only Way to Win: Enter at $0.50
After burning through momentum strategies and watching the math slowly eat my capital, I built a different bot. The next_window_bot.py — a next-window prediction bot.
The key insight: stop trying to trade the current window. Predict the NEXT one.
# next_window_bot.py — enter at symmetric prices
MAX_ENTRY_PRICE = 0.55 # NEVER buy above $0.55
MIN_ENTRY_PRICE = 0.45 # Don't buy below $0.45
At $0.50 entry:
- Win: +$0.50 per share
- Loss: -$0.50 per share
- Risk/reward: 1:1
- Breakeven: 50%
Even 55% accuracy at $0.50 entry is profitable. The edge is +5%. Compare that to needing 85%+ accuracy at $0.85 entry.
The signals I use are based on streaks and mean reversion from a 960-window backtest:
# Signal types (from backtest)
# TIER 1: BIG move (>0.15%) + streak 4+ = bet REVERSAL (69% accuracy)
# TIER 2: Streak 5+ (any size) = bet REVERSAL (67% accuracy)
# TIER 3: BIG move + streak 2+ = bet REVERSAL (55-59% accuracy)
69% accuracy at $0.50 entry = +19% edge. That's enormous. Even the weakest signal (55%) has +5% edge.
The catch? You have to place the order in the first 30 seconds of the new window, before the market has priced in any direction. That means predicting based on previous window patterns, not current price action. Harder to be right. But the math is radically more forgiving.
Here's the expected value calculation the bot runs before every trade:
# EV check — this must be positive or we don't trade
ev_per_share = confidence * (1.0 - ask_price) - (1.0 - confidence) * ask_price
if ev_per_share <= 0:
log.info(
f"SKIP {slug}: negative EV ${ev_per_share:.4f}/share "
f"at ${ask_price:.3f} with {confidence*100:.0f}% confidence"
)
continue
No positive EV, no trade. Period. The risk_governor.py module has veto power over everything else — if the math doesn't work, the order doesn't go, no matter how confident the signal looks.
The Formula Cheat Sheet
Every binary market bot builder needs these:
1. Breakeven Win Rate
breakeven_WR = entry_price
2. Expected P&L Per Trade
E[PnL] = WR × (1 - entry) - (1 - WR) × entry
Simplified:
E[PnL] = WR - entry
Yes, it's literally just win rate minus entry price. If that's positive, you make money over time. If it's negative, you don't. No amount of clever engineering changes this.
3. Required Win Rate for Target ROI
required_WR = entry + (target_ROI × entry × (1 - entry))
4. Kelly Criterion for Position Sizing
# Simplified Kelly for binary markets
kelly_fraction = (WR - entry) / (1 - entry)
# Use quarter-Kelly in practice (25% of Kelly)
safe_size = kelly_fraction * 0.25 * bankroll
This is the code from risk_governor.py:
# Kelly fraction adjustment (conservative: 0.25 Kelly)
if edge.edge_magnitude > 0:
kelly = edge.edge_magnitude / (1.0 - edge.edge_magnitude)
quarter_kelly_usd = kelly * 0.25 * available_capital
size = min(size, max(1.0, quarter_kelly_usd))
5. Number of Wins Needed to Recover One Loss
wins_to_recover = entry / (1 - entry)
| Entry | Wins to Recover 1 Loss |
|---|---|
| $0.50 | 1.0 |
| $0.60 | 1.5 |
| $0.72 | 2.6 |
| $0.85 | 5.7 |
| $0.92 | 11.5 |
| $0.95 | 19.0 |
At $0.92 entry, you need 11.5 consecutive wins to recover from a single loss. If your win rate is 92%, you'll get a loss roughly every 12.5 trades. The math is barely positive — and any friction (slippage, fees, latency) flips it negative.
What The Arb Traders Understood
The only consistently profitable strategy in my bot was binary arbitrage. Buy both UP and DOWN when their combined price is under $1.00.
# Binary arb — the math is beautiful
ARB_TARGET_COST = 0.99 # Buy both sides if combined < this
ARB_MIN_GAP = 0.02 # Minimum gap to take
# If UP = $0.48 and DOWN = $0.49:
# Total cost: $0.97
# Payout: $1.00 (guaranteed — one side always wins)
# Profit: $0.03 per share pair
# Win rate: 100%
# Edge: infinite
97% win rate (the 3% losses were partial fills — one side filled, the other didn't, then the filled side lost).
The profit per trade was small ($0.10-$0.30) but the risk was essentially zero. That's the point. The arb traders don't care which direction BTC moves. They don't need signals, backtests, or AI analysis. They need the market to be slightly inefficient for a few seconds.
This is why the top Polymarket earners are mostly sports bettors, not crypto traders. Sports markets have persistent mispricings because they cross-reference sportsbook odds. They're playing the arb game at scale.
The Real Lesson
If you're building a trading bot for binary prediction markets:
Calculate edge before building anything.
Edge = WR - entry_price. If you can't get that positive with realistic (not backtested) numbers, stop.Your backtest win rate is not your live win rate. Plan for 10-15% degradation from backtest to live, minimum. If your strategy needs >80% accuracy to be profitable, it won't survive contact with reality.
Entry price is everything. The same signal at $0.50 and $0.90 produces completely different outcomes. Guard entry price fanatically. My bot skips more trades than it takes — and that's the feature, not the bug.
Risk/reward asymmetry kills slowly. An 80% win rate feels great. Losing $0.85 for every $0.15 you make does not feel great. Do the math on asymmetry before you celebrate your win rate.
The market is faster than your bot. By the time your signal is "obvious," the market has already priced it in. Either get faster (latency game, not worth it at small scale), get earlier (predict before the move), or get orthogonal (find edges the market doesn't price, like arb).
Every trade decision in my bot generates a cryptographically signed receipt via ai-decision-tracer — a tamper-proof audit trail that proves what the bot saw, why it traded, and what happened. When real money is on the line, you want receipts, not logs.
Part 3 is coming: I'm building a copy trader that tracks whale wallets on Polymarket — following the top 0.5% of traders by ROI. The math question there: can you extract signal from someone else's trades when you're always one step behind?
The code is open source:
- polymarket-ai — the full bot
- ai-decision-tracer — signed trade receipts
- ai-starter-protocol — agent identity standard
If you're building on prediction markets and want to compare notes, I'm at @manja316.
Top comments (0)