AI Guide Map
Order Intent Chasing with Exchange APIs & WebSockets
A guarded execution layer that tries to follow the price with maker orders, with the goal of being filled as soon as possible without taker fees. Use this when the project already emits approved entry or exit order intents.
A chaser is execution plumbing, not a trading strategy. EXECUTION_MODE=DEMO, TESTNET, or LIVE submission requires explicit operator approval.
Default Scope
- Runtime: Node.js LTS
- Recommended language: TypeScript
- Package: selected exchange SDK
- Products: spot, margin, perpetuals, or futures where the exchange SDK supports the required order controls
- Implement execution for when EXECUTION_MODE=DEMO, TESTNET, or LIVE is enabled and all gates pass, but keep that path disabled by default.
- EXECUTION_MODE=DRY_RUN_PRIVATE is the default local mode for chaser plan records.
- Credentials: scoped API keys from environment variables only for private or write-capable execution modes.
Resources
Start with the task-specific resources below, then use SDK and exchange docs to verify exact method names, request fields, topics, and product rules.
Implementation Steps
Follow these in order; use the linked artifacts only where they clarify the current step.
1. Keep intent, risk, and execution separate
The chaser consumes an already-approved order intent and does not decide whether to trade.
- Define a typed parent OrderIntent that includes id, product, symbol, side, role, quantity, price limit, max slippage, time limit, chase interval, max replace count, execution mode, risk approval.
- Keep signal generation, risk approval, account reconciliation, and DEMO, TESTNET, or LIVE submission adapter code in separate modules.
- Reject any intent that does not specify whether it is entry or exit. Exit intents must preserve reduce-only or close-only semantics where the exchange supports them.
- For easier testing, include a mechanic to allow the operator to type the intent in CLI input (e.g. buy 1% BTCUSDT or sell 0.5% BTCUSDT or cancel buy BTCUSDT) and have the system parse that into the same order intent shape that strategy-generated intents use.
2. Verify exchange surfaces and filters
Before building request objects, inspect the selected SDK docs, examples, installed TypeScript declarations, package source, endpoint map, and exchange docs for the real market data, order placement, amendment, cancellation, time-in-force, and post-only support.
- Hydrate tick size, step size, min quantity, max quantity, min notional, price bands, post-only support, time-in-force support, and amend versus cancel-replace support.
- Use fresh top-of-book or book-depth data before price-changing child order place, amend, or replace decisions. A cleanup cancel of a known app-owned child order may proceed from child-order state, timeout, or risk policy without waiting for fresh market data.
- Pause price-changing place, amend, or replace decisions on stale market data, crossed books, sequence gaps, reconnects, spread spikes, volatility spikes, or failed market-data or child-order reconciliation.
3. Price bounded child orders
The adapter should build a candidate limit request from the current book, hydrated filters, and the parent intent boundary.
- For buys, never price above the configured price limit or max slippage cap. For sells, never price below the configured price limit or max slippage cap.
- For maker-only mode, never cross the book. For taker-allowed mode, crossing must be explicit and capped by the intent boundary.
- Quantize price and quantity from hydrated filters before comparing to caps and before logging the final request.
4. Submit one child at a time
A parent intent should have at most one write-capable child order at a time. Replacements must be serialized and traceable.
- Submit at most one write-capable child order per parent order intent at a time. Track the exchange-visible child order ID when available, local parent intent ID, local generation, remaining quantity, durable context status, and in-flight cancel/replace state.
- Track in-flight place, cancel, and amend calls so a private event cannot trigger a competing replacement.
- Do not replace on every tick. Use chase interval, minimum price movement, queue age, spread, and rate-limit budget before canceling or amending.
5. Reconcile before replacing
Cancel-replace logic waits for Order Trust before touching a child order.
- Verify current child order status and filled quantity from private events or trusted Account State before canceling, amending, or replacing.
- Use Scoped Recovery only when startup, reconnect, timeout, unknown outcome, missing prerequisites, or conflicting evidence requires it.
- Never assume a cancel succeeded until Private Stream Confirmation or Scoped Recovery proves the state.
- On partial fill, reduce remaining quantity, revalidate step size and min notional, and stop if the remainder is too small or the parent intent is complete.
6. Stop cleanly
The chaser needs explicit terminal states and cleanup policy.
- Stop on fill, timeout, max replace count, stale data, rejection, unknown order state, rate-limit pressure, risk-gate failure, or operator stop.
- On timeout, cancel, leave, or mark the child order for review according to explicit config.
- On shutdown, stop new replace attempts, reconcile app-owned child orders, cancel only configured transient chaser orders, and log a compact summary.
7. Prove the execution chain
Trace the parent intent through risk approval, market-data trust, child order creation, exchange acceptance, private confirmation or recovery, and terminal state.
- For order adapters that can submit DEMO, TESTNET, or LIVE orders, add fixtures for REST acceptance as provisional, private fill before REST acceptance, stale market data, reconnect recovery, partial fills, duplicate child generations, missing parent context, timeout cleanup, exchange rejection, and unsupported non-production venue selection.
- Every execution claim needs a fixture or a documented non-claim.
- Do not mark a chaser with an implemented EXECUTION_MODE=DEMO, TESTNET, or LIVE submission path complete until three consecutive full intent-to-child-order review passes produce no code, tests, fixtures, or documentation changes.
Adapter path
This is the sequence a generated chaser utility should follow for each parent order intent.
- Validate parent order intent, execution boundary, and risk approval.
- Hydrate exchange filters and current market data.
- Build a dry-run child limit candidate and log the bounded request.
- If EXECUTION_MODE=DEMO, TESTNET, or LIVE is not enabled, stop at EXECUTION_MODE=DRY_RUN_PRIVATE output.
- If EXECUTION_MODE=DEMO, TESTNET, or LIVE is enabled and all gates pass, submit one app-owned child order and record Pending Confirmation until Private Stream Confirmation or Scoped Recovery confirms it.
- Listen for private order updates and use Scoped Recovery only at trust boundaries.
- After reconnect, timeout, or conflicting evidence, restore market-data trust and child-order state before price-changing child order decisions. Cleanup cancels may proceed from trusted child-order state and explicit risk or timeout policy.
- On replace trigger, cancel or amend only the app-owned child order, then submit the next generation only after state is known.
- Stop on fill, timeout, max replace count, stale data, rejection, unknown order state, rate-limit pressure, risk-gate failure, or operator stop.
Readiness gates
| State | Source | Required before workflow |
|---|---|---|
| Intent approved | Strategy or operator-created order intent plus risk gate | Yes |
| Filters hydrated | Exchange metadata REST call | Yes |
| Market data fresh | Top-of-book, book-depth stream, or current REST quote | Yes before price-changing place, amend, or replace |
| Child order state known | Private Stream Confirmation, trusted Account State, or Scoped Recovery | Yes before cancel, amend, or replacement |
| Market data trust restored | Fresh book/quote after reconnect or sequence recovery | Yes before price-changing place, amend, or replace |
| Workflow lock idle | Per-parent intent execution lock | Yes before place, cancel, amend, or replace |
Bounds and filters
A chaser is only acceptable if the exchange request stays inside both strategy bounds and exchange rules.
- Reject an order intent if limit price, slippage cap, time limit, max replace count, or quantity is missing.
- Quantize candidate price and quantity from hydrated filters, then re-check the quantized values against the parent intent bounds and exchange filters.
- Block the request locally when remaining quantity falls below minimum quantity or minimum notional.
- Separate maker-only, taker-allowed, and post-only-retry modes in config and logs.
Order update handling
Private order events, Private Stream Confirmation, and Scoped Recovery update the execution state machine; they are not strategy signals.
- Classify child order updates by app-owned Custom Order ID, then resolve parent order intent and generation from Durable Context.
- Group duplicate order updates and ignore unowned manual orders.
- Treat unknown order state as paused until Private Stream Confirmation or Scoped Recovery resolves it.
- Partial fills update remaining quantity before any replace decision.
- REST acceptance creates Pending Confirmation; child state changes need Private Stream Confirmation or Scoped Recovery evidence.
Adapter sketchReference
The exact SDK methods vary by exchange. Keep the typed boundary and state machine stable.
Intent contract
The chaser consumes an approved order intent and hydrated market context.
type OrderIntent = {
id: string;
product: string;
symbol: string;
side: 'buy' | 'sell';
role: 'entry' | 'exit';
quantity: string;
reduceOnly?: boolean;
priceLimit: string;
maxSlippageBps: number;
timeLimitMs: number;
chaseIntervalMs: number;
maxReplaceCount: number;
executionMode: 'DRY_RUN_PRIVATE' | 'DEMO' | 'TESTNET' | 'LIVE';
riskApprovalId: string;
postOnly?: boolean;
};
const chaserPlan = buildChaserPlan(intent, {
bestBid,
bestAsk,
tickSize,
stepSize,
minNotional,
});Lifecycle
Each transition should be logged and covered by tests or replay fixtures.
queued -> hydrating_market -> pricing -> placing -> open
open -> replacing -> open
open -> partially_filled -> replacing
open -> filled
open -> timed_out -> canceling -> abandoned
open -> rejected -> pausedFixture casesReference
Use these behavior checks in local replay or fixture tests before live order paths are trusted.
| Case | Purpose | Expected result |
|---|---|---|
| Dry-run buy entry chaser | Proves an entry intent becomes a bounded buy limit candidate. | Candidate price is quantized, does not exceed buy limit or slippage cap, and includes a child generation. |
| Dry-run sell exit chaser | Proves an exit intent preserves reduce-only or close-only behavior. | Candidate price is quantized, does not go below sell limit or slippage cap, and never increases exposure. |
| Post-only would cross | Proves maker-only mode does not accidentally take liquidity. | Candidate is repriced behind the book or blocked before submission. |
| Partial fill before replace | Proves remaining quantity is reconciled before replacement. | Remaining quantity is reduced, revalidated against filters, and abandoned if below minimum size or notional. |
| Cancel replace race | Proves replacement cannot submit while previous child order state is unknown. | Workflow pauses or reconciles until cancel, amend, fill, or open state is known. |
| Stale market data | Proves the chaser stops repricing when market data is not authoritative. | No order is submitted or replaced until REST/WebSocket resync succeeds. |
| Timeout with app-owned child order | Proves timeout behavior follows explicit cleanup policy. | Adapter cancels, leaves, or marks the child order for review according to config and logs final parent state. |
| REST acceptance is provisional | Proves an accepted child order request does not confirm active child-order state. | Duplicate place/replace is blocked until private order evidence or scoped recovery resolves the child order. |
| Reconnect before replace | Proves reconnect recovery refreshes market data and child-order state before mutation. | No replace, cancel, or amend call runs from stale pre-reconnect state. |
Chaser invariants
- EXECUTION_MODE=DRY_RUN_PRIVATE is the default local mode for chaser plan records.
- The chaser must never create an order intent; it only executes an already-approved intent.
- EXECUTION_MODE=DEMO, TESTNET, or LIVE submission requires explicit config, scoped credentials, exchange-rule verification, and reviewed code.
- Submit at most one write-capable child order per parent order intent at a time. Track the exchange-visible child order ID when available, local parent intent ID, local generation, remaining quantity, durable context status, and in-flight cancel/replace state.
- Every child order is app-owned and linked to a parent order intent plus local generation in Durable Context.
- Do not amend or cancel unowned manual orders.
- Reconciliation is required before every replace after private updates, partial fills, reconnects, rejects, or unknown states.
- Emergency exits and hard stops should not rely only on a passive chaser; any fail-safe path is a separate explicit operator decision.
- Completion requires fixtures for the full parent order intent to child-order lifecycle.