Hello, and welcome to this lesson on the Interactive Brokers Client Portal API. In this lesson, we will be discussing how to find a contract id using the contract symbol, how to pull option chain data, and how to pull future data.
Searching for contract by underlying symbol
To begin, let’s start with searching for a contract by the underlying symbol. We can import the same libraries from the last episode. Now I will create a method for our request, contractSearch() method.
With the framework set, we can go back to the contractSearch() method and add some variables. I will create our base_url variable once again, and an endpoint variable set to “iserver/secdef/search”. This endpoint allows us to search for an underlying symbol or company name and retrieve a relevant contract ID. The contract ID, or conid, is a unique contract identifier that will correspond to a specific symbol, security type, and currency. Every contract at Interactive Brokers will have a unique ID.
Once we have built our URL, we will need to use a JSON body. I will create the variable, ‘json_body’, and set it equal to a set of curly brackets to create an array value. Inside these brackets we need to create a few fields. In this case, we’ll create “symbol”, “secType”, and “name”. For Symbol I will use “ES”, and for secType, I will use “STK”. For the moment, I will set “name” to “false”. This field can be used to search for a company name instead of just the standard symbol.
With the body set, I will create a reference to our coming request. I’ll create the variable ‘contract_req’ and set it equal to requests.post. Here we can set the URL to our base_url+endpoint and verify to False. Then the ‘json’ tag to the variable, json_body.
We can show the response status code in the console by printing our contract_req variable. Before doing so, I will use the json library to help make this more legible. We will print the json-encoded content of the response using json.dumps. Json.dumps function will convert a string into a json dictionary. The parameters are the contract_req.json() and indent=2. If indent is a non-negative integer, the json array elements will be pretty-printed with that indent level.
Once we have added these initial parameters we can now run this code and view the returned values. Initially our status Response code [200] indicates that the request has succeeded.
In this case there is a long list of values returned. First, we can see the conid we were initially looking for along with the companyHeader, name, description, as well as further information relating to each security type. As this lists all contracts with symbol ES, we can also see further conids and companyNames returned. For example, Eversource Energy and Esso STE in this case.
How to request contract details for Futures
Next, we will be calling the iserver/secdef/info endpoint for more informative Contract Details based on conid. It is important for derivatives to call the /secdef/search endpoint for the underlying contract before calling any other secdef endpoints. We will use the previously obtained conid for ES, or the E-mini S&P 500, in this case.
When requesting contract details for Futures, we can use the same initial python file while then creating our new contract_info.py file.
In this case, the futures_url variable will point to the iserver/secdef/info endpoint and the parameters will contain the conid, sectype, month and exchange values. These details can all be pulled from our prior request.
Parameters are unique from how a json body is constructed. Instead of a comma separated array, we will be appending a question mark, followed by the parameter set equal to our value, and then delimited using an ampersand. So, to construct this, I will create four variables.
- conid=”conid=11004968″
- secType=”secType=FUT”
- month=”month=SEP23″
- exchange=”exchange=CME”
Then I will create the variable “params” and set it equal to ‘“&”.join([conid,sectype,month,exchange])’. This will concatenate all of my strings with an ampersand between them. We can then follow this by defining request_url and setting that equal to ‘“”.join([base_url, endpoint, “?”, params])’. Now, we have a full url that displays our base url, our endpoint, and then a question mark to signify our parameters are starting. Finally, we end the string with our concatenated parameters string.
While this can certainly all be written in a single string for our example, this is a common structure to help with automating the request flow once you have developed a self-sufficient program.
Now, we can wrap up this program by creating another Get request and assigning it to contract_req. We will use our request_url as the destination to create our request. Now if we print the status value and the json.dumps value of our request, we can see a range of details on our futures contract. If we ever need to double check a derivative conid, review the validExchanges of the contract, or otherwise.
We can now run this code and see the futures contract details returned as expected.
How to request contract info for options
Requesting Options or Futures Options are quite similar. In the case of options or futures options, we must request the secdef/search endpoint, followed by the secdef/strikes endpoint before requesting the info or rules endpoint. Regardless of whether you have the contract ID beforehand or not, these endpoints must be called first.
Now can create a new file for the strikes endpoint to represent this. I will use the same framework we have been operating with, and create a new method called strikeSearch(). I will create and endpoint variable referencing the iserver/secdef/strikes string. Just like my secdef/info endpoint, I will create a conid, sectype, month, and exchange variable. I will set the conid to the underlying contract ID field, secType to “FOP”, month to “JUL23” to review the July 23 futures option, and finally in the case of Futures Options, I will define the exchange as CME. It is important to note that for standard options, you may leave out the Exchange value, as SMART is set by default.
Maintaining the other formatting as I had before, when I call this endpoint, I will see a huge range of all potential strikes a contract could use. With my knowledge of my current expiry and strike information, I will make a call to the info endpoint for my futures option. I can maintain all the same parameters as with my prior call to /info, but now include both a strike, which I will set to ‘4800', and right, which I will set to C for ‘Call'. With my derivative contract IDs found, I can now proceed to request market data, place orders, and more.
Thank you for watching this lesson on Contract Details 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 – contractDetails.py
import requests import json # Disable SSL Warnings import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # reauthenticate def contractSearch(): base_url = "https://localhost:5000/v1/api/" endpoint = "iserver/secdef/search" json_body = {"symbol" : "ES", "secType": "STK", "name": False} contract_req = requests.post(url=base_url+endpoint, verify=False, json=json_body) contract_json = json.dumps(contract_req.json(), indent=2) print(contract_json) if __name__ == "__main__": contractSearch()
Code Snippet – contractInfo.py
import requests import json # Disable SSL Warnings import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # reauthenticate def contractInfo(): base_url = "https://localhost:5000/v1/api/" endpoint = "iserver/secdef/info" conid="conid=11004968" secType = "secType=FOP" month = "month=JUL23" exchange = "exchange=CME" strike = "strike=4800" right = "right=C" params = "&".join([conid, secType, month, exchange, strike, right]) request_url = "".join([base_url, endpoint, "?", params]) contract_req = requests.get(url=request_url, verify=False) contract_json = json.dumps(contract_req.json(), indent=2) print(contract_req) print(contract_json) if __name__ == "__main__": contractInfo()
contractStrikes.py
import requests import json # Disable SSL Warnings import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # reauthenticate def contractStrikes(): base_url = "https://localhost:5000/v1/api/" endpoint = "iserver/secdef/strikes" conid = "conid=11004968" secType = "secType=FOP" month = "month=JUL23" exchange = "exchange=CME" params = "&".join([conid, secType, month, exchange]) request_url = "".join([base_url, endpoint, "?", params]) strikes_req = requests.get(url=request_url, verify=False) strikes_json = json.dumps(strikes_req.json(), indent=2) print(strikes_req) print(strikes_json) if __name__ == "__main__": contractStrikes()
Hello – the video linked here seems to be the same video that’s linked in the next lesson for market data.
Hello, thank you for bringing this to our attention. The Contract Search video has been posted. We hope you continue to engage with our lessons!
Its the wrong video posted here. The video posted was for data, not for the contract search.
Hello Andy, thank you for bringing this to our attention. The Contract Search video has been posted. We hope you continue to engage with our lessons!
hello, very instreseting. Howeve when I run Code Snippet – contractDetails.py I got th is erro
{
“error”: “Init session first”,
“statusCode”: 400
}
Hello Adam, thank you for reaching out. It looks like your session is not initialized. We would recommend reviewing Lesson 2: Launching and Authenticating the Gateway. If you have any other questions or concerns on this topic, we recommend contacting Client Services for further troubleshooting.
Please confirm, if I want to simply get the conid for a STK = MSFT, is there a way to just get the search to return it rather than the whole JSON object. I am having trouble searching the JSON as it has multiple objects with secType = STK and in those records sometimes there are no connid’s. here is the object for MSFT
[
{
“conid”: “272093”,
“companyHeader”: “MICROSOFT CORP – NASDAQ”,
“companyName”: “MICROSOFT CORP”,
“symbol”: “MSFT”,
“description”: “NASDAQ”,
“restricted”: null,
“fop”: null,
“opt”: “20240105;20240112;20240119;20240126;20240202;20240209;20240216;20240315;20240419;20240517;20240621;20240719;20240816;20240920;20241220;20250117;20250620;20251219;20260116”,
“war”: “20231130;20231201;20231205;20231206;20231207;20231208;20231211;20231212;20231213;20231214;20231215;20231219;20231220;20231221;20231222;20231227;20231228;20231229;20240104;20240105;20240111;20240112;20240116;20240117;20240118;20240119;20240126;20240209;20240213;20240214;20240215;20240216;20240308;20240312;20240313;20240314;20240315;20240417;20240418;20240419;20240515;20240516;20240517;20240614;20240618;20240619;20240620;20240621;20240718;20240917;20240918;20240919;20240920;20241217;20241218;20241219;20241220;20250114;20250115;20250116;20250117;20250318;20250319;20250320;20250321;20250617;20250618;20250619;20250620;20250918;20250919;20251216;20251218;20251219;20260113;20260114;20260115;20260116;20260319;20260616;20260618;20261217;20270114”,
“sections”: [
{
“secType”: “STK”
},
{
“secType”: “OPT”,
“months”: “JAN24;FEB24;MAR24;APR24;MAY24;JUN24;JUL24;AUG24;SEP24;DEC24;JAN25;JUN25;DEC25;JAN26”,
“exchange”: “SMART;AMEX;BATS;BOX;CBOE;CBOE2;EDGX;EMERALD;GEMINI;IBUSOPT;ISE;MERCURY;MIAX;NASDAQBX;NASDAQOM;PEARL;PHLX;PSE”
},
{
“secType”: “WAR”,
“months”: “NOV23;DEC23;JAN24;FEB24;MAR24;APR24;MAY24;JUN24;JUL24;SEP24;DEC24;JAN25;MAR25;JUN25;SEP25;DEC25;JAN26;MAR26;JUN26;DEC26;JAN27”,
“exchange”: “BVME;EBS;FWB;GETTEX;SBF;SWB”
},
{
“secType”: “IOPT”
},
{
“secType”: “CFD”,
“exchange”: “SMART”,
“conid”: “118239139”
},
{
“secType”: “BAG”
}
]
},
{
“conid”: “38708990”,
“companyHeader”: “MICROSOFT CORP – MEXI”,
“companyName”: “MICROSOFT CORP”,
“symbol”: “MSFT”,
“description”: “MEXI”,
“restricted”: null,
“fop”: null,
“opt”: null,
“war”: null,
“sections”: [
{
“secType”: “STK”,
“exchange”: “MEXI;”
}
]
},
{
“conid”: “518938052”,
“companyHeader”: “MICROSOFT CORP-CDR – AEQLIT”,
“companyName”: “MICROSOFT CORP-CDR”,
“symbol”: “MSFT”,
“description”: “AEQLIT”,
“restricted”: null,
“fop”: null,
“opt”: null,
“war”: null,
“sections”: [
{
“secType”: “STK”
}
]
},
{
“conid”: “415569505”,
“companyHeader”: “MICROSOFT CORP – EBS”,
“companyName”: “MICROSOFT CORP”,
“symbol”: “MSFT”,
“description”: “EBS”,
“restricted”: null,
“fop”: null,
“opt”: null,
“war”: null,
“sections”: [
{
“secType”: “STK”
}
]
},
{
“conid”: “493546075”,
“companyHeader”: “LS 1X MSFT – LSEETF”,
“companyName”: “LS 1X MSFT”,
“symbol”: “MSFT”,
“description”: “LSEETF”,
“restricted”: null,
“fop”: null,
“opt”: null,
“war”: null,
“sections”: [
{
“secType”: “STK”
}
]
},
{
“issuers”: [
{
“id”: “e1393444”,
“name”: “Microsoft Corp”
}
],
“bondid”: 5,
“conid”: “2147483647”,
“companyHeader”: “Corporate Fixed Income”,
“companyName”: null,
“symbol”: “MSFT”,
“description”: null,
“restricted”: null,
“fop”: null,
“opt”: null,
“war”: null,
“sections”: [
{
“secType”: “BOND”
}
]
}
]
Hello, thank you for reaching out. As you indicated, there are several instruments returned related to MSFT and return STK values. As such, you would need to filter the return details locally. Assuming you are looking to trade the U.S. Microsoft Corporation, you can use the “description” tag from each object to identify the exchange. So using python we can implement something like:
for i in contract_req.json():
if i[‘description’] == ‘NASDAQ’:
print(i[‘conid’])
Please reach back out with any more questions. We are here to help!
Hello, thank you for these instructional videos. It appears my contractDetails is working successfully, but when I attempt to run contractInfo or contractStrikes using the exact same code, I get ” no contracts received”, and an empty options chain, respectively. I have confirmed with my auth_status that my session is still enabled. Appreciate any thoughts.
Hello, thank you for reaching out. The typical reason that empty strikes may be retrieved, or an empty /info response is returned is because the underlying contract was not first requested through the /secdef/search endpoint. We would recommend double-checking that the underlying was requested with /secdef/search first, followed by /secdef/strikes, and finally /secdef/info when requesting options. If you have any additional questions or concerns, please contact our Customer Service team: https://www.interactivebrokers.com/en/support/customer-service.php
We hope this helps!
Hello.
Very grateful for the tutorials. Despite not being sure if this is what I’m looking for.
My specific idea is to use the IBKR API to retrieve data from my portfolio, such as:
Instruments I currently own.
Date of purchase.
Date of sale.
Profits or losses in the trade.
Transaction history of my portfolio.
Then, I want to dump all this data into an Excel spreadsheet and analyze it separately.
Are there endpoints available to make all the necessary requests?
Hello Jose, thank you for reaching out. Please check out our API resources on IBKR Campus for guidance: https://www.ibkrcampusdev.wpengine.com/campus/ibkr-api-page/ibkr-api-home/. If you don’t find the answers there, you can create a web ticket for this inquiry; we have a category specifically for “API.” One of our API experts will be happy to guide you! https://www.interactivebrokers.com/sso/resolver?action=NEW_TICKET
Hi,
Using the exact contract search function which I have tested on multiple instruments works perfectly.
However, I have a handful of instruments which return:
{
“error”: “No symbol found”
}
The symbol name, secType are all based on the IBKR Products and therefore should be in the system.
Here are some examples of the STK symbols I have tried: AACIU, AACI, AEZS, ARYD, MYMD
Am I missing something here?
Thank you for asking. In all of the cases mentioned below, these are contracts that are in a closing only mode that are listed on the Value exchange. A simple means to resolve this would be to include the “name”:true field such that any contracts that match the name will be returned. This field will essentially match the included “symbol” value to any result of the contract’s symbol field rather than working as an exact value. We hope this answers your question!