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 9 of 11

Stage 9

Inventory, settlement, and accounting

Turn raw fills into a clean capital ledger — free, reserved, redeemable, realised.

Challenge we are solving

After a fill, the hard part is not "what did we buy?" — it is "what is reserved against live orders, what is free, what can be redeemed when the market resolves?".

What this stage does

Tracks position by market and token, reserves inventory against live orders, updates avg cost and PnL, and plans split / merge / redeem actions when resolution is final.

Why this stage exists

It is the only stage that knows what capital is actually available to the next OrderIntent.

Flow

Fill+2,000 YES
Balancesfree · reserved · redeemable
PnLavg cost · unrealised · realised
Settlementsplit · merge · redeem

What the backend should expose

  • market_id, token_id, position (qty)
  • free_qty, reserved_qty, redeemable_qty
  • avg_cost, realised_pnl, unrealised_pnl
  • settlement_status (open · resolving · resolved · redeemed)
  • redemption_jobs (queued · running · done)
  • ledger entries (one per fill, append-only)

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

Position from cumulative fills

\[position = \sum_{i \in buys} qty_i - \sum_{i \in sells} qty_i\]
SymbolMeaningUnits / range
\(buys / sells\)Sets of filled buy and sell records on this (market, token)list of fills
worked example\[\sum buys = 2{,}000,\; \sum sells = 0 \;\Rightarrow\; position = +2{,}000\;\text{YES}\]
2

Volume-weighted average cost

\[avg\_cost = \frac{\sum_i price_i \cdot qty_i}{\sum_i qty_i}\]
SymbolMeaningUnits / range
\(price_i\)Fill price on trade i0..1
\(qty_i\)Shares filled on trade ishares
worked example\[\text{fills: } 1{,}200@0.64,\; 800@0.65 \;\Rightarrow\; avg\_cost = \tfrac{1200{\cdot}0.64 + 800{\cdot}0.65}{2000} = 0.644\]

Average cost is reset on each round-trip close so realised PnL is unambiguous on partial exits.

3

Reserve invariant

\[free\_qty + reserved\_qty = total\_qty\]
SymbolMeaningUnits / range
\(free_qty\)Quantity available for new ordersshares
\(reserved_qty\)Quantity locked against live ordersshares
\(total_qty\)Position (filled, not yet redeemed)shares
worked example\[total=2{,}000,\; reserved=800\;(\text{live sell order}) \;\Rightarrow\; free=1{,}200\]

Reservations are released only when the live order moves to filled, cancelled, or rejected. No reservation may leak past order lifetime.

4

Unrealised PnL (mark-to-mid)

\[unrealised\_pnl = (mid - avg\_cost) \cdot position\]
SymbolMeaningUnits / range
\(mid\)Current mid-price0..1
\(avg_cost\)Volume-weighted average cost0..1
\(position\)Net signed positionshares
worked example\[mid=0.66,\; avg\_cost=0.644,\; position=+2{,}000 \;\Rightarrow\; unrealised\_pnl = (\$0.016)\cdot 2{,}000 = +\$32\]
5

Redemption math at resolution

\[redemption\_value = \begin{cases} position \cdot 1.0 & \text{if YES resolves true} \\ position \cdot 0.0 & \text{otherwise} \end{cases}\]
SymbolMeaningUnits / range
\(position\)Net YES shares at resolutionshares
worked example\[position = +2{,}000\;\text{YES},\;\text{market resolves YES} \;\Rightarrow\; redemption = \$2{,}000\]

Split / merge / redeem actions are queued by SettlementPlanner — never executed inline with trading.

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-bots/src/governanceReference accounting bots: positionledger, settlementreconciler, redemptionplanner.
  • packages/polytraders-contracts/src/ReportEnvelope.tsThe envelope that wraps every fill/redemption event for audit.
  • packages/polytraders-mock-clob-v2/src/envelopes.jsReference envelope writer — links fills to inventory updates by correlation_id.

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

  • GOV_*GOV — governance, accounting, replay, monitoring
  • EXEC_*EXEC — execution, OMS, fills

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.