Gold Standard — Kalshi event-market forecaster

A pre-registered, paper-only test of whether an LLM can out-forecast the market's own price. Nothing here places real orders.

Headline scorecard

Resolved
1037
of 150 gate threshold
Brier (ours)
0.227
Brier (market)
0.137
Edge
-0.090
positive = we beat the market
BOTH gates FAIL -- kill, write the post-mortem, keep the track record

By category

CategorynBrier oursBrier mktedgehit
Climate and Weather3490.2580.139-0.11960%
Commodities2890.2160.183-0.03364%
Economics1980.2240.099-0.12569%
Financials640.2150.196-0.01859%
Politics1000.1820.061-0.12073%
Science and Technology350.1830.061-0.12266%
World20.0410.000-0.041100%

By context kind

Context kindnBrier oursBrier mktedgehit
fred870.1940.121-0.07471%
news1710.1960.078-0.11872%
none1680.2390.138-0.10158%
nws3260.2550.134-0.12261%
prices2850.2160.180-0.03564%

Calibration

BandnSaid %Actual %
0.5-0.620353%47%
0.6-0.721163%58%
0.7-0.817374%66%
0.8-0.921684%63%
0.9-1.023494%84%

Paper P&L

n_trades=530   total_pnl=$-2576.87   total_fees=$1164.45   win_rate=27%

Open forecasts

