====== Order Routing ======
[[developers:apiv2|◀ WebSocket API (V2)]]
**Prerequisite:** [[developers:apiv2:accounts|subscribe to the account]] first, and hold a Trading role. Orders into an unsubscribed account are rejected.
**Prices and Volumes are [[https://github.com/CTS-Futures/t4-api-tools/blob/main/proto/t4/v2/common/price.proto|Decimal]] Strings** — for example ''"5"'', ''"1.50"'', ''"4200.50"''. See [[developers:apiv2:pricing|Prices & Data Types]].
===== Client Order Messages =====
^ Message ^ Purpose ^
| [[https://github.com/CTS-Futures/t4-api-tools/blob/main/proto/t4/v2/orderrouting/orderrouting.proto#L30|OrderSubmit]] | Place one or more orders into a single account+market. |
| [[https://github.com/CTS-Futures/t4-api-tools/blob/main/proto/t4/v2/orderrouting/orderrouting.proto#L74|OrderRevise]] | Change working orders: price, volume, max show, stop price, trail price, tag or activation data. |
| [[https://github.com/CTS-Futures/t4-api-tools/blob/main/proto/t4/v2/orderrouting/orderrouting.proto#L100|OrderPull]] | Cancel working orders. |
| [[https://github.com/CTS-Futures/t4-api-tools/blob/main/proto/t4/v2/orderrouting/orderrouting.proto#L66|OrderBatch]] | Submit several orders as an all-or-nothing batch. |
| [[https://github.com/CTS-Futures/t4-api-tools/blob/main/proto/t4/v2/orderrouting/orderrouting.proto#L118|CreateUDS]] | Define a user-defined strategy. |
===== Submit, Revise, Pull =====
==== Submit ====
Send ''OrderSubmit'' to place one or more orders into a single account+market.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
order_link: ORDER_LINK_NONE
manual_order_indicator: false
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "5" }
limit_price: { value: "4200.50" }
ClOrdId: "my-order-1"
}
}
Multiple orders in one ''OrderSubmit'' share the same ''account_id'' and ''market_id''.
==== Revise ====
Send ''OrderRevise'' to change one or more working orders. Address the order by ''unique_id'' from ''OrderUpdate'', or by your original ''ClOrdId''. Set only the fields you are changing.
order_revise {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
manual_order_indicator: false
revisions {
unique_id: "a3b1c5f2-7d43-4f9b-88e2-1e2f75c6d9a1"
volume: { value: "10" }
limit_price: { value: "4250.00" }
}
}
==== Pull ====
Send ''OrderPull'' to cancel one or more working orders. Address the order by ''unique_id'' or ''ClOrdId''.
order_pull {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
manual_order_indicator: false
pulls {
unique_id: "a3b1c5f2-7d43-4f9b-88e2-1e2f75c6d9a1"
}
}
===== Routing Orders on Behalf of Another User =====
Set ''user_id'' to route for another user. Omit it, or leave it empty, to trade as the authenticated user.
Requirements:
* The authenticated user must have the Order Routing role.
* The routed user must belong to the authenticated user's firm or child firm, and must be enabled.
* The account must be one the routed user is entitled to trade.
* The account must already be subscribed by the authenticated session.
Example ''OrderSubmit'' on behalf of another user:
order_submit {
user_id: "efda0709-af12-4b65-8971-5089edb4aaf0"
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
manual_order_indicator: true
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "5" }
limit_price: { value: "4200.50" }
ClOrdId: "customer-order-1"
}
}
The same field is available on ''OrderRevise'' and ''OrderPull'':
order_pull {
user_id: "efda0709-af12-4b65-8971-5089edb4aaf0"
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
manual_order_indicator: true
pulls {
unique_id: "a3b1c5f2-7d43-4f9b-88e2-1e2f75c6d9a1"
}
}
Order validation uses the routed user's own roles, accounts, exchange permissions and permitted order types. ''OrderUpdate'' identifies both parties using ''user_name'' and ''routing_user_name''.
===== Margin Inquiry =====
Set ''margin_inquiry: true'' on a submitted ''Order'' to receive a ''MarginInquiryResponse''. No order is sent to the exchange.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
limit_price: { value: "4200.50" }
```
margin_inquiry: true
margin_inquiry_id: "margin-check-1"
```
}
}
The response includes current margin, margin with the hypothetical order, and the margin impact.
===== Order Types =====
Full enum lists are in [[https://github.com/CTS-Futures/t4-api-tools/blob/main/proto/t4/v2/common/enums.proto|proto/t4/v2/common/enums.proto]].
^ Price type ^ Time in force ^
| ''PRICE_TYPE_MARKET'' | ''TIME_TYPE_NORMAL'' |
| ''PRICE_TYPE_LIMIT'' | ''TIME_TYPE_IMMEDIATE_AND_CANCEL'' |
| ''PRICE_TYPE_STOP_MARKET'' | ''TIME_TYPE_COMPLETE_VOLUME'' |
| ''PRICE_TYPE_STOP_LIMIT'' | ''TIME_TYPE_GOOD_TILL_CANCELLED'' |
| ''PRICE_TYPE_FLATTEN'' | ''TIME_TYPE_MARKET_ON_OPEN'' / ''TIME_TYPE_MARKET_ON_CLOSE'' |
| ''PRICE_TYPE_RFQ'' | |
==== Market Order ====
A market order executes immediately at the best available price.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_MARKET
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
}
}
==== Limit Order ====
A limit order executes at the specified price or better.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
limit_price: { value: "2376.50" }
}
}
==== Stop Market Order ====
A stop market order becomes a market order when the stop price is reached.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_STOP_MARKET
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
stop_price: { value: "2376.50" }
}
}
==== Stop Limit Order ====
A stop limit order becomes a limit order when the stop price is reached.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_STOP_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
stop_price: { value: "2375.00" }
limit_price: { value: "2375.00" }
}
}
==== Trailing Stop Order ====
A trailing stop order moves the stop price automatically based on price movement.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_STOP_MARKET
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
stop_price: { value: "2375.00" }
trail_distance: { value: "50" }
}
}
==== Fill or Kill (FOK) Order ====
A Fill or Kill order must execute immediately in full or it is canceled.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_COMPLETE_VOLUME
volume: { value: "1" }
limit_price: { value: "2375.00" }
}
}
==== Immediate or Cancel (IOC) Order ====
An Immediate or Cancel order executes immediately for the available quantity and cancels the rest.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_IMMEDIATE_AND_CANCEL
volume: { value: "1" }
limit_price: { value: "2375.00" }
}
}
==== Good Till Cancelled (GTC) Order ====
A Good Till Cancelled order remains working until filled or canceled.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_GOOD_TILL_CANCELLED
volume: { value: "1" }
limit_price: { value: "2375.00" }
}
}
===== Linked Orders =====
==== Order Cancels Order (OCO) ====
An OCO is a pair of orders submitted together. Both orders are placed at the same time. When one fills, the other is automatically canceled. If one order partially fills, the remaining volume of the other order is adjusted.
OCO orders must use the same ''account_id'' and ''market_id''.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
order_link: ORDER_LINK_OCO
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
limit_price: { value: "2375.00" }
}
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_STOP_MARKET
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
stop_price: { value: "2380.00" }
}
}
==== AutoOCO ====
An AutoOCO is three orders:
* A trigger order.
* A take-profit order.
* A stop-loss order.
When the trigger order fills, the take-profit and stop-loss orders are submitted as an OCO pair. Child prices are differentials from the trigger fill price.
order_submit {
account_id: "ACCT1"
market_id: "XCME_Eq ES (H26)"
order_link: ORDER_LINK_AUTO_OCO
manual_order_indicator: true
// Trigger order
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
limit_price: { value: "6858.00" }
}
// Take profit: 25.00 points above the trigger fill
orders {
buy_sell: BUY_SELL_SELL
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_GOOD_TILL_CANCELLED
volume: { value: "0" }
limit_price: { value: "25.00" }
activation_type: ACTIVATION_TYPE_HOLD
}
// Stop loss: 12.50 points below the trigger fill
orders {
buy_sell: BUY_SELL_SELL
price_type: PRICE_TYPE_STOP_MARKET
time_type: TIME_TYPE_GOOD_TILL_CANCELLED
volume: { value: "0" }
stop_price: { value: "12.50" }
activation_type: ACTIVATION_TYPE_HOLD
}
}
==== Take Profit and Stop Loss ====
Take profit and stop loss is the common AutoOCO bracket: the first order opens the position, then a profit target and stop loss are placed after the trigger fills.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
order_link: ORDER_LINK_AUTO_OCO
// Trigger order
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
limit_price: { value: "2375.00" }
}
// Take profit
orders {
buy_sell: BUY_SELL_SELL
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_GOOD_TILL_CANCELLED
volume: { value: "0" }
limit_price: { value: "10.00" }
activation_type: ACTIVATION_TYPE_HOLD
}
// Stop loss
orders {
buy_sell: BUY_SELL_SELL
price_type: PRICE_TYPE_STOP_MARKET
time_type: TIME_TYPE_GOOD_TILL_CANCELLED
volume: { value: "0" }
stop_price: { value: "15.00" }
activation_type: ACTIVATION_TYPE_HOLD
}
}
==== Flatten Position ====
A flatten order closes the entire position in the specified market using an offsetting market order.
order_submit {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
price_type: PRICE_TYPE_FLATTEN
}
}
The server determines the side and volume from the current position. Clip size limits are ignored so the entire position can be closed.
===== Batch =====
''OrderBatch'' groups multiple ''OrderSubmit'' messages and validates them together.
order_batch {
batch_id: "batch-1"
submissions {
account_id: "ACCT1"
market_id: "XCME_C ZC (H25)"
orders {
buy_sell: BUY_SELL_BUY
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
limit_price: { value: "2375.00" }
ClOrdId: "batch-order-1"
}
}
submissions {
account_id: "ACCT2"
market_id: "XCME_Eq ES (H26)"
orders {
buy_sell: BUY_SELL_SELL
price_type: PRICE_TYPE_LIMIT
time_type: TIME_TYPE_NORMAL
volume: { value: "1" }
limit_price: { value: "6858.00" }
ClOrdId: "batch-order-2"
}
}
}
* All pass → ''OrderBatchAcknowledge'', then normal per-order ''OrderUpdate'' messages follow.
* Any fails → ''OrderBatchReject'' and nothing is submitted.
''batch_id'' is echoed as ''tag_relation_id'' on the resulting updates.
===== What You Receive =====
==== OrderUpdate ====
V2 delivers all order lifecycle events through one ''OrderUpdate'' message. Read ''update_type'' first.
^ ''update_type'' ^ Meaning ^
| ''SNAPSHOT'' | Existing order sent on account subscribe. |
| ''STATUS'' | Working, revised, pulled or rejected state change. |
| ''TRADE'' | A fill occurred. |
| ''TRADE_LEG'' | A fill on a strategy leg. |
| ''FAILED'' | The request failed. |
Key fields:
* ''unique_id'' — server order id.
* ''status'' — high-level state: ''ORDER_STATUS_WORKING'', ''ORDER_STATUS_FINISHED'', ''ORDER_STATUS_REJECTED'', ''ORDER_STATUS_HELD''.
* ''change'' — fine-grained lifecycle transition.
* ''status_detail'' — human-readable reason, including reject/failure text.
* ''current_volume'', ''new_volume'', ''working_volume'', ''total_fill_volume'' — decimal strings.
* ''current_limit_price'', ''new_limit_price'', ''current_stop_price'', ''new_stop_price'' — prices.
* ''tag_cl_ord_id'' — echo of your ''ClOrdId''.
* ''tag_relation_id'' — batch or linked-order correlation id.
==== OrderTrade ====
Each fill is also delivered as ''OrderTrade''.
Key fields: ''volume'', ''price'', ''residual_volume'', ''exchange_trade_id'', ''exchange_time'', and ''leg_index'' for strategy legs.
===== Order Status Summary Reference =====
When displaying order status to users, combine ''OrderUpdate.status'', ''OrderUpdate.change'' and fill volume.
The table below omits the common enum prefixes to keep it readable:
* ''ORDER_STATUS_''
* ''ORDER_CHANGE_''
^ Status ^ Change ^ Display message ^ Notes ^
| **Finished states** ||||
| ''FINISHED'' | ''PULL_FAILED'', ''PULL_REJECTED'', ''PULL_RISK_FAILED'' | Cancel Failed | Include ''status_detail''. |
| ''FINISHED'' | ''PULL_SUCCESS'', ''PULL_SENT'', ''PULL_RISK_SUCCESS'' | Completed, Partial Fill | When ''total_fill_volume'' is not zero. |
| ''FINISHED'' | ''PULL_SUCCESS'', ''PULL_SENT'', ''PULL_RISK_SUCCESS'' | Canceled | When ''total_fill_volume'' is zero. |
| ''FINISHED'' | ''TRADE_COMPLETED'' | Completed, Partial Fill | When ''total_fill_volume'' is less than the original volume. |
| ''FINISHED'' | ''TRADE_COMPLETED'' | Completed, Filled | When ''total_fill_volume'' equals the original volume. |
| ''FINISHED'' | ''STATUS_REQUEST_FAILED'', ''STATUS_REQUEST_REJECTED'', ''STATUS_REQUEST_RISK_FAILED'', ''STATUS_REQUEST_RISK_SUCCESS'', ''STATUS_REQUEST_SENT'', ''STATUS_REQUEST_SUCCESS'', ''TAG_FAILED'', ''TAG_SUCCESS'' | Completed, Partial Fill, {change} | When partially filled. |
| ''FINISHED'' | ''STATUS_REQUEST_FAILED'', ''STATUS_REQUEST_REJECTED'', ''STATUS_REQUEST_RISK_FAILED'', ''STATUS_REQUEST_RISK_SUCCESS'', ''STATUS_REQUEST_SENT'', ''STATUS_REQUEST_SUCCESS'', ''TAG_FAILED'', ''TAG_SUCCESS'' | Completed, Filled, {change} | When fully filled. |
| ''FINISHED'' | ''REVISION_RISK_FAILED'' | Completed, Filled, {change} | When fully filled. |
| ''FINISHED'' | ''TRADE_BUSTED'' | Completed, {change} | |
| ''FINISHED'' | ''SUBMISSION_SUCCESS'' | Completed | RFQ only. |
| **Rejected states** ||||
| ''REJECTED'' | ''STATUS_REQUEST_FAILED'', ''STATUS_REQUEST_REJECTED'', ''STATUS_REQUEST_RISK_FAILED'', ''STATUS_REQUEST_RISK_SUCCESS'', ''STATUS_REQUEST_SENT'', ''STATUS_REQUEST_SUCCESS'' | Rejected, {change} | Include ''status_detail''. |
| ''REJECTED'' | Other changes | Rejected | Include ''status_detail''. |
| **Working states** ||||
| ''WORKING'' | ''PULL_RISK_SUCCESS'', ''PULL_SENT'', ''PULL_SUCCESS'' | Canceling... | |
| ''WORKING'' | ''REVISION_SENT'', ''REVISION_RISK_SUCCESS'' | Revising... | |
| ''WORKING'' | ''REVISION_SUCCESS'' | Working, Revised | |
| ''WORKING'' | ''REVISION_FAILED'', ''REVISION_REJECTED'', ''REVISION_RISK_FAILED'' | Working, Revision Failed | Include ''status_detail''. |
| ''WORKING'' | ''PULL_FAILED'', ''PULL_REJECTED'', ''PULL_RISK_FAILED'' | Working, Cancel Failed | Include ''status_detail''. |
| ''WORKING'' | ''TRADE'', ''SUBMISSION_SENT'', ''SUBMISSION_SUCCESS'', ''SUBMISSION_RISK_SUCCESS'' | Working... | |
| ''WORKING'' | ''HANDOVER'' | Working, Handover | |
| ''WORKING'' | ''ROLLOVER'' | Working, Rollover | |
| ''WORKING'' | ''STATUS_REQUEST_FAILED'', ''STATUS_REQUEST_REJECTED'', ''STATUS_REQUEST_RISK_FAILED'', ''STATUS_REQUEST_RISK_SUCCESS'', ''STATUS_REQUEST_SENT'', ''STATUS_REQUEST_SUCCESS'', ''TAG_FAILED'', ''TAG_SUCCESS'' | Working, {change} | |
| ''WORKING'' | Any change with fills | {base message}, Partial Fill | Append when ''total_fill_volume'' is greater than zero. |
| **Pre-submission states** ||||
| ''NONE'' | ''NONE'' | Submitting... | |
| ''NONE'' | ''SUBMISSION_RISK_SUCCESS'' | Submitting to Exchange | |
| ''NONE'' | ''SUBMISSION_REJECTED'', ''SUBMISSION_RISK_REJECTED'' | Submission Rejected | Include ''status_detail''. |
| ''NONE'' | ''SUBMISSION_FAILED'' | Submission Failed | Include ''status_detail''. |
| ''NONE'' | ''SUBMISSION_SENT'', ''SUBMISSION_SUCCESS'' | Submission Sent | |
| **Held states** ||||
| ''HELD'' | Any change | Held on Server... / Held on Client... | Server-held for real markets; client-held for non-real markets. |