From 7c67986adb3a4ad83e1f282fd85b8e4be3e159ac Mon Sep 17 00:00:00 2001
From: Vlad <55182132+titov-vv@users.noreply.github.com>
Date: Sun, 7 Apr 2024 16:43:31 +0100
Subject: [PATCH] Interactive Brokers statement import: processing of extra tax
for MLP.
---
jal/data_import/broker_statements/ibkr.py | 24 +++++++++++++++++++++--
jal/data_import/statement.py | 1 +
tests/test_data/ibkr_dividends.json | 15 ++++++++++----
tests/test_data/ibkr_dividends.xml | 8 ++++++++
4 files changed, 42 insertions(+), 6 deletions(-)
diff --git a/jal/data_import/broker_statements/ibkr.py b/jal/data_import/broker_statements/ibkr.py
index ff1eb15c..076f6725 100644
--- a/jal/data_import/broker_statements/ibkr.py
+++ b/jal/data_import/broker_statements/ibkr.py
@@ -43,7 +43,8 @@ class IBKR_AssetType:
'FUT': FOF.ASSET_FUTURES,
'WAR': FOF.ASSET_WARRANT,
'RIGHT': FOF.ASSET_RIGHTS,
- 'CFD': FOF.ASSET_CFD
+ 'CFD': FOF.ASSET_CFD,
+ 'MLP': FOF.ASSET_MLP
}
def __init__(self, asset_type, subtype):
@@ -982,7 +983,26 @@ def aggregate_taxes(self, taxes: list) -> list:
part['amount'] = sum(tax['amount'] for tax in group_list) # and update quantity in it
lieu_aggregated.append(part)
taxes_aggregated = sorted(other_taxes + lieu_aggregated, key=key_func)
- return taxes_aggregated
+
+ # There might be additional record to withhold 10% of extra tax on partnerships (currently faced for MLP) reported in different dates
+ key_func = lambda x: (x['account'], x['asset'], x['currency'], x['description'], x['timestamp'])
+ mlp_taxes = [x for x in taxes_aggregated if self._find_in_list(self._data[FOF.ASSETS], 'id', x['asset'])['type'] == FOF.ASSET_MLP]
+ non_mlp_taxes = [x for x in taxes_aggregated if x not in mlp_taxes]
+ mlp_processed = []
+ for k, group in groupby(mlp_taxes, key=key_func):
+ group_list = sorted(list(group), key=lambda x: (x['amount'])) # sort to have higher tax first
+ if len(group_list) > 2:
+ raise Statement_ImportError(self.tr("Too many records for MLP tax: ") + f"{group_list}")
+ if len(group_list) == 2: # 1st line is expected to be a base tax and 2nd line seems to be additional 10%
+ tax = group_list[1] # Store 2nd line as separate asset payment record
+ tax['id'] = max([0] + [x['id'] for x in self._data[FOF.ASSET_PAYMENTS]]) + 1
+ tax['type'] = FOF.PAYMENT_FEE
+ tax['description'] += " - Extra 10% tax due to IRS section 1446"
+ self.drop_extra_fields(tax, ["source", "currency", "reported"])
+ self._data[FOF.ASSET_PAYMENTS].append(tax)
+ mlp_processed.append(group_list[0]) # Keep only base tax
+ taxes_processed = sorted(non_mlp_taxes + mlp_processed, key=key_func)
+ return taxes_processed
def load_taxes(self, taxes):
cnt = 0
diff --git a/jal/data_import/statement.py b/jal/data_import/statement.py
index 121cc2de..56d7f724 100644
--- a/jal/data_import/statement.py
+++ b/jal/data_import/statement.py
@@ -43,6 +43,7 @@ class FOF:
ASSET_RIGHTS = "right"
ASSET_CRYPTO = "crypto"
ASSET_CFD = "cfd"
+ ASSET_MLP = "mlp"
ACTION_MERGER = "merger"
ACTION_SPLIT = "split"
diff --git a/tests/test_data/ibkr_dividends.json b/tests/test_data/ibkr_dividends.json
index 25035d4b..975ac135 100644
--- a/tests/test_data/ibkr_dividends.json
+++ b/tests/test_data/ibkr_dividends.json
@@ -7,17 +7,20 @@
{"id": 1, "name": "", "type": "money"},
{"id": 2, "type": "stock", "name": "BROOKFIELD RENEWABLE PARTNER", "isin": "BMG162581083", "country": "ca"},
{"id": 3, "type": "adr", "name": "TELEFONICA SA-SPON ADR", "isin": "US8793822086", "country": "es"},
- {"id": 4, "type": "stock", "name": "OWL ROCK CAPITAL CORP", "isin": "US69121K1043", "country": "us"}
+ {"id": 4, "type": "stock", "name": "OWL ROCK CAPITAL CORP", "isin": "US69121K1043", "country": "us"},
+ {"id": 5, "type": "mlp", "name": "USA COMPRESSION PARTNERS LP", "isin": "US90290N1090", "country": "us"}
],
"symbols": [
{"id": 1, "asset": 1, "symbol": "USD"},
{"id": 2, "asset": 2, "symbol": "BEP", "currency": 1, "note": "NYSE"},
{"id": 3, "asset": 3, "symbol": "TEF", "currency": 1, "note": "NYSE"},
- {"id": 4, "asset": 4, "symbol": "ORCC", "currency": 1, "note": "NYSE"}
+ {"id": 4, "asset": 4, "symbol": "ORCC", "currency": 1, "note": "NYSE"},
+ {"id": 5, "asset": 5, "symbol": "USAC", "currency": 1, "note": "NYSE"}
],
"assets_data": [
{"id": 1, "asset": 3, "reg_number": "879382208"},
- {"id": 2, "asset": 4, "reg_number": "69121K104"}
+ {"id": 2, "asset": 4, "reg_number": "69121K104"},
+ {"id": 3, "asset": 5, "reg_number": "90290N109"}
],
"asset_payments": [
{"id": 1, "type": "stock_dividend", "account": 1, "timestamp": 1595017200, "number": "13259965038", "asset": 3, "amount": 3.0, "price": "4.73", "tax": 0, "description": "TEF (US8793822086) STOCK DIVIDEND US8793822086 416666667 FOR 10000000000"},
@@ -35,7 +38,11 @@
{"id": 13, "type": "dividend", "account": 1, "timestamp": 1621023600, "number": "", "asset": 4, "amount": 20.46, "tax": 2.05, "description": "ORCC(US69121K1043) CASH DIVIDEND USD 0.31 PER SHARE (Ordinary Dividend)"},
{"id": 14, "type": "dividend", "account": 1, "timestamp": 1628886000, "number": "", "asset": 4, "amount": 31.0, "tax": 3.1, "description": "ORCC(US69121K1043) CASH DIVIDEND USD 0.31 PER SHARE (Ordinary Dividend)"},
{"id": 15, "type": "dividend", "account": 1, "timestamp": 1611087600, "number": "", "asset": 4, "amount": 38.61, "tax": 3.58, "description": "ORCC(US69121K1043) PAYMENT IN LIEU OF DIVIDEND (Ordinary Dividend)"},
- {"id": 16, "type": "dividend", "account": 1, "timestamp": 1621023600, "number": "", "asset": 4, "amount": 10.54, "tax": 1.05,"description": "ORCC(US69121K1043) PAYMENT IN LIEU OF DIVIDEND (Ordinary Dividend)"}
+ {"id": 16, "type": "dividend", "account": 1, "timestamp": 1621023600, "number": "", "asset": 4, "amount": 10.54, "tax": 1.05,"description": "ORCC(US69121K1043) PAYMENT IN LIEU OF DIVIDEND (Ordinary Dividend)"},
+ {"id": 17, "type": "dividend", "account": 1, "timestamp": 1675455600, "number": "", "asset": 5, "amount": 5.25, "tax": 1.94, "description": "USAC(US90290N1090) CASH DIVIDEND USD 0.525 PER SHARE (Ordinary Dividend)"},
+ {"id": 18, "type": "dividend", "account": 1, "timestamp": 1683318000, "number": "", "asset": 5, "amount": 5.25, "tax": 1.94, "description": "USAC(US90290N1090) CASH DIVIDEND USD 0.525 PER SHARE (Ordinary Dividend)"},
+ {"id": 19, "type": "fee", "account": 1, "timestamp": 1675455600, "number": "", "asset": 5, "amount": -0.53, "description": "USAC(US90290N1090) CASH DIVIDEND USD 0.525 PER SHARE - US TAX - Extra 10% tax due to IRS section 1446"},
+ {"id": 20, "type": "fee", "account": 1, "timestamp": 1683318000, "number": "", "asset": 5, "amount": -0.53, "description": "USAC(US90290N1090) CASH DIVIDEND USD 0.525 PER SHARE - US TAX - Extra 10% tax due to IRS section 1446"}
],
"corporate_actions": [],
"income_spending": [
diff --git a/tests/test_data/ibkr_dividends.xml b/tests/test_data/ibkr_dividends.xml
index 3bc2bde5..c722a3cb 100644
--- a/tests/test_data/ibkr_dividends.xml
+++ b/tests/test_data/ibkr_dividends.xml
@@ -10,6 +10,7 @@
+
@@ -73,6 +74,13 @@
+
+
+
+
+
+
+