Skip to content

Instantly share code, notes, and snippets.

@robcarver17
Created March 15, 2017 06:23
Show Gist options
  • Save robcarver17/7b4a8e2f1fbfd70b4aaea5d205cb35eb to your computer and use it in GitHub Desktop.
Save robcarver17/7b4a8e2f1fbfd70b4aaea5d205cb35eb to your computer and use it in GitHub Desktop.
# Gist example of IB wrapper ...
#
# Download API from http://interactivebrokers.github.io/#
#
# Install python API code /IBJts/source/pythonclient $ python3 setup.py install
#
# Note: The test cases, and the documentation refer to a python package called IBApi,
# but the actual package is called ibapi. Go figure.
#
# Get the latest version of the gateway:
# https://www.interactivebrokers.com/en/?f=%2Fen%2Fcontrol%2Fsystemstandalone-ibGateway.php%3Fos%3Dunix
# (for unix: windows and mac users please find your own version)
#
# Run the gateway
#
# user: edemo
# pwd: demo123
#
# Now I'll try and replicate the time telling example
from ibapi.wrapper import EWrapper
from ibapi.client import EClient
from threading import Thread
import queue
class TestWrapper(EWrapper):
"""
The wrapper deals with the action coming back from the IB gateway or TWS instance
We override methods in EWrapper that will get called when this action happens, like currentTime
"""
## error handling code
def init_error(self):
error_queue=queue.Queue()
self._my_errors = error_queue
def get_error(self, timeout=5):
if self.is_error():
try:
return self._my_errors.get(timeout=timeout)
except queue.Empty:
return None
return None
def is_error(self):
an_error_if=not self._my_errors.empty()
return an_error_if
def error(self, id, errorCode, errorString):
## Overriden method
errormsg = "IB error id %d errorcode %d string %s" % (id, errorCode, errorString)
self._my_errors.put(errormsg)
## Time telling code
def init_time(self):
time_queue=queue.Queue()
self._time_queue = time_queue
return time_queue
def currentTime(self, time_from_server):
## Overriden method
self._time_queue.put(time_from_server)
class TestClient(EClient):
"""
The client method
We don't override native methods, but instead call them from our own wrappers
"""
def __init__(self, wrapper):
## Set up with a wrapper inside
EClient.__init__(self, wrapper)
def speaking_clock(self):
"""
Basic example to tell the time
:return: unix time, as an int
"""
print("Getting the time from the server... ")
## Make a place to store the time we're going to return
## This is a queue
time_storage=self.wrapper.init_time()
## This is the native method in EClient, asks the server to send us the time please
self.reqCurrentTime()
## Try and get a valid time
MAX_WAIT_SECONDS = 10
try:
current_time = time_storage.get(timeout=MAX_WAIT_SECONDS)
except queue.Empty:
print("Exceeded maximum wait for wrapper to respond")
current_time = None
while self.wrapper.is_error():
print(self.get_error())
return current_time
class TestApp(TestWrapper, TestClient):
def __init__(self, ipaddress, portid, clientid):
TestWrapper.__init__(self)
TestClient.__init__(self, wrapper=self)
self.connect(ipaddress, portid, clientid)
thread = Thread(target = self.run)
thread.start()
setattr(self, "_thread", thread)
self.init_error()
if __name__ == '__main__':
##
## Check that the port is the same as on the Gateway
## ipaddress is 127.0.0.1 if one same machine, clientid is arbitrary
app = TestApp("127.0.0.1", 4001, 10)
current_time = app.speaking_clock()
print(current_time)
app.disconnect()
@vpribish
Copy link

vpribish commented Jan 7, 2018

i forked this to move error handling initializing to before the connect() attempt. Probably helpful for people just trying this for the first time.

see fork here: https://gist.github.com/vpribish/350a7fb49b8fdeba74dd5eb74106f4b5

@pashute
Copy link

pashute commented Jan 9, 2018

Line 107 should be indented into the exception handling. No?

@jptc460
Copy link

jptc460 commented May 12, 2019

Thanks for the code, very helpful.
I am getting some AttributeError with self._my_errors, which gets fixed if I simply do e.g. 'self._my_errors = queue.Queue()' at l 127. Not clear if it's setup-dependent, or if the native TestWrapper was updated.

@coulterpeterson
Copy link

i forked this to move error handling initializing to before the connect() attempt. Probably helpful for people just trying this for the first time.

see fork here: https://gist.github.com/vpribish/350a7fb49b8fdeba74dd5eb74106f4b5

That ran for me - thank you for posting

@christian-oudard
Copy link

Thanks for the example!

When I run this code, it works fine and gives me the server time, but when it disconnects, it hits the error "Bad file descriptor":

ERROR:ibapi.reader:unhandled exception in EReader thread                                                                                                    
Traceback (most recent call last):                                                                                                                          
  File "/home/christian/third-party-code/IBJts/source/pythonclient/ibapi/reader.py", line 34, in run                                                        
    data = self.conn.recvMsg()                                                                                                                              
  File "/home/christian/third-party-code/IBJts/source/pythonclient/ibapi/connection.py", line 99, in recvMsg                                                
    buf = self._recvAllMsg()                                                                                                                                
  File "/home/christian/third-party-code/IBJts/source/pythonclient/ibapi/connection.py", line 119, in _recvAllMsg                                           
    buf = self.socket.recv(4096)                                                                                                                            
OSError: [Errno 9] Bad file descriptor 

Is this a problem with the API or with the example code? How do I make sure the socket is not re-used after it is closed?

Copy link

ghost commented Dec 5, 2020

An old thread. Still commenting if someone's facing @christian-oudard's error.

You can install the latest version of the api (9.81). They have added the following code in the recvMesg(self) function in the connection.py file:

 except socket.error:
      logger.debug("socket broken, disconnecting")
      self.disconnect()
      buf = b""

Thanks for the example!

When I run this code, it works fine and gives me the server time, but when it disconnects, it hits the error "Bad file descriptor":

ERROR:ibapi.reader:unhandled exception in EReader thread                                                                                                    
Traceback (most recent call last):                                                                                                                          
  File "/home/christian/third-party-code/IBJts/source/pythonclient/ibapi/reader.py", line 34, in run                                                        
    data = self.conn.recvMsg()                                                                                                                              
  File "/home/christian/third-party-code/IBJts/source/pythonclient/ibapi/connection.py", line 99, in recvMsg                                                
    buf = self._recvAllMsg()                                                                                                                                
  File "/home/christian/third-party-code/IBJts/source/pythonclient/ibapi/connection.py", line 119, in _recvAllMsg                                           
    buf = self.socket.recv(4096)                                                                                                                            
OSError: [Errno 9] Bad file descriptor 

Is this a problem with the API or with the example code? How do I make sure the socket is not re-used after it is closed?

@algonitish
Copy link

@Sritanu thanks for the tip, the error went away after the upgrade. However, it doesn't seem to make a clean exit. In the sixth video of this (https://www.udemy.com/course/python-api-for-trading/learn/lecture/18810050) course, the simple program ends with:
Process finished with exit code 0
Same code running on upgraded IBAPI ends abruptly with:
OrderStatus, Id: 6 , Status: Submitted , Filled: 0.0 , Remaining: 10.0 , LastFillPrice: 0.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment