intraday-alpha-platform

An event-driven trading research platform for equities and FX, written in three languages on purpose: Python for research and the reference implementation, C++ for the latency-critical path, Rust for the hard risk engine and infrastructure (the Java strategy layer is archived, frozen at v1.14.0 and retired from the release in v1.17). Market data → order books → 205-feature factory → 24 alphas → validation → ML → portfolio → fail-closed risk → execution/SOR → deterministic replay → TCA → decision trace → 7-state promotion lifecycle. Cross-language golden tests hold it together, and one command (python -m iap.mvp run) runs the whole loop on one instrument. Its golden result loses money, and the page says so.

Seven real Nasdaq ITCH sessions and a two-day 2026 holdout have been studied. The signals are statistically real; none pays its trading costs. Nothing is claimed to be profitable.

Start here. New to the repository? The three-minute read is docs/SHOWCASE.md: what the platform is, what is proven and what is not (the negative results stated plainly), the numbers a CI check re-derives, one architecture diagram and a ten-minute quick start. The sections moved out of the README (release history, the reviews that moved the numbers, usage notes, references) are in docs/README_HISTORY.md.

What this is, and what it is not

It is

A research platform built to make self-deception hard: one seeded generator, integer prices and timestamps, byte-identical goldens across three languages, a ledger that counts the looks recorded through it and raises the significance bar with it (a lower bound on the search, not a complete history: research/v118/LEDGER_INVENTORY.md), and pre-registration checked by code and anchored in git. The loop from market data to TCA runs end to end in Python (python -m iap.mvp), and the Python iap.metrics process is what the deployment scrapes.

It is not

A profitable strategy: no alpha has been promoted. Not connected to a venue: there is no live order gateway, so the risk checks guard a simulator. Not a large-sample study: the real data is nine Nasdaq sessions on AAPL, MSFT and QQQ, enough to show a signal exists and too little to size it. Not four production services: the Java tree is an archived copy frozen at v1.14.0, not built and not a port target; only its risk engine is kept as the byte-identical mirror of the Rust one.

Why three languages

Each one owns what it is good at, and the duplication is the test. Python defines the semantics; C++ and Rust must reproduce them from the same golden files. Parity has caught real bugs (a Rust feature engine reading a half-built book) and missed others (three risk engines agreeing on a wrong answer). Both stories are in LEARN.md §21 and §36.

Results so far

