Short answer: Time in force (TIF) tells a trading venue what to do with the part of an order that cannot fill at once. GTC rests until filled or canceled, GTD until a set expiry, IOC fills what it can and cancels the rest, FOK fills completely or not at all, and post only, a related instruction, refuses to take liquidity. Official documents read on 5 November 2026 spell and default these differently (FIX tag 59 means Day when absent), so multi-venue software needs one internal model and a per-venue mapping.
One order idea can become timeInForce=GTX on one venue, oflags=post on the next, ordType=post_only on a third and a key inside order_configuration on a fourth.
A field reference for developers normalizing venues, from official API documentation and FIX Latest read on 5 November 2026. Naming a venue is not a recommendation, examples are hypothetical, and no setting here is advice. General design is in crypto exchange API integration.
What does time in force mean?
Time in force sets how long an order stays active, which in practice decides what happens to quantity that cannot fill on arrival.
| Instruction | Fills now | The other quantity | Partial fill? |
|---|---|---|---|
| GTC, good till canceled | 600 | 400 rests until filled or canceled | Yes |
| GTD, good till date | 600 | 400 rests until the expiry time | Yes |
| Day (stock markets) | 600 | 400 rests until the session ends | Yes |
| IOC, immediate or cancel | 600 | 400 canceled at once | Yes |
| FOK, fill or kill | 0 | All 1,000 canceled | No |
| Post only | 0 | All 1,000 refused, because it would take liquidity | No taker fill |
Fill or kill vs immediate or cancel, hypothetical: neither rests on the book; they differ only on partial fills, so on the book above IOC ends with 600 units and FOK with none.
Binance Spot's enum page documents EXPIRED, not CANCELED, for a limit FOK with no fill and for a limit IOC or market order that fills partly, so code that waits for CANCELED misses them.
Time in force across exchange APIs: one idea, seven spellings
Behavior is close across venues, but the field, the value and sometimes the request shape differ.
| Venue | Field | GTC | IOC | FOK | Post only |
|---|---|---|---|---|---|
| Binance Spot | timeInForce, type | GTC | IOC | FOK | type=LIMIT_MAKER, no TIF |
| Binance USD-M | timeInForce | GTC | IOC | FOK | GTX |
| Bybit V5 | timeInForce | GTC | IOC | FOK | PostOnly |
| Coinbase Advanced Trade | order_configuration key | limit_limit_gtc | sor_limit_ioc | limit_limit_fok | post_only: true inside the GTC or GTD key |
| Hyperliquid | t.limit.tif | Gtc | Ioc | Not listed | Alo |
| Kraken Spot REST | timeinforce, oflags | GTC | IOC | FOK, added 12 May 2026 (opens in a new tab) | oflags=post |
| OKX | ordType | limit | ioc | fok | post_only |
| Venue | GTD | If omitted | Post only would cross |
|---|---|---|---|
| Binance Spot | Not in the enum | Mandatory on LIMIT, -1102 if missing | Rejected: -2010, Order would immediately match and take. |
| Binance USD-M | GTD with goodTillDate (opens in a new tab), over 600 seconds ahead | Mandatory on LIMIT | Rejected: -5022 (opens in a new tab) |
| Bybit V5 | Not in the enum | GTC | Canceled; reject reason EC_PostOnlyWillTakeLiquidity |
| Coinbase | limit_limit_gtd with end_time | No default, the key is the policy | Failure reason INVALID_LIMIT_PRICE_POST_ONLY |
| Hyperliquid | None; expiresAfter expires the request, not a resting order | Part of the required type | Status error BadAloPx |
| Kraken | GTD with expiretm, up to one month | GTC | Canceled on arrival, per its FIX page; the REST page names no error |
| OKX | No such ordType | ordType is required | Canceled; cancelSource 31 |
What is a post only order? Binance and other venues
A post only order asks to rest on the book as a maker and is refused if it would trade immediately, so a refusal is a normal outcome rather than a fault.
The refusal arrives in two ways:
- Refused in the reply. Binance Spot, Binance USD-M, Coinbase and Hyperliquid document an error or failure reason in the response, as in the table above; Hyperliquid's message (opens in a new tab) includes the best bid and offer.
- Accepted, then canceled. Bybit says its reply only acknowledges the request and the WebSocket confirms the status, and OKX cancels an order that would execute at placement. A success code is not proof that the order is resting.
Do not retry the same price in a loop; what happens next belongs in your own written rules. Post only controls how the order enters the book; the fee you pay remains the venue's schedule.
RPI is a separate post only type: Binance USD-M and Bybit both say it matches only orders from their app or website, not API orders. Wider error handling is in Binance API error codes.
Time in force FIX tag: FIX 59 values
FIX carries time in force in tag 59 (TimeInForce), and the FIX Latest code set, version EP312 on Orchimate, says an absent tag means Day.
| Value | Name | Meaning |
|---|---|---|
| 0 | Day | Expires at the end of the trading day |
| 1 | GTC | In effect until executed or canceled |
| 2 | OPG | Executes at the opening or not at all |
| 3 | IOC | Executes in whole or part, the rest is canceled |
| 4 | FOK | Executes in full or is canceled |
| 5 | GTX | Canceled before the market enters an auction or crossing phase |
| 6 | GTD | Until ExpireDate (432) or ExpireTime (126) |
| 7, 8, 9, A, B, C | Others | At the Close, Good Through Crossing, At Crossing, Good for Time, Good for Auction, Good for this Month |
- GTX is not post only in FIX. Tag 59=5 concerns auction phases, while Binance USD-M uses GTX for post only. A mapper that matches on the letters sends the wrong instruction.
- Post only is not in tag 59. Binance's FIX API sends
LIMIT_MAKERas40=2|18=6, using ExecInst value 6, Participate don't initiate, and accepts only 1, 3 and 4 in tag 59. Kraken's FIX 4.4 requires tag 59 and uses18=P, while the OnixS FIX 4.4 dictionary (opens in a new tab) lists P as Market peg. On Kraken FIX, FOK and GTD are Spot only.
Session mechanics are in broker API integration.
Good til canceled: does a GTC order ever expire?
Yes: FIX describes GTC as lasting until executed or canceled, but venues and brokers can set their own limit, so store an expiry rather than assume none.
- Binance USD-M: its Common Definition page, last modified 30 October 2026, gives GTC a validity of 1 year from placement.
- Alpaca: its order documentation says an aged order policy cancels GTC orders 90 days after creation, with the date in
expires_at. - US stock brokers: the SEC's Investor.gov bulletin on order types says the limit varies by brokerage firm.
Account types and API access vary by broker and country, so read your own terms. The other venue pages read here state no limit, which does not mean none exists. A forgotten GTC order can fill long after its reason has passed, so read open orders from the venue at every restart.
A tested Python mapper for time in force
Normalize once: one validated internal order model, one small function per venue, and a hard refusal for any combination the venue does not document.
from dataclasses import dataclass
from datetime import datetime, timedelta
NOW = 1_800_000_000 # synthetic clock
class Unsupported(ValueError):
pass
@dataclass(frozen=True)
class Order:
tif: str # GTC, IOC, FOK, POST or GTD
expire_s: int = 0 # unix seconds, GTD only
def __post_init__(self): # bad input never reaches a mapper
if (self.tif not in ("GTC", "IOC", "FOK", "POST", "GTD") or type(self.expire_s) is not int
or not (NOW < self.expire_s < 253_402_300_799 if self.tif == "GTD"
else self.expire_s == 0)):
raise Unsupported(f"bad order {self}")
def utc(s, fmt): # date math: no gmtime year limit
return (datetime(1970, 1, 1) + timedelta(seconds=s)).strftime(fmt)
def kraken_month(o): # GTD "up to one month"; 28 days fits any month
if o.tif == "GTD" and o.expire_s > NOW + 28 * 86400:
raise Unsupported("GTD over one month ahead")
def binance_spot(o):
if o.tif == "GTD":
raise Unsupported("no GTD in the enum")
if o.tif == "POST":
return {"type": "LIMIT_MAKER"} # needs no timeInForce
return {"type": "LIMIT", "timeInForce": o.tif}
def binance_usdm(o):
if o.tif == "GTD":
if o.expire_s <= NOW + 600:
raise Unsupported("goodTillDate must be over 600 s ahead")
return {"type": "LIMIT", "timeInForce": "GTD", "goodTillDate": o.expire_s * 1000}
return {"type": "LIMIT", "timeInForce": {"POST": "GTX"}.get(o.tif, o.tif)}
def bybit(o):
if o.tif == "GTD":
raise Unsupported("no GTD in the enum")
return {"orderType": "Limit", "timeInForce": {"POST": "PostOnly"}.get(o.tif, o.tif)}
def coinbase(o):
key, extra = {"GTC": ("limit_limit_gtc", {"post_only": False}),
"POST": ("limit_limit_gtc", {"post_only": True}),
"IOC": ("sor_limit_ioc", {}), "FOK": ("limit_limit_fok", {}),
"GTD": ("limit_limit_gtd", {"end_time": utc(o.expire_s, "%Y-%m-%dT%H:%M:%SZ")})}[o.tif]
return {"order_configuration": {key: extra}}
def hyperliquid(o):
if o.tif in ("FOK", "GTD"):
raise Unsupported("tif is Alo, Ioc or Gtc")
return {"t": {"limit": {"tif": {"GTC": "Gtc", "IOC": "Ioc", "POST": "Alo"}[o.tif]}}}
def kraken(o):
kraken_month(o)
if o.tif == "POST":
return {"timeinforce": "GTC", "oflags": "post"}
return {"timeinforce": o.tif} | ({"expiretm": str(o.expire_s)} if o.tif == "GTD" else {})
def okx(o):
if o.tif == "GTD":
raise Unsupported("no ordType for GTD")
return {"ordType": {"GTC": "limit", "IOC": "ioc", "FOK": "fok", "POST": "post_only"}[o.tif]}
def binance_fix(o):
if o.tif == "GTD":
raise Unsupported("tag 59 takes only 1, 3 or 4")
return {18: "6"} if o.tif == "POST" else {59: {"GTC": "1", "IOC": "3", "FOK": "4"}[o.tif]}
def kraken_fix(o): # Spot; tag 59 is required
kraken_month(o)
return {"GTC": {59: "1"}, "IOC": {59: "3"}, "FOK": {59: "4"}, "POST": {59: "1", 18: "P"},
"GTD": {59: "6", 126: utc(o.expire_s, "%Y%m%d-%H:%M:%S")}}[o.tif]
for build in (binance_spot, binance_usdm, bybit, coinbase, hyperliquid, kraken, okx,
binance_fix, kraken_fix):
refused = []
for tif in ("GTC", "IOC", "FOK", "POST", "GTD"):
try:
build(Order(tif, NOW + 3600 if tif == "GTD" else 0))
except Unsupported:
refused.append(tif)
print(f"{build.__name__:13}", build(Order("POST")), "refuses", refused or "nothing")
for build, args in ((binance_usdm, ("GTD", NOW + 60)), (okx, ("DAY",)), (okx, ("IOC", float("1e400")))):
try:
build(Order(*args))
except Unsupported as err:
print(f"{build.__name__}: {err}")Output:
binance_spot {'type': 'LIMIT_MAKER'} refuses ['GTD']
binance_usdm {'type': 'LIMIT', 'timeInForce': 'GTX'} refuses nothing
bybit {'orderType': 'Limit', 'timeInForce': 'PostOnly'} refuses ['GTD']
coinbase {'order_configuration': {'limit_limit_gtc': {'post_only': True}}} refuses nothing
hyperliquid {'t': {'limit': {'tif': 'Alo'}}} refuses ['FOK', 'GTD']
kraken {'timeinforce': 'GTC', 'oflags': 'post'} refuses nothing
okx {'ordType': 'post_only'} refuses ['GTD']
binance_fix {18: '6'} refuses ['GTD']
kraken_fix {59: '1', 18: 'P'} refuses nothing
binance_usdm: goodTillDate must be over 600 s ahead
okx: bad order Order(tif='DAY', expire_s=0)
okx: bad order Order(tif='IOC', expire_s=inf)This ran on Python 3.11 on 5 November 2026 with synthetic orders and no network. It maps only time in force fields; symbol, side, quantity and price need the same care. No request was sent, because order endpoints need real keys, so run each path on the venue's test environment first, where it has one, as the Binance Python guide shows.
Keep the refusals. Falling back to GTC when GTD was asked for leaves an order resting after you meant it to end.
Failure cases to test before live orders
Test the paths where an order ends without trading; a happy-path demo never shows them.
| Case | Pass condition |
|---|---|
| Post only would cross | Handles a rejected reply and a later cancel, with no retry at the same price |
| FOK finds too little | No position change; EXPIRED on Binance Spot and -5021 on USD-M are both handled |
| IOC fills partly | Position uses the filled quantity; the rest is not re-sent without a rule |
| GTD reaches its expiry | The venue's expiry event closes the local order, not your clock; Binance USD-M warns its auto-cancel can run late in extreme markets |
| Field left out | The mapper sends a value wherever the venue takes one, since Bybit and Kraken default to GTC and FIX to Day |
| GTC outlives a broker limit | Reconciliation marks the local order closed |
Rules depend on your jurisdiction and each platform's terms. For readers in Turkey: Article 99/A of Capital Markets Law No. 6362 treats activity by foreign crypto-asset platforms directed at Turkish residents as unauthorized. The Capital Markets Board (SPK) says being on its operating list (opens in a new tab) does not mean authorization. For integration work in general, see Fincode's exchange API integration page; naming these venues here does not mean Fincode integrates them or has built on them. Automated orders can lose money, and tests show how software behaves, not future results.
Frequently asked questions
What does GTC mean in trading?
Good till canceled: the order stays active until it fills or you cancel it. Some venues and brokers still cap it, such as 1 year on Binance USD-M and 90 days at Alpaca, as read on 5 November 2026.
What is the difference between an immediate or cancel order and a fill or kill order?
Both execute at once and never rest: IOC keeps what fills and cancels the rest, while FOK cancels everything unless the whole quantity can fill.
Is GTX the same as post only?
On Binance USD-M, yes. In the FIX standard, no: tag 59=5 means an order canceled before an auction or crossing phase, and Binance and Kraken FIX send post only through ExecInst (18).
Which time in force should a bot use?
That depends on rules you wrote for your own purpose; this guide recommends no setting. Software must send the value explicitly and handle every way the order can end.
Sources
- Binance Spot API documentation: Enum definitions (timeInForce, order types, EXPIRED) (opens in a new tab)
- Binance Spot API documentation: Errors (-1102, -2010 and order placement messages) (opens in a new tab)
- Binance Spot API documentation: FIX API (ExecInst, TimeInForce, LIMIT_MAKER) (opens in a new tab)
- Binance USD-M Futures: Common Definition (time in force, last modified 30 October 2026) (opens in a new tab)
- Bybit V5 API: Place Order (opens in a new tab)
- Bybit V5 API: Enums Definitions (timeInForce, rejectReason) (opens in a new tab)
- Coinbase Advanced Trade API: Create Order (order_configuration, failure reasons) (opens in a new tab)
- Hyperliquid API: Exchange endpoint (tif values, expiresAfter) (opens in a new tab)
- Kraken API: Add Order (timeinforce, oflags, expiretm) (opens in a new tab)
- Kraken API: FIX New Order Single (tags 18 and 59) (opens in a new tab)
- OKX API v5: Place order (ordType, cancelSource) (opens in a new tab)
- FIX Latest EP312 on Orchimate, where FIX Trading Community Fiximate links now redirect: TimeInForceCodeSet (opens in a new tab)
- SEC Investor.gov: Understanding Order Types, Investor Bulletin (opens in a new tab)
- Alpaca: Orders at Alpaca (time in force, aged order policy) (opens in a new tab)
- Capital Markets Law No. 6362, consolidated text, Article 99/A (Turkish) (opens in a new tab)
This guide is general information about software and markets, not investment, legal or tax advice. Automated trading can lose money, past or backtested performance does not guarantee future results, and the rules that apply depend on your jurisdiction and your exchange's terms. Sources, checks and corrections: see the editorial policy.