TickerCategoryOur pMkt pClose timeRationale
KXDEEPSHARE-26SEP28-25.2Science and Technology0.500.022026-09-28T03:59:00ZDeepSeek's share plausibly near this level given past dominance in cheap inference.
KXBABASHARE-26SEP28-6.2Science and Technology0.500.892026-09-28T03:59:00ZQwen's OpenRouter share plausibly near this level.
KXBABASHARE-26SEP28-6.5Science and Technology0.450.392026-09-28T03:59:00ZQwen's OpenRouter share plausibly near this level.
KXTOPUSAGEAI-26SEP21-ANTHScience and Technology0.040.012026-09-28T03:59:00ZAnthropic rarely leads OpenRouter weekly usage vs DeepSeek/Google.
KXXIAOMISHARE-26SEP28-1.9Science and Technology0.500.982026-09-28T03:59:00ZXiaomi is a newer OpenRouter entrant; share plausibly near this level.
KXXIAOMISHARE-26SEP28-2.5Science and Technology0.280.352026-09-28T03:59:00ZXiaomi's share reaching 2.5%+ is less likely for a newer entrant.
KXTENCENTSHARE-26SEP28-4.9Science and Technology0.250.012026-09-28T03:59:00ZTencent reaching near 5% OpenRouter share is a higher bar.
KXOPENSHARE-26SEP28-19.3Science and Technology0.320.012026-09-28T03:59:00ZOpenAI exceeding ~19% OpenRouter share is less typical.
KXGOOGSHARE-26SEP28-18.3Science and Technology0.350.992026-09-28T03:59:00ZGoogle's share growing but 18.3% is on the higher end of typical range.
KXGOOGSHARE-26SEP28-16.7Science and Technology0.550.992026-09-28T03:59:00ZGoogle's OpenRouter share plausibly near mid-teens to high-teens.
KXDEEPSHARE-26SEP28-28.1Science and Technology0.350.012026-09-28T03:59:00ZDeepSeek historically a top OpenRouter provider but 28%+ is a high bar.
KXANTHSHARE-26SEP28-2.5Science and Technology0.550.992026-09-28T03:59:00ZAnthropic's OpenRouter share is typically low single digits.
KXANTHSHARE-26SEP28-3.1Science and Technology0.300.012026-09-28T03:59:00ZAnthropic's OpenRouter share rarely exceeds low-3% range.
KXTRUMPAPPROVE-26SEP27-E38.6Politics0.050.242026-09-27T16:59:00ZExact tenth-point RCP average unlikely among many possible values.
KXIPHONERELEASE-IPHONE18PRO-26SEP28Financials0.960.502026-09-28T03:59:00ZApple debuted iPhone 18 Pro Sep 9; retail launch typically ~2-3 weeks later.
KXTENCENTSHARE-26SEP28-3.5Science and Technology0.500.012026-09-28T03:59:00ZTencent's OpenRouter share plausibly near this level; no exact figure available.
KXOPENSHARE-26SEP28-14.0Science and Technology0.650.992026-09-28T03:59:00ZOpenAI historically holds a mid-teens OpenRouter share.
KXTRUMPACT-26SEP20-T10Politics0.300.012026-09-27T14:00:00ZTen+ actions in one week is a high bar vs typical pace.
KXTRUMPNOMNUM-26SEP20-T1Politics0.850.012026-09-27T14:00:00ZPresidents almost always send at least one nomination weekly.
KXTRUMPAPPROVE-26SEP27-E38.7Politics0.050.642026-09-27T16:59:00ZExact tenth-point RCP average unlikely among many possible values.
KXTEMPMIAH-26SEP2706-T73.99Climate and Weather0.920.502026-09-27T10:00:00ZNWS overnight low forecast 75F, well above 74 threshold at 6am.
KXTEMPMIAH-26SEP2706-T74.99Climate and Weather0.600.032026-09-27T10:00:00ZOvernight low forecast exactly 75F; 6am likely near but not certainly below low.
KXTEMPCHIHS-26SEP2706-T48.99Climate and Weather0.950.142026-09-27T10:00:00ZChicago overnight low forecast 55F, far above 49 threshold.
KXTRUMPNOMNUM-26SEP20-T10Politics0.350.012026-09-27T14:00:00ZTen+ nominations in one week is above typical weekly pace.
KXTRUMPACT-26SEP20-T4Politics0.700.012026-09-27T14:00:00ZAdmin typically issues several actions weekly; 4+ plausible baseline.
KXLOWTCHI-26SEP26-T55Climate and Weather0.250.012026-09-27T06:00:00ZNWS lows 55F overnight and Saturday night; min above 55 unlikely.
KXLOWTAUS-26SEP26-B66.5Climate and Weather0.020.032026-09-27T06:00:00ZNWS lows 74-75F; 66-67 very unlikely.
KXLOWTAUS-26SEP26-T66Climate and Weather0.010.022026-09-27T06:00:00ZNWS lows 74-75F; below 66 very unlikely.
KXHIGHTSATX-26SEP26-B94.5Climate and Weather0.280.592026-09-27T06:00:00ZNWS Saturday high 93F, mostly cloudy; 94-95 plausible.
KXHIGHMIA-26SEP26-B87.5Climate and Weather0.400.242026-09-27T05:00:00ZNWS Saturday high 87F, sunny then showers.
KXLOWTOKC-26SEP26-T70Climate and Weather0.450.012026-09-27T06:00:00ZNWS lows 71F overnight, 70F Saturday night; storms may cool.
KXLOWTMIN-26SEP26-T58Climate and Weather0.150.012026-09-27T06:00:00ZNWS lows 58F and 56F with rain; minimum above 58 unlikely.
KXLOWTDAL-26SEP26-T73Climate and Weather0.400.012026-09-27T06:00:00ZNWS overnight low 73F, Saturday night 75F; min near threshold.
KXHIGHPHIL-26SEP26-B67.5Climate and Weather0.040.922026-09-27T05:00:00ZNWS Saturday high 63F with rain showers.
KXHIGHPHIL-26SEP26-T68Climate and Weather0.020.062026-09-27T05:00:00ZNWS high 63F with rain; 69+ very unlikely.
KXHIGHNY-26SEP26-B62.5Climate and Weather0.350.272026-09-27T05:00:00ZNWS Saturday high 63F, light rain.
KXHIGHNY-26SEP26-T62Climate and Weather0.350.742026-09-27T05:00:00ZNWS high 63F; rain may hold it to 61 or below.
KXHIGHMIA-26SEP26-B89.5Climate and Weather0.150.542026-09-27T05:00:00ZNWS high 87F; 89-90 needs upside miss.
KXHIGHTBOS-26SEP26-B61.5Climate and Weather0.300.842026-09-27T05:00:00ZNWS Saturday high 60F, patchy fog; 61-62 plausible upside.
KXHIGHTBOS-26SEP26-B63.5Climate and Weather0.080.152026-09-27T05:00:00ZNWS high 60F; 63-64 needs notable upside miss.

