Order Type and Time-in-Force Mapping

Direct Answer

Every broker uses different string values, integer codes, or enumeration constants to represent the same economic order intent. Interactive Brokers uses "LMT" for limit orders; Alpaca uses "limit"; the old TD Ameritrade API used the integer 1. A trailing stop is "TRAIL" in some APIs and requires separate fields for "trailPercent" vs "trailPrice" in others. Order type and time-in-force (TIF) mapping is the adapter-layer logic that translates your system's canonical vocabulary into the exact values each broker expects, and translates responses back.

The mapping is not a simple lookup table. Some brokers support an order type only with certain TIF values: market orders may only accept DAY TIF, while limit orders accept GTC. Some support a parameter name for trailing stops but only for a subset of asset classes. Some require additional fields to be present or absent depending on the order type. The mapping logic must encode all these constraints as validation rules that fire before the wire call, not after a rejection.

Key Takeaways

  • Use canonical vocabulary internally: Define your system's own order type and TIF enum values. Never let broker-specific strings leak into strategy logic. The adapter is the only layer that knows what string value a specific broker uses for "limit".
  • Map TIF and order type together: Valid combinations depend on both dimensions. A mapping that only translates order type without enforcing TIF compatibility will produce rejections for valid-looking orders at runtime.
  • Validate before the wire call: Check the canonical order against the capability manifest before serializing. An order your system cannot fulfill at this broker should be rejected at the adapter input boundary, not after a network round-trip.
  • Handle trailing stops carefully: Trailing stop implementations vary: some brokers track the trail relative to the best price since submission, others require you to update the stop price manually. Some use percent offset; others use price offset. Verify the exact semantics before trusting the broker's execution.
  • GTC expiry varies by venue: GTC does not mean "active forever". NYSE/Nasdaq cancel GTC orders on ex-dividend dates and after 90 calendar days by default. Some brokers cancel GTC on quarterly option expiry. Know your broker's specific GTC lifecycle.
  • IOC and FOK require fill-or-cancel confirmation: When an IOC or FOK order comes back with no fill, you need to confirm the order was fully canceled, not partially open. The broker's response should include the canceled quantity alongside any filled quantity.
  • Synthesize missing types when safe: If a broker doesn't support stop-limit but supports stop and limit separately, you can synthesize a stop-limit using a conditional: when the stop condition is triggered, submit a limit. Document the synthesis and its timing risks explicitly.
  • Re-validate mapping after API upgrades: Brokers add new order types and deprecate old enum values in API version upgrades. Mapping tables must be version-aware and updated at upgrade time.

Core Concepts

The Order Type Taxonomy

A minimal order type taxonomy for equity and crypto integration covers five types. Market orders execute immediately at the best available price; they accept only DAY TIF at most brokers. Limit orders execute at the specified price or better; they accept DAY, GTC, IOC, and FOK. Stop orders become market orders when a trigger price is reached; they typically accept DAY and GTC. Stop-limit orders become limit orders at a specified price when a trigger price is reached; they accept DAY and GTC at most brokers. Trailing stop orders set a dynamic stop that follows the market price at a fixed distance (dollar or percent).

Beyond these five, some brokers add session-specific types: MOO (market-on-open) and MOC (market-on-close) execute at the opening or closing auction. LOO (limit-on-open) and LOC (limit-on-close) add a limit price to the auction orders. Midpoint peg orders execute at the NBBO midpoint. These session-specific types often have their own TIF constraints, LOC orders may not accept GTC because the closing auction happens only once per day.

Map your canonical taxonomy to broker-specific values in a translation table, not in conditional logic scattered across the codebase. A translation table is easy to diff, version, and test. Conditional logic accumulates bugs as cases multiply.

Test each entry in the translation table as an independent unit test: given canonical {orderType: "stop_limit", tif: "gtc"}, the adapter should produce {type: "stop_limit", time_in_force: "gtc"} for Alpaca and {orderType: "STP LMT", tif: "GTC"} for IBKR. If the table changes, the test fails, and you catch the mismatch before deployment.

Time-in-Force Semantics

DAY: Active until end of the current trading session. If unfilled at close, the order is canceled. The exact close time depends on the instrument and venue, regular session close is 16:00 ET for US equities, but post-market session close is 20:00 ET at some brokers. Confirm with your broker whether "day" includes extended hours.

GTC (Good-Till-Canceled): Intended to remain active until filled or explicitly canceled. In practice, most US brokers cancel GTC orders after 90 calendar days if unfilled. Exchanges also cancel GTC orders on ex-dividend dates for equities, because a pending buy limit at $100 before a $2 dividend record date becomes economically different after the dividend reduces the stock price. Track your GTC orders and alert when they are auto-canceled unexpectedly.

