how-to from: Polymarket Profits

The 5-Minute Probability Test That Fixes Your Trading

by J Cook · 7 min read·

Summary:

  1. 93% of prediction market traders lose money because they trade on gut feeling instead of math.
  2. Five calibration scenarios you score right now to find your bias.
  3. Expected value formula that tells you exactly when a trade is worth taking.
  4. Python calibration tracker you run against your own trade history.

93% of active Polymarket traders are underwater. That’s not a guess. That’s the leaderboard data. The median active trader is losing money.

The 7% who profit have one thing in common: they calculate expected value before every trade. Here’s how to join them.

What is implied probability on Polymarket?

Implied probability is the market’s price converted to a percentage. A market trading at $0.42 means the crowd thinks there’s a 42% chance of Yes.

def implied_probability(price):
    """Market price IS the probability."""
    return price  # $0.42 = 42% chance

# Examples from live markets
print(f"Market at $0.35 = {implied_probability(0.35):.0%} chance")  # 35%
print(f"Market at $0.72 = {implied_probability(0.72):.0%} chance")  # 72%
print(f"Market at $0.08 = {implied_probability(0.08):.0%} chance")  # 8%

Here’s what’s live on Polymarket right now:

MarketPriceImplied probability
US x Iran ceasefire by April 30~$0.2525% chance
Will Crude Oil hit $72 by end of March?~$0.4040% chance
DHS shutdown ends by April~$0.5555% chance

That’s it. No conversion formula. The price IS the probability. If you think the real probability is different from the price, you have an edge. Go to polymarket.com and practice reading prices as probabilities on live markets.

How do you calculate expected value?

Expected value (EV) is the only number that matters. Positive EV = take the trade. Negative EV = skip.

def expected_value(your_probability, market_price):
    """Calculate EV per share. Positive = good trade."""
    profit_if_right = 1.0 - market_price
    loss_if_wrong = market_price
    ev = (your_probability * profit_if_right) - ((1 - your_probability) * loss_if_wrong)
    return round(ev, 4)

# "Will Company X announce layoffs?" — market at $0.35, you estimate 55%
ev = expected_value(0.55, 0.35)
print(f"EV: ${ev} per share")  # EV: $0.2000 per share — strong positive, take this trade

# "Will BTC hit $100K?" — market at $0.60, you estimate 58%
ev = expected_value(0.58, 0.60)
print(f"EV: ${ev} per share")  # EV: $-0.0120 per share — negative, skip

# "Iran strike?" — market at $0.38, you estimate 15%
ev = expected_value(0.15, 0.38)
print(f"EV: ${ev} per share")  # EV: $-0.2870 per share — market is way off, but YOU'RE the No side
# Flip it: buy No at $0.62, your probability of No = 85%
ev_no = expected_value(0.85, 0.62)
print(f"No side EV: ${ev_no} per share")  # EV: $0.1330 per share — that's the trade

The Iran market is a real example. $529 million traded on Iran-conflict bets in one week. The market jumped to $0.38 for a US strike. Base rate for that scenario: under 5%. The crowd panicked. The math didn’t.

How do you estimate probability better than the crowd?

The crowd gets it wrong in three predictable ways:

BiasWhat happensExample
Recency biasOne headline shifts market 15+ pointsIran tensions: $0.15 → $0.35 on a single news story
AnchoringMarket was $0.70, dropped to $0.55, “feels cheap”Traders buy at $0.55 regardless of new information
Favorite-longshotPeople overpay for 20x payouts$0.05 markets get bought up to $0.08 on hope

Beat all three with this process:

def estimate_probability(base_rate, adjustments):
    """
    Start with the base rate. Adjust for specific evidence.

    base_rate: historical frequency (0-1)
    adjustments: list of (reason, shift) tuples
    """
    estimate = base_rate
    print(f"Base rate: {base_rate:.0%}")
    for reason, shift in adjustments:
        estimate += shift
        print(f"  {reason}: {shift:+.0%}{estimate:.0%}")
    estimate = max(0.01, min(0.99, estimate))
    print(f"Final estimate: {estimate:.0%}")
    return estimate

# Presidential impeachment — market surged to $0.45 after scandal
estimate_probability(0.07, [  # base rate: 3 of 46 presidents impeached
    ("Single scandal, no investigation yet", -0.02),
    ("House controlled by same party", -0.02),
    ("No bipartisan pressure", -0.01),
])
# Base rate: 7%
#   Single scandal, no investigation yet: -2% → 5%
#   House controlled by same party: -2% → 3%
#   No bipartisan pressure: -1% → 2%
# Final estimate: 2%
# Market says 45%. Your edge: 43 points. Buy No.

The 5-minute calibration test

Score these 5 scenarios. Write down your probability BEFORE looking at the base rates.

Scenario 1: A non-incumbent candidate wins a presidential primary. Your estimate: ___%

Scenario 2: A biotech company’s Phase 2 drug trial succeeds. Your estimate: ___%

Scenario 3: A major tech stock drops 20%+ in a single quarter. Your estimate: ___%

Scenario 4: A hurricane makes landfall within 48 hours of a forecast. Your estimate: ___%

