From 8c86a39de3d38669e81a2a0fa18c861b9cbebb4c Mon Sep 17 00:00:00 2001 From: Patrick Ruckstuhl Date: Tue, 14 Mar 2023 19:27:14 +0000 Subject: [PATCH] Support multiple account for ib --- src/tariochbctools/importers/ibkr/importer.py | 176 +++++++++--------- src/tariochbctools/plugins/prices/ibkr.py | 19 +- 2 files changed, 101 insertions(+), 94 deletions(-) diff --git a/src/tariochbctools/importers/ibkr/importer.py b/src/tariochbctools/importers/ibkr/importer.py index 7fddccd..0682272 100644 --- a/src/tariochbctools/importers/ibkr/importer.py +++ b/src/tariochbctools/importers/ibkr/importer.py @@ -46,104 +46,109 @@ def extract(self, file, existing_entries): 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 self.matches(trx, t)), None - ) + for stmt in statement.FlexStatements: + for trx in stmt.CashTransactions: + existingEntry = None + if CashAction.DIVIDEND == trx.type or CashAction.WHTAX == trx.type: + existingEntry = next( + (t for t in transactions if self.matches(trx, t)), 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 + 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: - 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, - } - ) + 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, + "account": stmt.accountId, + } + ) - result = [] - for trx in transactions: - if trx["type"] == CashAction.DIVIDEND: - asset = trx["symbol"].rstrip("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 + result = [] + for trx in transactions: + if trx["type"] == CashAction.DIVIDEND: + asset = trx["symbol"].rstrip("z") + payDate = trx["date"].date() + totalDividend = trx["amount"] + totalWithholding = -trx["whAmount"] + totalPayout = totalDividend - totalWithholding + currency = trx["currency"] + account = trx["account"] + + _, 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;', ) - remainingWithholding -= myWithholding + 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"], + account, + ) + ) + + lastRow = rows[-1] result.append( self.createSingle( - myPayout, - myWithholding, - myQuantity, - myAccount, + remainingPayout, + remainingWithholding, + lastRow.quantity, + lastRow.account, asset, currency, payDate, priceLookup, trx["description"], + account, ) ) - lastRow = rows[-1] - result.append( - self.createSingle( - remainingPayout, - remainingWithholding, - lastRow.quantity, - lastRow.account, - asset, - currency, - payDate, - priceLookup, - trx["description"], - ) - ) - return result def createSingle( @@ -157,6 +162,7 @@ def createSingle( date, priceLookup, description, + account, ): narration = "Dividend for " + str(quantity) + " : " + description liquidityAccount = self.getLiquidityAccount(assetAccount, asset, currency) @@ -191,7 +197,7 @@ def createSingle( ) postings.append(data.Posting(incomeAccount, None, None, None, None, None)) - meta = data.new_metadata("dividend", 0) + meta = data.new_metadata("dividend", 0, {"account": account}) return data.Transaction( meta, date, "*", "", narration, data.EMPTY_SET, data.EMPTY_SET, postings ) diff --git a/src/tariochbctools/plugins/prices/ibkr.py b/src/tariochbctools/plugins/prices/ibkr.py index 9c9cb43..4c326cd 100644 --- a/src/tariochbctools/plugins/prices/ibkr.py +++ b/src/tariochbctools/plugins/prices/ibkr.py @@ -23,15 +23,16 @@ def get_latest_price(self, ticker: str): 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) + for custStatement in statement.FlexStatements: + for position in custStatement.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