Skip to content

Sim-to-paper fill agreement: replay a retained Alpaca paper trial through NautilusTrader rc5 (audit gap #7) - #217

Closed
seathatflowsinourveins wants to merge 13 commits into
mainfrom
claude/sim-paper-fill-compare-20260924
Closed

seathatflowsinourveins wants to merge 13 commits into
mainfrom
claude/sim-paper-fill-compare-20260924

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Owner

What

Trading-lane audit gap #7 (sim-to-paper agreement), first measurement. blueprints/us-equities/sim-paper-compare/replay_compare.py replays the retained Alpaca paper trial 20260923g-main-passed (5 orders) through NautilusTrader 2.0.0rc5's simulated exchange. It uses the same SIP quotes, retained as a hash-ledgered page cache. It then scores sim-vs-paper fill agreement per order.

This is one trial and an agreement measurement, not a calibration.

Result (receipts/20260923g-main-passed.json)

Latency model Agreement Mean |Δprice|
0 / 5 / 50 ms 3/5 0.375 bps
70 / 250 / 650 / 1000 ms 5/5 0.281 bps
100 ms 5/5 0.489 bps (order 2 alone)

Bisected flip. The simulator disagrees with paper at 69.216918 ms and agrees at 69.217529 ms. Order 4 was already marketable at submit and stopped being marketable 69.273 ms later. With less latency than that, the simulator fills it; paper did not.

  • The paper broker's submit-to-fill intervals on its other orders were 0.65–1.09 s. That is consistent with this explanation, but it is a hypothesis; no fill-vs-cancel race was measured.
  • Order 5's flip depends on order 4. The counterfactual sweep with order 4 removed agrees at all eight latencies.

Disclosed engine semantics (pinned rc5 engine.rs). A delayed command settles on either of two events:

  • the order's own instrument's next quote;
  • any due timer, including a no-op timer.

A foreign instrument's quote alone does not settle it. So sweep times and prices are not a function of the latency L alone.

Clock provenance. Submit times come from the broker. Cancel times come from host stamps taken before send, and the host leads the broker by at least 27.99–40.77 ms. Cancel pairing uses an open-order uniqueness rule that refuses ambiguous cases. Its assumptions and two constructed counterexamples are stated in the README. Logging client_order_id on cancel requests would remove the heuristic.

Review

Five fix rounds with two model families.

  • Claude reviewers verified every claim against source, reproduced the receipt from --replay, and ran a 200k-trial differential fuzz of the pairing rule. They mutation-tested with about 25 mutants, each now killed by a behavioural test.
  • Codex (gpt-6-astra) CLI, read-only, reviewed the same rounds.
  • The final Claude verdict was ready at 59211ea. Round 5 closed Codex's last wording, stdout-basis and test-comment items, plus the Claude wording follow-ups.

Checks.

  • 105 tests pass on the pinned runtime (nautilus-trader 2.0.0rc5) and on system python3 (18 pinned-only skips), each with and without -b.
  • All six validators pass. The four new files are registered in manifests/evidence.json.
  • No paper orders were placed; every run used --replay against the retained cache.

Not covered

  • A single trial and a single fetch.
  • Partial fills: rc5 in this configuration never partially fills, so extraction is tested on constructed events.
  • SIP-vs-broker clock agreement is not established.
  • The pairing rule is a heuristic under stated assumptions.

🤖 Generated with Claude Code

Scout and others added 10 commits September 24, 2026 13:34
Replay the retained adaptive-paper trial 20260923g-main-passed's five order
decisions (four filled, one canceled) through NautilusTrader 2.0.0rc5's
BacktestEngine, fed with real Alpaca SIP quotes for the trial window, using
the accepted engine-nautilus/equity-replay fee/fill-model baseline
(FixedFeeModel at $0, native default FillModel, L1_MBP matching).

Result: 3/5 fill agreement; the 3 orders with unambiguous paper timestamps
agree with sub-bp fill-price deltas (mean 0.375 bps) and sub-second
fill-time deltas (mean 0.78 s). Both disagreements trace to one declared
gap: broker-orders.json has no recorded cancel timestamp for the canceled
GOOGL sell, so the replay holds it open longer than the paper trial did.

One trial, five orders: this is an agreement measurement, not a fill-rate
or slippage calibration. The retained receipt records input hashes, data
provenance (SIP quote page ledger sha256), engine version and fill-model
parameters. Seventeen offline tests cover the comparison/decision-building
logic against synthetic fixtures and the retained trial fixture; no
network or credential file is touched by the tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…cy sweep, harden replay

Independent review of blueprints/us-equities/sim-paper-compare/ found the disagreement
between order 4 (canceled by paper, filled by the zero-latency sim) and order 5 was
misattributed to unknown cancel timing (H1). The real cause is that order 4's limit was
marketable for only ~69ms after submit while the paper broker's own fill latency
(648ms-1.09s) let Alpaca cancel it first. build_decisions() now uses the actual recorded
cancel timestamp from paper-output.json's requests log (or submit + order_timeout_seconds
from the matching adaptive-paper config) instead of inferring a cancel time from the next
order's submit; using the real recorded cancel time still produces 3/5 agreement, so the
old explanation is withdrawn. A declared latency-sensitivity sweep (0/5/50/70/100/250/650/
1000ms via StaticLatencyModel) is now run and committed to the receipt/README: agreement
flips from 3/5 to 5/5 between 50ms and 70ms, matching order 4's marketable window.