Scenario 5: Two countries currently in a diplomatic crisis go to war within 6 months. Your estimate: ___%

Now check:

calibration = {
    "Presidential primary (non-incumbent)": {"base_rate": 0.12, "common_guess": 0.50},
    "Biotech Phase 2 success":             {"base_rate": 0.33, "common_guess": 0.65},
    "Tech stock -20% in quarter":          {"base_rate": 0.22, "common_guess": 0.40},
    "Hurricane landfall at 48hrs":         {"base_rate": 0.47, "common_guess": 0.78},
    "Diplomatic crisis → war (6mo)":       {"base_rate": 0.08, "common_guess": 0.35},
}

print("CALIBRATION RESULTS")
print("=" * 60)
for scenario, data in calibration.items():
    your_guess = float(input(f"Your estimate for '{scenario}': "))
    error = abs(your_guess - data['base_rate'])
    typical_error = abs(data['common_guess'] - data['base_rate'])
    verdict = "BETTER than average" if error < typical_error else "WORSE than average"
    print(f"  Base rate: {data['base_rate']:.0%}")
    print(f"  Your error: {error:.0%} | Typical error: {typical_error:.0%}")
    print(f"  → {verdict}")
    print()

Most people are overconfident by 10-15 points on every scenario. The presidential primary is the worst: people guess 40-60% when the base rate is 8-15%. That’s a 30-point gap. On Polymarket, that gap is money.

What broke

I ran this calibration on myself after my first month of trading. Turns out I was consistently overconfident on political markets and underconfident on sports markets. That single insight — stop trading politics, size up on sports — added $800/month to my returns.

The mistake most people make: they never check. They trade for months without grouping results by category and confidence level. They have no idea where their bias lives.

How do you track calibration over time?

After 30-50 trades, group by confidence level and compare predicted vs actual:

def calibration_check(trades):
    """
    trades: list of dicts with 'confidence' (0-1) and 'won' (bool)
    Groups by confidence bucket and compares predicted vs actual win rate.
    """
    buckets = {}
    for trade in trades:
        # Round to nearest 10%
        bucket = round(trade['confidence'] * 10) / 10
        if bucket not in buckets:
            buckets[bucket] = {'wins': 0, 'total': 0}
        buckets[bucket]['total'] += 1
        if trade['won']:
            buckets[bucket]['wins'] += 1

    print("CALIBRATION REPORT")
    print(f"{'Confidence':>12} {'Trades':>8} {'Actual':>8} {'Gap':>8} {'Status':>12}")
    print("-" * 52)
    for conf in sorted(buckets.keys()):
        b = buckets[conf]
        actual = b['wins'] / b['total']
        gap = actual - conf
        status = "CALIBRATED" if abs(gap) < 0.05 else ("OVERCONFIDENT" if gap < 0 else "UNDERCONFIDENT")
        print(f"{conf:>11.0%} {b['total']:>8} {actual:>7.0%} {gap:>+7.0%} {status:>12}")

# Example: 50 trades from your journal
sample_trades = [
    {"confidence": 0.6, "won": True},
    {"confidence": 0.6, "won": False},
    {"confidence": 0.6, "won": True},
    {"confidence": 0.7, "won": True},
    {"confidence": 0.7, "won": False},
    {"confidence": 0.7, "won": True},
    {"confidence": 0.8, "won": True},
    {"confidence": 0.8, "won": False},
    # ... add your real trades
]
calibration_check(sample_trades)
# Confidence   Trades   Actual      Gap       Status
# ----------------------------------------------------
#         60%        3      67%      +7%  UNDERCONFIDENT
#         70%        3      67%      -3%     CALIBRATED
#         80%        2      50%     -30%   OVERCONFIDENT  ← fix this

When your 80% confidence trades only win 50% of the time, you know exactly where to adjust.

What should you actually do?

  • Before your first trade → run the 5-scenario calibration test. Know your bias before you risk money.
  • After 30 trades → run calibration_check() on your journal. Find which categories you’re overconfident in. Reduce position size there.
  • After 100 trades → you’ll have real data. Double down on categories where you’re calibrated. Drop categories where you’re not.

bottom_line

  • The difference between the 7% who profit and the 93% who don’t is one formula: expected value. Calculate it before every trade.
  • Your brain lies to you in predictable ways. The calibration test exposes where. Most people are 10-15 points overconfident.
  • Track your trades by confidence level. The data tells you exactly where to bet more and where to stop.

Frequently Asked Questions

How do I calculate expected value on Polymarket?+

EV = (your probability x profit if right) - (1 - your probability x loss if wrong). If a market trades at $0.35 and you estimate 55% chance of Yes, your EV is (0.55 x $0.65) - (0.45 x $0.35) = +$0.20 per share.

What win rate do I need to be profitable on prediction markets?+

55-60% is the realistic target for intermediate traders. Goldman Sachs targets 55-60% on their best strategies. Anyone claiming 85%+ is lying.

How do I know if my probability estimates are accurate?+

Track 30-50 trades grouped by confidence level. If your '70% confident' trades actually resolve 70% of the time, you're calibrated. Most people are overconfident by 10-15 points.