IOC (Immediate-Or-Cancel): The order must be filled immediately on submission; any unfilled portion is canceled. IOC can result in a partial fill. The broker fills what's available at the limit price immediately and cancels the rest. Verify that your position tracking handles partial IOC fills correctly.

FOK (Fill-Or-Kill): The entire order must be filled immediately or the entire order is canceled, no partial fills. FOK is used when you need a specific quantity at a specific price and cannot accept a partial execution that leaves you needing a follow-up order. Fewer brokers support FOK than IOC; verify support before depending on it.

GTD (Good-Till-Date): Active until a specified date and time, then automatically canceled if unfilled. Not all brokers support GTD; some require polling and manual cancellation to achieve the same effect. When GTD is not supported, your adapter can synthesize it by scheduling a cancel command at the expiry time.

Trailing Stop Mechanics and Mapping Pitfalls

Trailing stops come in two flavors: percent-based (stop trails at X% below the best price since order entry) and price-offset (stop trails at $X below the best price). Brokers use different field names for these: Alpaca uses trail_percent and trail_price. Interactive Brokers uses auxPrice for the offset and requires tif="GTC" with trailing stops. Ensure your canonical trailing stop model includes both the offset type (percent vs. price) and the offset value, so the adapter can populate the correct fields.

The critical semantic question for trailing stops is who tracks the high-water mark. In broker-managed trailing stops, the broker's infrastructure monitors the real-time price and adjusts the effective stop price. In client-managed synthetic trailing stops, your code must subscribe to real-time price updates and issue cancel-and-replace orders as the price moves. Broker-managed is more reliable (no dependency on your connectivity) but less flexible (you can't add custom logic). Client-managed is flexible but introduces timing risk: a price move during a reconnect window may advance the high-water mark without your system updating the stop.

Test trailing stop behavior specifically by verifying the acknowledgment includes the initial effective stop price, then verifying how the broker communicates stop-price updates (some send WebSocket events; others require polling). Confirm that a trailing stop on a crypto asset follows 24/7 pricing, not session-based pricing.

Record in your capability manifest: trailing stop supported (yes/no), offset type supported (percent, price, both), stop-price update mechanism (event-based, poll-based), and whether the stop is broker-managed or client-managed.

Handling Unsupported Order Types

When a required order type is not supported by a broker, you have four options. Synthesis: Decompose the unsupported type into supported primitives. A stop-limit can be synthesized as a monitoring loop that submits a limit order when a stop condition is detected on live price data. Document timing risk: there is always a gap between when the synthetic stop triggers and when the limit reaches the broker. Venue routing: Route orders requiring the unsupported type to a different broker. This requires multi-broker infrastructure but keeps order execution fidelity. Hard rejection: Reject at the adapter boundary with a specific error that allows the strategy to decide its own fallback, perhaps a market order, a wider limit, or no order at all. Soft rejection with flag: Accept the order but downgrade the type (e.g., trailing stop to a fixed stop at current price), set a flag on the returned acknowledgment, and let the caller decide whether to accept the degraded execution. Hard rejection is safest because it forces an explicit decision; silent downgrade is the most dangerous because the strategy may not know its risk profile changed.

Worked Scenario

  1. Strategy intent. Your strategy signals: buy 50 shares of QQQ with a trailing stop at 2% offset below the high-water mark, GTC.
  2. Canonical order. Your internal model creates: {symbol: "QQQ", side: "buy", orderType: "trailing_stop", trailOffsetType: "percent", trailOffset: 2.0, tif: "gtc", quantity: 50}.
  3. Adapter lookup. The Alpaca adapter's capability manifest shows: trailing_stop supported, percent offset supported, TIF must be "gtc" for trailing stops.
  4. Translation. The adapter translates to: {symbol: "QQQ", side: "buy", type: "trailing_stop", trail_percent: 2.0, time_in_force: "gtc", qty: 50}. Note: Alpaca uses trail_percent not trailOffset, and qty not quantity.
  5. IBKR adapter path (alternate). If routed to Interactive Brokers, the adapter translates to: {action: "BUY", orderType: "TRAIL", auxPrice: null, trailingPercent: 2.0, tif: "GTC", totalQuantity: 50}. Different field names, different structure, same economic intent.
  6. Response normalization. Both brokers return a confirmation. The IBKR adapter maps orderId, the Alpaca adapter maps id, both normalize to the canonical OrderAck.clientOrderId and OrderAck.venueOrderId fields.
  7. Fill event. When the trailing stop triggers and fills, both brokers emit execution reports through different channels. Both adapters normalize to Fill{orderId, symbol, side, quantity: 50, price: 487.32, fees: 0, timestamp}.

