Skip to content

IBKR paper orders through NautilusTrader 1.231.0's IB engine, with an after-hours plan - #147

Merged
seathatflowsinourveins merged 9 commits into
mainfrom
claude/ibkr-paper-orders-20260923
Sep 24, 2026
Merged

seathatflowsinourveins merged 9 commits into
mainfrom
claude/ibkr-paper-orders-20260923

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Owner

What

  • A bounded paper-order harness (blueprints/us-equities/engine-nautilus/ibkr-paper-orders/) that runs four predeclared cases (accept resting, cancel resting, marketable buy fill, flatten) for 1 SPY share through NautilusTrader 1.231.0's Python IB adapter on a paper IB Gateway (port 4002, DU account). The 2.0.0rc5 destination still blocks stock orders (nautilus_trader#4983).
  • Receipt of the 2026-09-23 regular-session run: passed, flat at the end. The earlier refusal caused by the Read-Only API setting is retained too. The ibkr-local-acceptance gate stays not_established.
  • plan-post.json (revision 4, frozen before its first run): identical bounds and cases, with the session set to 16:00-20:00 ET. Every order carries IBOrderTags(outsideRth=True), and today's window comes from the contract's tradingHours. Only the two predeclared plans can be selected.

Checks

  • tests/test_ibkr_paper_orders.py: 73 OK under the pinned 1.231.0 environment. This includes a backtest in which every order is tagged outsideRth under the after-hours plan and untagged under the regular plan.
  • python3 scripts/validate.py passed; guarded gitleaks on origin/main..HEAD found no leaks.
  • Rebased onto main (includes verdict-review-gate).

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5468df17c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread blueprints/us-equities/engine-nautilus/ibkr-paper-orders/run.py
Comment thread blueprints/us-equities/engine-nautilus/ibkr-paper-orders/run.py
Comment thread blueprints/us-equities/engine-nautilus/ibkr-paper-orders/run.py Outdated
Comment thread blueprints/us-equities/engine-nautilus/ibkr-paper-orders/run.py
Comment thread blueprints/us-equities/engine-nautilus/ibkr-paper-orders/README.md
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-23T23:10:06.545121Z c5468df PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

… adapter (not yet run)

