Bitnomial DCM Edition (AIEX)
A temporary US-regulated edition of AX — list Architect products on Bitnomial's DCM and introduce customers to Bitnomial's FCM — built by forking the EP3 hot-path services onto a shared ax-bitnomial client crate, to be cut away once Architect's own DCM is live.
§0Principles
This edition is a stopgap, not a platform, and every design call follows from that. The four invariants below — plus one deliberate carve-out from the first — explain the whole shape of the work; everything in the tracker is mechanics.
It's temporary, so fork — don't abstract
The edition may run only a few months, so we build separate, copy-pasted hot-path services (aiex-risk-engine, aiex-marketdata-publisher, bitnomial-order-gateway, FIX fill ingestion) on a shared ax-bitnomial client crate, rather than paying for a generic EP3↔Bitnomial abstraction we'd then have to maintain and unwind. EP3 coupling is not isolated to one adapter — it lives in identity, provisioning, instruments, lifecycle, and settlement — so a "clean adapter" would create misleading compatibility.
Exception to (1): the api-gateway is switched, not forked
The one carve-out from "fork, don't abstract." The api-gateway's EP3 surface is a small part of the whole, so instead of forking it we route through a single AX_MATCHING_ENGINE / AX_VENUE switch that fails fast on misconfig and gates EP3-only admin surfaces (price-band edits, market-surveillance alerts) off under Bitnomial. This is the one place a thin abstraction earns its keep.
FIX drop copy is the authority; BTP replies are only a low-latency hint
The protocol split assigns each job to the right channel: BTP DMA for order entry and fast accept/reject feedback, FIX 4.4 drop copy as the authoritative order/fill lifecycle source, REST for product catalog / funding rates / startup backfill, and BTP pricefeed / WebSocket for market data. Lifecycle truth never comes from the BTP reply alone.
One omnibus connection multiplexes many accounts
Bitnomial confirmed a single order-entry connection can route to many clearing accounts via an "attributed open" message (a normal Open plus an account field) reserved for FCM-class partners. So AX trades through one connection, owns its own subaccounting, and maps each AX account_id → a Bitnomial clearing account — it does not need one connection per customer.
Positions are dead-reckoned exact; only margin is approximate
AX tracks positions by exact dead reckoning from its own order-fill stream and reconciles against the FCM at end of day — positions are not "approximate," they're precise and checked. What's genuinely approximate is margin: AX may ultimately apply a different risk model than the FCM, so the intraday margin number is an estimate, not a copy of the clearing figure. Until AX is a direct DCM entity, Bitnomial's authoritative margin/settlement state is reachable only through the FCM (Dorman, via GMI) on the daily cycle.
§1Progress & Dependencies
This is not a linear sequence — it's nine parallel tracks, mostly one per forked service and one per owner, that converge on a working edition. The flat order would hide what actually matters: which tracks can run independently, and the handful of hard dependencies where one track genuinely blocks another. The dependency map shows those edges; the swimlanes below show progress per track. Snapshot 2026-06-06.
Dependency map
How the tracks block one another. Solid arrows are hard blockers (the downstream work cannot finish first); dashed arrows are foundational or soft. Node colour is status. The critical path to a demoable edition runs drop-copy → risk-engine and accounts → order-gateway, both converging — with the api-gateway seam — on Edition works E2E; the external-dependency tail then gates go-live.
tin/bitnomial-fix-dropcopy) landed on main on 2026-06-07, taking its branch-local PRs (#2237, #2196, #2193) with it — so the risk-engine cutover stack (Track D) rooted on it can now rebase onto main. The remaining integration-branch root is ababkin/md-btp-fork-2-service (#1944, Track C), still open. Landing it, plus the accounts rekey (Track G) beneath the order-gateway (Track F), is what unblocks Edition works E2E.
The shared substrate every forked service builds on — done bar BTP codec clean-ups. Unblocks all venue tracks (soft edges in the map).
A1ax-bitnomial client crate — BTP codec/session, REST, FIX wrapperdone›
The shared venue client all four services build on: the ax-btp wire crate (binary little-endian framing via binrw + tokio_util::codec, sequence IDs, heartbeats), the BTP order-entry bodies (Open/Modify/Reject/Closed/AttributedOpen), the authenticated REST client (products, orders, fills, funding, HMAC), and a FIX 4.4 wrapper. See §2b.
- Merged to main
- #1943 add
ax-btpwire crate andax-btp-mockscenario server - #1965 use
binrwandtokio_util::codecforax-btp - #2044 wrapper for Bitnomial's FIX protocol
- #2131
ax_bitnomial::restREST client (A-3491) - #2133 authenticated
/ordersendpoint - #2203 shared
ax_bitnomial::instrumentsmapping helper - #2208 BTP order-entry Modify/Reject/Closed/AttributedOpen bodies (A-3545)
A2BTP codec hardening — heartbeats, body guards, frame & status handlingTinin progress›
Make the wire layer robust against a real venue: validate heartbeat frames, bound body lengths, surface (not silently drop) corrupt order-entry frames, tolerate unknown order statuses, retry authed REST on 429, and guard order pagination. Mostly merged; a couple of clean-ups still open and two superseded spikes closed.
- Merged to main
- #2244 reject malformed BTP heartbeats
- #2246 reject oversized BTP bodies
- #2206 surface corrupt order-entry frames instead of dropping them (A-3542)
- #2207 retry authed REST on 429 and guard order pagination (A-3543)
- #2195 tolerate unknown Bitnomial order statuses
- Open
- #2245 preserve unknown BTP bodies (keep raw)
- Superseded / closed
- #2243 align fill layout with BTP docs (folded into other fixes)
- #2247 inbound BTP sequence validator (superseded)
A3ax-btp-mock scenario serverababkindone›
A4SDK leak guard — forbid bitnomial / btp in the public SDKLocdone›
A CI check that forbids the terms bitnomial and btp from leaking into the public rs/sdk — the venue is an internal implementation detail that must not surface in the customer-facing protocol. (A-3541.)
- #2204 forbid
bitnomialandbtpterms in SDK leak check
The one deliberate non-fork (§2g) plus instrument/catalog loading. The convergence integration point — epic A-3489, the only Urgent epic in the set.
B1Matching-engine / venue selection seamLocin progress›
A single AX_MATCHING_ENGINE selection seam routes the gateway to EP3 or Bitnomial and gates EP3-only admin surfaces off under Bitnomial. The seam and the EP3-surface gates are merged; the fail-fast-on-misconfig hardening (A-3515) and the data-plane parity verifier (A-3497) are still open. Epic A-3489 (P1/XL, In Progress).
- Merged to main
- #2132
AX_MATCHING_ENGINEselection seam (A-3494) - #2162 gate EP3 market-surveillance alert routes (A-3516)
- #2197 gate off EP3 price-band edit admin surfaces (A-3517)
- Open
- #2153 single matching-engine switch with fail-fast on misconfig (A-3515)
- #2240 Bitnomial data-plane parity verifier (A-3497)
B2Instruments & product catalog + price bandsLoc · ababkindone›
Load Bitnomial products from REST /product/specs/ into the instruments table via a DB-driven product map (futures + perpetual futures only; product_id is the routing key, symbol is display identity). Seed hardening and authoritative price bands on the instrument spec followed. Price-band harmonization (A-3562) has one remaining sub-item — publishing bands in the md-btp ticker (A-3563) — but the instrument-spec surface is done.
- Merged to main
- #2148 load Bitnomial instruments via product mapping (A-3492)
- #2191 repoint seed example to a real loadable product (A-3531)
- #2192 warn-only row failures on BTP instrument seed (A-3532)
- #2242 surface Bitnomial price bands on instrument spec (A-3564)
- Funding rates (REST)
- #1938 estimated funding-rate API + GUI (A-3345)
- #2140 serve estimated funding rate over WebSocket
aiex-marketdata-publisher (md-btp)
Fork of marketdata-publisher onto the BTP pricefeed. Hard-feeds the risk engine (marks) and the live exchange. Lives on an unmerged integration branch (#1944).
C1aiex-marketdata-publisher (md-btp) forkababkin · Locin progress›
Fork marketdata-publisher to consume the BTP pricefeed and publish the AX market-data protocol (top-10 aggregated depth, documented as such). The service fork lives on the long-lived ababkin/md-btp-fork-2-service branch (renamed aiex-marketdata-publisher); marks-to-Redis and a probe merged into that branch, not main. The earlier phase-by-phase md-core cutover (A-3310/3312/3313) was canceled in favor of this consolidated fork (epic A-3311 V3 "fork not abstract").
- Open — root + stacked on the fork branch
- #1944 fork
marketdata-publishertoax-md-btpwith BTP feed (root) - #1946 testcontainer integration suite (stacked)
- #2178 probe Bitnomial market-data publisher (stacked)
- Merged into the fork branch (not main)
- #2199 mirror Bitnomial mark prices to Redis (A-3537)
- Superseded / closed (phased md-core)
- #1918 md-core scaffold (A-3310, canceled approach)
- #1945 md-btp REST stats poller (superseded)
- #1919 / #1920 / #1921 / #1923 phased md proposal/adapters (drafts, superseded)
aiex-risk-engine fork
Forked risk engine cut over to Bitnomial inputs — furthest-along service fork (A-3470, In Review). Drop-copy (E) landed on main, so the cutover stack can rebase off that branch; now gated mainly on market data (C).
D1aiex-risk-engine fork + cut over to Bitnomial inputsTinin progress›
Fork ax-risk-engine and replace its EP3 venue I/O with Bitnomial inputs: a FIX ExecutionReport → calculator adapter, marks polled from md-btp's Redis (depends on Track C), REST open-orders bootstrap + ProductSpecIndex, a FIX drop-copy task bridging quickfix → tokio mpsc (depends on Track E), and an account map off logical replication (depends on Track G) — then cut run() over. The fork itself is merged (#2136); the cutover is a deep open stack that was rooted on the drop-copy branch and can now rebase onto main since #2138 landed (2026-06-07). The area saw ~7 abandoned fork attempts (#2125–#2135) before stabilizing.
| Sub-step | PR | Linear |
|---|---|---|
| FIX ExecReport → ToCalculator adapter | #2160 | A-3471 |
| Poll md-btp marks from Redis | #2156 | A-3511 |
| REST open-orders bootstrap + ProductSpecIndex | #2157 | A-3513 |
| FIX dropcopy task bridge (quickfix→mpsc) | #2158 | A-3512 |
Cut run() over to Bitnomial inputs | #2159 | A-3514 |
| Index trading accounts off logical replication | #2202 | A-3540 |
- Merged to main
- #2136 fork
ax-risk-engine→aiex-risk-engine(A-3472) - Open — cutover stack (was rooted on the now-merged drop-copy branch; rebasing onto main)
- #2160 · #2156 · #2157 · #2158 · #2159 · #2202
- Backlog: end-to-end risk smoke test (A-3475), risk-engine2 + Redis margin parity in OG (A-3473), contract-multiplier in margin/PnL (A-3544).
The authoritative lifecycle source (§2b). Root branch #2138 landed on main 2026-06-07, unblocking the risk-engine cutover (D).
E1FIX drop-copy ingestion / fill attributionTin · Michael · Locdone›
A shared FIX drop-copy initiator, a dedicated FIX consumer, and a persist-first Sink + contiguous Watermark ingest contract. Fills are single-sided and attributed to AX accounts via the order-mapping table — not paired both-sides like EP3 trade ingestion. The root branch tin/bitnomial-fix-dropcopy (#2138) merged to main on 2026-06-07, bringing the dedicated consumer, persist-first Sink/Watermark, and REST-host parameterization with it; a hardened second iteration (batched ClickHouse inserts, MsgSeqNum validation, replay/recovery) continues on the -v1 branch.
main, the risk-engine cutover stack (Track D) can rebase off the integration branch onto main.
- Merged to main
- #2138 shared FIX dropcopy initiator module (root branch, landed 2026-06-07)
- #2237 dedicated FIX consumer for Bitnomial drop copy (rode in on #2138)
- #2196 persist-first
Sink+Watermarkingest contract (rode in on #2138) - #2193 parameterize Bitnomial REST host (rode in on #2138)
- #2067 accept SPD SecurityType for spread fills (A-3413, groundwork)
- Open / draft
- #2086 port trade-engine to Bitnomial FIX 4.4 drop copy (A-3348)
- Superseded / closed
- #2184 require + validate FIX dictionary / file-store paths from env (closed)
bitnomial-order-gateway
The biggest remaining technical piece (A-3448). End-to-end PoC worked 2026-06-04, then held pending the accounts rekey (G).
F1bitnomial-order-gateway fork — PoC → productionAndrew · ababkinin progress›
Fork order-gateway: preserve the AX REST/WS order API, replace Ep3Identity with Bitnomial account/connection routing, persist the AX order_id → (connection, BTP orderId, ackId, modifyId, account) mapping, use BTP replies for fast feedback and FIX drop copy as the lifecycle authority. An end-to-end PoC worked on 2026-06-04 — a real user placed and cancelled a QQQ-PERP order via the trader GUI. The PoC base-stack PRs were then put on hold pending the account rekey (Track G).
- Open — refound stack
- #2209 refound
bitnomial-order-gatewaycrate (venue glue + tests) - #2211 order-gateway auth + users-replica (stacked)
- #2212 order-gateway PoC-0 — connectable WS + deploy (stacked)
- #2210 order-gateway open-orders cache (stacked)
- Superseded / closed
- #2075 earlier scaffold (superseded by the refound stack)
The internal mega-blocker. Rides the multi-accounts rekey; gates the order gateway (F) and feeds the risk engine's account map (D).
G1Account / identity provisioning & rekeyAndrew · Tin · Locin progress›
EP3 identity is jammed into users.ep3_username / trading_accounts.ep3_account; Bitnomial routing needs its own mapping (AX account_id → Bitnomial clearing account + connection). This rides on the separate multi-accounts rekey (splitting user_id into identity/ownership/membership) — without that abstraction the edition "is gonna really have a bad time." Bitnomial account columns + a provisioning loader are open; the gateway identity decouple (A-3495 → A-3499/A-3500) is still backlog.
- Open
- #2154 add
trading_accountsBitnomial account columns + map on load (A-3510) - #2198 provision account identity on trading accounts (A-3538, stacked)
- Backlog: decouple gateway identity from EP3 (A-3495), nullable EP3 columns + Bitnomial mapping migration (A-3499), mint native IDs + load account map (A-3500). Account-key risk-engine internal state (A-3582, owner Andrew).
The substrate the forked services deploy onto — kept separate from the live AX stack.
H1aiex instances, terraform UAT, CI/releaseMichael · Alanham · Locdone›
Standalone aiex-demo / aiex-prod instances, the bitnomial-uat terraform stack, the aiex build-and-release CI workflow (with TigerBeetle re-enabled), and a service deploy runbook.
- Merged to main
- #2047 add
aiex-prodinstance - #2060 add
aiex-demoinstance - #2090 aiex target build-and-release workflow
- #2117 re-enable TigerBeetle step in aiex image builds
- #1950 add
bitnomial-uatterraform stack - #2083 commit
bitnomial-uatlock file - #2190 aiex service deploy runbook (A-3529)
- Open / draft
- #2229 aiex GUI integration branch + build config
The external-dependency tail — blocked on Bitnomial (margin APIs, onboarding portal) and the commercial agreement. Gates go-live, parallel to the engineering tracks.
I1Position / margin reconciliation (DCO / FCM)TBDnot started›
Bitnomial's authoritative margin / settlement APIs are gated behind contract execution — AX won't get direct access until it's the actual DCM / a direct entity; reconciliation otherwise routes through the FCM (Dorman) via GMI. The plan (§2e): positions are dead-reckoned exact and reconciled against the FCM end-of-day; margin is the approximate part (AX may run a different risk model). A read-only Clearing API hookup is scoped (A-3579) but backlog. The residual risk is concentrated in margin (§3.3).
- No PRs — blocked externally on contract execution / FCM API access. Scoped: A-3579 (read-only Clearing API), A-3506 (reconcile client rate-limiting with Bitnomial's hard REST limits).
I2Customer onboarding / FCM IB flowsKevin · Brettnot started›
As Introducing Broker, AX onboards customers to Bitnomial's FCM. Bitnomial's institutional onboarding portal and a programmatic onboarding/provisioning API are not yet delivered ("as soon as they can"); today it's a manual portal workflow. The current onboarding work collects customer emails to forward to Bitnomial. Account/connection setup is treated as an ops/admin workflow, with mappings stored in Postgres.
- No PRs landed for the programmatic flow — blocked on Bitnomial's onboarding API/portal. Manual ops workflow in the interim.
I3Go-live, certification & eventual cutawayBrett · Michaelnot started›
Bring the edition to production behind a real customer, then — once Architect's own DCM is live — cut away from Bitnomial "as soon as regulatorily possible." A soft go-live target of ~mid-June 2026 ("an exchange that sort of works, with rough edges and limited functionality") was floated, but it is not a committed date and is downstream of tracks D–G and I1.
- No PRs — gated on a working order-gateway (F), reconciliation (I1), and the commercial agreement.
main (2026-06-07); C is still pooled on an unmerged integration branch, D is in flight, and F is gated behind the cross-cutting accounts rekey (G). I is the external-dependency tail (reconciliation, onboarding, go-live), blocked on Bitnomial and the commercial agreement. The hard-dependency edges (map above) are: E→D, C→D, G→F, then D, F, B → Edition E2E → go-live.
Notebook
Reference design — the mechanics and reasoning behind the tracker and the open questions. Drawn from the RFC and the team's working decisions. Sections 2a–2h.
§2aThe "aiex" strategy — fork, don't abstract
AX is an exchange built over Connamara EP3. The Bitnomial Edition (nicknamed AIEX = ax + bitnomial) lets Architect operate a US-regulated venue now — listing Architect-licensed products on Bitnomial's DCM and introducing customers to Bitnomial's FCM — while Architect's own DCM spins up. Because the edition may run only a few months, the preferred shape is separate, copy-pasted services wherever that reduces abstraction work and risk.
The reason a generic EP3 adapter was rejected: EP3 coupling is not isolated to one seam. It appears in service-layer assumptions around identity, account provisioning, instruments, order lifecycle, market data, and settlement — order-gateway logs into EP3 at startup, loads instruments from EP3, converts requests into EP3 protobuf, and drives lifecycle off EP3 drop-copy semantics. Bitnomial is different enough at each point (binary BTP DMA not gRPC; ConnectionId+AuthToken not user impersonation; modify-in-place not two-order replace; FIX 4.4 drop copy not EP3 drop copy; top-10 aggregated depth not book entries) that forcing it through EP3 shapes would create misleading compatibility.
transaction-engine, and risk-engine2 internals. We fork: order-gateway, marketdata-publisher, risk-engine venue I/O, and fill ingestion.
§2bThe protocol split
Bitnomial exposes several protocols; each is assigned the job it's best at, and lifecycle truth is deliberately separated from the fast path.
| Channel | Used for | Authority? |
|---|---|---|
| BTP DMA order entry binary TCP | open, modify, cancel-as-modify, and fast accept/reject replies | Low-latency hint only — not the source of lifecycle truth |
| FIX 4.4 drop copy | private order/fill lifecycle, reconciliation, recovery via gap-fill/resend | Authoritative for order & fill lifecycle |
| REST | product/spec catalog, funding rates, orders/fills backfill, reference data; HMAC auth | Authoritative for reference data & backfill |
| BTP pricefeed / public WebSocket | market data — top-10 aggregated levels, trades, market state | Market data only (top-10 depth, documented as such) |
Fills from drop copy are single-sided — we get our account's view, not both sides of the trade as EP3 trade ingestion pairs them — so fills are attributed to AX accounts through the order-mapping table rather than matched. REST /fills is the recovery source when the FIX session gaps. Ports in UAT: 11000 BTP order entry, 12000 BTP pricefeed, 10001 FIX drop copy.
§2cThe omnibus connection & attributed-open routing
The RFC's first and most important question was whether one BTP order-entry connection can route to multiple clearing accounts — public BTP Open carries only orderId, productId, side, price, quantity, timeInForce, with no documented account field. If the answer were no, AX would need one connection per customer.
Open plus an account field — a capability they reserve for FCM-class partners. Confirmed live in UAT. So AX trades through one omnibus connection, owns its own subaccounting, and the AttributedOpen body landed in #2208.
Self-match handling is "cancel on self-match" and is always enabled / not caller-configurable, so exercising both sides of a market in test requires distinct accounts (Bitnomial provisioned UBU00005–UBU00008 for Architect). One consequence for identity: the mapping is AX account_id → Bitnomial clearing account, and Bitnomial account IDs may not be globally unique across FCMs — so the mapping must also carry the clearing firm.
§2dIdentity & account mapping at the seam
AX currently encodes user/account identity into EP3 participant/account names (users.ep3_username, users.ep3_account, trading_accounts.ep3_username, trading_accounts.ep3_account). Bitnomial needs its own mapping, and the cleanest place to put it is new nullable Bitnomial columns on trading_accounts plus a publication/replica into the risk engine — not a restructuring of the EP3 columns.
user_id into identity / ownership / membership and removing from_default_account_id shortcuts from the risk engine. The order-gateway fork (step 11) was explicitly put on hold pending this work: without the accounts abstraction the edition "is gonna really have a bad time." See the account-keying threads in the multi-accounts plan.
Provisioning, by contrast, is an ops/admin workflow, not an API: Bitnomial's public docs expose no programmatic user/account/connection creation, so AX stores Bitnomial account/connection mappings in Postgres and treats creation as a portal/manual step until Bitnomial ships an onboarding API.
§2eMargin, positions & reconciliation authority
Positions are a solved problem — exact dead reckoning, reconciled daily. What is intentionally unresolved is final authority over margin, and the reason is structural, not a missing feature.
Working model, therefore — and note the deliberate split between positions and margin:
- Positions are exact, not approximate. AX dead-reckons positions precisely from its own order/fill stream (the authoritative FIX drop-copy lifecycle) and reconciles them against the FCM record at end of day. The goal is an exact intraday position that ties out daily — not a best-effort estimate.
- Margin is the approximate part. AX may ultimately run a different risk model than the FCM, so the intraday margin/equity figure is an internal estimate used for AX's own risk controls — it is not expected to be byte-identical to the clearing margin.
- FCM / Bitnomial daily margin and balance state is authoritative for settlement; daily reconciliation corrects any position drift and is the only window onto the authoritative margin/settlement numbers (reached via the FCM, not a direct Bitnomial API).
The residual correctness risk is concentrated in margin, not positions: the intraday margin view has no independent intraday cross-check, and the contract-multiplier handling in margin/PnL (A-3544) is a known open gap on top of it.
§2fAX API semantics over BTP
We preserve AX's two-order replace model at the client/API boundary even though Bitnomial modifies orders in place. A replacement creates a new AX order_id; venue-side it's a BTP modify against the original Bitnomial orderId with a new modifyId.
| Event | AX behavior |
|---|---|
| Replace ack / FIX report | old AX order → terminal Replaced; new AX order → Accepted |
| Replace reject | reject the new AX replacement order; leave the old order live |
Unsupported or unconfirmed AX features are rejected (or documented) rather than faked:
post_only— reject unless Bitnomial confirms BTP support.GTC— reject for BTP unless confirmed; public BTP documents onlyDayandIOC.- Custom self-trade-prevention flags — reject/ignore with clear docs; Bitnomial SMP is always on and not caller-configurable.
Cancel-all is implemented by iterating known open orders per connection unless Bitnomial provides an admin cancel API. A reported (unanswered) concern: order state after partial fills, and after a replace mid-partial-fill, was historically hard to read on Bitnomial — see §3.4.
§2gService fork map & branch reality
The components and how each maps to an EP3 service — plus where the code actually lives today.
| Component | Forked from | Where it lives now |
|---|---|---|
rs/bitnomial (ax-bitnomial / ax-btp) | new shared crate | main (step 1) |
api-gateway venue seam | not forked — single AX_MATCHING_ENGINE switch | main (step 5) |
aiex-marketdata-publisher | marketdata-publisher | ababkin/md-btp-fork-2-service (open #1944) |
aiex-risk-engine | ax-risk-engine | fork on main; cutover on the drop-copy branch |
| FIX drop-copy / fill ingestion | not EP3 trade-engine literally (single-sided) | main (merged #2138) |
bitnomial-order-gateway | order-gateway | ababkin/bitnomial-order-gateway stack (open, held) |
tin/bitnomial-fix-dropcopy and ababkin/md-btp-fork-2-service — absorbed many PRs that showed as "merged" but were not on main. The first root, drop-copy #2138, landed on main 2026-06-07 (with its branch-local PRs), so the 6-deep risk-engine cutover stack rooted on it can now rebase onto main; only the md-btp root #1944 remains off main. The api-gateway seam (epic A-3489) is the only Urgent epic and is the integration point they all converge on.
§2hConnectivity & environments
Network and environment facts that shape testing and deploy:
- Order entry is private-only — BTP order entry and FIX drop copy run over PrivateLink / VPN / DirectConnect, not the public internet. Dev started on VPN/Tailscale; prod targets PrivateLink. Market data is available over the public WebSocket.
- Session identity — SenderCompID is
ARCHITECT; connection id79(parsed as hex, not decimal) plus an auth token. Env vars standardize on aBTNL_*prefix; the edition is selected byEXCHANGE_EDITION=aiex. - REST catalog is served (currently unauthenticated, internet-only, not yet on PrivateLink) from
85is.net:/product/specs/,/product/data/{id}. Bitnomial manages product provisioning on the test env. - Sandbox vs prod is murky — orders against sandbox product IDs were rejected ("account not found") while a prod product went through; the team was directed to the prod
/product/specspath. Carries a real risk of accidentally trading against prod products in test (§3.6).
init.sql hardcoding the ax database would have dropped ~29 live aiex ClickHouse tables. Keep aiex schema/migrations isolated from the live AX database.
§3Open Questions
The questions the code can't answer — most are dependencies on Bitnomial. Each carries its current resolution.
-
Can one BTP order-entry connection route to multiple clearing accounts? And where is the account specified?
-
Does BTP support
GTCorpost_onlyoutside the public docs?- Not yet answered No answer from Bitnomial in any channel. Public BTP documents only
DayandIOC. Current plan: reject both at the API boundary until confirmed (§2f).
- Not yet answered No answer from Bitnomial in any channel. Public BTP documents only
-
What is the authoritative margin/settlement API, and the recovery process after disconnect/crash/DR failover?
- Answered — blocked Bitnomial's margin/settlement APIs are gated behind contract execution; AX gets no direct access as an interim IB — the authoritative numbers come through the FCM (Dorman) via GMI on the daily cycle. No confirmed public Position REST API. The accepted model: positions dead-reckoned exact + reconciled daily, margin approximate (possibly a different risk model than the FCM). The residual risk lives in margin, not positions (§2e, step 13).
-
How does order state read after partial fills, and after a replace mid-partial-fill?
- Not yet answered Raised from an ex-Bitnomial market-maker's report that this was historically hard to determine; the thread to Bitnomial went unanswered. An unmitigated protocol risk on the order-gateway lifecycle path — needs a definitive spec answer before production (§2f).
-
Does Bitnomial expose programmatic account / connection / risk provisioning & onboarding APIs?
- Partially — coming Not today. Bitnomial says they'll expose the onboarding API "as soon as they can"; the institutional portal link is also outstanding. Interim: a manual/portal ops workflow, mappings stored in Postgres (§2d, step 14).
-
What are the sandbox limitations vs prod for production-like testing?
- Partially answered Real confusion observed — sandbox product IDs rejected ("account not found") while a prod product went through; team directed to the prod
/product/specspath. The sandbox/UAT/prod boundary remains murky, with a live risk of submitting against prod products in test (§2h).
- Partially answered Real confusion observed — sandbox product IDs rejected ("account not found") while a prod product went through; team directed to the prod
-
How long does the Bitnomial Edition run before cutaway to Architect's own DCM?
- Strategic — open By design, "as soon as regulatorily possible" once Architect's own DCM is live. The fork-don't-abstract strategy (§2a) is the bet on this being short. The actual window depends on the DCM standup and the Bitnomial LOI (exclusivity, no certification-timing commitment, assignable to an affiliate) — outside engineering's control (step 15).
-
Internal gate: must the account/identity rekey land before the order-gateway?
- Answered — yes Yes. The order-gateway stack was explicitly put on hold pending the accounts rekey; without splitting identity from ownership and removing
from_default_account_idshortcuts, the edition "is gonna really have a bad time." This is the internal critical path (§2d, steps 11–12).
- Answered — yes Yes. The order-gateway stack was explicitly put on hold pending the accounts rekey; without splitting identity from ownership and removing
§4Documentation
The reference material this project is built against — internal design docs, the in-repo BTP specs that are our source of truth for the wire, Bitnomial's public API docs, and the related AX plans.
Internal — design & specs
- RFC: Bitnomial DCM Integration — the founding design (
docs/rfc/bitnomial-dcm-integration.md); this plan tracks its execution. - BTP wire-format reference —
rs/bitnomial/BTP_SPEC.md; the source of truth for every byte theax-btpcodec andax-btp-mockemit/accept. - BTP REST catalog spec —
rs/bitnomial/BTP_REST_SPEC.md; the authoritative reference for theGET /product/specs/JSON used by instrument loading. BTNL_FORK.md— fork reference doc. ondevelop-bitnomial— not on main
Bitnomial — public API docs
- BTP order-entry / pricefeed protocol
- REST API overview · authentication (HMAC) · products · orders
- REST base:
https://bitnomial.com/exchange/api/v1/— prod (prod/product/specs/) vs sandbox (sandbox/product/specs/). The sandbox/prod boundary is murky — see §2h, §3.6. - bitnomial/wireshark-btp — upstream Wireshark BTP dissector, cross-referenced by the wire spec.
- Onboarding / private-doc requests:
help@exchange.bitnomial.com(BTP certification guide, FIX recovery spec, Position API, provisioning APIs — see RFC §"Private Or Missing Docs To Request").
Linear — epics
| Epic | Area | Owner | Status |
|---|---|---|---|
| A-3489 P1 / urgent | API Gateway: Bitnomial venue support | Loc Nguyen | In Progress |
| A-3470 | Risk-engine parity for Bitnomial edition | Tin Chung | In Review |
| A-3448 | bitnomial-order-gateway (BTP + FIX drop copy) | Andrew Lee | In Progress |
| A-3311 | Multi-backend market data (EP3 + BTP) | Alex Babkin | Backlog |
| A-3486 | Load Bitnomial instruments into the API gateway | Loc Nguyen | In Progress |
| A-3348 | BTP port of trade-engine2 | m.rees | In Progress |
All under the Perpetuals exchange project · Integrations milestone. There is no standalone Bitnomial Linear project — issues carry the AIEx label.
Related AX plans
- Multi-Accounts — the identity/ownership rekey the Bitnomial account mapping rides on (the internal critical path, §2d).
- Position Feed Promotion — the EP3-side position-cache cutover; adjacent risk/margin work.