Measurement Framework

MeasurementQuestion to Answer
Mapping coverage (% of canonical types tested)Has every canonical order type × TIF combination been tested against every configured broker?
Translation error rateWhat fraction of orders fail validation at the adapter boundary before reaching the wire?
Unsupported type rejection rateHow often does the strategy request an order type a broker doesn't support, and what's the fallback path?
Silent modification detection rateWhat fraction of broker acknowledgments show field values that differ from the submitted order?
GTC auto-cancellation eventsHow many GTC orders are auto-canceled by the broker (90-day expiry, ex-dividend, etc.) per month?

Common Failure Modes

Market Order Submitted with GTC TIF

A strategy that sets GTC as the default TIF for all orders will fail at brokers that reject market+GTC combinations. The broker returns a 400 error. If the adapter doesn't catch this at validation, the order fails on the wire and the strategy enters an error-recovery loop that may or may not result in the intended trade being placed.

Close-up of a person using a laptop with a payment terminal and calculator on the desk.
Photo by Mikhail Nilov via Pexels

Always validate TIF against the order type before serialization. Market orders must use DAY TIF at all standard equity brokers. Define this constraint in the capability manifest and enforce it in the adapter's input validation rather than relying on the broker's error response to catch it.

Trailing Stop Offset Applied to Wrong Price Reference

A trailing stop configured as "2% offset from current price" and a trailing stop configured as "2% offset from the best price since order entry" are different orders. If your canonical model doesn't distinguish between the initial offset and the high-water-mark offset, and the broker interprets the parameter differently than you intended, the stop triggers at the wrong price.

Test trailing stop behavior explicitly in the sandbox: submit an order, let the price move up 1%, then verify the broker's reported effective stop price moved up correspondingly. If the effective stop price didn't update. The broker is using a different high-water-mark logic than you assumed.

Partial IOC Fill Treated as Full Fill

An IOC order for 1000 shares that fills 300 and cancels the remaining 700 returns a 200 response. If the adapter parses only the filled quantity from the acknowledgment and doesn't check the canceled quantity, the strategy believes it now holds 1000 shares when it actually holds 300. The subsequent sizing logic and risk calculations are wrong from that point forward.

Parse IOC responses completely: extract filled_quantity, canceled_quantity, and average_fill_price from the acknowledgment. Emit a fill event for the filled portion and a cancel event for the unfilled portion. The strategy must handle the case where a partial fill requires a follow-up order.

GTC Order Silently Canceled on Ex-Dividend Date

A GTC buy limit on an equity is automatically canceled by the broker on the ex-dividend date because the stock price drops by approximately the dividend amount and the limit price is no longer meaningful. Most brokers do this without sending a cancellation notification through the normal event channel, the order just disappears from the open orders list. A position manager that doesn't periodically reconcile open orders against broker state will believe the GTC order is still working when it isn't.

Implement periodic open-order reconciliation (at minimum once per trading session) that compares your internal list of working orders against the broker's reported open orders. Any discrepancy triggers an investigation: was the order filled (no fill event received), canceled by the broker, or expired? Log the resolution and update internal state accordingly.

FOK Misinterpreted as IOC in Multi-Leg Strategies

FOK (Fill-Or-Kill) requires the full quantity to fill immediately or the order is canceled. IOC (Immediate-Or-Cancel) allows partial fills. A multi-leg strategy that uses FOK to ensure all legs are filled or none are filled will encounter incorrect behavior if a broker interprets FOK as IOC, partially filling some legs while canceling others, resulting in an unhedged position.

Verify FOK semantics empirically: submit an FOK order for a quantity larger than the available ask depth at the current limit price in the sandbox, and confirm that the broker returns a fully-canceled order with zero filled quantity, not a partial fill. If the broker treats it as IOC, find a broker that properly supports FOK for your strategy's needs or implement atomic order-group logic at a higher level.

FAQ

What is the difference between a stop order and a stop-limit order?

A stop order becomes a market order when the stop trigger price is reached. It guarantees execution but not price, in a fast-moving market, the fill may be far from the trigger price (slippage). A stop-limit order becomes a limit order at a specified price when the trigger is reached. It guarantees price but not execution, if the market gaps past your limit price, the order won't fill. Stop orders are more appropriate for priority-of-execution strategies; stop-limit orders are more appropriate for priority-of-price strategies where you'd rather not fill at all than fill at a bad price.

