From 74c354ca18f400c7830d0b6c89a909de14ea726c Mon Sep 17 00:00:00 2001 From: scientes <34819304+scientes@users.noreply.github.com> Date: Mon, 16 Aug 2021 18:05:58 +0200 Subject: [PATCH 1/3] add margin --- src/book.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/book.py b/src/book.py index 61541bc2..ff105b8a 100644 --- a/src/book.py +++ b/src/book.py @@ -78,6 +78,8 @@ def _read_binance(self, file_path: Path) -> None: "Launchpool Interest": "StakingInterest", "Cash Voucher distribution": "Airdrop", "Super BNB Mining": "StakingInterest", + "Margin loan": "Buy", + "Margin Repayment": "Sell", } with open(file_path, encoding="utf8") as f: From 63c97093c1969d6c66b99e24d8977d2137d0e7c7 Mon Sep 17 00:00:00 2001 From: scientes <34819304+scientes@users.noreply.github.com> Date: Mon, 16 Aug 2021 18:27:57 +0200 Subject: [PATCH 2/3] add extra Taxation type for margin --- src/book.py | 6 ++--- src/taxman.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++ src/transaction.py | 8 ++++++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/book.py b/src/book.py index ff105b8a..b647edeb 100644 --- a/src/book.py +++ b/src/book.py @@ -78,8 +78,8 @@ def _read_binance(self, file_path: Path) -> None: "Launchpool Interest": "StakingInterest", "Cash Voucher distribution": "Airdrop", "Super BNB Mining": "StakingInterest", - "Margin loan": "Buy", - "Margin Repayment": "Sell", + "Margin loan": "MarginBuy", + "Margin Repayment": "MarginSell", } with open(file_path, encoding="utf8") as f: @@ -106,7 +106,7 @@ def _read_binance(self, file_path: Path) -> None: change = abs(change) # Validate data. - assert account == "Spot", ( + assert account in ("Spot", "CrossMargin"), ( "Other types than Spot are currently not supported. " "Please create an Issue or PR." ) diff --git a/src/taxman.py b/src/taxman.py index 85c3f06d..552a70f3 100644 --- a/src/taxman.py +++ b/src/taxman.py @@ -146,6 +146,69 @@ def _evaluate_taxation_GERMANY( remark, ) self.tax_events.append(tx) + elif isinstance(op, transaction.MarginBuy): + balance.put(op) + elif isinstance(op, transaction.MarginSell): + sold_coins, unsold_coins = balance.sell(op.change) + if unsold_coins: + # Queue ran out of items to sell and not all coins + # could be sold. + if coin == config.FIAT: + # This is OK for the own fiat currencies (not taxable). + continue + else: + log.error( + f"{op.file_path.name}: Line {op.line}: " + f"Not enough {coin} in queue to sell " + f"(transaction from {op.utc_time} " + f"on {op.platform})\n" + "\tThis error occurs if your account statements " + "have unmatched buy/sell positions.\n" + "\tHave you added all your account statements " + "of the last years?\n" + "\tThis error may also occur after deposits " + "from unknown sources.\n" + ) + raise RuntimeError + if self.in_tax_year(op) and coin != config.FIAT: + taxation_type = "Sonstige Einkünfte aus Margin Trading" + # Price of the sell. + sell_price = self.price_data.get_cost(op) + taxed_gain = decimal.Decimal() + # Coins which are older than (in this case) one year or + # which come from an Airdrop, CoinLend or Commission (in an + # foreign currency) will not be taxed. + for sc in sold_coins: + if not config.IS_LONG_TERM( + sc.op.utc_time, op.utc_time + ) and not ( + isinstance( + sc.op, + ( + transaction.Airdrop, + transaction.CoinLendInterest, + transaction.StakingInterest, + transaction.Commission, + ), + ) + and not sc.op.coin == config.FIAT + ): + partial_sell_price = (sc.sold / op.change) * sell_price + sold_coin_cost = self.price_data.get_cost(sc) + taxed_gain += partial_sell_price - sold_coin_cost + remark = ", ".join( + f"{sc.sold} from {sc.op.utc_time} " + f"({sc.op.__class__.__name__})" + for sc in sold_coins + ) + tx = transaction.TaxEvent( + taxation_type, + taxed_gain, + op, + sell_price, + remark, + ) + self.tax_events.append(tx) elif isinstance( op, (transaction.CoinLendInterest, transaction.StakingInterest) ): diff --git a/src/transaction.py b/src/transaction.py index c909a8c2..f4405c41 100644 --- a/src/transaction.py +++ b/src/transaction.py @@ -91,6 +91,14 @@ class Sell(Transaction): pass +class MarginBuy(Transaction): + pass + + +class MarginSell(Transaction): + pass + + class CoinLendInterest(Transaction): pass From 0b341478ee33f7687f90ff68f8052ee693185afd Mon Sep 17 00:00:00 2001 From: scientes <34819304+scientes@users.noreply.github.com> Date: Mon, 16 Aug 2021 18:36:05 +0200 Subject: [PATCH 3/3] separated losses from gains --- src/taxman.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/taxman.py b/src/taxman.py index 552a70f3..acf0b04c 100644 --- a/src/taxman.py +++ b/src/taxman.py @@ -196,6 +196,10 @@ def _evaluate_taxation_GERMANY( partial_sell_price = (sc.sold / op.change) * sell_price sold_coin_cost = self.price_data.get_cost(sc) taxed_gain += partial_sell_price - sold_coin_cost + + if taxed_gain < 0: + taxation_type = "Sonstige Versluste aus Margin Trading" + remark = ", ".join( f"{sc.sold} from {sc.op.utc_time} " f"({sc.op.__class__.__name__})"