Polytraders Dev Guide
internal
v3 spine Phase 1 · Shared contracts 9 demo-wired · 0 shadow-ready · 0 production-live · 100 pending · 109 total 15/33 infra tasks the plan status board

← All stages · stage 8 of 11

Stage 8

Order manager and reconciliation

Live trading fails at the edges — retries, missed cancels, duplicate acks. The OMS keeps local state aligned with the exchange.

Challenge we are solving

Networks lose packets. Heartbeats expire. Orders get partially filled while a cancel is in flight. If internal state and exchange state diverge, you place a duplicate or leak an orphan order.

What this stage does

Signs the order (EIP-712 v2), submits it via the CLOB V2 client, listens for accept/partial/fill/cancel/reject events, renews heartbeats, reconciles when internal ≠ exchange, and exposes the full lifecycle for audit.

Why this stage exists

This is where operational discipline matters most. Bugs here cost real capital silently.

Flow

Intent
received
from stage 7
Order
signed
EIP-712 v2
SubmittedCLOB V2
Acceptedack
Partially
filled
1,200
Confirmedfilled · cancelled · rejected
Reconciledinternal = exchange

What the backend should expose

  • order_id, client_order_id, status timeline
  • open_quantity, filled_quantity, cancelled_quantity
  • reject_reason (if any)
  • heartbeat status, ack_age_ms
  • exchange refs (tx hash · CLOB id)
  • reconciliation state (matched · diverged · resolving)
  • builderCode applied (0xb000000000000000000000000000000000000000000000000000000000003f7a)

Maths we expect here

Every formula below is implemented in packages/polytraders-bots/ or packages/polytraders-runner/. Treat the worked example as the unit-test sanity check you should be able to reproduce locally.

1

Open quantity (the live exposure)

\[open\_qty = order\_qty - filled\_qty - cancelled\_qty\]
SymbolMeaningUnits / range
\(order_qty\)Quantity submitted with the ordershares
\(filled_qty\)Cumulative shares filled so farshares
\(cancelled_qty\)Cumulative shares cancelled so farshares
worked example\[order=2{,}000,\; filled=1{,}200,\; cancelled=0 \;\Rightarrow\; open=800\]

Stages 9 reserves capital against open_qty, not order_qty. Confusing the two is how desks accidentally double-spend.

2

Ack age (heartbeat / liveness)

\[ack\_age\_ms = now - last\_exchange\_update\_ts\]
SymbolMeaningUnits / range
\(last_exchange_update_ts\)Time of the most recent ack from the venuems epoch
worked example\[now - last\_ack = 4{,}600\,\text{ms} > 3{,}000 \;\Rightarrow\; \text{trigger heartbeat renew}\]
3

EIP-712 v2 typed-data digest

\[digest = \mathrm{keccak256}(0x19\;\Vert\;0x01\;\Vert\;domain\_separator\;\Vert\;hash(struct))\]
SymbolMeaningUnits / range
\(domain_separator\)CLOB V2 EIP-712 domain hash (chainId, verifyingContract = CTFExchangeV2)32 bytes
\(struct\)Order struct (taker, maker, side, price, size, nonce, builder)typed
worked example\[\text{wrong domain} \Rightarrow \text{venue returns SEC\_DOMAIN\_MISMATCH;\; no funds at risk because the venue refuses to sign}\]

We use the V2 domain only. Mixing V1 and V2 domains is the single most expensive class of bug at this layer.

4

Reconciliation invariant

\[internal\_state \equiv exchange\_state \;\;\text{at every confirmed tick}\]
SymbolMeaningUnits / range
\(internal_state\)Local view of (open orders, fills, cancels) per marketstruct
\(exchange_state\)Server view fetched via REST snapshotstruct
worked example\[diff(\{open: 800\},\{open: 0\}) \neq \emptyset \;\Rightarrow\; \text{flag DIVERGED}\;\Rightarrow\; reconcile()\]

Stage 11 pauses the affected scope automatically if reconciliation cannot close the gap within the SLO.

How a developer codes this stage

Reference TypeScript implementation lives in packages/polytraders-* at the repository root. Stage owners maintain these files — read them before writing new code.

  • packages/polytraders-mock-clob-v2/src/client.jsReference CLOB V2 client — submit, cancel, amend, listen. Uses EIP-712 v2 domain.
  • packages/polytraders-mock-clob-v2/src/eip712.jsDomain separator + typed-data signer. **V2 only**. Wrong domain = hard reject.
  • packages/polytraders-bots/src/execOMS-side bots: orderlifecyclemanager, heartbeatrenewer, reconciler.

See it in the platform mock

The platform mock is the source of truth for what each stage's UI exposes. Open these alongside the code references.

Reason codes emitted at this stage

  • EXEC_*EXEC — execution, OMS, fills
  • SEC_*SEC — signing, contracts, EIP-712 v2

Hover or tap any reason code on this page (or anywhere on the site) to see its canonical short description. Full registry: /standards/reason-codes.