How long does a GTC order actually stay active?

GTC duration depends on the broker and exchange. Most US equity brokers and exchanges cancel GTC orders after 90 calendar days (approximately). GTC orders are also routinely canceled on ex-dividend dates, at end of quarter, and sometimes at end of month depending on the broker's internal policies. Interactive Brokers cancels GTC at the end of the calendar year for most instruments. Always check your specific broker's GTC policy and implement a reconciliation job that alerts you to unexpected cancellations.

Can I use FOK on all asset classes?

FOK support varies significantly. For US equities, most brokers support FOK but route FOK orders through specific execution venues that can assess the full available liquidity before committing. For options, FOK is widely supported for single-leg orders but may not be supported for spreads. For crypto, FOK is supported on most major exchanges (Coinbase Advanced, Binance) but not universally. For futures, FOK is exchange-defined behavior rather than broker-defined. Verify FOK support in your capability matrix before depending on it.

What does "extended hours" mean for order types?

Extended-hours trading (pre-market 4:00-9:30 ET and after-hours 16:00-20:00 ET for US equities) typically accepts only limit orders, not market orders. This is a regulatory convention, not a broker-specific rule, market orders in thin extended-hours markets carry extreme price risk. Some brokers require an explicit "extended_hours: true" flag on orders submitted outside regular session hours; others infer it from the submission time. If your strategy submits limit orders in the pre-market, confirm whether your broker requires the extended-hours flag and whether GTC orders carry over from after-hours to pre-market the next day.

How do I safely synthesize a trailing stop if my broker doesn't support it natively?

Client-managed trailing stop synthesis requires: (1) a real-time price feed for the instrument, (2) tracking the high-water mark (highest price since entry for a long position), (3) computing the current effective stop price as high_water_mark × (1 - trail_percent / 100), (4) when the current price falls below the effective stop, submit a market or limit sell. The risk is the gap between when the stop condition triggers and when your order reaches the broker, typically 100-500ms. In a fast market, the fill may be significantly below the intended stop. Document this risk in your strategy's performance analytics so you can measure actual stop slippage versus expected.

What's the right canonical vocabulary for order types across equity and crypto?

A vocabulary that covers both domains well includes: market, limit, stop_market, stop_limit, trailing_stop_market, trailing_stop_limit, market_on_open, market_on_close, limit_on_open, limit_on_close. TIF values: day, gtc, ioc, fok, gtd, opg (opening auction), cls (closing auction). The equity-specific types (MOO, MOC, LOO, LOC) have no direct crypto equivalent; crypto-specific types like post_only (limit that adds liquidity only, never takes) have no standard equity equivalent. Design your canonical vocab to be the superset, each adapter maps what it can support and rejects what it can't.

How do crypto exchange order types differ from equity broker order types?

Crypto exchanges add order types that equity brokers generally don't offer. Post-only (limit that cancels rather than taking liquidity at current market price) is common on maker-taker fee models and is unique to crypto. Reduce-only orders can only reduce an existing position, never increase it, useful for risk-controlled stop orders. Conditional orders on some crypto platforms allow complex trigger conditions based on index price vs. mark price vs. last price, which matters for perpetual futures. Map these to your canonical vocab as extension types, not replacements for core order types.

Why does my limit order sometimes fill at a better price than the limit?

Price improvement. Equity exchanges route orders through market makers who are required by Regulation NMS to fill at the NBBO or better. If the market moved favorably between your order submission and execution, the exchange may fill at a better price than your limit. This is called "price improvement" and is generally beneficial. Your position tracking should handle fills at better-than-limit prices as valid, not as data errors. The fill price in the execution report is the truth; your limit price was the worst-case ceiling, not a fixed fill price.

What is a post-only order and how does it map across venues?

A post-only instruction tells the venue to reject or reprice the order rather than execute against resting liquidity, so it can only add to the book. It exists mainly where maker and taker fees differ, which makes it common on crypto venues and less so in retail equity APIs. The mapping problem is that some venues reject a crossing post-only order while others silently reprice it, producing different outcomes from the same instruction. A canonical model needs to record which behavior each venue applies rather than assuming one.

References

Educational Disclaimer

This guide is for educational and informational purposes only and does not constitute financial, investment, or legal advice. Order type availability, TIF constraints, and broker behavior change frequently. Verify all mapping details against current broker documentation and empirical testing before deploying to a live trading environment.