Also fixes, per the review:
- M1: decisions are scheduled with clock.set_time_alert_ns at their exact recorded
  timestamps instead of polling on the next quote of any symbol; applied-decision log
  now records the clock's actual application time alongside the scheduled time.
- M2: report hashes are computed over fills/orders rows with the random per-order
  init_id stripped; README's reproduce section uses a scratch --receipt path and diffs
  against the committed one instead of overwriting it.
- M3: --replay never opens or requires a credential file.
- M4: receipt now carries sim order status/reject reason, explicit engine
  latency_model/queue_position, a measured (not hardcoded) alpaca-py version,
  evidence_class, redacted argv, start/end times, exit code and a stdout hash.
- L1-L7: per-page network/cache source tracking with a corrected "identical" claim;
  crossed quotes dropped and counted (locked quotes kept); signed side-aware slippage;
  DAY-only/integral-qty enforcement instead of silent truncation, correct partial-fill
  scoring by quantity, and the recorded-cancel fix above; network_interfaces dropped;
  ts_last/status/reject reason read from strategy.cache.orders() instead of a pandas
  tz-column conversion; corrected reuse claim against equity-replay (market orders on
  daily bars, not limit orders vs. quotes); ledger writes open/close per record instead
  of holding a handle open; --out now refuses a non-empty directory; private cache dirs
  are chmod 0700 explicitly (mkdir's mode= is masked by umask).

Adds PageFetcher tests (replay/hash-mismatch/pagination), a receipt-consistency test
that recomputes aggregates and checks inputs_sha256/runner_sha256, crossed/locked/
quantization normalization tests, and a gated pinned-runtime suite (skips outside
nautilus_trader==2.0.0rc5) covering a tiny fixture where an order is marketable only
briefly -- the shape of case that would have caught H1 and M1 -- plus a --replay run
of main() with no credential file argument at all.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… provenance, argv-redaction bypass

Both independent reviews (Claude and Codex gpt-6-astra) found the prior fix round's
H1 explanation, latency claims and several receipt/README details wrong or overstated.

H1 (the disagreement mechanism was backwards): order 4 (SELL GOOGL @338.42) was
already marketable at submit (bid 338.44 since 16:46:37), not "becomes marketable
at submit+69ms" as previously written. It stops being marketable at submit+69.273ms
(raw SIP quotes) / 69.216918-69.217529ms (bisected actual engine flip, now the cited
number). The 16:51:06.696Z timestamp cited previously was ~8ms after submit, an
artifact of the old quote-polling implementation, not a crossing point. The paper
broker's own fill lag on other orders is now stated as a hypothesis consistent with
the data, not a demonstrated broker mechanism.

Latency semantics: disclosed that the pinned engine (StaticLatencyModel) processes a
deferred command at the next event for that instrument at or after the modeled
arrival, not exactly at submit+latency (cites crates/backtest/src/engine.rs L883 at
nautilus_trader 1b0a49d2). The sweep now reports a bisected flip boundary
(latency_sensitivity_sweep.flip_bisections, 1us resolution) instead of a quote-derived
window boundary, and the README documents the sparse-quote artifacts (order 3's
266.9/466.4ms lag, order 2's 100ms price-delta outlier) this causes.

Clock provenance: submit timestamps are broker-clock, cancel timestamps are
adaptive-paper's host clock (captured pre-send, no client_order_id recorded);
measured +27.994 to +40.769ms host-ahead-of-broker offset for this trial, now in a
new clock_provenance receipt section and README section. Cancel-request-to-order
pairing (no client_order_id available) is now validated for temporal sanity rather
than trusted positionally, and falls back to submit+order_timeout_seconds for all
canceled orders in the trial if any pairing fails validation.

Also fixes, per both reviews:
- partial-fill timestamps now come from the actual OrderFilled event(s)
  (sim_by_id["fill_ts_ns"]), not order.ts_last, which could surface a later
  cancel's timestamp as the fill time.
- README's per-order table and headline numbers are now generated from, and a new
  test cross-checks them against, the committed receipt (was stale: -0.84s vs.
  the receipt's -1.093899s for order 3).
- argv redaction closed structurally: allow_abbrev=False rejects --pag/--ou/--rec
  outright, and the recorded argv is built from the parsed namespace
  (redact_args), not scanned from raw argv text.
- stdout_sha256 now hashes the exact bytes written (including print's trailing
  newline); exit_code (always a misleading constant 0, since a failed run raises
  before a receipt is written) is removed; alpaca_py_version moved out of
  data_provenance into a new runtime_environment section with a note that this
  script fetches via urllib directly, not alpaca-py.
- os.umask(0o077) is now scoped and restored, not left changed for the rest of
  the process.
- checksum-ledger and "the suite recomputes report hashes" claims corrected to
  match what is actually demonstrated (same-page reproducibility, not
  independent-request reproducibility; a new gated test actually reruns
  run_replay from the retained pages and compares report hashes to the receipt).
- the credential-loader-never-called claim is now verified by pre-seeding
  sys.modules with a fake runner.credentials() that raises if called, not just
  by asserting main() returns 0.
- the M1 fixture no longer submits exactly on a quote timestamp (which could not
  have distinguished exact-instant scheduling from quote-arrival polling); it now
  asserts the applied-decision's clock_ts_ns equals the scheduled ts_ns exactly.
- reproduce snippet no longer interpolates $PRIVATE_CACHE_DIR inside a quoted
  heredoc (which raised FileNotFoundError); the scratch-receipt path is now
  passed as argv and read via sys.argv[1].

New tests: cancel-boundary (a canceled sim order must not fill on a later
marketable quote), partial-fill-then-cancel (native and synthetic), BUY/SELL
slippage sign assertions on compare_orders' output, ambiguous-cancel-match
refusal, clock provenance, argv-redaction abbreviation/equals-form coverage,
report-hash reproducibility, and README-vs-receipt consistency. Three
independent in-memory mutations (omitted cancellation, halved latency
magnitude, reversed slippage side at the compare_orders call sites) were
applied to scratch copies of replay_compare.py and confirmed killed by their
respective new tests (cancel-boundary, latency-flip-bisection, BUY/SELL
slippage-sign), with no false failures against the unmutated source.

73 tests pass on both system python3 (8 skipped: pinned-runtime-only) and the
pinned runtime (nautilus-trader==2.0.0rc5, all 73 run). validate.py,
validate_catalogs.py, landscape.py, evidence_manifest.py --check,
verdict_review_gate.py and trading_gates.py --check all pass.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…, partial-fill honesty, mutation gaps

Both reviews found the prior round's bisection labels backwards, the latency
disclosure incomplete, and several test/wording gaps that let real mutations escape.

H1/bisection direction: bisect_fill_agreement_flip always labeled the lower latency
endpoint "agrees" and the higher one "disagrees", regardless of which way the actual
flip ran. For this trial it is the opposite (disagrees below the boundary, agrees
above it -- a lower-latency sim fills an order paper did not). The function now
returns each endpoint's actual measured agreement explicitly (lo/hi, each
{latency_ns, agrees}) instead of assuming a direction; the receipt and README are
corrected to match, and order 5 is now documented (and receipt-verified, not
assumed: independent_flip/depends_on_client_order_ids, computed by re-running the
replay with order 4 removed) as a dependent consequence of order 4's flip, not an
independent second one.

Latency disclosure completed: the pinned engine's advance_time_impl settles ALL
instruments' due timers together at each processed event, not just "the next event
for that instrument" as previously stated -- reproduced exactly as the reviewer
described (order A, quotes at 0/100ms, submitted at 10ms with 20ms latency, fills at
50ms against its existing book when order B, a different instrument, is submitted at
50ms) and added as a native test.

Partial-fill fixture made honest: the current engine configuration
(liquidity_consumption=False, the declared no-partial-fill baseline) ignores quoted
size entirely and always fills in full, so it cannot natively produce a
partial-fill-then-cancel case -- documented as such (with a test asserting the
full-fill boundary directly) rather than silently passing on a fixture that never
exercised the case. The fill_ts_ns extraction that matters for that case is now
factored into a standalone summarize_sim_order() function and tested directly
against constructed OrderFilled/OrderCanceled/OrderRejected events, independent of
the native engine's current boundary -- this is the test that actually kills a
ts_last-revert mutation now.

Other fixes: cancel-request pairing validation now checks every order (not just
canceled ones), catching a cancel request that lost its race to a fill from being
silently absorbed by a different canceled order; clock_provenance's submit pairing
is now count-checked; the host-vs-broker clock offset is now stated as a lower bound
(host stamps before send, broker stamps after receipt); "decision-to-fill latency"
reworded to "broker submission-to-fill interval" (both timestamps are broker-
reported); the four-fill range corrected to 0.65-1.09s (was excluding order 5's
0.648s); the "processed the cancel before a fill" claim removed as unmeasured;
--trial/--receipt are now trimmed to repo-relative/basename in argv instead of
recorded verbatim; sweep points now carry full per-order rows, not just aggregates,
so every per-order figure cited in prose is traceable to receipt data; stdout is
now written with sys.stdout.write (works when stdout has no .buffer attribute, e.g.
under `python -m unittest -b`, which previously raised AttributeError after the
receipt was already saved).

Test-order-dependence fixed: the umask-restoration test previously compared against
whatever the ambient process umask happened to be, so it passed even without a
restore if an earlier test's main() call had already left the process umask
changed; it now sets a known, distinctive umask immediately before the call.

The five mutations from the reviewer's mutation harness (halved latency, ts_last
revert, umask not restored, stdout hash without the trailing newP, bisection labels
swapped) are now each killed by a specific behavioral test, not only by the
runner_sha256 hash-equality test -- verified by rebuilding each mutant in an
isolated mirror tree and running the full suite against it.

92 tests pass on system python3 (12 skipped: pinned-runtime-only) and on the pinned
runtime (nautilus-trader==2.0.0rc5, all 92 run, including under `python -m unittest
-b`). validate.py, validate_catalogs.py, landscape.py, evidence_manifest.py --check,
verdict_review_gate.py and trading_gates.py --check all pass.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… shifted-flip detection, exact stdout bytes

Both reviews confirmed round 3's core fixes reproduce; this round corrects remaining
precision issues and closes the last surviving mutations.

1. README wrongly blamed order 1 for the 100ms sweep-point price outlier; the
   receipt's own per-order rows show order 1 is unchanged across 50-650ms while
   order 2 changes specifically at 100ms (120.55 at neighboring 70/250ms vs 120.54
   at 100ms) -- order 2 is what makes 100ms an outlier relative to its neighbors.
   Corrected in both the README and the test comment/assertions that had the same
   error.

2. Settlement-semantics wording was imprecise: "next event for that instrument"
   understated that eligible settlement events are specifically due order-command
   TIMERS (any order's submit/cancel being applied), not any event -- a plain
   market-data quote for another instrument does not trigger cross-instrument
   settlement. Verified and added as a new native quote-only control test
   alongside the existing timer test; cited crates/backtest/src/engine.rs
   L1559-1585/L1716-1747; updated the receipt's own `latency_model_semantics`
   metadata string (previously stale) and regenerated.

3. Cancel-request pairing rewritten around a sound rule (a cancel request is
   attributed to an order only if it is the *unique* open, not-yet-terminal order
   across the whole trial at that instant, chronologically evaluated so an
   earlier-resolved canceled order becomes terminal for later requests) --
   replacing the previous heuristic, which both wrongly accepted a race-lost
   cancel for an unrelated earlier-submitted filled order and wrongly refused a
   valid timeout cancel merely because another symbol's unrelated order was
   submitted in between. New behavioral tests reproduce both of the reviewer's
   exact scenarios plus the input-order-independence (tie) case, a case where two
   requests matching the same order leave another unmatched, and a case where a
   long-open filled order could otherwise steal a pairing slot from a genuinely
   canceled order -- all of which the code now refuses (never guesses, never
   raises) rather than mis-accepting.

4. `clock_provenance()` no longer reports offsets from a truncated, misaligned
   zip when submit-request and order counts disagree (a constructed case reached
   ~195 seconds of bogus "offset"); it now reports `null` with an explicit
   `..._unavailable_reason`. Both the README and a new test (which forces
   `counts_match=True` to confirm the offsets are genuinely gated on it) cover
   this.

5. `classify_flip_dependence` now scans the entire declared latency sweep for the
   counterfactual (other order removed) run, not just the original bisection
   bracket's two endpoints, and retains every counterfactual observation in the
   receipt (`counterfactual_sweep`). Probing only the original endpoints could
   misread a flip that merely *shifted* elsewhere in the sweep as one that
   disappeared; a new pure-Python test (via a controlled fake of the underlying
   per-latency check, no native runtime needed) constructs exactly that shifted
   case and confirms it is still correctly reported independent.

6. `stdout_sha256` now hashes the exact bytes written to `sys.stdout.buffer` when
   one exists (the normal case for a real process); only when it doesn't (e.g.
   unittest's `-b` StringIO capture) does it fall back to text-mode `.write()`,
   and the receipt now records which basis applies (`stdout_sha256_basis`:
   `exact_bytes_written` vs. `utf8_lf_normalized_text`). New tests cover both
   paths, including one whose fake stdout deliberately mangles newlines in its
   text `.write()` to prove the buffer path is what actually gets used.

7. Two previously-surviving mutations (halving the latency actually passed to
   run_replay inside the sweep loop specifically, and dropping per-order rows
   from sweep points) are now killed by new tests that call run_latency_sweep
   live against the retained trial, rather than only reading the already-generated
   committed receipt (which a code mutation in the generator can't affect).

8. "Moving the cancel instant later within the plausible clock-offset range"
   was backwards: the host clock leads the broker clock, so the broker-clock
   instant corresponding to a recorded cancel request is earlier, not later,
   than the raw host-clock number used. Corrected in both the docstring and the
   README.

Also: the cancel-pairing rewrite's two innermost per-request guards ("target must
be a canceled order", "target not already paired") were found to be provably
subsumed by the algorithm's final accumulated-pairing-equals-canceled-ids check
for every reachable single-request-window scenario; removed as redundant, with a
mutation-tested exception (a filled order open across multiple request instants
can still take a pairing slot meant for a genuinely canceled order) that only the
final check catches -- confirmed by a dedicated new test and the mutation run
below.

Every mutation from both reviewers' mutation harnesses (23 total, including this
round's new ones for items 1-7 above) is now killed by a specific behavioral
test, verified by rebuilding each mutant in an isolated mirror tree and running
the full suite against it.

103 tests pass on system python3 (16 skipped: pinned-runtime-only) and on the
pinned runtime (nautilus-trader==2.0.0rc5, all 103 run), with and without
`python -m unittest -b`. validate.py, validate_catalogs.py, landscape.py,
evidence_manifest.py --check, verdict_review_gate.py and trading_gates.py
--check all pass.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… honest test comment, pairing-rule assumptions

Three small Codex fixes plus one Claude nit, all confirmed empirically before writing:

1. Settlement wording (replay_compare.py:1115, README:132, receipt
   latency_model_semantics) understated the eligible triggers as only
   order-command timers. There are two: (a) an order's own instrument's next
   quote (what produces order 3's 266.9ms/466.4ms lags when no timer
   intervenes), and (b) any due clock timer the engine processes at all, from
   any source, including one with no order effect whatsoever -- verified with a
   new native test that schedules a bare no-op timer at 50ms (via a new,
   test-only extra_timers_ns hook on run_replay, empty by default) and confirms
   it alone moves order A's fill from 100ms to 50ms, exactly like a real order's
   decision timer would. A foreign instrument's quote alone still does neither.

2. stdout_sha256_basis selection used hasattr(sys.stdout, "buffer") while the
   actual write used getattr(..., "buffer", None) is not None -- these disagree
   whenever a wrapper has a buffer attribute that is itself None. Both now use
   one condition, computed once. New test uses a fake stdout with buffer = None
   to confirm the recorded basis and the actual write path agree.

3. A test comment claimed its fixture could only be caught by the accumulated-
   pairing check; tracing it through shows the *second* request actually finds
   zero open orders and is refused by the primary per-request check first.
   Corrected the comment to say so (the fixture that genuinely requires the
   accumulated check, added last round, is a different one and its comment was
   already accurate).

4. The cancel-pairing README called the open-order-uniqueness rule "sound"
   without qualification. It is sound only under three assumptions (one cancel
   request per canceled order; no un-logged broker-side cancellations;
   host/broker clocks aligned within the pairing tolerance), none of which the
   code checks. Documented both, plus two constructed counterexamples: (a) a
   repeated DELETE for one order paired with a different, un-logged-cancel
   order submitted in between; (b) a DELETE that loses its race to a fill
   inside the measured >=41ms host-clock lead. Noted that logging
   client_order_id on cancel requests (adaptive-paper/transport.py:502 calls
   before_request(kind) with no order identifier) would remove the heuristic
   entirely. Confirmed (not assumed) that this retained receipt is unaffected:
   order 4 is the only open order at its cancel-request time in this trial.

105 tests pass on system python3 (18 skipped: pinned-runtime-only) and on the
pinned runtime (nautilus-trader==2.0.0rc5, all 105 run), with and without
`python -m unittest -b`. validate.py, validate_catalogs.py, landscape.py,
evidence_manifest.py --check, verdict_review_gate.py and trading_gates.py
--check all pass.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Scout and others added 3 commits September 24, 2026 18:15
The host clock leads the broker's, so a race-lost cancel request appears
after the fill, which excludes the targeted order and permits misattribution.
The previous text described the opposite direction, which yields a refusal.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gitleaks' generic-api-key rule flagged two 32-hex request-cache digests stored
under a field named "key" (a false positive; they are sha256 prefixes of the
request path and parameters). Renamed in the receipt-facing page events only;
the private cache ledger format is unchanged. Receipt regenerated with --replay;
only the field names, runner_sha256 and run-local times changed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1461732

Follows the repository's .gitleaksignore convention for reviewed historical
false positives: exact commit:path:rule:line fingerprints only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@seathatflowsinourveins

Copy link
Copy Markdown
Owner Author

Superseded by #218. It is the same final tree, carried as one commit on current main. Commit 1461732 on this branch stored two request-cache digests in the receipt under a field named key. gitleaks' generic-api-key rule flags them, and .gitleaksignore only accepts fingerprints for the two reviewed narrative files (tests/test_gitleaks_config.py), so the fix is a clean history rather than an ignore entry. The review rounds and per-round commits stay here for reference.

🤖 Generated with Claude Code

seathatflowsinourveins added a commit that referenced this pull request Sep 24, 2026
…ough NautilusTrader rc5 (audit gap #7) (#218)

Replays paper trial 20260923g-main-passed (5 orders) through NautilusTrader 2.0.0rc5's simulated exchange on the same SIP quotes. Agreement is 3/5 at 0-50 ms latency and 5/5 from 70 ms, with a bisected flip at 69.217 ms: order 4 was marketable for 69.273 ms after submit, and order 5 depends on it. Engine settlement semantics, clock provenance and the cancel-pairing assumptions are disclosed. This is one trial and an agreement measurement, not a calibration. Reviewed across five rounds by Claude and Codex (#217).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/sim-paper-fill-compare-20260924 branch September 25, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant