Skip to content

The NautilusTrader boundary

VerifiedOwner Backend / platformLast verified backend@efa38e04e2db37a444e9f17100323c2ad4b83647 nautilus@2.0.0rc3

ONIX's backend is built as an application and contract layer around one exact, pinned NautilusTrader v2 release. This page states what that pin is, what ONIX consumes from it unchanged, where ONIX deliberately extends the official surface, and the one bounded support difference ONIX maintains privately.

The pin

Package nautilus-trader (PyPI)
Version 2.0.0rc3
Source commit 648970ce64a304d93da0a29320cb6e19b905fa39
License LGPL-3.0-or-later
Locked by python/uv.lock
Official docs https://nautilustrader.io/docs/
Official source https://github.com/nautechsystems/nautilus_trader

This is a release-candidate pin, accepted deliberately (ADR 0001): the artifact is depended on by version and hash, and the ONIX Rust workspace declares zero Nautilus dependencies — Nautilus enters the build only as a Python wheel, consumed from python/, never statically linked into an ONIX Rust crate. That split exists for two independent reasons: Nautilus owns the trading domain and an ONIX crate that knew about Portfolio or OrderFactory would be doing Nautilus's job badly, and consuming an LGPL library dynamically from Python (rather than statically from Rust) is the ordinary, well-understood boundary for that license.

"Never forked" is not the accurate description of the whole picture — see the private support boundary below. For the macOS/arm64 development platform, the wheel is the ordinary, unmodified public PyPI artifact. For Linux/x86_64 — the platform the deployment envelope actually targets — ONIX resolves nautilus-trader from a separate, non-public wheel path carrying one narrow, private patch. The accurate statement is: official base plus one surfaced private Linux patch, with no long-lived public fork — not a blanket claim that the upstream wheel is globally unmodified. No conclusion about licensing or legal obligations is drawn on this page or anywhere in this documentation set; a private, source-auditable, narrowly-scoped patch is described here only as an engineering fact, and any licensing question it may raise is explicitly out of scope for this documentation.

For upstream behavior — API surfaces, adapter configuration, venue capability, migration notes — this page and the rest of the backend section link to the official Nautilus documentation and source rather than reproducing it. Where ONIX's own source cites a specific upstream file or line for a factual claim, that citation is to the pinned commit above, not to develop or latest.

What ONIX takes from upstream unchanged

Per the repository's own system-boundary statement, Nautilus is the trading engine, full stop: instruments, market data, aggregation primitives, the clock, cache, portfolio, accounting, risk, orders, fills, positions, execution, and runtime (LiveNode) lifecycle are all Nautilus's. ONIX's durable catalog is a thin, typed façade over Nautilus's own ParquetDataCatalog — it adds no custom Parquet layout, compaction, sharding, or archival logic of its own (see data/catalog.md). Derived chart resolutions are Nautilus's own TimeBarAggregator/composite-bar-type mechanism, not a re-implementation (see data/aggregation.md). Backtests run through the official BacktestNode fed from the same catalog, and every reported order/fill/position/account value is read verbatim off official Nautilus objects — no ONIX recomputation of any trading statistic (see trading/backtesting.md).

Where ONIX extends the official surface

