Repository navigation
Phase C: NautilusTrader vs hftbacktest cross-check with an independent oracle; engines agree after fixing our driver's use-after-free - #245
Merged
seathatflowsinourveins merged 4 commits intoSep 25, 2026
Conversation
Add blueprints/us-equities/sim-engine-crosscheck/: replays one shared, deterministic order stream (reusing sim-capacity's own schedule.py) over a bounded SPY+NVDA Alpaca SIP sample through both NautilusTrader 2.0.0rc5 (sim-capacity's engine) and hftbacktest 2.4.4 (PartialFillExchange and NoPartialFillExchange), at 70ms and 250ms latency, and compares fill rate, time-to-fill, touch share and cost via engine-agnostic metrics. Overall fill rate diverges by >20% at both latencies (sim-capacity's own overturn condition), but the divergence is concentrated almost entirely in NVDA (SPY agrees within -0.3%) and is attributed to a documented model-semantics difference: NautilusTrader releases a deferred order at its own instrument's next quote or any due timer, while hftbacktest evaluates against the book at exactly submit+latency -- on a sparser, gappier name this keeps Nautilus orders marketable far more often. Median time-to-fill stays within 2x at both latencies. Conclusion: diverges for a documented model-semantics reason, not a matching bug. A separate, smaller effect is also documented: hftbacktest's own PartialFillExchange and NoPartialFillExchange disagree on NVDA at 70ms only (vanishing at 250ms), traced via direct instrumentation and pinned-source reading to PartialFillExchange's depth momentarily reporting the "no quote" sentinel where NoPartialFillExchange's does not, on byte-identical fed data. Flagged as a suspected hftbacktest-internal inconsistency, not filed externally per policy, with proposed next steps. Registers the new files in manifests/evidence.json and appends a dated cross-check result to sim-capacity/experiment.json (observations, commands, frozen_inputs.tasks and limitations all extended additively; no existing entries rewritten), validated with scripts/validate_convergence.py. Tests (tests/test_sim_engine_crosscheck.py) are hermetic and synthetic: order_stream.py and metrics.py have no engine dependency and are checked unconditionally; NautilusTrader- and hftbacktest-driver smoke tests skip cleanly without the corresponding runtime and were verified passing on both pinned runtimes plus system Python. All six repository validators pass; gitleaks (dir and git-history mode) finds no leaks. The hftbacktest venv this task rebuilt was removed afterward per the existing blueprint's own cleanup convention. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…racle An independent adversarial review refuted the first attempt's conclusion (commit d5cc0c5) outright. Root cause, confirmed by this task's own independent reproduction: a use-after-free in run_hftbacktest.py -- a per-symbol numpy feed array lost its only Python reference when the loop variable holding it was reassigned to the next symbol, while hftbacktest's Rust side kept a raw, non-owning pointer into that freed memory for the rest of the run. Running the unmodified old driver twice gave different outcome hashes (non-determinism); NVDA-alone vs NVDA-within-a-two-symbol-run also gave different hashes (cross-symbol contamination). Both checks are now hash-identical with the fix applied. Withdraws both prior findings: F1 (an ~82% NVDA fill-rate divergence "explained" by Nautilus latency-release timing) and F2 (a PartialFillExchange vs NoPartialFillExchange NVDA-only disagreement) were both artifacts of the corruption, not real engine behavior. Corrected: NautilusTrader and hftbacktest agree within 0.30-0.36% fill rate and 1.16-1.59x median time-to-fill (1.0x against a new NautilusTrader exact-latency variant) -- sim-capacity's 20%/2x overturn condition is not triggered, and the NautilusTrader destination is not overturned. Fixes: keep every per-symbol feed array referenced through hbt.close(); submit orders at their exact scheduled time (elapse() to each order's own ts_ns) instead of a 10ms polling grid; read filled quantity as qty - leaves_qty, not exec_qty (which upstream holds only the last fill call's own quantity). Adds oracle.py, an independent engine-free last-NBBO-crossing predictor (>=99.58% agreement with every engine/symbol in the corrected data) and a hard better-than-touch report check (zero violations across all 8 runs; the first attempt never ran this against hftbacktest's own output -- it would have caught the corruption directly). Reports a separate, minor, real NautilusTrader timing finding (release at the next quote-or-timer, not exactly at submit+latency), with a fix for sim-capacity's own exerciser recommended as a separate follow-up PR, not made here. The first attempt's receipt is preserved unmodified at receipts/20260925-crosscheck-superseded.json (not deleted); its sim-capacity experiment.json observation is marked failed/superseded (not rewritten in place) with a new, passing repair-round observation appended. Tests: adds hermetic oracle.py and better-than-touch checks, receipt-level oracle-agreement/violation assertions, and runtime-gated two-symbol-vs- single-symbol isolation plus determinism-rerun checks -- both verified failing against the unmodified pre-fix driver before this round's fix, passing after. All 51 cross-check tests pass on system Python and both pinned runtimes. All six repository validators pass; gitleaks (dir and git-history mode) finds no leaks. The hftbacktest venv rebuilt for this round was removed afterward. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eck; pin hftbacktest's oracle agreement Merge of main at 4b594d4. sim-capacity/experiment.json keeps both sides' appended limitations (this branch's two cross-check entries, then main's #242 frozen-source re-pin note) and main's re-pinned replay_compare.py digest. manifests/evidence.json is main's registry plus this branch's 11 registrations, with every digest recomputed. The independent re-check of 08a684e returned "ready": its own oracle reproduced all 8 configurations exactly, and it confirmed the fix from hftbacktest source. Its minor corrections are recorded in a README section. The run's code and receipt bytes are left as produced, since the receipt pins their hashes. The corrections: only the isolation test is a reliable use-after-free guard; the Nautilus-to-oracle residual is short-sale rejects plus timing; locked quotes changed no outcome; and three citation nits. The receipt test now pins hftbacktest's oracle agreement at its measured 100% (Nautilus keeps the 99% floor). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
A full python3 -m unittest run failed with 18 errors (AttributeError: 'metrics' has no attribute 'better_than_touch_violations'). adaptive-paper/metrics.py shares the bare module name, and whichever suite imported it first won sys.modules['metrics']. The test now loads sim-engine-crosscheck/metrics.py via spec_from_file_location as sim_engine_crosscheck_metrics. oracle and order_stream keep plain imports, since their names are unique and OrderIntent must stay one class. Both import orders now pass in one process. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins
deleted the
claude/sim-engine-crosscheck-20260925
branch
September 25, 2026 12:57
seathatflowsinourveins
added a commit
that referenced
this pull request
Sep 25, 2026
… engine merges and credential blocker (#248) - Simulation lane: hftbacktest agrees with NautilusTrader within 0.36% once our driver's use-after-free is fixed (#245). The evidence reference points to the cross-check receipt. - Paper lane: the engine P0 release (#221) and exact cancel identity (#242) merged today. The native-fault rerun and the 1x ladder attempt are blocked: at the open, the stored paper keys were rejected with HTTP 401 on the trading account and on both data feeds, so they need rotating through the credential terminal. No order was sent. Co-authored-by: Scout <scout@local> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This is Phase C of the sim-lane engine work. The same bounded order stream is replayed through NautilusTrader 2.0.0rc5, the sim-capacity engine from #235, and hftbacktest 2.4.4, the independent engine installed in #232. Each order's outcome is then checked against a new engine-independent oracle built from the retained SIP quotes.
Result
The engines agree, and the sim-capacity overturn condition does not fire.
sim-capacity/experiment.jsonand evaluated on these corrected numbers. Fill rates differ by 0.30–0.36% (the threshold is 20%), and the median time-to-fill ratio is 1.16–1.59× (the threshold is 2×).The first attempt was wrong, and it is kept on record
The first attempt (d5cc0c5) reported a divergence of more than 20%, all of it in NVDA (hftbacktest 53% against Nautilus 97%). It explained the gap as a model difference (F1) and a suspected upstream bug (F2).
An independent adversarial review (Opus 5.5) built its own oracle and refuted both. The real cause was a use-after-free in our own driver: NVDA's event array was freed while hftbacktest's Rust reader still held a non-owning pointer to it.
The repair round (08a684e):
qty − leaves_qty;oracle.py, a hard better-than-touch check and a determinism command;The superseded receipt is kept byte-identical as
receipts/20260925-crosscheck-superseded.json. The sim-capacity record marks the old observation failed, then appends the correction.A real, separate Nautilus finding
This is a timing-realism issue. It does not make fills optimistic.
Review
Codex cross-family review is unavailable until 2026-09-30, so it was skipped.
Checks
tests.test_sim_engine_crosscheckandtests.test_sim_capacitypass on system Python: 113 tests, of which 32 are engine-gated skips. The builder ran the cross-check tests on both pinned runtimes, and the re-check reran them with hftbacktest installed.validate.py,evidence_manifest.py --checkandvalidate_convergence.py --all-recordedpass.sim-capacity/experiment.json.Evidence class and limits
metrics.pyskips fills that have no quote in force.🤖 Generated with Claude Code