helpme
helpme

Reputation: 95

How to return positions from IBKR API (interactive brokers) consistently?

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

Answers (3)

Mike K
Mike K

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

Mark
Mark

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

MatthewScarpino
MatthewScarpino

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

Related Questions