Current Blog
How to Model Time-in-Force Orders in a Trading Backtest
A time-in-force backtest gives every order an explicit eligibility window, applies venue-specific Day, IOC, FOK, or timed-expiry rules, and cancels the unfilled remainder at the correct event time.
This article was prepared with AI assistance and checked through automated editorial and source review. No named human review is recorded.
A time-in-force backtest should decide when an order is eligible before it decides whether the order fills. Each accepted order needs an instruction, eligible session, venue acceptance time, expiration event, and terminal reason. An order that has expired must not receive a later trade simply because its price would have matched.
Keep lifetime logic inside the order state machine. Price, quantity, queue position, and latency still matter, but they operate only while the order is live. Record requested and accepted time in force separately because a broker or venue may reject, translate, or constrain the instruction.
Define each instruction as a state rule
The SEC staff's order-types bulletin describes common timing instructions. A Day order generally remains good only for the trading day and does not automatically carry into the next session. A Good-Til-Canceled order lasts until it is filled or canceled, subject to the broker's own time limit. An Immediate-Or-Cancel order executes immediately and cancels any unfilled portion. A Fill-Or-Kill order must execute immediately in full or cancel without a partial execution.
These are general descriptions, not a universal venue rulebook. Store a rule version keyed by venue, account, instrument, session, and effective date. If historical evidence does not establish the accepted instruction, mark the order outcome uncertain instead of assigning the most convenient behavior.
Use venue fields, not labels alone
The Nasdaq OUCH 5.0 specification maps its Time In Force field to Day for market hours, IOC, GTX for extended hours, GTT with a required ExpireTime, and after-hours handling. That mapping shows why a string such as DAY is incomplete without the session it applies to.
For every accepted order, store the venue code, session designation, expiration timestamp when required, and the source rule. Normalize those fields for analysis only after preserving the original values. A generic GTC label from a broker should not be translated into Nasdaq GTT unless the historical routing record proves that conversion.
Work an IOC and FOK example
Assume a synthetic buy limit order for 1,000 shares at $25.00 reaches the matching engine at 10:00:00.000 Eastern Time. At that instant, 350 shares are executable at $25.00 and 250 more are executable at $24.99. Ignore routing, hidden quantity, fees, and latency after venue acceptance for this example.
With IOC, the model fills 600 shares immediately and cancels the remaining 400. The volume-weighted price is ((350 × $25.00) + (250 × $24.99)) ÷ 600, or $24.995833 per share before fees. The fill ledger contains two executions, while the order ledger records an IOC remainder cancellation.
With FOK, the same 1,000-share order receives no fill because only 600 shares are immediately executable. Test all available eligible liquidity before mutating position or cash. A simulator that books 600 shares and then cancels the remainder has modeled IOC, not FOK. The numbers are illustrative, not observed market results.
Expire orders on venue time
Expiry is a market event. A GTT order accepted with an expiration time of 10:00:05.000 can fill from eligible venue events before that instant. An execution opportunity timestamped 10:00:05.200 arrives too late even if the strategy receives both messages in the opposite order.
Maintain venue event time separately from local receipt time, then use the venue sequence to decide state. The strategy can react only after messages reach its local clock, but local network delay must not extend the venue's order lifetime. Apply the same timestamp discipline used in the partial-fill model.
Respect sessions and auction eligibility
The current NYSE rulebook defines a Day modifier to expire at the end of the designated session and describes IOC limit orders as trading in whole or in part on receipt, with untraded quantity canceled. It also states that IOC overrides posting instructions. The accepted venue instruction therefore controls whether a remainder may rest.
Do not infer session boundaries from a date label. Holidays, early closes, extended sessions, and delayed openings change the event schedule. Load the historical market calendar and time zone, and treat auction-only instructions through the separate auction model. A Day order's auction eligibility remains venue-specific.
Test terminal outcomes explicitly
Time in force should end with a recorded state transition: filled, expired, remainder canceled, user canceled, rejected, or replaced. Do not delete the order when it expires. Preserve the accepted timestamp, every execution, the unfilled quantity, and the rule that caused the terminal event.
No fill occurs before acceptance or after the expiration event.
IOC leaves no resting remainder after its immediate execution attempt.
FOK either fills the full quantity atomically or fills zero.
A Day order expires at the correct designated session boundary.
GTT requires a valid timezone-aware expiration timestamp.
Cumulative fills plus canceled or expired quantity reconcile to accepted quantity.
Fill prices still obey the limit-order constraints.
Test zero liquidity, partial immediate liquidity, full liquidity at several prices, an expiry tied with an execution timestamp, an early close, a rejected instruction, a cancel racing with expiry, and a replacement that changes time in force. When two events share a timestamp, use the venue sequence or publish the tie-breaking assumption. The model is auditable when every live interval and terminal quantity can be reconstructed from the event log.




