Reputation: 95
IBKR gives me horribly inconsistent results so far, I hope it's just because I don't understand something.
Here is my code to try to get my account positions, but it only worked the first time I ran it, and doesn't work anymore. I find that half of the things I try to do on IBKR are this way... Is there like a simpler API that doesn't require me instantiating classes to simply get a list of positions in my account? Thanks guys.
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)
Upvotes: 2
Views: 2197
Reputation: 71
While using a sleep time can address this challenge, waiting for 3 seconds in a production environment to obtain positions and potentially follow up with placing an order is impractical. A more effective approach is to wait for the event to complete, which can also be applied to "most" IB functions.
import threading
class ib_class(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.all_positions = pd.DataFrame([], columns = ['Account','Symbol', 'Quantity', 'Average Cost'])
self.execution_event = threading.Event()
def position(self, account, contract, pos, avgCost):
index = str(account)+str(contract.symbol)
self.all_positions.loc[index]=account,contract.symbol,pos,avgCost
# set the event
self.positions_event.set()
def error(self, reqId:TickerId, errorCode:int, errorString:str):
if reqId > -1:
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
# set the event
self.positions_event.set()
def positionEnd(self):
super().positionEnd()
self.disconnect()
ib_api = ib_class()
ib_api.connect("127.0.0.1", 7496, 0)
ib_api.positions_event.clear() # reset positions_event
ib_api.reqPositions()
ib_api.positions_event.wait() # Wait for positions data to come in
current_positions = ib_api.all_positions
ib_api.run()
return(current_positions)
Upvotes: 0
Reputation: 1
I have the same issue, which seems to be caused by the newer TWS version. With TWS 1012 positions come back consistently 100% of the time, with TWS 1019 50% of the time, 0 positions are returned. I'm waiting 3 seconds in both cases:
ib_api.reqPositions()
time.sleep(3.0)
Upvotes: 0
Reputation: 5936
IB doesn't respond to reqPositions
instantly, so you should wait a second or two before accessing the result. Will this work for you?
import time
...
ib_api = ib_class()
ib_api.connect("127.0.0.1", 7496, 0)
ib_api.run()
ib_api.reqPositions()
time.sleep(2)
current_positions = ib_api.all_positions
return(current_positions)
I'm not at my dev computer, so I can't verify that this works properly.
EDIT: Here's a short program that demonstrates how reqPositions
can be used. I've tested that it works.
class ib_class(EWrapper, EClient):
def __init__(self, addr, port, client_id):
EClient. __init__(self, self)
self.connect(addr, port, client_id)
self.index = ''
thread = Thread(target=self.run)
thread.start()
def position(self, account, contract, pos, avgCost):
self.index = str(account) + str(contract.symbol)
ib_api = ib_class('127.0.0.1', 7497, 0)
ib_api.reqPositions()
time.sleep(0.5)
print('Index: ' + ib_api.index)
ib_api.disconnect()
Upvotes: 1