QuestionAnswerWhere
Does any alpha pass every gate on the bundled data?No. 0 PROMOTE of 24; 18 never forecast a move larger than their cost, and the 6 that trade lose.REPORT
Are the signals real on real data?Statistically, yes: EQ01 microprice IC 0.105, t 21 (v1.13 statistics, before the v1.14 day-separated HAC, which will lower the t).REAL_DATA §3.1
Do they pay?No. A 1 s edge of ~0.07 bp against a ~0.7 bp taker round trip.LEARN §31
Do they hold out of time?4 of 4 confirmatory signals confirmed on two 2026 sessions, pre-registered first. Their size is not established, and those two days are spent.REAL_DATA §3.2
Does the closing-cross strategy work?No demonstrated edge: +19.4 bp, 95% CI −254 to +293 bp, from 3 trades. Underpowered, not negative. Holdout not confirmed, 0 trades.LEARN §42
Can a maker do better than a taker?No, not on real data (v1.16). Taker capacity: 0 of 45 cells break even. Two-sided quoting v2 (in-sample, 6 test sessions): every cell loses $5–7k per session, adverse selection about 4x the spread captured; skewing with EQ01/EQ05 cuts the loss by about $750–920 per session, so the signals help execution, not a standalone maker. Synthetic maker backtest: −6.7 bp per trip.ROADMAP §3.8
What does the full loop do?Loses 82.84 USD on its golden session.MVP
v1.18.0 (prepared 2026-10-24): a measurement instrument and recorded negative results. No signal promoted, no edge claimed. Release notes (v1.18.0), CHANGELOG.
v1.17.1 (released 2026-10-17): a patch release. Negative results first. Release notes, CHANGELOG.
v1.17.0 (released 2026-10-16): execution quality and breadth. Negative results first. Also shipped: a real second venue (IEX HIST), an implementation-shortfall benchmark, quote fading, queue-aware cancels, budgeted LLM agents, and C++/Rust parity for the new rules. Next: v1.17.1 (B8 real-data results, the remaining 8 IEX overlap days, the #211 manifest fix; B7 closed 2026-10-16). Release notes, CHANGELOG, Showcase.
v1.16.0 (2026-10-15): monetisation. Realistic execution costs shipped first. The taker route does not pay: the in-sample study made zero trades in 480 cells, and no instrument has a break-even size (0 of 45 cells). The edge is about 0.1–0.9 bp, against 0.8–2.4 bp to cross the spread. Two-sided quoting v2: no edge (every cell loses $5–7k per session; skewing with EQ01/EQ05 cuts the loss by about $750–920 per session). AI4 DeepLOB: closed after an in-sample failure (−0.69 bp per trade net; holdout not used).
v1.15.0 (2026-10-13): the confirmatory release. The pre-registered confirmatory round R7-CONFIRM-1, owner-signed before any data was read, ran once on 7 unseen Nasdaq sessions (2025-11 to 2026-06), six years after the in-sample data. Write-ups: R7_RESULTS, MVP_REAL_20191018. Next, in v1.16: monetisation — realistic execution costs first, then a cost-aware strategy tested once on fresh sessions.
v1.14.0 (2026-10-11): the correctness release. An independent review of v1.12 listed every place where a published number was weaker than it read. v1.13 fixed what could be fixed without moving a number; v1.14 fixes the rest, once, and regenerates goldens, the synthetic feature store and the reports together. The conclusions did not change: 0 promoted, no trade at 1x costs. Not yet done: the real sessions have not been re-ingested under the new rules, so the real-data figures on this page are still v1.13 statistics. Recipes 69-74 of the cookbook walk through each change. Next, in v1.15: the confirmatory round on unseen sessions, deep order-book baselines and a QQQ basis study, whose code is in review.

Measured, not claimed

No latency edge; benchmarks are not colocation numbers. Every latency or speed figure below was measured in-process on a shared CI runner or a small container with steady_clock and no CPU pinning: no network, NIC, kernel bypass or venue round trip. The signals are execution inputs, not strategies: B7 saved no cell the 2 bp minimum, the net-of-cost screen passes 0 of 22, and the v1.16 monetisation study found no taker, capacity, quoting or DeepLOB edge. Real-data and synthetic-data looks are counted separately below.

Cross-language parity    python 3208  · cpp 333  · rust 376 tests — 3,917 green, one command; golden groups 217/74/75 (Java archived in v1.15)
Golden suites             identical book states, byte-identical IAP1 SHA-256, features/alphas to 1e-9, byte-identical canonical JSON, trace digests, risk audit and lifecycle registry in python, cpp and rust (Java archived in v1.15)
C++ hot path              2-CPU container (Intel Xeon 2.10 GHz, no pinning, steady_clock, cache-resident means; not colocation): IAP1 decode 184.1 ns/event (CRC-32 verified) · book update 26.4 ns · replay 27.2M events/s · 48-feature engine 514.1 ns/event · one decision trace 31.7 µs/trace off the event loop
Determinism               full dataset regeneration is byte-identical (sha256-verified); replays reproduce fills exactly; the MVP run twice and replayed from its capture reproduces its trace digest
Contracts                 17 JSON Schemas · 22 typed contracts · 18 Protocols; Python risk and execution ports proven by the Rust and C++ goldens (audit + snapshot byte-identical, fills bit-identical)
Feature factory           205 registered, versioned features across 10 families; validity-bitset semantics, no NaN ever valid
Alpha research            24 flagship alphas · walk-forward + purging/embargo · 6,826-look multiple-testing ledger over 640 distinct configurations after the v1.18 REL-02 migration (real data: 256 configurations holding 1,132 of the looks, per-dataset real ledgers and B7/B8 execution studies included; synthetic data: 384 configurations holding 5,694 of the looks), every dataset and method revision counted, hash-chained (expected max |t| 4.202, Bonferroni |t| ≥ 4.484; source research/experiments.json)
Promotion lifecycle      7 states · 17 pinned edges · 20 gates; bundled data: 23 alphas at CANDIDATE, 0 beyond (FX11 held in RESEARCH by the time-shift leakage gate) — every candidate fails net P&L after costs and capacity
MVP golden run           15,805 events · 800 decisions · 231 parent orders · 163 fills · P&L −82.84 USD (cost-negative, stated) · digest a7f1ee60…
Adaptive lifecycle       PSI/KS drift monitors · 88 drift-triggered refits in the study · CUSUM retirement rule · RETIRED halts allocation in the backtest, pages a human live
Verdicts (honest)        0 PROMOTE · 12 ITERATE · 12 REJECT (v1.14.0) — 7 alphas clear the multiple-testing threshold (t ≥ 4.426), 18 never forecast a move larger than their cost and make no trade, the 6 that trade lose; nothing survives costs, and we say so
Real data                 7 Nasdaq ITCH sessions (2019-01-30 … 2020-01-30; AAPL, MSFT, QQQ; 3,100,181 feature rows) · 0 PROMOTE / 8 ITERATE / 4 REJECT · strong ICs (EQ01 microprice 0.105, t 21) but not one trade survives costs: a 1 s edge of ~0.07 bp against a ~0.7 bp taker round trip
Out-of-time holdout     six hypotheses pre-registered and pushed before any 2026 feature existed · 4 of 4 confirmatory signals confirmed on 2026-05-15/18 (EQ01 t 7.7 · EQ02 t 8.0 · EQ10 t 8.1 · EQ05 t 9.5) · both controls behaved as registered · no trade at 1x costs
Power study              planted order flow detected at the PROMOTE threshold (t ≥ 4.365) in 2 of 20 runs on 2 sessions, 10 of 20 on 4 and 20 of 20 on 8 (EQ04, declared 5 s label) · planted lead-lag 0 of 20 at EQ10's declared 1 s label, 16 of 20 at a 5 s label on 8 sessions · null 0 of 20 throughout · nothing promoted at any size — 20 seeds per cell, Wilson 95 % intervals
Maker economics          calibration from the event stream (touch fill rates by queue-ahead, depletion hazards, latency, maker markouts at 100 ms/1 s/10 s, impact) · posting backtest with FIFO queue fills, rebates and a passive exit · P&L identity tested · synthetic only so far: −6.7 bp/trip passive exit vs −11.4 bp crossing out
Quoting                  Avellaneda–Stoikov two-sided quoter with an alpha-skewed reservation price, hard inventory limit, calibrated adverse-selection floor and end-of-session flatten · P&L split into spread, markout, inventory, flatten, rebates, fees · real-data result (v1.16 quoting v2, in-sample, 6 test sessions): no quoting edge, every cell loses $5.0–6.9k per session, skew with EQ01/EQ05 cuts the loss by $750–920 per session
Auctions & execution   ITCH NOII decoded in a separate opt-in pass (dataset bytes unchanged) · closing-cross strategy with purged day-aligned walk-forward, pre-registration required · Almgren–Chriss trajectory and efficient frontier, alpha urgency, forecast VWAP curve — all opt-in, pinned schedules unchanged
Research governance    a pre-registration costs one look and records a code + feature + dependency fingerprint · blackboard history checked against git and anchored to the first commit holding each entry · agent writes Ed25519-signed, broker holds public keys only
Rust engine (pyo3)       the 45 native feature slots from Python: ~790,000 events/s in Rust vs ~5,250 through the Python reference, 150x on the golden vectors (CI runner ubuntu-24.04, wall clock; not colocation) · not a pipeline speed-up: 160 features stay in Python · opt-in --engine rust
LLM agent evals          4 of 4 mocked in CI (p-hacking, prompt injection, hallucinated citation, task success), each control also shown to fail when removed · live on claude-haiku-5-5 (2026-10-10): 4 of 4, est. $0.0096 — the model behaved, so the live run did not stress the controls
Polyglot policy          18 canonical / 20 frozen copies (24 paths) · 2 retire candidates kept as parity evidence · nothing deleted · a change to a frozen copy needs POLYGLOT-OVERRIDE:
Tick-to-trade (C++)     decoded IAP1 frame → book → features → alpha → order decision, per event, shared CI runner (AMD EPYC 7763, no pinning, steady_clock; not colocation): golden eq_mbo p50 1,279 ns · p99 2,559 ns · p99.9 11,263 ns · max 33,112 ns; generated day p50 1,407 · p99 1,727 · p99.9 12,287 ns · in-process only: no network, no kernel bypass, no C++ risk engine
Deflated Sharpe          CPCV paths, PBO, PSR / DSR / minimum track record with N from the ledger's distinct configurations (DSR at raw looks beside it) · paper's worked example reproduced (DSR 0.9004) · opt-in v4 bundle, report-only
Auction study (AUC01)   exploratory, in-sample, 7 real sessions: closing cross C-300s 3 trades, 2 of 6 test sessions, session-clustered mean +19.4 bp, 95% CI −254 to +293 bp → no demonstrated edge (underpowered: 21 decisions; below the registered 4 active sessions) · opening O-300s 4 trades, +6.1 bp, 95% CI −9.7 to +21.9 → no demonstrated edge · 2026 holdout not confirmed (0 trades) · maker and quoting forks merged onto main in v1.16 (boards archived unchanged); quoting v2: no edge; taker capacity: 0 of 45 cells; AI4 DeepLOB closed (net −0.69 bp per trade in-sample, holdout not used)
Release history, v1.3 to v1.13: what each review found and what moved
Research truth over backtest cosmetics. The adversarial review of this platform found — and fixed — a generator artifact that left the consolidated equity book crossed 95% of the time and silently inflated ML information coefficients. After the fix (a shared efficient price per instrument) the crossed fraction is 0.26% on the current dataset, every golden file and research report was regenerated, and the alpha promotion count honestly fell from 2 to 0. The full story is a worked case study in LEARN.md §7.
v1.3.0 (2026-10-03): the safety code was wrong in ways its tests could not see. A review found the hard risk engine trusting a reference price stamped in the future, letting NaN through its limit checks, overflowing 64-bit arithmetic differently in each of its three languages, and letting router-bound orders past a venue kill. The execution simulator re-filled a resting order against the same displayed shares on every event. The paper platform could resume a cursor beside a risk snapshot from another moment. All three engines agreed byte for byte throughout — parity proves agreement, not correctness. Each is fixed, pinned by a regression test, and written up as a case study in LEARN.md §21–§25; the changelog lists what is still open.
v1.4.0 (2026-10-03): the dataset was wrong, and every number that came from it was regenerated. Up to v1.3.0 the seeded generator stopped each equity stream's continuous flow 37.6–43.2% of the way through the session, so the equity research had only seen the first part of each day. The flow calibration is fixed (flow now reaches the close; the old dataset is still reproducible byte for byte with equities.flow.calibration = "legacy_budget") and the reports, the ledger, the lifecycle registry and four goldens were regenerated in one CI job. The equity statistics are weaker on the corrected data: one alpha fell from ITERATE to REJECT, EQ03's uncrossed IC went from 0.0298 (t 10.57) to 0.0190 (t 5.78), and the power study detects less than it did. The ML gate now passes and the tree models and the MLP were fitted; none earns its costs. The MVP session trades more and loses more. The looks spent on the old dataset stay in the multiple-testing ledger. Still 0 PROMOTE; details in the changelog.
v1.5.0 (2026-10-04): the corrected research methods are the defaults. v1.3.0 added eleven corrected methods as opt-ins and v1.4.0 kept them opt-in, so every committed research number was still computed under rules the repository itself described as deficient. They are now what runs when nothing is named, and each old rule stays selectable under a legacy name (--methods legacy_v1 reproduces the v1.4.0 report). Same dataset, new rules: the gate t is the HAC t of the pooled slope and the PROMOTE threshold is the ledger's multiple-testing threshold (4.365 instead of 3.0), so three alphas are significant where six were; the cost-aware backtest shows 18 of the 24 alphas never forecasting a move larger than their round-trip cost, so they make no trade, and the six that trade lose 22 to 733 USD where the old sign policy lost five or six figures; verdicts are 0 PROMOTE / 11 ITERATE / 13 REJECT (FX03 down, FX10 and FX11 up); EQ11's gate IC falls from 0.0261 to 0.0038 once blackout rows are scored. The MVP's events, fills and P&L are identical. Nothing was tuned to recover a v1.4.0 conclusion. Still 0 PROMOTE; details in the changelog.
v1.6.0–v1.8.0 (2026-10-04 … 10-10): real data, then an honest out-of-time test. v1.6.0 ran the 24-alpha batch on seven real Nasdaq ITCH sessions: 0 PROMOTE / 8 ITERATE / 4 REJECT, and no trade survived costs. v1.7.0 added the agent layer (a governed broker, pre-registration, a reserve) and combined the equity signals: higher IC (up to t 25), still cost-negative. v1.7.2 measured detection power on real-noise nulls (0 of 20 false flags). v1.8.0 cut a full-day ingest from 260 min / 17.6 GB to 59 min / 7.75 GB with byte-identical output, and ran the first out-of-time holdout: four signals pre-registered and git-timestamped before the 2026 data was touched, all four confirmed. The signals are real; at a one-second horizon they are too small to pay a taker's spread and fees. Those 2026 days are now spent.
v1.9.0 (2026-10-10): harden the evidence, then build the maker side. Two of the seven in-sample days were FOMC days, QQQ was half the rows, and every t-statistic ignored day-level clustering. A new opt-in v3 method bundle samples days by seed and stratum and reports with and without event days, clusters inference by day (and bootstraps whole days), cuts folds at session starts, gates on the equal-weight per-instrument IC, labels ITCH-only results honestly as one Nasdaq book, and bounds label freshness causally. The feature build runs one day per process (--workers N, byte-identical, 5.1x on 5 synthetic days). And because a taker cannot pay ~0.7 bp for a ~0.07 bp edge, the platform now has the maker side: a simulator calibrated from the event stream, a backtest that posts at the touch, fills by queue position, earns the rebate and is charged its measured markout, with an optional passive exit. On synthetic data it still loses (−6.7 bp per trip with the passive exit, −11.4 bp crossing out); the real-session maker run comes next. Every default and published number is unchanged.
v1.10.0: test the maker side properly, and make the research record hard to rewrite. A quoter that keeps a bid and an ask resting through the queue simulator, centred on a reservation price the alpha shifts, with a hard inventory limit and a flatten before the close. On the synthetic golden vector the toy score does not help (+86.50 USD skewed against +120.20 USD unskewed); with a synthetic look-ahead signal the skew earns more over eight days (+3,326.66 vs +2,535.66 USD) at a slightly lower Sharpe per day (34.75 vs 36.95). A look-ahead signal tests the plumbing; it is not evidence about any alpha. Also new, all opt-in and Python-only: the Nasdaq auction-imbalance stream with a closing-cross strategy, Almgren–Chriss schedules, alpha-driven urgency and a forecast VWAP curve. Pre-registrations now cost a look and commit to a fingerprint of the code; the blackboard is anchored to git history; agent writes carry Ed25519 signatures that anyone can re-verify with public keys. A pre-registered, in-sample maker study on the seven real sessions is running; there is no result yet, and an in-sample positive could only justify an out-of-sample test.
v1.11.0: scale and AI, under the governance that came first. The Rust feature engine is now callable from Python (one abi3 wheel built with maturin; about 150x on the 45 native slots in CI, not a pipeline speed-up). Comparing it with the Python reference on every row, not just the golden checkpoints, found a real bug: inside a SNAPSHOT recovery burst the Rust engine read a half-built book. Every golden test had passed, because no checkpoint sits in a burst; the bug is fixed in this release. A polyglot policy freezes 20 duplicated copies so they can no longer grow on their own; nothing was deleted. Fitted models get a content-hashed, immutable registry tied to a pre-registration, with drift and calibration monitoring and a shadow mode that cannot act. And an LLM research agent can now propose, pre-register, run and report, but only through the signed broker: it never sees the signing key, code computes every number, and a finding is refused if it quotes a number its cited artefacts do not contain. Its four behaviour evals pass mocked (where a scripted model attacks the controls) and live (where the model behaved well, so the controls were not stressed). Real-data maker, auction and quoting studies are running, pre-registered and in-sample; no result is reported yet. Deferred: QQQ vs constituents, futures lead-lag, deep order-book baselines.
v1.12.0: deflate the Sharpe, time the hot path, and read the first auction result. Research statistics gain combinatorial purged cross-validation, the probability of backtest overfitting and the deflated Sharpe ratio, with the number of trials taken from the ledger rather than chosen by the author (opt-in v4 bundle, report-only; the paper's worked example reproduces at DSR 0.9004). A C++ tick-to-trade benchmark times every event from a decoded frame to an order decision: p50 1,279 ns and p99 2,559 ns on the golden vector on a CI runner (not colocation), with the boundary stated (no network, no kernel bypass, no C++ risk engine). Also opt-in and Python-only: 19 extended features with event and volume clocks, a cost-aware multi-venue router (capability only: the real data is one Nasdaq book), and a fill-hazard model with post-only posting, hazard-driven reprices and markout feedback. Ops: page / ticket / watchdog alert routing with receiver URLs from Secret files, latency burn-rate SLOs with promtool tests, and a state-backup job. The first real-data study result is in: the pre-registered closing-cross strategy AUC01, exploratory and in-sample, shows no demonstrated edge (session-clustered mean +19.4 bp from 3 trades on 2 sessions, 95% CI −254 to +293 bp): an underpowered result, not a negative one. Its 2026 holdout and the maker and quoting studies were then running (outcomes in the v1.13 box).
v1.13.0: an independent review, and the hardening it asked for. Five independent read-only reviews of v1.12 found that no headline conclusion flips (0 alphas promoted, no trade at 1x costs, no auction edge) but that some published statistics were weaker than they read: the research backtest blocks rows by future label validity, the gate t-statistics have no day clustering, and the 2026 holdout refit its parameters on 2026 rows although the write-up said "frozen" (the wording is now corrected). v1.13 is the part that changes no published number: LF artefacts on every OS, an O(1) order lookup, CI on Python 3.11 and 3.12 with slow tests split out, hashed dependencies and a secrets scan; SEC Section 31 and FINRA TAF fees (default 0), one markout reference convention, the auction MOC entry cutoff enforced; frozen-parameter scoring and pre-registered thresholds; and a required governance CI job that verifies the blackboard and checks ledgers only grow. The quoting study was aborted before any result was read: its registered Avellaneda–Stoikov parameters were numerically inert (every quote a fixed 1–2 ticks behind the touch), so it could not test skew against no skew; a tick-based protocol will be pre-registered. The maker study is still running. AUC01's 2026 holdout: not confirmed, 0 trades. v1.14, the correctness release that regenerates goldens and reports once, has its own box above.

Data terms. The real sessions are Nasdaq TotalView-ITCH sample files from emi.nasdaq.com (no terms were shown on the directory as of 2026-10-11). Raw and normalized data and feature stores are never committed or redistributed; only aggregate derived statistics that cannot reconstruct the data are published. Commercial use would need a Nasdaq data agreement (REAL_DATA §2.1).

v1.17 results

Execution quality

Algorithms and the SOR judged on implementation shortfall (B2–B6: benchmark, quote fading, queue-aware cancels and related rules). B1 depth-50 finding (in-sample): at 0.5 % ADV the old 10-level walk cap caused the depth exhaustion (60–67 % of orders, 0 % with 50 levels); at 2 % ADV the displayed book itself runs out; costs rise 2–5 bps at 1–2 % ADV, so depth-10 understated cost. B10 dark venue: modelled, not measured. DEPTH_COMPARISON_multi7, EXECUTION_QUALITY

Breadth

A cross-sectional breadth book behind a net-of-cost screen. Result: 0 pass / 22 fail / 1 not screened of 23 candidates; net IC negative in every screened row. The book was registered under option (a), so it makes no confirmatory look and the holdout stays unread. SCREEN_multi7, PORTFOLIO_BREADTH

IEX second venue

IEX HIST is a free, daily second venue. 9 overlap days approved; day 1 (2025-11-28) is processed: 148,115,121 IEX-TP messages, 0 sequence gaps, and the TOPS oracle shows 0 mismatches for AAPL, MSFT and QQQ. The other 8 days are for v1.17.1. IEX_OVERLAP_SET

Agents

E1 spend ledger with a monthly cap of USD 30; E2 research assistant; E3 morning ops and E4 docs sync on a smaller model. The LLM never computes a number, signs, registers or merges. AGENTS

Start here

How the quant, algo and AI sides work

A guided explanation for a newcomer: the pipeline on one page, how a signal is researched and judged, how an order becomes fills, the risk engine that says no, what the ML layer showed, and where the line for LLMs and agents is drawn. Every section ends with where to look and a command that runs. HOW_IT_WORKS

AI, LLMs and agents: the boundary

The rule was pinned first: LLM reasoning is never on the trading path, is read-only, and cannot override risk or send an order. The governance an agent has to pass through came next (v1.7–v1.10): a write broker over a hash-chained blackboard, costed and code-bound pre-registration, a hidden-seed reserve, signed human approvals, a read-only MCP server, git anchoring and Ed25519 agent signatures. Since v1.11 one optional component calls a model, the research agent, and only when an operator runs it with a key; no test or CI job does. Since v1.13 it may request only pinned model ids and its numbers rule is stricter. The page says what would be theatre on this data. HOW_IT_WORKS §6

Research validity & the power study

Corrected statistics and policies, added opt-in in v1.3.0 and the defaults since v1.5.0, each with its old rule selectable under a legacy name: a pooled-slope HAC t, a ledger-derived threshold, a cost-aware position policy, a recompute leakage probe, per-fold diagnostics (report-only). A planted-signal study measures what the validation chain can detect — and shows it promotes nothing. RESEARCH_VALIDITY, POWER_REPORT

Distance to production

Stated plainly, with a backlog epic for each gap: real exchange data at scale (ITCH 5.0 / LOBSTER ingestion exists; v1.6.0 ran all alphas on 7 real Nasdaq days — real but untradable signals, no trade survives costs; v1.8.0 confirmed four of them out of time), measured tick-to-trade latency, a simulator calibrated to live fills, book-level risk, research throughput. Nothing here is a claim about a market. ARCHITECTURE §14

What's inside

LLM research agent

A Claude model with eight research tools and nothing else: propose, pre-register (signed by a key the model never sees, one look each, capped per session), run a gated study on an allowed dataset, read a report, file a finding. Code computes every metric and the verdict; a finding is filed only if every number in it appears in a cited artefact. Budgets cap spend, tokens, tool calls and pre-registrations; the transcript is kept. Optional [llm] extra; mocked evals in CI (GOVERNANCE §2b).

Model registry & shadow mode

Fitted models as citable records: the id is a content hash of the artefact, data version and dates, features, code fingerprint and seed; records are immutable and re-verified on load; registration needs a pre-registration or is marked exploratory. Feature, prediction and calibration drift (PSI, KS, ECE, Brier, IC decay) as OK/ALERT, and a candidate scored beside the champion that never acts (API_ADAPTIVE §9).

Polyglot policy

Every component that exists in more than one language has one decision per copy: canonical (new behaviour lands here) or frozen (built, tested, golden-pinned, no new features). 18 canonical, 20 frozen, nothing deleted. A CI gate fails a pull request that changes a frozen copy without a POLYGLOT-OVERRIDE: line, and one that adds an API without new-api (POLYGLOT).

Market data foundation

Seeded synthetic equity MBO + multi-venue FX quote generator (regime-switching efficient price, clustered flow, halts/auctions, injected anomalies), raw→normalized pipeline with sequence-gap/duplicate/out-of-order QC, JSONL + IAP1 binary codecs byte-identical across languages, Parquet research datasets.

Order books

L1/L2/MBO reconstruction with FIFO queues, pinned modify semantics, marketable crossing ADDs, snapshot recovery (incl. broken-burst rule), per-venue + consolidated views, deterministic checkpoints — identical state in Python, C++, Rust and Java after every event.

Feature factory

205 registered features across price, microstructure, order flow (OFI L1–L10), liquidity, volatility, time-of-day, cross-asset, venue, regime and execution families; event-driven incremental engines in all four languages validated to 1e-9 against golden checkpoints. Since v1.11 the Rust engine is callable from Python (pyo3, one abi3 wheel, opt-in --engine rust) for the 45 native slots; its row-by-row comparison with Python found and fixed a snapshot-burst bug the checkpoints could not see.

Alpha library

12 equity + 12 FX flagship alphas (microprice, multi-level OFI, queue depletion, momentum/reversal, VWAP deviation, lead-lag, carry-style currency factors, regime-conditioned variants), each with a mandatory economic-rationale docstring and declared feature dependencies.

Validation framework

Event-time labels at 11 horizons (10ms–15m), walk-forward with purging + embargo, automatic leakage tests incl. a recompute-from-raw-events probe, IC/RankIC/pooled-slope HAC t/hit/decay/turnover/edge-breakeven capacity, a persistent multiple-testing ledger, and cost/latency/regime stress — the §20 promotion gates, enforced literally. The opt-in v3 bundle (v1.9) adds day-aligned folds, day-clustered and day-block-bootstrap t, an FOMC/holiday-excluded block and the equal-weight per-instrument gate IC.

ML & meta-labeling

Linear baselines gate the advanced models, literally: trees and the MLP run only if the best linear model shows OOS signal against the frictionless label. On the bundled data it does, barely (ridge, pooled OOS IC +0.0081), so xgboost, lightgbm and the MLP were fitted — and no model earns its costs. A calibrated trade/no-trade meta-label gate, evaluated economically, takes zero trades and is reported as degenerate rather than as a success. Reproducibility manifests (data/feature/model versions, windows, hardware) on every fit.

Portfolio construction

alpha'w − λ·w'Σw − tc(Δw) under position/gross/net/participation/turnover/ vol-target and FX currency-exposure constraints; deterministic projected-gradient production optimizer (Java) matching the Python reference to 1e-9, with a constraint-audit report.

Fail-closed risk

Fat-finger, price-band, stale-price, position/notional/gross/net, loss limits, rate throttle, duplicate-order and self-match prevention, sequence-gap gating, venue-disconnect handling and four-scope kill switches — Rust reference with Java and Python ports, byte-identical audit logs, replayable. Since v1.3.0 also closed against future-stamped marks, NaN, integer overflow and router-bound orders under a venue kill, with an edge golden all three engines replay. Since v1.14 the audit log is a SHA-256 hash chain that survives restores, and SEC 15c3-5 pre-trade checks 23-29 run after the legacy set, so no existing rule id or golden decision moved.

Execution & SOR

Market/limit/IOC/FOK, VWAP/TWAP/POV/IS parent algos, deterministic queue-position modeling for passive orders (pinned depletion rules), fees/rebates/impact, venue latency with seeded jitter, and fee-aware smart order routing — C++ reference fills reproduced exactly by Java and Python. The simulator never fills more than the market displayed or traded. Opt-in since v1.10 (Python only): an Almgren–Chriss IS trajectory and efficient frontier, alpha-driven urgency, and a VWAP on a forecast volume curve. Since v1.13, opt-in SEC Section 31 and FINRA TAF fees (default 0).

Maker economics & quoting

A versioned calibration estimated from the event stream (fill rates, queue-depletion hazards, latency, maker markouts, impact) feeds the simulator. A maker backtest posts at the touch behind a gate on expected edge versus measured adverse selection, with a taker or passive exit; a two-sided quoter skews an Avellaneda–Stoikov reservation price with the alpha. Both decompose P&L exactly; since v1.13 quotes can be set in ticks and markouts use one reference convention. Python research code, opt-in; results so far are synthetic (API_TRADING §2.6–2.8).

Auction imbalance

Nasdaq NOII and cross messages decoded in a separate opt-in pass, so the normalized dataset and its version do not change. Auction features (imbalance ratio, reference-price drift, far/near spread, time to cross), cross targets, and a closing-cross strategy with a purged, day-aligned walk-forward. The CLI refuses to backtest without a pre-registration. First real-data result (v1.12, exploratory, in-sample, 7 sessions): no demonstrated edge on the closing or the opening cross, with only 21 decisions per cell; the 2026 holdout was not confirmed (0 trades), and since v1.13 an exit at or after the MOC entry cutoff is priced as a taker trade (REAL_DATA §3.3).

Overfitting statistics & the deflated Sharpe

Combinatorial purged cross-validation (all C(N,k) splits, reassembled into backtest paths, day-aligned), the probability of backtest overfitting by CSCV, and the probabilistic and deflated Sharpe ratios with a minimum track record length. The trial count comes from the ledger's distinct configurations, with the DSR at the raw look count printed beside it. A helper puts a DSR block next to any study's per-day P&L without touching its verdict rule. Opt-in v4, report-only (RESEARCH_VALIDITY §1b).

Passive execution: hazard, post-only, routing

A discrete-time (cloglog) fill-hazard model fitted on maker labels and versioned as iap.fill_hazard/1; post-only orders that reject or slide instead of taking; entry reprices that give up when the hazard says a repost will not fill; and markout feedback that stands down, widens or shrinks while fills are toxic (synthetic quoting markout −62.75 → −1.75 with a 2 bp threshold). A cost-aware multi-venue router prices fill probability, toxicity, latency and fee tiers. Python, opt-in, synthetic only (API_TRADING §2.9–2.10).

Extended features & event clocks

Nineteen opt-in features: queue time-to-depletion, trade-sign autocorrelation, Hawkes intensities with online recursion, and odd-lot / non-displayed execution shares, with rows sampled on an event or volume clock. They carry their own feature version; the default registry hash and every golden are unchanged. Not yet run on real data (API_FEATURES §8).

Alerting & latency SLOs

Alertmanager routes page, ticket and a Watchdog heartbeat, with receiver URLs read from Secret files (nothing secret committed) and a local echo sink for compose. Multi-window burn-rate SLOs on the existing JVM latency histograms (99% under ~1.05 ms over 30 days) with promtool tests, and a state-backup CronJob. HA is one pod restarting and resuming from its checkpoint, not active-active (RUNBOOK_alerting).

Research governance

Every agent write goes through one broker onto a hash-chained blackboard. A pre-registration debits a look on the multiple-testing ledger and records a fingerprint of the alpha's code, features and pinned dependencies; the gate refuses a run if any changed. verify-board checks the chain, that each committed version is a prefix of the current one, the git anchors, and every Ed25519 signature. Since v1.13 a required governance CI job runs it on every change, with checks that every signer has a registered key and that ledgers and the board only grow; human lifecycle edges need a signed approval. Since v1.14 the agent key registry must be signed by a maintainer trust root read from main, the look ledger is itself a hash chain, and pip-audit, cargo audit, cargo deny and Trivy block the build (GOVERNANCE).

Event-driven backtester

Replays every market event in event-time through book → features → alphas → portfolio → risk → execution with modeled decision/wire/venue latency, partial fills and queue position; identity-tested P&L accounting; checkpoint/restart bit-identical to uninterrupted runs.

TCA & attribution

Arrival/VWAP/TWAP benchmarks, Perold implementation-shortfall decomposition (delay/trading/opportunity — exact identity), spread/impact/timing split, post-fill adverse-selection markouts at 100ms/1s/10s, and impact regression versus participation.

Adaptive lifecycle

Models decay, so the platform measures it: pinned PSI/KS drift monitors against serialized research baselines, rolling realized-vs-research IC, drift-triggered refits on purged/embargoed windows, and an IC-gated ACTIVE→WATCH→RETIRED state machine with hysteresis and a CUSUM retirement rule (the legacy consecutive-breach rule stays selectable). In the adaptive backtest RETIRED verifiably halts the allocation; in the live paper loop the gauge is deliberately observational — the AlphaLifecycleRetired alert pages a human, nothing reduces the position automatically (API_ADAPTIVE §6, PLATFORM_CONVENTIONS §12.6). Live PSI, rolling-IC and lifecycle gauges are scraped in paper trading.

Cross-language golden parity

The Python reference generates validated golden vectors (events, book states, codec SHA-256, features, alphas, risk decisions, fills, portfolio); C++, Rust and Java must reproduce every one. tests/harness/run_all.sh prints the parity table in one command. Agreement is not correctness: four engines can agree on a wrong rule, and engines that agree at every checkpoint can differ between them.

Contracts & the Python reference ports

17 JSON Schemas mirrored by 22 frozen, validated Python contracts and 18 runtime-checkable Protocols; canonical JSON reproduced byte for byte in four languages. Python ports of the hard risk engine and the execution stack proven by the same goldens the Java ports use (API_CONTRACTS, API_TRADING).

Promotion lifecycle

RESEARCH → CANDIDATE → VALIDATING → PAPER → ACTIVE ⇄ WATCH → RETIRED: 17 pinned edges, 20 gates reading typed evidence, a byte-deterministic registry and transition log, ports in Java and Rust from one golden. Bootstrapped on the bundled research: 23 CANDIDATE, 0 beyond.

Decision trace & data model

One validated record per decision — signal, portfolio, risk, orders, routing, fills, TCA, attribution — as canonical JSONL with a stream digest that an incident replay must reproduce, indexed by a SQLite/PostgreSQL-portable store (24 tables, 3 views) and rendered by explain() identically in Python, Java, Rust and C++.

The executable MVP

python -m iap.mvp run: seeded feed → books → features → EQ01/EQ03/EQ06 → portfolio → hard risk → TWAP/POV/IS → SOR over three venues → simulator → TCA → trace → SQLite → report, deterministic twice over. The golden run loses 82.84 USD, the realized-IC gap is attributed to the data rather than a leak, and the document says so.

Observability & deployment

Prometheus metrics from the Python iap.metrics process (/metrics, /health, /ready, /status; 30 live metric families read from the MVP run's artefacts and the live risk limits, every retired Java-only name exposed as _available 0), recording + alert rules with promtool unit tests, two Grafana dashboards, structured JSONL logs, three Dockerfiles (python, cpp, rust) + docker-compose + Kubernetes manifests pinned by digest at release, runbooks, governance and reproducibility docs, and a paper-trading mode. Alertmanager routes the alerts by severity (page / ticket / watchdog); real delivery needs operator-supplied page_url and ticket_url Secret files, and compose echoes to a local sink until then. NetworkPolicies default-deny ingress and egress.

Research papers

Six case studies written from the platform's own measured outputs: OFI predictability, microprice/queue dynamics in FX, cross-venue lead-lag, alpha decay vs latency economics, queue-aware execution and adverse selection, and C++ vs Rust vs Java for event-driven trading.

Performance engineering

Benchmark suite with published methodology (hardware, toolchain, boundaries, variance caveats — no isolated numbers): codec, book, replay, feature engine, alpha scoring and execution-sim stages, plus demo-scale Rust/Java replay throughput. Since v1.12 a tick-to-trade benchmark reports per-event p50 / p99 / p99.9 / max latency end to end and per stage (decode 271, book 83, features 735, alpha 135, decision 30 ns at p50 on the golden vector, shared CI runner, not colocation), guarded in CI at 8× the baseline.

Part of a wider portfolio

quant-portfolio

The end-to-end quantitative finance portfolio this platform sits alongside: 10 project areas built twice each (equity + FX) in Python with C++ and Rust performance twins — 31 sub-projects, 6,446 tests, golden-vector cross-language validation, a 481-question learning guide and a 63-recipe cookbook. GitHub →

quantfinlib

A zero-dependency quantitative finance platform for the JVM — research, validation, execution and connectivity, from walk-forward backtesting to a measured sub-microsecond tick-to-order path, with 1,090+ tests and CI on every push. GitHub →

Quick start

git clone https://github.com/AshJha0/intraday-alpha-platform && cd intraday-alpha-platform

# generate the deterministic synthetic dataset, then the feature/label store
cd python && PYTHONPATH=src python3 -m iap.marketdata && PYTHONPATH=src python3 -m iap.features && cd ..

# run everything — builds and tests python, cpp and rust, prints the parity table
bash tests/harness/run_all.sh

# the whole trading loop on one instrument, fully traced; then replay it from its capture
cd python && PYTHONPATH=src python3 -m iap.mvp run && PYTHONPATH=src python3 -m iap.mvp replay --run ../data/mvp/58a10f2194a3c81c && cd ..

# research pipelines (honest reports in research/)
PYTHONPATH=python/src python3 research/alpha_reports/run_all.py
PYTHONPATH=python/src python3 research/ml_reports/run_ml.py