oddsx · read-only research status
Generated 2026-09-14T10:00:49Z · HEAD 9612e75

fundamental_arb dossier — does Black-Scholes fair value beat Polymarket price-threshold markets OOS, net?

Status: INSUFFICIENT_DATA (pre-registered 2026-09-13, before any result was computed; result recorded 2026-09-13).

Pre-registration

Frozen with the G4 checks in tests/g4/. Nothing below may change after a result exists; a change means a new, separately registered hypothesis.

Hypothesis. For Polymarket markets that ask whether an asset's price will be above, below, or touch a strike by a date, a Black-Scholes fair probability (archived fundamental_arb pricer, realized volatility) identifies mispriced YES prices. Taking the model's side when the gap is large earns a positive net return out of sample and beats a no-skill benchmark under the same costs.

This is a limited test. Volatility is realized volatility for every asset. The archived bot preferred ATM implied volatility for equities; that variant is not tested here.

Universe.

Decision time. One decision per market.

YES price at decision. Price of trades in [t_dec − 60 min, t_dec), weighted by token_amount.

Model inputs.

Signal. edge = p_model − yes_price.

Returns. Hold to resolution, $1 notional per bet.

Costs. oddsx.research.validation cost model, spread 0.02.

Split. Calendar split on t_dec: TRAIN before 2026-07-01T00:00:00Z, TEST on or after it. TRAIN is reported, never used to choose anything.

Benchmark. The favorite null on the same decision set and costs. Buy YES when yes_price ≥ 0.5, otherwise sell YES. edge_vs_naive = strategy TEST mean net − benchmark TEST mean net.

Verdict rule (TEST, pooled).

Also reported (no effect on the verdict).

Promotion. A VALIDATED verdict does not move anything into strategies/. Promotion is a separate operator decision.

Results

Computed by research/hypotheses/fundamental_arb/run.py on runs/g4/decisions.parquet (commit 34f1db2). Numbers are copied from registry/results/fundamental-arb.json and runs/g4/universe.json.

Universe accounting. 106,318 markets parsed in the window; 3,005 kept (one decision each). Exclusions:

reasonmarkets
end − t_dec under 12 hours66,064
no trades26,595
not cleanly resolved5,042
between side3,125
no YES trade in the hour before t_dec2,475
strike sanity12

Kept decisions by t_dec month: April 176, May 1,507, June 1,230, July 83, August 9. By cohort: crypto|above 918, crypto|touch_above 1,296, stock|above 786, stock|touch_above 5. No below or touch_below market survived the filters.

TRAIN vs TEST (pooled, $1 per bet, net of costs unless stated).

metricTRAINTEST
n_decisions2,91392
n_bets41415
mean_gross+0.5720−0.3956
mean_net+0.4712−0.6679
median_net+0.1696−1.0253
Sharpe (bet-level)+0.1413−0.6406
favorite-null mean_net−0.0139+0.0410
edge_vs_naive+0.4851−0.7089
cluster-bootstrap 95% lower bound of mean_net+0.1747−1.2193
top-1% |net PnL| share0.21950.2092

TEST cohorts (reported, no vote). crypto|above: 0 bets. crypto|touch_above: 11 bets, mean net −0.7536. stock|above: 4 bets, mean net −0.4321.

Tails. In TEST the median bet loses the whole stake (median net −1.03) and the mean is −0.67. In TRAIN the median is well below the mean (+0.17 vs +0.47) and the largest 1% of bets carry about 22% of absolute PnL, so the TRAIN mean leans on a few large winners.

Caveats.

Verdict

INSUFFICIENT_DATA

The frozen rule needs at least 200 TEST bets, and TEST produced 15, so the out-of-sample question stays open: neither validated nor refuted. Nothing moves into strategies/.

Follow-up: fundamental_arb_short (goal G4b) is a separate hypothesis with its own pre-registration. It decides 1 hour before end instead of 24 (at least 30 minutes to resolution), so it can include the short-dated markets this rule excluded. It does not change or re-run this verdict.