Complex Orders
Overview
This document describes how the Trading Data Model API supports complex orders. Specifically, it addresses scenarios where a trader wants to open a LONG position (using an “enter” BUY order) and immediately protects this position with a pair of take profit and stop loss SELL orders.
The Complex Orders API enables the transmission of such complex orders to the Order Management System (OMS) through a sequence of API calls. However, grouping these orders together allows for an “all or none” semantic. This means that if one of the orders in a group fails OMS validation, the entire group is rejected.
Terminology
This section aims to clarify the confusion surrounding terminology by distinguishing between two similar order types: OCO (One-Cancels-the-Other) and OUO (Order Updates Order).
OCO (One-Cancels-the-Other) - A One-Cancels-the-Other (OCO) order is a pair of conditional orders that, when one order is executed, the other order is automatically canceled. This order type is commonly used in automated trading platforms and often combines a stop order with a limit order. Both orders remain active in the marketplace simultaneously until one of them is executed, and cancellation of the Contingent Order happens on a best efforts basis. When either the stop price or limit price specified in the OCO order is reached, resulting in the execution of one order, the other order is immediately canceled. Partial executions also trigger an attempt to cancel the other order.
OUO (Order Updates Order) - An Order-Updates-Order (OUO) decreases the quantity of another linked order when it is executed. This reduction in quantity is done on a best effort basis. With an OUO order, both orders are live in the marketplace at the same time. The execution of either order triggers an attempt to reduce the remaining quantity of the other order, including any partial executions.
The term "Bracket order" is synonymous with Order-Updates-Order (OUO). Any references to OCO in the context of Bracket order discussions are incorrect and should be considered a mistake.
Types of Complex Orders
Bracket Orders (OUO)
A bracket order is a special instance of an OUO (Order Updates Order). Bracket orders are used to exit an existing position. They are designed to limit loss and lock in profit by “bracketing” an order with a simultaneous stop and limit order.
Bracket orders are limited so that the orders are all for the same symbol and are on the same side of the market (either all to sell or all to cover), and they are restricted to closing transactions. These restrictions are necessary to facilitate automatic decrements when a partial fill occurs with one of the orders.
For instance, consider a scenario where a customer has a sell limit order for 1000 shares and a sell stop order for 1000 shares. If the limit order is partially filled for 500 shares, it is desirable for the stop order to remain active but automatically adjust its quantity to match the remaining open position, resulting in a decrement to 500 shares.
Exit Bracket
The Exit Bracket order combines a Sell Stop (Stop Loss) order and a Sell Limit (Take Profit) order. This order type is designed for users who already have a position and wish to box their position. It allows users to set a stop loss level to limit potential losses and a take profit level to secure profits. These orders should be vetted against current balances when used as an exit bracket.
In the future, we plan to introduce support for short positions and expand the usage of this order type as an entry order. While it is currently acceptable to use a Stop Market order, our goal is to incorporate Stop Limit orders.
Entry - Breakout/Fade Buy OUO
The Entry - Breakout/Fade Buy OUO template consists of a Buy Stop order placed above the current market price and a Buy Limit order placed below the current market price. This order template is suitable when you want to enter a long position but are uncertain whether the market will break out in an upward direction or retrace to a lower support level before continuing its upward movement.
Order Submit Order (OSO)
Order Submit Orders (OSO) are typically used to enter a protected position (LONG or SHORT). This complex order consists of an entry order and one or more Exit orders, which become activated when the entry order is filled.
Let’s consider an OSO consisting of three legs:
- Entry order: A limit BUY order for 1000 units.
- Attached to the entry order are two SELL orders (OUO) - an exit bracket order consisting of two legs:
- A limit SELL 1000 (take profit) order.
- A stop SELL 1000 (stop loss) order.
After the Entry order completes, the Exit order(s) are sent to the market. The quantity of Exit orders is set to the cumulative filled quantity of the Entry order. If the Entry order is cancelled without a fill or is rejected, the Exit orders are not sent.
To avoid complexity and prevent self-trading, Exit orders wait until Entry order is complete. A partially filled Entry order results in an unprotected (naked) position until the Entry order is active.
The OSO can trigger a single Exit order (e.g., LIMIT or STOP) or an OUO order bracket consisting of two legs.
In the case of a partially filled Entry order with a GTC (Good 'Til Cancelled) or GOOD_TILL_DATE time-in-force condition, it will be converted to a DAY order, expiring at the end of the day.
Restrictions/Limitations
- All orders in group must be for the same symbol (contract).
- All orders in the group must have the same quantity.
- Nested groups are not supported. There is one exception - a 3-legged group of
Entry
+Bracket Exit
orders is supported.
Implementation Approach 1: Linked orders
General Idea
The implementation approach of linked orders is commonly utilized by venues such as Integral FX and Interactive Brokers. This approach represents a bracket order as a pair of linked order requests.
The process of submitting a bracket order follows these steps:
Submit the first component order with ContingencyType(1385) set to OUO. The order's TimeInForce(59) of the order should have an expiry other than Immediate or Cancel (IOC) or Fill or Kill (FOK).
Receive an Execution Report message confirming that the first component order is valid, indicated by the OrdStatus(39) field set to PendingNew(A).
Submit the second component order with ContingencyType(1385) set to OUO, and the ClOrdLinkID(583) set to the client order ID (ClOrdID(11)) of the first component order.
The system performs the following validation:
Ensures that the first component order is still in the Pending New state, meaning it has not expired, been cancelled, or filled.
Checks that the TimeInForce(59) expiry of the second component order is not set to IOC or FOK.
If the second component order passes validation, you receive two Execution Report messages indicating that both orders are working for the first component order. Each report message will have the OrderStatus field set to New(0).
If either one of the component orders is filled or partially filled, the system adjusts the other component order by either cancelling it or reducing its effective size.
If one component order expires or is cancelled, the other order is not cancelled and remains in effect until it is filled, expired, or cancelled. In all other aspects related to the execution, expiry, and status, each component order behaves the same as any other order with the same expiry and execution characteristics.
Special Order Attributes
Here is a summary of custom order attributes used by the bracket order pair:
Name (FIX tag) | Required | Type | Description |
---|---|---|---|
ContingencyType(1385) | Y | Enum | 1 = OCO (One cancels other) 2 = OTO (One triggers other, also known as OSO) 3 = OUO, Absolute (One updates other) ← BRACKET ORDER 100 = OSO,OUO |
ClOrdLinkID(583) | C | Text | ID of the previous order in group. This attribute is skipped on the first order but required on subsequent orders of the group. |
Diagrams
The following diagrams illustrate this approach:
Notes
Here are some important points to consider regarding the implementation of linked orders:
- Orders can be submitted in rapid succession (fire and forget) without waiting for acknowledgements. The API client doesn't need to wait for the acknowledgement of the first order before submitting subsequent orders.
- Order destinations that support group orders should wait for all legs to arrive before initiating the execution of the first leg. This ensures that all component orders are received before processing begins.
- Order destinations that support group orders are responsible for canceling partially submitted orders after a configurable timeout. For example, if the second leg is lost during transmission, the destination should cancel any partially submitted orders to avoid inconsistencies.
- In certain abnormal conditions, the legs of a group order may be delivered to the destination out of order. The destination should be designed to handle such situations appropriately.
Disadvantages of this approach:
- There is no mechanism to atomically modify the order quantity of a group order. To modify the quantity, clients must cancel each leg and resubmit a new bracket order with the desired quantity.
Enrichment
After assembling the entire group of orders, Deltix OMS enriches each order with additional information to simplify reporting.
The following table describes the enriched attributes:
Name (FIX tag) | Required | Type | Description |
---|---|---|---|
LegRole(7101) | Enum | Text | Specifies the role of the leg within the group. For Example: ENTRY - Order enters into long or short position UPPER_BRACKET - Part of a bracket order with a higher price LOWER_BRACKET - This attribute simplifies reporting and allows for easier identification of grouped orders. |
NumLegs(7102) | Y | Int | Defines how many legs are in an order group. It also marks the start of the repeating group of ClOrdLinkID(583) entries for each leg. |
The following diagram illustrates these attributes applied to a group of three orders:
Bracket Order Lifecycle Events
Bracket orders follow the same order lifecycle events as independent orders for each leg. Clients will receive order acknowledgements, cancellations, fills, and other relevant events for each leg of the bracket order.
Here are a few examples illustrating the order lifecycle events for bracket orders.
Example 1
- The client submits the first leg of the bracket order.
- The system confirms the first leg with an Order Pending New Event.
- The client submits the second leg of the bracket order, but it is invalid.
- The system rejects the second leg with an Order Reject Event and cancels the first leg with an Order Cancel Event.
Example 2
- The client submits the first leg of the bracket order.
- The system confirms the first leg with an Order Pending New Event. (The order is received but not working).
- The client submits the second leg of the bracket order.
- The system confirms the second leg with an Order New Event.
- The system confirms that the first leg is now working with an Order New Event.
- One of the orders is completely filled.
- An Order Filled Event is triggered, reflecting the trade quantity for the entire order.
- An Order Cancel Event is triggered for the other leg.
In cases where one leg is partially filled while the other leg is active, the system uses an Order Restated Event to indicate a reduction in the order quantity for the leg that was not filled.
Example 3
- The client submits the first leg of the bracket order.
- The system confirms the first leg with an Order Pending New Event. (The order is received but not working).
- The client submits the second leg of the bracket order.
- The system confirms the second leg with an Order New Event.
- The system confirms that the first leg is now working with an Order New Event.
- The second leg is partially filled.
- An Order Filled Event is triggered for the second leg, reflecting the trade quantity of the fill.
- An Order Restated Event is triggered for the first leg, indicating a reduction in the order quantity.
REST API Samples
This section describes a REST API request that can be used to submit complex orders.
Sample 1: POST request for bracket order
The first order:
{
"order_id": "Order A",
"destination": "TSSR",
"expire_time": 1580247316000,
"price": "3000",
"quantity": "0.1239",
"security_id": "BTCUSD",
"side": "buy",
"submission_time": 1579200906345,
"time_in_force": 1,
"type": "limit",
"attributes": {
{ 1385, 3 } // Contingency Type=OUO
}
}
The second order:
{
"order_id": "Order B",
"destination": "TSSR",
"expire_time": 1580247316000,
"price": "4000",
"quantity": "0.1239",
"security_id": "BTCUSD",
"side": "sell",
"submission_time": 1579200906345,
"time_in_force": 1,
"type": "limit",
"attributes": {
{ 1385, 3 }, // Contingency Type=OUO
{ 583 = "Order A"} // LinkedOrderID
}
}
Sample 2: POST request for 3-legged order group
The first order:
{
"order_id": "Order A",
"destination": "TSSR",
"expire_time": 1580247316000,
"price": "3000",
"quantity": "0.1239",
"security_id": "BTCUSD",
"side": "buy",
"submission_time": 1579200906345,
"time_in_force": 1,
"type": "limit",
"attributes": {
{ 1385, 100 } // ContingencyType=OSO,OCO
}
}
The second order:
{
"order_id": "Order B",
"destination": "TSSR",
"expire_time": 1580247316000,
"price": "4000",
"quantity": "0.1239",
"security_id": "BTCUSD",
"side": "sell",
"submission_time": 1579200906345,
"time_in_force": 1,
"type": "limit",
"attributes": {
{ 1385, 100 }, // Contingency Type=OSO,OCO
{ 583 = "Order A"} // LinkedOrderID
}
}
The third order:
{
"order_id": "Order C",
"destination": "TSSR",
"expire_time": 1580247316000,
"price": "4000",
"quantity": "0.1239",
"security_id": "BTCUSD",
"side": "sell",
"submission_time": 1579200906345,
"time_in_force": 1,
"type": "limit",
"attributes": {
{ 1385, 100 }, // Contingency Type=OSO,OCO
{ 583 = "Order B"} // LinkedOrderID
}
}
Sample 3: Order response for bracket order
{
orderId = "Order A"
side = "BUY"
quantity = 10
attributes: {
{ 1385, 3 } // 3 = One-Updates-Other
{ 7101, "UPPER_BRACKET" }, // Do you need this?
{ 7102, 2 }, // number of legs to follow
{ 583, "Order A" }, // Sequence of orders in this list is not important
{ 583, "Order B" }, // for Bracket, but very important for OSO and others
}
}
{
orderId = "Order B"
side = "BUY"
quantity = 10
attributes: {
{ 1385, 3 } // 3 = One-Updates-Other
{ 7101, "LOWER_BRACKET" }, // Do you need this?
{ 7102, 2 }, // number of legs to follow
{ 583, "Order A" },
{ 583, "Order B" },
}
}
Ember CLI Example
The following example of a 3-legged order submission can be used with the ember-cli tool:
set destinationId TSSR
set sourceId TRADER-CLI
set orderId OSOENTRY2
set side BUY
set quantity 1
set symbol BTC/USD
set instrumentType FX
set timeInForce DAY
set orderType LIMIT
set limitPrice 6700
set attributes 1385=100
unset stopPrice
submit -f
set orderId OSOBRACKETPROFIT2
set side SELL
set orderType LIMIT
set limitPrice 6705
set attributes 1385=100,583=OSOENTRY2
submit -f
set orderId OSOBRACKETLOSS1
set side SELL
set orderType STOP
set stopPrice 6680
set attributes 1385=100,583=OSOBRACKETPROFIT2
unset limitPrice
submit -f