Skip to main content

Order lifecycle

Who it’s for
Users debugging why an order did or did not happen
Assumes
You have a deployed strategy

From a condition becoming true to a position appearing on your dashboard. This page is the map you want open when something did not happen that you expected to.


The path

Before placement, in order:

StepStageDetail
1Candle closes
2Evaluate the strategy's conditionsEntry true, exit true, or neither. Neither means no action, and the engine waits for the next candle
3Signal producedCarrying an idempotency key
4Trading window checkOutside the window, no entry
5Kill switch and halt checkHalted means no entry. Fail-closed
6Position sizingRisk budget, then quantity, then step or lot rounding
7Nine risk gatesThe first violation stops the order
8Margin validationMargined instruments only

The nine gates run in this order: max_order_value, per_trade_risk, max_open_positions, max_trades_per_day, max_consecutive_losses, daily_loss_limit, mark_to_market_loss, max_capital_allocation, available_capital.

Then the two modes diverge:

PaperLive
Order constructionNone neededThe broker adapter builds the order
Where it goesThe internal simulator, against live pricesYour venue, which accepts or rejects it
FillsRecorded immediatelyOne or more fills, possibly partial

After the fill, both modes rejoin: the position ledger is updated on FIFO lots, and P&L, risk metrics and notifications follow from it.


Evaluation

At candle close, on the strategy's timeframe. Not intra-candle, not per tick.

Three possible outcomes: an entry signal, an exit signal, or no action. Most bars are no action, and that is normal.

For a strategy with higher-timeframe gates, every gate must pass on its most recently closed higher-timeframe bar before a lower-timeframe entry is allowed through.


Idempotency

Every signal carries a stable idempotency key, and the orders table enforces uniqueness on (user, idempotency key).

This is what prevents a duplicate order from a retry, a restart, or a redelivered signal. A signal without a stable key is refused rather than sent, because an order that could be placed twice is a worse outcome than an order not placed at all.

Duplicate detection surfaces as DUPLICATE_ORDER or DUPLICATE_STRATEGY_EXECUTION. Those are not risk violations; they are the deduplication working.


Pre-placement checks, in order

OrderCheckBlocks
1Trading windowEntries outside the time-of-day range
2Kill switch / haltNew entries when halted. Fail-closed, an unreadable halt state blocks
3Position sizingNothing; it computes the quantity
4-12The nine risk gatesThe first violation stops the order
13Margin validationMargined orders without sufficient margin

Why the gate order matters

Cheapest and most decisive first. max_order_value and per_trade_risk need nothing but the order itself; the gates that need position counts, today's P&L or capital figures declare that requirement and those reads happen only if the order survives the cheap checks.

An order failing on shape never costs a database query.

Entries are gated; exits are not

Every exposure and velocity gate applies to entries only. A strategy at its position cap must still be able to close a position.

The consequence: a breached daily-loss cap stops new trades and leaves the open position running to its own stop. See Alerts & breaches


Order states

What you will see on the live terminal and in the order history:

StateMeaning
PENDING / PENDING_NEWSubmitted, awaiting venue acknowledgement
NEW / OPENLive on the book
TRIGGER_PENDINGA stop or trigger order waiting for its level
PARTIALLY_FILLEDSome quantity filled, the rest still working
FILLEDComplete
PENDING_CANCELCancellation submitted
CANCELLEDCancelled
REJECTEDThe venue or a pre-placement check refused it
EXPIREDAged out at the venue

PARTIALLY_FILLED deserves attention: the backtest never produces it. A partial fill leaves you with less exposure than the strategy intended, and the remaining quantity is still working. See Backtest limitations.


Fills and the position ledger

Fills update a FIFO lot ledger. Open exposure is derived from open buy lots plus fully-unfilled working buy entries.

Two things that follow from FIFO accounting:

Working orders count toward max_open_positions. An entry sitting unfilled occupies a slot, so the cap cannot be exceeded by racing two entries.

Short-side exposure is asymmetric in one place. The mark_to_market_loss gate derives open exposure from the buy-lot ledger, so a short position contributes quantity but not a mirrored unrealised sign. That narrowing is documented rather than hidden. See The nine order gates.


Rejection reasons

CodeCause
MAX_ORDER_VALUE_EXCEEDEDGate 1
PER_TRADE_RISK_EXCEEDEDGate 2
MAX_OPEN_POSITIONS_REACHEDGate 3
MAX_TRADES_PER_DAY_REACHEDGate 4
MAX_CONSECUTIVE_LOSSES_REACHEDGate 5
DAILY_LOSS_LIMIT_EXCEEDEDGate 6
MARK_TO_MARKET_LOSS_EXCEEDEDGate 7
MAX_CAPITAL_ALLOCATION_EXCEEDEDGate 8
INSUFFICIENT_AVAILABLE_CAPITALGate 9
INSUFFICIENT_BROKER_BALANCEFunds at the broker
INSUFFICIENT_MARGINMargin validator
DUPLICATE_ORDERDeduplication, not a risk violation

Every violation reports the rule, the current value and the limit, so "which rule and by how much" is always answerable.


Reconciliation

The platform reconciles its view of orders and positions against the broker's, because the two can diverge, a fill the platform did not see, a cancellation it missed, a position that exists at the venue and not in the ledger.

Your broker is the record of truth

For your positions, your balance and your obligations, the broker's statement is authoritative. Reconcile against it rather than against the platform's view.


Debugging: what to check, in order

SymptomCheck
No orders at allIs the strategy running? Is the entry condition ever true? Is it inside the trading window?
Orders rejectedThe risk panel for a violation, and the reason code
Rejected on fundsBroker balance, and whether other strategies hold the capital
Rejected on authToken expiry, key revocation, IP allowlist
Entries stopped but the position is still openA gate tripped. Gates block entries, never exits
Fewer shares than expectedQuantity step or lot rounding, or a partial fill
Nothing after a restartCooldown may still be elapsing, it is computed, not persisted
Duplicate-looking signal did nothingIdempotency deduplication working correctly

Next