Hello, and welcome to this lesson on Complex Orders in the Interactive Brokers Client Portal API. In this lesson, we will be discussing how to place bracket and spread orders using the Client Portal API.
Bracket Order
To begin, let’s first discuss how to create a bracket order for using the CPAPI. Given the starting point is the same, I will present the same foundation as my previous lesson for discussing order placement. Here we can see I will still be using the iserver/account/{accountId}/orders endpoint. We will still be using the same json_body value for my request, and using the standard post request and json.dumps method I have use through the series.
Now can start moving into newer territory. You may have noticed that our body references ‘orders’ rather than just submitting a single ‘order’. That is because multiple legs can be sent in a single request. We can start with my original AAPL MKT order I had made before, but now I can add a slight tweak. I will simply implement the field, ‘cOID’, which stands for ‘customer order identifier.’ While you are welcome to place orders sequentially like before and retrieve the order id before placing the next, we are able to pre-define an orderId that can be used to attach multiple legs together. I will set my ‘cOID’ variable equal to ‘AAPL_BRACKET-MMDD’. Though you can set this to any simple identifier that would help you.
With our parent order set and our cOID defined, we can move on to our first child order. I can copy my parent array as a starting point. I’m still going to keep most of my fields the same, but with a few tweaks. I will change my orderType to LMT, and create a price field of 190. Then, I will change my cOID to ‘AAPL_BRACKET-MMDD-PT’ to signify a profit taker. Finally, I can introduce a new field, ‘parentId’ and set it equal to the original ‘cOID’, ‘AAPL_BRACKET-MMDD’. So now we have a profit taker built.
I can copy this, and then change my orderType again, now to ‘STP’. Then I will drop my price down to 185. Finally, I’ll change the ‘cOID’ from “-PT” to “-SL”. Now I have a full bracket order with the parent, profit taker and stop loss legs attached.
I would note that the Client Portal API maintains the same limitations as Trader Workstation, with maximum of 6 legs per order.
With everything built, I will run my code to send all three of my orders. Just like in standard orders, you might encounter a precautionary setting form an order. If I utilize my reply endpoint, I can confirm this order, and we will see all three order confirmations.
Combo or Spread Orders
Combination orders or spread orders may also be placed using the same orders endpoint. However, these are a bit different than how bracket orders are handled. Let’s start with a basic limit order again. In the case of combo orders, we will be replacing the conid field with ‘conidex’ instead. The conidex field is a string representation of our combo order parameters. This will follow the format of: ‘{spread_conid};;;{leg_conid1}/{ratio},{leg_conid2}/{ratio}‘
Let’s go ahead and break this down. First, spread_conid is a unique identified used to denote a spread order. For US combos, the spread_conid is set to 28812380. For all other countries, you will need to use the format ‘spread_conid@exchange’.
Other countries spread_conid: {AUD – 61227077, CAD – 61227082 ,CHF – 61227087 ,CNH – 136000441,EUR – 58666491,GBP – 58666494,HKD – 61227072,INR – 136000444 ,JPY – 61227069 ,KRW – ,136000424,MXN – 136000449,SEK – 136000429,SGD – 426116555 ,USD – 28812380}
Following our spread_conid, we will then follow with 4 semicolnons, and then introduce our first leg_coind. This will be the first contract to trade. In my case, I will use 497222760, which is the coming ES Futures contract. You will need to follow this with ‘/’, and then your spread ratio.
The ratio indicates two parts. The first is the sign of the ratio, whether it is positive or negative. Positive signs indicate a ‘Buy’ side, while a negative value represents a ‘Sell’ side. This could also be explained as a state of ‘Long’ and ‘Short’ respectively, depending on your current position and intention.
Moving on from the sign, we have the actual ratio. These are multipliers of your quantity value. For example, we are using a quantity of ‘3’ in our order today. If I use a ratio on my first leg of a positive ‘1’, then I will be buying 3 contracts. However, in options you may choose to have 1 options contract per 100 shares of the underlying stock. In that case, your options leg would use a ratio of 1, while your stock leg would use a ratio of 100.
Now that we have the spread_conid and our first leg, we can now comma-separate any additional legs for our order. I will add a comma after our last ratio, followed by the conid for the ES back month, 495512552, and set my ratio to a -1. This means that I will be buying the front month and shorting the back. You are welcome to sell both legs, buy both, or change which leg is bought and which is sold.
The only remaining outlier would involve the ‘price’ field. This price is the combined value of both legs, including their ratio. Given I have a long and a short leg, I will need to subtract the value of my back month from my front month to find my price. Given I know my values are as follows:
Front month = ( 1) * 4493.00
Back month = (-1) * 4543.00
Total = -50.00
With all of my values set, I can go ahead and place my order. After receiving my 200 OK response, I can see my order submitted successfully from the “submitted” field.
Thank you for watching this lesson on complex orders in the Client Portal API. If you find this lesson helpful, please check out our other lessons in the Client Portal API tutorial series.
Code Snippet – bracketOrder
import requests import json import urllib3 # Ignore insecure error messages urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def orderRequest(): base_url = "https://localhost:5000/v1/api/" endpoint = "iserver/account/DU5240685/orders" json_body = { "orders": [ { "cOID": "AAPL_BRACKET_MMDD", "conid": 265598, "orderType": "MKT", "side": "BUY", "tif": "DAY", "quantity": 10 }, { "parentId":"AAPL_BRACKET_MMDD", "cOID": "AAPL_BRACKET_MMDD-PT", "conid": 265598, "orderType": "LMT", "price":190, "side": "SELL", "tif": "DAY", "quantity": 10 }, { "parentId":"AAPL_BRACKET_MMDD", "cOID": "AAPL_BRACKET_MMDD-SL", "conid": 265598, "orderType": "STP", "price":185, "side": "SELL", "tif": "DAY", "quantity": 10 } ] } order_req = requests.post(url=base_url+endpoint, verify=False, json=json_body) order_json = json.dumps(order_req.json(), indent=2) print(order_req.status_code) print(order_json) if __name__ == "__main__": orderRequest()
Code Snippet – comboOrder.py
import requests import json import urllib3 # Ignore insecure error messages urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def orderRequest(): base_url = "https://localhost:5000/v1/api/" endpoint = "iserver/account/DU5240685/orders" json_body = { "orders": [ { "conidex":"28812380;;;497222760/1,495512552/-1", "orderType": "LMT", "price": -50, "side": "BUY", "tif": "DAY", "quantity": 3 } ] } order_req = requests.post(url=base_url+endpoint, verify=False, json=json_body) order_json = json.dumps(order_req.json(), indent=2) print(order_req.status_code) print(order_json) if __name__ == "__main__": orderRequest()
Shouldn’t SL and TP have “side”: “SELL” in this bracket order?
Hello, thank you for pointing this out. This is now reflected in the article. We hope you continue to engage with IBKR Campus!
In your example of an bracket order is a error. look at the sides.
It is: ‘BUY’, ‘BUY’, ‘BUY’.
It should be: ‘BUY’, ‘SELL, ‘SELL’.
Hello Daniel, thank you for pointing this out. This should now be reflected in the article. We hope you continue to engage with IBKR Campus!