The NautilusTrader boundary¶
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-subscriptionclient_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(...)makesadd_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. Seetrading/execution-runtime.md. - A synchronous runtime host chosen over the async one. RC3 removed
LiveNode.start()/poll(). ONIX drives the official blockingrun()surface through one host object rather than the officialrun_async()coroutine, because a measured GIL/native-waker lock-order inversion in the pinned wheel'srun_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. Seeruntime/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/StrategyConfigandBacktestNode; 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. Seetrading/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.mdbackend@efa38e04:docs/decisions/0001-nautilus-v2-dependency.mdbackend@efa38e04:python/uv.lockbackend@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.