fundamental_arb_short dossier — does Black-Scholes fair value beat Polymarket price-threshold markets in their last hour, OOS, net?
Status: VALIDATED under the pre-registered rule (results 2026-09-13, commit e3f919f). Post-hoc diagnostics indicate a likely stale-price artifact that is not executable; not promoted. Pre-registered 2026-09-13 as a separate hypothesis, after the fundamental_arb decision set showed only 92 TEST decisions and before any return of either hypothesis was computed.
Pre-registration
Frozen with the G4b checks in tests/g4b/. 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.
- Markets parsed by the archived parser
archive/oddsoddy/strategies/fundamental_arb/fundamental_arb_strategy/scanner.py::parse_market, imported verbatim. endDatebetween 2026-04-10T00:00:00Z and 2026-08-21T09:07:27Z,closedtrue, and a clean resolution:oddsx.data.markets.resolve_outcomegives YES = 0 or 1.- Sides
above,below,touch_above,touch_below.betweenis excluded (the archived config disabled it). - Symbols: BTC/USD, ETH/USD, SOL/USD, AAPL, MSFT, GOOGL, AMZN, NVDA, TSLA, META, SPY.
- Strike sanity: 0.5 ≤ strike / spot at decision ≤ 2.0. This removes index-level strikes mapped to SPY and non-price "index" markets.
Decision time. One decision per market.
t_dec = max(first_trade + 10 minutes, end − 1 hour), rounded up to the whole second.- Skip the market if
end − t_dec < 30 minutes. - Skip the market if no trade priced it in the 10 minutes before
t_dec.
YES price at decision. Price of trades in [t_dec − 10 min, t_dec), weighted by token_amount.
- YES is the first token in
clobTokenIds. - A trade whose outcome token is the second token is converted to YES price as
1 − price.
Model inputs.
spot: the close of the last Alpaca 1-minute bar that ended at or beforet_dec. Crypto usesBTC/USD,ETH/USD,SOL/USD; stocks use the SIP feed with raw (unadjusted) prices.sigma: annualized standard deviation (ddof=1) of daily log returns between the closes of Alpaca daily bars that started within the 30 days beforet_decand ended at or beforet_dec(no partial bar); × √365 for crypto, × √252 for stocks.T: (end − t_dec) in days / 365.25.r= 0.05.p_modelcomes from the archived pricer:bs_prob_above(above),1 − bs_prob_above(below),bs_prob_touch_above,bs_prob_touch_below.
Signal. edge = p_model − yes_price.
- Buy YES if
edge > 0.08. - Sell YES (buy NO) if
edge < −0.08. - Otherwise no bet.
- 0.08 is the archived bot's 6% edge plus its cost buffer. It is fixed a priori, not tuned on TRAIN.
Returns. Hold to resolution, $1 notional per bet.
- Buy at price p:
(1 − p) / pif YES resolves, otherwise −1. - Sell at price p:
p / (1 − p)if NO resolves, otherwise −1.
Costs. oddsx.research.validation cost model, spread 0.02.
fee_ratefrom the market's fee flags:feesEnabledfalse → 0.0;crypto_fees_v2→ 0.07;finance_prices_feesortech_fees→ 0.04; any other enabled fee type → 0.05.
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).
INSUFFICIENT_DATAif TEST has fewer than 200 bets.VALIDATEDonly if all three hold: mean net > 0,edge_vs_naive> 0, and the 95% lower bound of mean net > 0. The lower bound comes from a cluster bootstrap: clusters are (symbol, end), 2000 resamples, seed 7.FALSIFIEDotherwise.
Also reported (no effect on the verdict).
- Per-cohort results by asset type and side.
- Median vs mean net return.
- The top-1% |net PnL| share.
Promotion. A VALIDATED verdict does not move anything into strategies/. Promotion is a separate operator decision.
Results
Computed by research/hypotheses/fundamental_arb_short/run.py on runs/g4b/decisions.parquet (commit e3f919f). Numbers are copied from registry/results/fundamental-arb-short.json and runs/g4b/universe.json.
Universe accounting. 106,318 markets parsed in the window; 29,623 kept (one decision each). Exclusions:
| reason | markets |
|---|---|
end − t_dec under 30 minutes | 33,872 |
| no trades | 26,595 |
no YES trade in the 10 minutes before t_dec | 8,061 |
| not cleanly resolved | 5,042 |
between side | 3,125 |
Kept decisions by t_dec month: April 603, May 5,992, June 6,479, July 8,564, August 7,985. By cohort: crypto|above 29,132, stock|above 356, crypto|touch_above 135. No below or touch_below market survived the filters.
TRAIN vs TEST (pooled, $1 per bet, net of costs unless stated).
| metric | TRAIN | TEST |
|---|---|---|
| n_decisions | 13,074 | 16,549 |
| n_bets | 1,546 | 1,228 |
| mean_gross | +1.4990 | +0.2807 |
| mean_net | +1.3211 | +0.1449 |
| median_net | +0.1259 | +0.1047 |
| Sharpe (bet-level) | +0.1401 | +0.0624 |
| favorite-null mean_net | −0.0110 | −0.0101 |
| edge_vs_naive | +1.3321 | +0.1550 |
| cluster-bootstrap 95% lower bound of mean_net | +0.8528 | +0.0097 |
| top-1% |net PnL| share | 0.3447 | 0.1236 |
TEST cohorts (reported, no vote). crypto|above: 1,227 bets, mean net +0.1449. crypto|touch_above: 0 bets. stock|above: 1 bet, mean net +0.1258.
Tails. In TEST the median and mean are close (+0.105 vs +0.145) and the largest 1% of bets carry about 12% of absolute PnL. In TRAIN the mean is ten times the median (+1.32 vs +0.126) and the largest 1% carry about 34% of absolute PnL, so the TRAIN mean is driven by a few longshot winners.
Caveats.
- Limited test: realized volatility for every asset. The archived bot's ATM implied volatility for equities was not tested.
- TRAIN never votes. Its large numbers chose nothing.
- TEST is effectively one cohort (crypto|above, 1,227 of 1,228 bets), so the pooled verdict says nothing about stocks or touch markets.
Post-hoc diagnostics (not part of the verdict)
Computed by the controller on 2026-09-13, after the verdict. None of this was pre-registered and none of it changes the verdict below. It bears on whether the measured edge could be traded.
- Lookahead audit: clean. For 1,225 parsed TEST bets (and a 3,000-row sample of all decisions), the price-reference time in the question ("… on June 30, 9PM ET") equals
endDateexactly. Every decision is 30–60 minutes before it (median 45 minutes); none is at or after it. The markets resolve on the Binance BTC/USDT (ETH/USDT) 1-hour candle close. - Stale-price artifact: likely. The YES price is a 10-minute VWAP. At
t_decthe median age of the last trade in that window is 542 s (p25 242 s, p75 and p90 600 s). TEST net return by last-trade age:
| last-trade age | n | mean_net |
|---|---|---|
| ≤ 60 s | 107 | −0.297 |
| 60–180 s | 126 | +0.290 |
| 180–600 s | 995 | +0.174 |
The measured edge sits where the market price is stale relative to the model's fresh spot, and the bets with the freshest prices lose. It is likely not executable at the recorded prices.
- Thin markets. 2–4 trades in the window: n = 565, mean net +0.259. 5 or more trades: n = 663, mean net +0.048.
- One-sided. Buy YES: n = 314, mean net +0.593. Sell YES: n = 914, mean net −0.009. Median |edge| is 0.15.
- Spot freshness (40-bet sample). Age of the last Alpaca 1-minute bar at
t_dec: median 30 s, p90 60 s, max 175 s. The model's spot is fresh; the market price is the stale input. - Fragility. The TEST 95% lower bound is only +0.0097. TEST is effectively one cohort (crypto|above). TRAIN's mean of 1.32 against a median of 0.126, with a top-1% share of 34%, is driven by longshots.
Verdict
VALIDATED
Under the pre-registered rule, TEST has 1,228 bets (above the 200 floor), mean net +0.1449 > 0, edge_vs_naive +0.1550 > 0, and a cluster-bootstrap 95% lower bound of +0.0097 > 0. The protocol verdict is recorded as computed.
Plain conclusion: the post-hoc diagnostics indicate that this edge is most likely an artifact of stale YES prices in thin hourly markets. It is not evidence of an executable edge. Do not promote: nothing moves into strategies/. A follow-up hypothesis that uses executable entry prices (order-book or fresh-trade prices at t_dec) must be registered separately and pass before any paper trading.