def get_latest_price(self, ticker): token = environ['IBKR_TOKEN'] queryId = environ['IBKR_QUERY_ID'] try: response = client.download(token, queryId) except client.ResponseCodeError as e: if e.code == '1018': sleep(10) response = client.download(token, queryId) else: raise e statement = parser.parse(response) for position in statement.FlexStatements[0].OpenPositions: if position.symbol.rstrip('z') == ticker: price = D(position.markPrice) timezone = tz.gettz("Europe/Zurich") time = datetime.combine( position.reportDate, datetime.min.time()).astimezone(timezone) return source.SourcePrice(price, time, position.currency) return None
def test_request_statement(self, mock_requests_get: Mock): output = client.download( token="DEADBEEF", query_id="0987654321", ) self.assertIsInstance(output, bytes) self.assertEqual( mock_requests_get.call_args_list, [ call( client.REQUEST_URL, params={ "v": "3", "t": "DEADBEEF", "q": "0987654321" }, headers={"user-agent": "Java"}, timeout=5, ), call( client.STMT_URL, params={ "v": "3", "t": "DEADBEEF", "q": "1234567890" }, headers={"user-agent": "Java"}, timeout=5, ), ], ) response = parser.parse(BytesIO(output)) self.assertIsInstance(response, Types.FlexQueryResponse)
def extract(self, credsfile, existing_entries=None): # the actual processing of the flex query # get the IBKR creentials ready try: with open(credsfile.name, 'r') as f: config = yaml.safe_load(f) token = config['token'] queryId = config['queryId'] except: warnings.warn('cannot read IBKR credentials file. Check filepath.') return[] # get prices of existing transactions, in case we sell something #priceLookup = PriceLookup(existing_entries, config['baseCcy']) if self.filepath == None: # get the report from IB. might take a while, when IB is queuing due to # traffic try: # try except in case of connection interrupt # Warning: queries sometimes take a few minutes until IB provides # the data due to busy servers response = client.download(token, queryId) statement = parser.parse(response) except: warnings.warn('could not fetch IBKR Statement. exiting.') # another option would be to try again return[] assert isinstance(statement, Types.FlexQueryResponse) else: print('**** loading from pickle') with open(self.filepath,'rb') as pf: statement = pickle.load(pf) # convert to dataframes poi=statement.FlexStatements[0] # point of interest reports=['CashReport','Trades','CashTransactions'] # relevant items from report tabs={report:pd.DataFrame([{key:val for key,val in entry.__dict__.items()} for entry in poi.__dict__[report]]) for report in reports} # get single dataFrames ct=tabs['CashTransactions'] tr=tabs['Trades'] cr=tabs['CashReport'] # throw out IBKR jitter, mostly None ct.drop(columns=[col for col in ct if all(ct[col].isnull())],inplace=True) tr.drop(columns=[col for col in tr if all(tr[col].isnull())],inplace=True) cr.drop(columns=[col for col in cr if all(cr[col].isnull())],inplace=True) transactions = self.Trades(tr) + self.CashTransactions(ct) + self.Balances(cr) return transactions
inout.amount[inout.amount < 0].sum() ], index=['Deposit', 'Withdrawal']) def save_df(df, path): df.to_csv(path, index=False) return if __name__ == '__main__': query_id_list = 'YOUR DICT' token = 'YOUR TOKEN' for tbl, query_id in query_id_list.items(): response = client.download(token, query_id) print(response) filename = tbl + '.xml' report_file = open(filename, 'wb') report_file.write(response) report_file.close() statements = FlexStatement('trade.xml', 'trade') trade = statements.trade print(trade) statements = FlexStatement('dividend.xml', 'dividend') fees = statements.fees print(fees) dividends = statements.dividends
def extract(self, file, existing_entries): with open(file.name, 'r') as f: config = yaml.safe_load(f) token = config['token'] queryId = config['queryId'] priceLookup = PriceLookup(existing_entries, config['baseCcy']) response = client.download(token, queryId) statement = parser.parse(response) assert isinstance(statement, Types.FlexQueryResponse) transactions = [] for trx in statement.FlexStatements[0].CashTransactions: existingEntry = None if CashAction.DIVIDEND == trx.type or CashAction.WHTAX == trx.type: existingEntry = next((t for t in transactions if t['date'] == trx.dateTime), None) if existingEntry: if CashAction.WHTAX == trx.type: existingEntry['whAmount'] = trx.amount else: existingEntry['amount'] = trx.amount existingEntry['description'] = trx.description existingEntry['type'] = trx.type else: if CashAction.WHTAX == trx.type: amount = 0 whAmount = trx.amount else: amount = trx.amount whAmount = 0 transactions.append({ 'date': trx.dateTime, 'symbol': trx.symbol, 'currency': trx.currency, 'amount': amount, 'whAmount': whAmount, 'description': trx.description, 'type': trx.type }) result = [] for trx in transactions: if trx['type'] == CashAction.DIVIDEND: asset = trx['symbol'].replace('z', '') payDate = trx['date'].date() totalDividend = trx['amount'] totalWithholding = -trx['whAmount'] totalPayout = totalDividend - totalWithholding currency = trx['currency'] _, rows = query.run_query( existing_entries, options.OPTIONS_DEFAULTS, 'select sum(number) as quantity, account where currency="' + asset + '" and date<#"' + str(payDate) + '" group by account;') totalQuantity = D(0) for row in rows: totalQuantity += row.quantity remainingPayout = totalPayout remainingWithholding = totalWithholding for row in rows[:-1]: myAccount = row.account myQuantity = row.quantity myPayout = round(totalPayout * myQuantity / totalQuantity, 2) remainingPayout -= myPayout myWithholding = round(totalWithholding * myQuantity / totalQuantity, 2) remainingWithholding -= myWithholding result.append(self.createSingle(myPayout, myWithholding, myQuantity, myAccount, asset, currency, payDate, priceLookup, trx['description'])) lastRow = rows[-1] result.append(self.createSingle(remainingPayout, remainingWithholding, lastRow.quantity, lastRow.account, asset, currency, payDate, priceLookup, trx['description'])) return result