Recent resolutions

TickerOur pMkt pOutcome
KXTRUMPENDORSEMENTS-26SEP25-A50.700.01No
KXTEMPMIAH-26SEP2606-T73.990.850.98Yes
KXTEMPMIAH-26SEP2606-T75.990.150.01No
KXEOWEEK-26SEP12-00.900.50Yes
KXTEMPNYCHS-26SEP2606-T56.990.400.06No
KXTEMPMIAH-26SEP2506-T75.990.750.96Yes
KXTEMPMIAH-26SEP2506-T76.990.500.86Yes
KXGOLDD-26SEP2417-T42680.740.39Yes
KXBRENTD-26SEP2417-T1000.400.49Yes
KXBRENTD-26SEP2417-T100.500.350.40No
KXWTI-26SEP2414-T88.990.960.98Yes
KXCBDECISIONMEXICO-26SEP24-H25P0.050.12No
KXCBDECISIONMEXICO-26SEP24-C50P0.050.03No
KXGOLDD-26SEP2417-T42580.820.48Yes
KXJOBLESSCLAIMS-26SEP24-2050000.320.17No
KX30YMORTW-26SEP24-T7.080.150.01No
KX30YMORTW-26SEP24-T6.980.550.89Yes
KXWTI-26SEP2414-T90.990.920.94Yes
KXTEMPMIAH-26SEP2406-T70.990.970.99Yes
KXTEMPCHIHS-26SEP2406-T58.990.620.90Yes

Pre-registration (locked before any forecast)

# PREREG.md — pre-registration of the gold-standard Kalshi forecaster

**Registered 2026-07-28 (America/Chicago), before any `source='ai'` forecast row exists.**
The git history is the proof: this file is committed at Phase 5, and the first production
(`source='ai'`) forecast is not created until Phase 7, after this commit. Any change to the rules
below requires a dated amendment appended to the "Amendments" section AND the owner's sign-off — the
original rules above the amendment line are never edited in place.

This is a paper-only research instrument. Nothing here places real orders. Educational / hypothetical.

---

## The pre-registered rules (copied verbatim from PLAN.md "LOCKED decisions")

1. **The model never sees the market price** in its prompt. We are testing independent skill;
   showing the price lets the model echo the crowd and fakes calibration. Log `mkt_p` separately
   at call time. (A later "sees-price" variant may be added as a separate scored segment. Not v1.)
2. **Question selection:** status open, `close_time` ≤ 30 days out, `volume_fp` ≥ 500, bid-ask
   spread ≤ $0.10, category in: Economics, Financials, Commodities, Climate and Weather, Politics,
   Science and Technology, World. Excluded: Sports, Entertainment, Mentions, Crypto, Elections,
   Companies, Social, Health. Max **2 markets per event** (for ladders pick the 2 strikes nearest
   $0.50 mid = nearest the money). Max **40 new forecasts per night**.
3. **One forecast per market**, made at first qualifying sighting, never revised. The model may
   **skip** any question (no informational basis); skips are logged and cost nothing.
4. **Paper trade rule:** fills at the **ask** (not mid). Buy YES if `our_p − yes_ask − fee(yes_ask)
   > 0.02`; buy NO if `(1 − our_p) − no_ask − fee(no_ask) > 0.02`. Kalshi fee per $1 contract:
   `fee(p) = ceil_to_cent(0.07 · p · (1 − p))`. Flat $10 notional per trade, max 1 trade per event.
5. **Scoring:** Brier of `our_p` vs Brier of `mkt_p` (mid at call time) on identical resolved sets,
   segmented by category and by context kind (fred / nws / prices / news / none), plus calibration
   buckets. Voided/unresolvable markets are excluded. Only rows with `source='ai'` count
   (`source='dev'` = build-time tests, never scored).
6. **Gates (evaluate at ≥150 resolved AI forecasts):** skill gate = our Brier < market Brier;
   money gate = paper P&L > 0 net of fees over ≥100 trades. Both pass → owner may fund a real
   bankroll ($500–2k, allowed to go to zero; separate authorization, separate build). Either fails
   → kill, write the post-mortem, keep the track record. Interim peeks fine; no action before n.
