-
-
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() |
Line 107 should be indented into the exception handling. No?
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.
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
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?
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 descriptorIs 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?
@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
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