Nautilus's core is venue-agnostic; official adapters translate each venue into its common data and execution interfaces, and ONIX profiles select and configure those adapters (see venues/onboarding.md). Concrete ONIX extensions on top of that, verified in source at this pin:

  • Sharded multi-client market data. For at least one venue, ONIX registers several official data-client instances for one integration and routes instruments across them by a deterministic hash, using first-class add_data_client(..., routing=...) / per-subscription client_id= parameters Nautilus already publishes. The mechanism is canonical upstream API; the reason (bounding a reconnect-resubscribe frame under a venue's own message-size cap) is an ONIX-local adaptation to an observed adapter limitation, not a fork of adapter code.
  • A structurally-enforced public-data/execution split. A wrapper around LiveNode.builder(...) makes add_exec_client(...) — the one call that registers a real venue execution client — raise immediately for any node built through it; Nautilus's own simulated execution (add_simulated_exec_client) remains reachable. See trading/execution-runtime.md.
  • A synchronous runtime host chosen over the async one. RC3 removed LiveNode.start()/ poll(). ONIX drives the official blocking run() surface through one host object rather than the official run_async() coroutine, because a measured GIL/native-waker lock-order inversion in the pinned wheel's run_async() driver stalls multi-client connects; run() is clean on the identical composition. This is a choice between two official run surfaces, not a patch to either. See runtime/index.md.
  • Coverage, hydration and gap accounting. Per-instrument subscribe/flow accounting, retry-safe historical hydration, and derived-resolution gap withholding are ONIX-owned bookkeeping layered on top of Nautilus's data delivery — Nautilus does not provide these itself. See data/ingestion.md.
  • Immutable, content-addressed strategy revisions and an admission gate. Nautilus provides Strategy/StrategyConfig and BacktestNode; ONIX's Strategy Studio adds versioned, content-hashed revisions with a demand-sealing and admission mechanism that is the sole door through which a revision becomes an executing child process. See trading/strategy-authoring.md.

Concern → ownership table

Concern Owner
Instrument definitions, clock, cache, portfolio, accounting upstream
Market-data delivery, subscription mechanics, reconnection upstream (per official adapter)
Bar aggregation math (TimeBarAggregator, calendar alignment) upstream
Parquet on-disk layout and read/write API upstream (ParquetDataCatalog)
Orders, fills, positions, risk engine, execution clients upstream
LiveNode lifecycle states and control surface upstream
Which run surface (run() vs run_async()) ONIX drives extension (ONIX operational choice)
Multi-client instrument sharding for one integration extension (canonical API, ONIX-local reason)
Public-data/execution structural separation extension (ONIX-only)
Coverage, hydration, gap/duplicate/out-of-order bookkeeping extension (ONIX-only)
Content-addressed strategy revisions and admission gate extension (ONIX-only)
Screener feature registry and confluence scoring extension (ONIX-only)
Governed /v2 gateway contract and schema set extension (ONIX-only)
Hyperliquid subscription-acknowledgement lifecycle on Linux extension, private support boundary (below)

The private support boundary

python/uv.lock resolves nautilus-trader from two different sources depending on platform: the public PyPI wheel for macOS/arm64 (used for local development), and a separate, digest-addressed wheel path for Linux/x86_64 — the platform the deployment envelope actually targets. The Linux path is not the public PyPI wheel.

Stated at the boundary this documentation is authorized to describe: ONIX maintains a private, source-auditable Linux build of NautilusTrader 2.0.0rc3 carrying one narrow, additional patch to the Hyperliquid adapter's subscription-acknowledgement (SubscriptionState) lifecycle. This patch is not publicly distributed. Its contents, its exact upstream diff, the build recipe that produces it, and any digest identifying the resulting artifact are deliberately withheld from this documentation and from every other publicly-readable surface. The backend's own source is explicit that this identity check exists specifically to prevent an environment running the ordinary public wheel from being trusted as if it were running the patched one — every verification path here fails closed rather than assuming the patch is present.

Scope of the "no other modification" claim. This documentation's search for a second private patch was bounded to the pinned repository tree at commit efa38e04e2db37a444e9f17100323c2ad4b83647 — a text search for patch/vendor/private-wheel naming conventions across that tree, not an audit of the wheel's own compiled bytes and not a search of any system outside this repository. Within that bounded search, everything else described as "extension" above is ONIX application code calling official, unmodified Nautilus APIs, not a change to Nautilus itself. A private patch introduced after this pin, maintained entirely outside this repository, or embedded in the wheel without a corresponding source-tree marker would not be visible to a search of this shape — this documentation states what it found, not a proof that nothing else exists.

What this means for support

If current first-party exchange documentation and the locked, unmodified adapter disagree, that is reported as a precise adapter gap rather than concealed behind an ONIX-local workaround (a real example — the sharded multi-client entry above — was adopted only after a time-boxed search of upstream issues/PRs found no fix to adopt). The one exception to "unmodified adapter" is the private Hyperliquid patch described above, which is scoped to acknowledgement lifecycle only and is bounded, source-auditable, and not part of the public Nautilus distribution.

Evidence and source pins for this page

Verified. Current behaviour, confirmed in source at the pinned commit.

Verified on against the following immutable sources:

  • backend@efa38e04:AGENTS.md
  • backend@efa38e04:docs/decisions/0001-nautilus-v2-dependency.md
  • backend@efa38e04:python/uv.lock
  • backend@efa38e04:python/src/onix_engine/spine/hyperliquid_patched_runtime.py

Status tokens are defined on the documentation and status model page. Every pin on this site is listed under versions and source pins.