7. **Prompt discipline:** `PROMPT_VER` constant logged on every forecast; any prompt change bumps
   it. LOUD failures only: a failed/malformed LLM call writes a `runs` row and stderr; **never**
   silently fall back (market-radar's silent-fallback bug is the cautionary tale).

---

## Exact prompt text (PROMPT_VER = "v1")

The nightly batched call (`brain.py`, `--model sonnet`) emits ONE prompt built from a fixed
preamble plus one block per question. The preamble is **verbatim**:

> You are a calibrated event forecaster. For each question output a probability 0-1 that it
> resolves YES. You have NO market price and must not guess one - reason only from the evidence
> given. If you have no informational basis, set skip=true (this costs nothing and is better than
> a blind guess). Today is {UTC date} (UTC). Output STRICT JSON ONLY: an object mapping each
> ticker to {"p":<0..1>,"why":"<=20 words","skip":<bool>}. No prose outside the JSON.

Each per-question block that follows the preamble contains ONLY: the ticker, the question title,
its sub-title, its resolution rules, and the Phase-2 context pack (external evidence — FRED / NWS /
prices / news — which is itself price-free by construction; `context.py` contains zero Kalshi price
fields). **No market price, bid, ask, or implied probability is ever placed in the prompt.** This is
enforced structurally: `build_prompt()` is a separate pure function and the price fetch lives in
`_fetch_mid()`; a grep proves the string `_dollars` never appears in the prompt path.

If v1 is ever changed, `PROMPT_VER` is bumped (e.g. "v2") and forecasts made under different
versions are scored as separate segments — v1's track record is never retroactively altered.

---

## Gate arithmetic (exactly what `score.py` computes)

Scored set = resolved `forecasts` rows with `source='ai'`, `outcome ∈ {0,1}` (void `-1` and
unresolved `NULL` excluded), and both `our_p` and `mkt_p` populated.

- `brier_ours = mean((our_p − outcome)²)` over the scored set.
- `brier_mkt  = mean((mkt_p − outcome)²)` over the identical set (the crowd's mid at call time).
- `edge = brier_mkt − brier_ours` (positive ⇒ we beat the market; lower Brier is better).
- Paper P&L: over settled `paper_trades` (`pnl` not NULL), `total_pnl = Σ pnl`, `n_trades = count`.
  Per-trade P&L (LOCKED #4 `$1`-contract math, `contracts = $10 / entry_p`,
  `total_fee = contracts · fee(entry_p)`): WIN `pnl = 10·(1/entry_p − 1) − total_fee`;
  LOSS `pnl = −10 − total_fee`; VOID `pnl = 0`.

**Decision (only at `n_resolved ≥ 150`):**
- **skill_gate_pass** ⟺ `n_resolved ≥ 150` AND `brier_ours < brier_mkt`.
- **money_gate_pass** ⟺ `n_trades ≥ 100` AND `total_pnl > 0`.
- **Both pass** → the forecaster has earned a real-bankroll funding decision ($500–2k, may go to
  zero; separate authorization + separate build). **Either fails** → kill it, write the post-mortem,
  keep the documented track record as the durable asset.
- Before `n_resolved = 150`: interim peeks are allowed but **no action is taken** — `score.py`'s
  verdict reads "accruing — N of 150 resolved; no decision yet".

---

## Note on the fee example in PLAN.md

PLAN.md's Phase-4 acceptance line ("fee(0.50) on 20 contracts = $0.70") is an arithmetic slip that
contradicts the LOCKED 0.07 coefficient. The **coefficient is unchanged** (`fee(p) =
ceil_to_cent(0.07·p·(1−p))`, i.e. $0.02/contract at p=0.50). The implemented order fee is
`contracts × fee(entry_p)` = 20 × $0.02 = **$0.40** at the example point. This clarification does not
alter any pre-registered rule; it records the correct arithmetic under the LOCKED formula.

---

## Amendments

(none — the rules above are the original registration. Append dated, owner-signed amendments below
this line; never edit the original rules in place.)