Steps 2-3 subset of engine-nautilus/acceptance-plan.md section 5 on the paper IB
Gateway through NautilusTrader's own IB execution engine. The pinned 2.0.0rc5
Rust adapter denies stock orders locally (nautilus_trader#4983); 1.231.0 is the
newest stable and still ships the Python adapter on the official ibapi.

Frozen plan (revision 3): SPY only, 1 share, at most 6 orders, 1000 USD notional
cap, RTH with a 10-minute close buffer and contract liquid hours (fail closed),
paper port plus a single DU account checked read-only immediately before, cases
C1 resting buy at half the bid, C2 cancel, C3 marketable buy, C4 flatten, a
provisional cleanup_required receipt before the node, an independent official-
ibapi flat proof on every exit path, bounded re-cancels and flatten retries.

Built and reviewed through two independent rounds (order-safety and API lenses,
then a pre-live safety pass); every finding fixed, with offline tests that fail
without each fix (65 tests; simulated-venue flows under 1.231.0 are synthetic,
not IBKR evidence). Known minor signal-handling residuals are in the README.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…0's IB engine (gate unchanged)

13:53 ET on the paper IB Gateway 10.50.1e from a read-only copy of c23525e:
passed in 11.5 s. C1 resting SPY buy accepted, C2 canceled, C3 marketable buy
filled 768.56, C4 flatten filled 768.50; net -2.08 USD after 2.02 USD
commissions; 3 of 6 orders; independent official-ibapi flat proof 0 positions
and 0 open orders; receipt holds no account ids or balances. An earlier run
refused while the Gateway API was Read-Only (IB 321), before any order.

ibkr-local-acceptance stays not_established: reconnect with an open order,
restart reconciliation and the step-4 kill switch are not run yet, and
1.231.0 is not the pinned 2.0.0rc5 destination (nautilus_trader#4983).

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

- plan-post.json (revision 4): revision 3 with only the session changed to
  16:00-20:00 America/New_York, outside_rth true, contract tradingHours.
- validate_plan accepts exactly the regular (09:30-16:00, no outsideRth, liquidHours)
  or after-hours (16:00-20:00, outsideRth, tradingHours) session.
- Every order builder passes IBOrderTags(outsideRth=True) under the after-hours plan and
  no tags otherwise; the data client's use_regular_trading_hours follows the plan.
- run --plan chooses between the two predeclared plans only; the receipt records the
  plan's sha256 and the contract-hours field used.
- Tests: plan equivalence and refusals, trading-hours window and refusal, predeclared
  plan choice, builder source check, and a 1.231.0 backtest showing every order tagged
  outsideRth under the after-hours plan and untagged under the regular plan. 73 OK.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…lete on the flatten step timeout)

evidence/receipt-20260923-post-incomplete.json from a frozen copy of c5468df (sums in
evidence/frozen-c5468df1.SHA256SUMS; 7 files match git archive). 18:58 ET, plan-post.json:
C1 resting buy accepted outside RTH, C2 cancelled, C3 marketable buy filled 768.01, C4 flatten
timed out at 45 s, cleanup filled 767.96; realized -2.07 USD with commission; flat proof passed;
no IB 399/2109 warnings; no account id in receipt or log. ibkr-local-acceptance note appended,
status unchanged (user decision).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nmeasured; record the plan-note time erratum

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…le run state, notional cap, commission gate, retained bytes

- refused_unpinned_runtime (exit 3) before any connection unless NautilusTrader and ibapi
  are exactly the plan's engine versions; versions_fn injectable for tests.
- The provisional cleanup_required receipt carries ctx.summary() and is rewritten on every
  case change, order, event and fill (RunContext.on_change), so a kill mid-run leaves the
  orders and fills on disk; cleared before the final receipt.
- OrderBudget enforces max_notional_per_order_usd on every reservation, including the C4
  flatten and cleanup sells; a reservation without a price is refused.
- A missing or adapter-zero commission sets roundtrip.commission_unresolved and blocks passed.
- evidence/harness/ retains the exact run.py and plan bytes behind all three receipts (named by
  sha256 prefix); a test resolves every receipt's harness_sha256 and plan_sha256.
- Backtest tests give the simulated venue a fixed 1 USD fee so the passed path stays covered.

Tests: 78 OK under nautilus_trader 1.231.0; 78 (13 skipped) under system python3.
validate.py passed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tence; name a cleanup notional refusal

Independent review follow-ups (none blocking): start_cleanup, each cancel request, _finish and
the end of the node phase now call ctx.changed(); changed() catches any exception; a notional
refusal during cleanup finishes as cleanup_notional_refused; README states that zero-commission
plans cannot pass and that the atomic writes have no fsync. New test covers the cleanup-start
write, the no-op on an already-ended case, and a failing writer.

Tests: 79 OK under 1.231.0; 79 (13 skipped) under system python3. validate.py passed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ain (after #149)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@seathatflowsinourveins
seathatflowsinourveins force-pushed the claude/ibkr-paper-orders-20260923 branch from 4a31d1f to 37d7330 Compare September 23, 2026 23:44
…acceptance gate unchanged)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@seathatflowsinourveins
seathatflowsinourveins merged commit a23ea55 into main Sep 24, 2026
23 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/ibkr-paper-orders-20260923 branch September 24, 2026 00:05
seathatflowsinourveins added a commit that referenced this pull request Sep 24, 2026
…h merged evidence (#170)

Records only, no gate status change: runtime-target IBKR cites the passed 1.231.0 paper receipt (#147) while rc5 local acceptance stays not_established (blocker nautilus#4983); dashboard checkpoint cites the 32-layer sweep (#153) and the #162 mover research result. Independently reviewed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Oct 10, 2026
Peer-path correction acknowledged by the CC as #984's owner in
correction #147 (2026-10-10T21:40Z).

Git 2.53.0's default pathspec '*' can match directory separators;
':(glob)' uses FNM_PATHNAME, so its wildcard cannot cross '/'.
Primary source: git/git v2.53.0, Documentation/glossary-content.adoc,
the pathspec and glob sections.

Reader references at merged main a7c15bd:
tools/local-pages/architecture_sources.py:375 and
tools/local-pages/architecture_builder.py:241 both use top-level
Path.glob('*.json'). The test now uses the equivalent supported
Git pathspec, ':(glob)catalogs/landscape/*.json'.

Regression evidence: the exact native inventory method from merged
main a7c15bd, compiled in memory with its policy and committed catalog
inputs, fails one test before on the nested gap-closeouts/schema.json
and passes one test after changing only the pathspec literal; zero
errors in either probe. The complete requested architecture, closeout
and workflow modules then pass 170 tests with one existing skip.

Integrate the already-landed #984 baseline through this one forward
merge on d965908, because the peer test did not exist in its earlier
base. Relative to Git's clean automatic integration, authored changes
are only the single inventory line and its files[] registration.
seathatflowsinourveins added a commit that referenced this pull request Oct 11, 2026
Peer-path correction acknowledged by the CC as #984's owner in
correction #147 (2026-10-10T21:40Z). This commit carries, as its own
linear commit on main eb31d23, the fold that a08b616 authored inside
its forward merge of d965908 and a7c15bd: the single inventory line
and its files[] registration, re-registered through
host_receipts.register_file and evidence_manifest.py --write.

Git 2.53.0's default pathspec '*' can match directory separators;
':(glob)' uses FNM_PATHNAME, so its wildcard cannot cross '/'.
Primary source: git/git v2.53.0, Documentation/glossary-content.adoc,
the pathspec and glob sections, re-read from the installed Git 2.53.0
gitglossary(7).

Reader references, unchanged from a7c15bd to main eb31d23:
tools/local-pages/architecture_sources.py:375 and
tools/local-pages/architecture_builder.py:241 both use top-level
Path.glob('*.json'). The test now uses the equivalent supported
Git pathspec, ':(glob)catalogs/landscape/*.json'.

Regression evidence carried from a08b616, measured at main a7c15bd:
the exact native inventory method from merged main, compiled in memory
with its policy and committed catalog inputs, fails one test before on
the nested gap-closeouts/schema.json and passes one test after
changing only the pathspec literal; zero errors in either probe.

Re-measured on this linear branch at parent e1c6df7
(2026-10-11T00:08Z): git ls-files lists 22 paths for
'catalogs/landscape/*.json', including
catalogs/landscape/gap-closeouts/schema.json, and 21 top-level paths
for ':(glob)catalogs/landscape/*.json'.
tests.test_local_pages_architecture_landscape_exclusions ran 7 tests
with 1 failure on that nested schema.json before this change, and
7 tests OK after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Oct 11, 2026
Peer-path correction acknowledged by the CC as #984's owner in
correction #147 (2026-10-10T21:40Z). This commit carries, as its own
linear commit on main eb31d23, the fold that a08b616 authored inside
its forward merge of d965908 and a7c15bd: the single inventory line
and its files[] registration, re-registered through
host_receipts.register_file and evidence_manifest.py --write.

Git 2.53.0's default pathspec '*' can match directory separators;
':(glob)' uses FNM_PATHNAME, so its wildcard cannot cross '/'.
Primary source: git/git v2.53.0, Documentation/glossary-content.adoc,
the pathspec and glob sections, re-read from the installed Git 2.53.0
gitglossary(7).

Reader references, unchanged from a7c15bd to main eb31d23:
tools/local-pages/architecture_sources.py:375 and
tools/local-pages/architecture_builder.py:241 both use top-level
Path.glob('*.json'). The test now uses the equivalent supported
Git pathspec, ':(glob)catalogs/landscape/*.json'.

Regression evidence carried from a08b616, measured at main a7c15bd:
the exact native inventory method from merged main, compiled in memory
with its policy and committed catalog inputs, fails one test before on
the nested gap-closeouts/schema.json and passes one test after
changing only the pathspec literal; zero errors in either probe.

Re-measured on this linear branch at parent e1c6df7
(2026-10-11T00:08Z): git ls-files lists 22 paths for
'catalogs/landscape/*.json', including
catalogs/landscape/gap-closeouts/schema.json, and 21 top-level paths
for ':(glob)catalogs/landscape/*.json'.
tests.test_local_pages_architecture_landscape_exclusions ran 7 tests
with 1 failure on that nested schema.json before this change, and
7 tests OK after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Oct 11, 2026
* Add the shared evidence-bound gap closeout loader

Validate dated layer closeouts through the pinned jsonschema 4.26.0
Draft 2020-12 API. Bind original crosswalk identity, registered evidence,
supported vendor sources and two passing GPT/Claude reports at the same head.
Preserve proposed/residual/blocked gaps and all current-main counts.

Retain the required failing-before controls, receipt/files compatibility
correction and final native fixture evidence. Make the existing validator
pin available through hash-pinned CI requirements.

Sources: python-jsonschema/jsonschema v4.26.0 at
a7277432b0f7bcd0551f6e589d30457017125df4, validators.py:307,348,812;
native-agent-stack main 9d4c00c,
catalog_decisions.py:57,85 and host_receipts.py:710.

Validation: 84 touched-module/inventory tests, zero skips; unchanged native
matrix check and final registered-tree FULL validation passed.

* Refresh the bounded advisory inventory for closeout reads

Account for the shared loader's eight additional input-read locations and
one measured dynamic shape in the existing repository workflow test.
Retain the historical inventory and every other script, shape, coverage
and enforcement expectation; no loader, schema or worker-policy change.

Source: native-agent-stack main 9d4c00c,
blueprints/runtime-workers/openhands/resolver/gate_reads.py:913-930.

Validation: the original assertion fails before correction; the touched
module passes 125 tests with one existing optional PyYAML skip using the
hash-pinned CI environment. Final registered-tree FULL validation passes.

* Normalize the retained advisory log endings

Remove the final empty line in each native advisory test log to satisfy
the repository whitespace contract. Refresh the explicit file bindings
and retain the prior hashes. Test assertions and results are preserved.

Validation: final registered-tree FULL validate passed after normalization;
the cached whitespace gate must pass before this forward commit.

* Correct the shared closeout registry and review-credit contract

Use files[] as the hash authority and model real metadata-only receipt
rows in the fixtures. Keep unreviewed residual/blocked records proposed
without changing counts or prior credit. Pin each missing closeout guard.

Use the existing missing-library SkipTest convention and install the
hash-locked schema validator before freshness discovery. Document the
Python 3.10 dependency floor and correct the upstream/native citations.

Regenerate the worker advisory snapshot through the native derivation and
remove hard-coded increments. Retain the prior snapshot and fail-before
measurements. Source: main 03a986e,
validate.py:665-666 and the native worker GateReads derivation;
jsonschema 4.26.0/a7277432b0f7bcd0551f6e589d30457017125df4.

Validation: required/schema-enabled modules 552 tests, 2 existing skips;
freshness-related modules 261 tests with the stale-registration case
rechecked after supported refresh; final FULL validation passed.

* Preserve the pinned freshness calendar install step

* Match architecture inventory to top-level native readers

Peer-path correction acknowledged by the CC as #984's owner in
correction #147 (2026-10-10T21:40Z). This commit carries, as its own
linear commit on main eb31d23, the fold that a08b616 authored inside
its forward merge of d965908 and a7c15bd: the single inventory line
and its files[] registration, re-registered through
host_receipts.register_file and evidence_manifest.py --write.

Git 2.53.0's default pathspec '*' can match directory separators;
':(glob)' uses FNM_PATHNAME, so its wildcard cannot cross '/'.
Primary source: git/git v2.53.0, Documentation/glossary-content.adoc,
the pathspec and glob sections, re-read from the installed Git 2.53.0
gitglossary(7).

Reader references, unchanged from a7c15bd to main eb31d23:
tools/local-pages/architecture_sources.py:375 and
tools/local-pages/architecture_builder.py:241 both use top-level
Path.glob('*.json'). The test now uses the equivalent supported
Git pathspec, ':(glob)catalogs/landscape/*.json'.

Regression evidence carried from a08b616, measured at main a7c15bd:
the exact native inventory method from merged main, compiled in memory
with its policy and committed catalog inputs, fails one test before on
the nested gap-closeouts/schema.json and passes one test after
changing only the pathspec literal; zero errors in either probe.

Re-measured on this linear branch at parent e1c6df7
(2026-10-11T00:08Z): git ls-files lists 22 paths for
'catalogs/landscape/*.json', including
catalogs/landscape/gap-closeouts/schema.json, and 21 top-level paths
for ':(glob)catalogs/landscape/*.json'.
tests.test_local_pages_architecture_landscape_exclusions ran 7 tests
with 1 failure on that nested schema.json before this change, and
7 tests OK after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Refuse conflicting receipt mirrors and unsupported validators

Fix the two P2s from the FIRST GPT read of ad2e1b1. files[] alone
supplies evidence bindings; optional receipt sha256/bytes mirrors must
agree with those bindings. Metadata-only rows remain valid. Nonempty
closeouts require installed jsonschema exactly 4.26.0 before schema or
document loading, with an actionable hash-pinned installation command.
The no-record path does not inspect package metadata.

Use CPython v3.13.16 Lib/importlib/metadata/__init__.py:980 (version)
and :49 (PackageNotFoundError), and python-jsonschema/jsonschema
 a7277432b0f7bcd0551f6e589d30457017125df4 jsonschema/__init__.py:27.
Both fetched primary source files match the installed bytes; retain
source hashes and the supported metadata API citation in the correction
receipt and decision record. No replacement validator is introduced.

The seven focused controls fail against the unchanged reviewed loader:
six assertion failures, zero errors, while equal mirrors, descriptive
receipts and the no-record behavior pass. All seven pass after the fix.
Actual Python 3.14.4/jsonschema 4.19.2 accepts the fixture before the fix
and refuses it afterward without returning a document. Actual missing-
package refusal and no-record compatibility controls also pass.

Keep the receipt key named receipt_path, distinct from the existing
filesystem iterator named path. The unchanged native worker assertion
caught four advisory locations on the unpublished preparation candidate;
the native alias control restores 330/98 with identical per-script counts
and shape multiplicities. Preserve that failure and the candidate-only
control; the final committed head is checked before the first push.

Required modules: 174 tests OK, zero skips (26 closeouts, 64 matrix,
84 validator). FULL validate: 70 components, 11466 hashed files,
4 profiles, 239 receipts, exit 0. Matrix --check: 32 rows, exit 0.
The worker snapshot remains SHA-256 8752740817bb41c1a582e33fa475e4ce4064f2ccfecadb706bce40ecb4512157,
330 locations and 98 shapes; frozen crosswalk and generated reports
remain unchanged. Preserve historical traces and refresh their source
locator and file registrations through the native registry function.

One forward commit on ad2e1b1. The GPT micro and the CC's disposition
of its prior Claude PASS remain required at this new loader head.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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