I wrote the code below to read information from my accounts at Interactive Brokers:
# Interactive Brokers functions to import data
def read_positions(): #read all accounts positions and return DataFrame with information
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.common import TickerId
import pandas as pd
class ib_class(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.all_positions = pd.DataFrame([], columns = ['Account','Symbol', 'Quantity', 'Average Cost'])
def position(self, account, contract, pos, avgCost):
index = str(account)+str(contract.symbol)
self.all_positions.loc[index]=account,contract.symbol,pos,avgCost
def error(self, reqId:TickerId, errorCode:int, errorString:str):
if reqId > -1:
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def positionEnd(self):
super().positionEnd()
self.disconnect()
ib_api = ib_class()
ib_api.connect("127.0.0.1", 7496, 0)
ib_api.reqPositions()
current_positions = ib_api.all_positions
ib_api.run()
return(current_positions)
def read_navs(): #read all accounts NAVs
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.common import TickerId
import pandas as pd
class ib_class(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.all_accounts = pd.DataFrame([], columns = ['reqId','Account', 'Tag', 'Value' , 'Currency'])
def accountSummary(self, reqId, account, tag, value, currency):
if tag == 'NetLiquidationByCurrency':
index = str(account)
self.all_accounts.loc[index]=reqId, account, tag, value, currency
def error(self, reqId:TickerId, errorCode:int, errorString:str):
if reqId > -1:
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def accountSummaryEnd(self, reqId:int):
super().accountSummaryEnd(reqId)
self.disconnect()
ib_api = ib_class()
ib_api.connect("127.0.0.1", 7496, 0)
ib_api.reqAccountSummary(9001,"All","$LEDGER")
current_nav = ib_api.all_accounts
ib_api.run()
return(current_nav)
If I call the two functions read_positions() or read_navs() I get the results I want, on DataFrame variables. However, I get an error message (on the console) that reads:
"OSError: [WinError 10038] An operation was attempted on something that is not a socket".
Before the error message itself, I get a lot of error-related messages:
unhandled exception in EReader thread Traceback (most recent call last): File "C:\Users\xxxxx\Anaconda3\lib\site-packages\ibapi-9.76.1-py3.7.egg\ibapi\reader.py", line 34, in run data = self.conn.recvMsg() File "C:\Users\xxxxx\Anaconda3\lib\site-packages\ibapi-9.76.1-py3.7.egg\ibapi\connection.py", line 99, in recvMsg buf = self._recvAllMsg() File "C:\Users\xxxxx\Anaconda3\lib\site-packages\ibapi-9.76.1-py3.7.egg\ibapi\connection.py", line 119, in _recvAllMsg buf = self.socket.recv(4096)
The helpdesk from IB refuses to answer my question: how do I either avoid this error message or suppress it? I don't know if it is something I'm doing wrong or if this is a bug on their API. As long as I can avoid this junk printed on my console, I will be OK. Any guidance is much appreciated.
Matt's answer above is correct: it was an API bug! I'm only adding this answer to provide more clear steps on how to downgrade to the older version:
1) Download the older version from here: http://interactivebrokers.github.io/downloads/TWS%20API%20Install%20974.01.msi
IB doesn't show the links for older versions but they keep the file on the Github (note the version name at the end of the link address)
2) Uninstall the current version. From IB's own website, do the following:
3) Install the API using the .msi file
4) Run the Anaconda prompt and navigate to the dir C:\TWS API\source\pythonclient
5) Run: "python setup.py install"
6) After python setup.py install, restart Spyder (if it was opened; I closed mine before step #5 above)
After I installed this older version, the error disappeared!
So instead of downgrading, I found a quick fix to suppressing the error message. Go to the script where its messing up at, it should be connection.py and at line 119 at the very bottom. This is what I did to catch the error and it worked.
while cont and self.socket is not None:
try:
buf = self.socket.recv(4096)
allbuf += buf
logger.debug("len %d raw:%s|", len(buf), buf)
if len(buf) < 4096:
cont = False
except OSError:
pass
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With