This guide applies to automated execution, quoting, portfolio automation, and other long-running trading systems. Strategy selection and profitability are outside the SDK's scope.
Health model
| Dependency | Healthy evidence | Response when unhealthy |
|---|---|---|
| Catalogs | wait_for_catalogs() completed; symbol and scale resolve | Do not encode or submit |
| Managed book | Recent update, bid below ask, no refresh in progress | Pause book-dependent writes |
| Private orders | Recent event or successful bounded reconciliation | Reconcile before replacing |
| Balances | Recent balances.list(...) snapshot | Stop the affected side |
| Dead-man switch | Last armed response has safe time remaining | Stop new orders immediately |
| Event queue | No Error::QueueOverflow | Replace subscription and resnapshot |
Track book age/sequence, refresh and reconnect counts, owned open orders, reserved and available balance, mutation latency, rejected batch items, unknown outcomes, dead-man expiry margin, and reconciliation duration. Generic queues hold 1000 items; the managed book queue holds 200.
Deployment and shutdown
- Start with writes disabled.
- Hydrate catalogs and validate configured symbols.
- Start managed public feeds and private order/balance streams.
- Reconcile open orders owned by this process prefix.
- Arm
orders.cancel_all_afterfor 10 to 120 seconds. - Enable writes only when all dependencies are healthy.
For shutdown: disable new orders, cancel owned IDs, confirm they disappear from orders.list_open,
then close streams. Do not disarm the dead-man switch until cleanup is confirmed. Avoid
account-wide cancellation as ownership cleanup; filter process-owned client IDs first. Treat ERROR_CODE_ORDER_ALREADY_TERMINAL and ERROR_CODE_ORDER_UNKNOWN from those targeted cancels as
idempotent success and propagate every other error.
Troubleshooting
- Post-only rejection: Refresh the book and calculate a new catalog-aligned price
- Insufficient balance: Refresh balances; reduce or disable the affected order flow
- Stale/one-sided book: Pause writes until a valid snapshot
mutation_outcome_unknown(): Query known client/request IDs before retrying- Missing fills: Use
wait_for_order_trades_complete Error::QueueOverflow: Replace the subscription, snapshot, and reconcile- Dead-man refresh failure: Stop writes and continue cleanup/reconciliation
- Authentication failure: Stop; treat as configuration/policy, not transient transport
Create status accepted is admission, not working state. Batch RPC success does not mean every
item was accepted.
Testing ladder
- Unit-test strategy math, rounding, limits, and reprice thresholds.
- Test how your code handles invalid input and malformed outcomes.
- Run public testnet books, trades, and candles.
- Run authenticated reads on a dedicated account.
- Gate mutations behind an explicit flag with unique IDs and targeted cleanup.
- Run bounded scheduled test cycles and assert final open-order state.
Every mutation test needs a strict notional cap, total timeout, guaranteed targeted cleanup, and a
final list_open assertion.
Upgrade checklist
The SDK is pre-1.0 and a minor release may break the API, so pin an exact version
(polyester-sdk = "=0.12.0"). Review request, default, status, and stream changes in the changelog,
run your tests, run public reads, execute one gated create-cancel-reconcile cycle, deploy one
instance first, then roll out gradually.