Welcome to this lesson on the essential components of a TWS API Python program. This includes the API classes EClient and EWrapper, a function call to create a connection to TWS, and a run loop for processing returned messages in the queue. This lesson will also include a brief discussion of the nextValidId method, and we can implement threading. Finally, we’ll walk through our reqCurrentTime method to create a basic “Hello World” style script.
To begin, in any TWS API program you’ll always see two main classes, which would be EClient and EWrapper. EClient is used for outgoing messages which are sent from the API program to TWS or the IB Gateway. EWrapper is used to handle incoming messages from the Interactive Brokers server through TWS or IB Gateway.
For this lesson, I will be using Visual Studio Code. However, you can use any development environment of your choice, or even just the command lines and a text editor. To begin, I will start by importing the necessary modules. I will start by importing EClient, using “from ibapi.client import *” and EWrapper, using “from ibapi.wrapper import *”. I will also be importing the time and threading modules, which we will touch on later.
After importing my modules, I will create a class to combine the EClient and EWrapper modules. I will type “class TestApp(EClient, EWrapper):”. Next, we instantiate the class by defining our init method with def __init__(self): followed by a newline EClient init request using EClient.__init__(self,self).
After our init, let’s create the EWrapper object for NextValidId(self, orderId): to receive order Ids. This will receive the EWrapper return of next valid order id, and retain valid session throughout the trading day to prevent duplicate values. Here, I can create an object for the order id, self.orderId = orderId. Now it may be confusing, but we can now make a new function, nextId, only retaining the object. Within the function, I will increment our newly made self.orderId value by 1, and then return the self.order variable. This way we can maintain the order Id throughout future requests and return the order id to our request.
We will circle back to some of the more elaborate EWrapper functionality in a moment. However, for now, we can just print out this id by creating our TestApp reference. All this takes is setting a variable, let’s use “app”, equal to the TestApp() class. Now, we’ll connect our app to Trader Workstation, by calling app.connect(“127.0.0.1”, 7497, 0). The values in this method are the host, port, and clientId.
Assuming your TWS is on the same machine where your API code is running, this will always be “127.0.0.1” or “localhost”. We have included a description of the standard port values in the transcript of this video. You can also review your TWS socket port setting in our prior video on setting up the Trader Workstation for API use. And then our client ID can be any value, as long as another client ID connection is not using the same value.
Platform |
Port |
TWS Live |
7496 |
TWS Paper |
7497 |
IBG Live |
4001 |
IBG Paper |
4002 |
With our connect methodology in place, we can implement a little bit of threading to get started. The simple implementation would be to call threading.Thread(target=app.run).start().
Please be aware that we reference the object of app.run, without including the parenthesis. Next, we’ll add a quick time.sleep(1) reference, to allow our object to instantiate before we start sending requests. This value will largely depend on your internal machine speed, so you increase or decrease this value as you see fit.
Then, as a quick test to show off our nextId method, we can use a for loop as the example. I will write the loop as for I in range(0,5): and then printing the app.nextId() method each time. If we run this script as is, we should see some notifications indicating our connection is OK, followed by our printed ids. These request IDs are used throughout our programming and need to be uniquely assigned on each request. As a result, creating this reliable incrementation tool will be essential.
We will explore this further through future videos.
But as a simple implementation of the EClient – EWrapper duality, we can move on to a call for the current time in Trader Workstation. Within our for loop, after our call for the nextId value, I will add a new request for app.reqCurrentTime(). This begins the initial request through EWrapper, but to capture the response, we should define the currentTime function within our class.
Calling def currentTime(self,time): we can receive our time value. Within the function, we can print our time value. This function will return the current epoch time observed in Trader Workstation. Epoch time is a single integer time representing the current timestamp in milliseconds. The connection between EClient.reqCurrentTime and EWrapper.currentTime will be an ongoing theme observed through nearly all endpoints used within the API. One external request will be met with one or more asynchronous responses.
One final method to create that will be used throughout the TWS API programming will be our EWrapper.error function. Error will automatically return any error generated by the Trader Workstation while processing your request. This will include values like invalid order formats, market data issues, and more. This will not reflect code issues or similar programming logic failures.
To define this, add the new definition for error within our TestApp class, containing the arguments for self, reqId, errorCode, errorString, and advancedOrderReject. While you are welcome to simply print all of these values directly, I will be adding context to each message through an f-string so we can quickly distinguish which value refers to which argument. If we run our script now, you’ll see various “error” messages. If we read the errorString value of these messages, we’ll realize these are just notifications mentioning that various market data connections are OK. While this method will largely capture error messages, we will receive system notifications such as the market data connectivity through EWrapper.error as well.
That concludes our lesson on the Essential Components of the TWS API. Thank you for watching. If you have any questions, please be sure to review our documentation or leave a comment below this video. We look forward to having you in the next lesson of our TWS API series.
Code Snippet – essentials.py
from ibapi.client import * from ibapi.wrapper import * import time import threading class TestApp(EClient, EWrapper): def __init__(self): EClient.__init__(self, self) def nextValidId(self, orderId): self.orderId = orderId def nextId(self): self.orderId += 1 return self.orderId def currentTime(self, time): print(time) def error(self, reqId, errorCode, errorString, advancedOrderReject=""): print(f"reqId: {reqId}, errorCode: {errorCode}, errorString: {errorString}, orderReject: {advancedOrderReject}") app = TestApp() app.connect("127.0.0.1", 7497, 0) threading.Thread(target=app.run).start() time.sleep(1) # for i in range(0,5): # print(app.nextId()) app.reqCurrentTime()
there are errors in output –should we ignore it ?
akotak@Ankitkumars-MacBook-Pro IBJts % /usr/bin/python3 /Users/akotak/Downloads/AlgoTrading/IBJ
ts/source/pythonclient/tests/lesson_3.py
ERROR -1 2104 Market data farm connection is OK:usfarm.nj
ERROR -1 2104 Market data farm connection is OK:cashfarm
ERROR -1 2104 Market data farm connection is OK:usfarm
ERROR -1 2106 HMDS data farm connection is OK:ushmds
ERROR -1 2158 Sec-def data farm connection is OK:secdefil
contract details: 265598,AAPL,STK,,0,,,SMART,NASDAQ,USD,AAPL,NMS,False,,,,combo:,NMS,0.01,ACTIVETIM,AD,ADJUST,ALERT,ALGO,ALLOC,AON,AVGCOST,BASKET,BENCHPX,CASHQTY,COND,CONDORDER,DARKONLY,DARKPOLL,DAY,DEACT,DEACTDIS,DEACTEOD,DIS,DUR,GAT,GTC,GTD,GTT,HID,IBKRATS,ICE,IMB,IOC,LIT,LMT,LOC,MIDPX,MIT,MKT,MOC,MTL,NGCOMB,NODARK,NONALGO,OCA,OPG,OPGREROUT,PEGBENCH,PEGMID,POSTATS,POSTONLY,PREOPGRTH,PRICECHK,REL,REL2MID,RELPCTOFS,RPI,RTH,SCALE,SCALEODD,SCALERST,SIZECHK,SMARTSTG,SNAPMID,SNAPMKT,SNAPREL,STP,STPLMT,SWEEP,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,WHATIF,SMART,AMEX,NYSE,CBOE,PHLX,ISE,CHX,ARCA,ISLAND,DRCTEDGE,BEX,BATS,EDGEA,CSFBALGO,JEFFALGO,BYX,IEX,EDGX,FOXRIVER,PEARL,NYSENAT,LTSE,MEMX,IBEOS,OVERNIGHT,PSX,1,0,APPLE INC,,Technology,Computers,Computers,US/Eastern,20230819:CLOSED;20230820:CLOSED;20230821:0400-20230821:2000;20230822:0400-20230822:2000;20230823:0400-20230823:2000;20230824:0400-20230824:2000,20230819:CLOSED;20230820:CLOSED;20230821:0930-20230821:1600;20230822:0930-20230822:1600;20230823:0930-20230823:1600;20230824:0930-20230824:1600,,0,,,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,1,[4311536688: ISIN=US0378331005;],,COMMON,,,,,,False,False,0,False,,,,,False,,0.0001,0.0001,100
End of contractDetails
akotak@Ankitkumars-MacBook-Pro IBJts %
Hello Ankit, thank you for reaching out. All supported API programming languages offer call back functions to receive error messages sent from the TWS for troubleshooting purposes. Socket-based APIs (e.g., C#, Java, VB.Net, C++, Python and ActiveX) handle error messages within the error() call back function in the EWrapper interface. For additional information, including a list of message codes, please review our API documentation. We hope this helps!
If your query is still not answered after reviewing the documentation, please create a web ticket in Client Portal with the category “API.” Our experts will be glad to help you out!
I directly copied the futures contract and received the error:
ERROR 1 200 No security definition has been found for the request
Im not sure where this is coming from or what it means
Hello Paul, thank you for reaching out. This error message is triggered to indicate the contract definition provided in your RTD formula cannot be found by TWS. Please view this User Guide for more information: https://interactivebrokers.github.io/tws-api/rtd_fqa_errors.html
Please reach back out if you have any more questions. We are here to help!
how to restrict the option contract for a particular date, not the all valid dates in the whole month? E.g. if on 1/Jan/2024, I only want to request data from the IB server for the SPY option contract expiry on that date?
Hello Nathan, thank you for reaching out. The contract specifications can be as precise or vague as needed in the TWS API. Our example assumed you have no knowledge of the expiration, so we look at the whole month of November. If you know an expiration is taking place on January 1st, 2024, you could set mycontract.lastTradeDateOrContractMonth = “20240101” to include the year, month, and day of the expiration. Please reach back out if you have more questions. We are here to help!
I have the same issue as Paul, which I understand, however one I get the “ERROR 1 200 No security definition has been found for the request”, the code continues to run in this infinite loop and I have to restart the kernel to stop it. I am using a Jupyter Notebook. Is there a way to stop it if this error occurs? Thanks
Hello, thank you for reaching out. For this situation, we recommend creating a web ticket to contact our API experts. They would be happy to help.
https://www.interactivebrokers.com/sso/resolver?action=NEW_TICKET
Hello, how can the forex contract be viewed?
Hello, thank you for reaching out. Forex contracts are constructed by setting the symbol to the target currency, while the ‘currency’ value is equal to the base. In an example of EUR.USD pairs, we would set the symbol, or target currency, to ‘EUR’ while our base currency value would be ‘USD’. You can find more details on contracts in our documentation here: https://www.ibkrcampusdev.wpengine.com/campus/ibkr-api-page/contracts/#forex. We hope this helps!
Fyi if you directly copy paste the futures example and run it, you will get an error. This is because you are trying to pull contract details for the DAX future with expiry 2022 which is too far in the past. Try updating the year to the current or next year and it should work.
@5.44 in the video i get the following errors: Traceback (most recent call last): File “”, line 2, in File “”, line 7, in nextId AttributeError: ‘TestApp’ object has no attribute ‘orderId’ Seems like this code and tutorial is no longer working.
your client(Ib gateway or TW) is not running. login to the client to fix this issue.
I got the same exact error.
Hello, thank you for reaching out. This is most likely a result of a typo in the code. If you directly copy the ‘Code Snippet – essentials.py’ does not replicate this behavior. That being said, if you were to interchangeably use lowercase and uppercase characters throughout the ‘nextValidId()’ and ‘nextId()’ functions, your described issue can be replicated. Please be sure to review your variable naming convention to make sure they are matched accordingly. If you have any additional questions, please 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! http://spr.ly/IBKR_ClientServicesCampus
Hello, thank you for reaching out. This is most likely a result of a typo in the code. If you directly copy the ‘Code Snippet – essentials.py’ does not replicate this behavior. That being said, if you were to interchangeably use lowercase and uppercase characters throughout the ‘nextValidId()’ and ‘nextId()’ functions, your described issue can be replicated. Please be sure to review your variable naming convention to make sure they are matched accordingly. If you have any additional questions, please 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! http://spr.ly/IBKR_ClientServicesCampus
there is error”TestApp.error() missing 1 required positional argument: ‘advancedOrderReject'”,how to fix it and why it is happened?
Hello, thank you for reaching out. It sounds like TWS may be providing 4 error arguments, while we accept 5. This is most common when using mismatched versions of TWS and the API. However, a simple fix for this issue is to create a default value for the AdvancedOrderRejectParams variable. This is done by modifying our error method definition to the following:
def error(self, reqId, errorCode, errorString, advancedOrderReject=””):
If you have any additional questions, please 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! http://spr.ly/IBKR_ClientServicesCampus
my orderId’s are not being printed with the following error message:
AttributeError: ‘TestApp’ object has no attribute ‘orderId’
Hi Troy, thank you for reaching out. This is most likely a result of a typo in the code. If you directly copy the ‘Code Snippet – essentials.py’ does not replicate this behavior. That being said, if you were to interchangeably use lowercase and uppercase characters throuhgought the ‘nextValidId()’ and ‘nextId()’ functions, your described issue can be replicated. Please be sure to review your variable naming convention to make sure they are matched accordingly. If you have any additional questions, please 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! http://spr.ly/IBKR_ClientServicesCampus