-
Talinn, Estonia
-
-
support@lnsolutions.ee
For English here
In der dynamischen Welt der Kryptowährungen, in der sich Volatilität und Innovation überschneiden, entwickelt sich die regulatorische Landschaft ständig weiter. Ein bemerkenswerter Aspekt dieser Entwicklung ist die Besteuerung von Kryptowährungsgewinnen. Während viele Länder verschiedene Steuerregelungen für Kryptowährungen eingeführt haben, bieten einige Länder eine günstige Politik, die langfristige Inhaber von bestimmten Steuerpflichten befreit. Eine solche Politik, die in mehreren Ländern an Zugkraft gewinnt, ist die Steuerbefreiung für Kryptobestände, die ein Jahr oder länger gehalten werden.
Die Politik des einjährigen Haltens, auch bekannt als Behandlung langfristiger Kapitalgewinne, ist ein steuerlicher Rahmen, der Steuerbefreiungen oder ermäßigte Steuersätze für Gewinne aus dem Verkauf oder Tausch von Kryptowährungen gewährt, die für eine Mindestdauer von einem Jahr gehalten werden. Diese Politik zielt darauf ab, Anreize für langfristige Investitionen in Kryptowährungen zu schaffen und gleichzeitig die Stabilität auf dem Markt zu fördern.
Mehrere Länder haben das Konzept der steuerfreien Kryptogewinne für langfristige Inhaber übernommen. Einige dieser Länder sind:
Das Paket ccGains (cryptocurrency gains) bietet eine Python-Bibliothek zur Berechnung von Kapitalgewinnen aus dem Handel mit Kryptowährungen oder Fremdwährungen. Es wurde von Jürgen Probst erstellt und wird in Github gehostet (Link hier). Einige ihrer Funktionen sind:
Sie benötigen Python (ccGains wurde unter Python 2.7 und Python 3.x getestet). Sie erhalten es hier: https://www.python.org/
ccGains kann dann einfach über den Python-Paketmanager pip installiert werden:
git clone https://github.com/probstj/ccgains.gitpip install . (beachten Sie das . am Ende)pip install --user .pip install -e .Bitte schauen Sie sich die Datei examples/example.pyan und folgen Sie den Kommentaren, um sie für Ihre Zwecke anzupassen.
Kopieren Sie es in eine neue Datei, zum Beispiel taxReport2023.py.
Stündliche Daten für viele Börsenplätze stehen zum Download bereit unter:
https://api.bitcoincharts.com/v1/csv/
Um zu verstehen, welche Datei heruntergeladen werden soll, konsultieren Sie diese Liste:
https://bitcoincharts.com/markets/list/
Für EUR-Kurse auf Kraken laden Sie bitte die folgende Datei herunter: https://api.bitcoincharts.com/v1/csv/krakenEUR.csv.gz und legen Sie sie in den Ordner ../data.
Für CHF-Preise, laden Sie herunter: https://api.bitcoincharts.com/v1/csv/anxhkCHF.csv.gz
Für SGD-Preise, laden Sie herunter: https://api.bitcoincharts.com/v1/csv/anxhkSGD.csv.gz
Die Datei besteht aus drei durch Komma getrennten Spalten: dem Unix-Zeitstempel, dem Preis und dem Volumen (gehandelter Betrag).
Erstellen Sie das HistoricData-Objekt, indem Sie die genannte Datei laden und die Preiseinheit, d.h. fiat/btc, angibt:
h1 = ccgains.HistoricDataCSV(
'../data/bitcoin_de_EUR_abridged_as_example.csv.gz', 'EUR/BTC')
Für alle Coins, die Sie irgendwann einmal besessen haben, muss ihr historischer Preis in Ihrer heimischen Fiat-Währung bekannt sein, der auch aus ihrem BTC-Preis und dem oben angegebenen BTC/Fiat-Preis abgeleitet werden kann (oder sogar aus ihrem Preis in einem anderen Altcoin, dessen Preis wiederum abgeleitet werden kann).
Diese Daten können von jeder Website zur Verfügung gestellt werden, die diese Daten über eine API bereitstellt, oder aus einer csv-Datei, wie oben. Beachten Sie, dass derzeit nur die API von Poloniex.com implementiert ist.
Erstellen Sie HistoricData-Objekte, um Kurse von Poloniex.com abzurufen: (es ist wichtig, hier zumindest alle gehandelten Coins zu erwähnen)
h2 = ccgains.HistoricDataAPI('data', 'btc/xmr')
h3 = ccgains.HistoricDataAPI('data', 'btc/eth')
h4 = ccgains.HistoricDataAPI('data', 'btc/usdt')
h5 = ccgains.HistoricDataAPI('data', 'btc/link')
h6 = ccgains.HistoricDataAPI('data', 'btc/bat')
h7 = ccgains.HistoricDataAPI('data', 'btc/zrx')
h8 = ccgains.HistoricDataAPI('data', 'btc/cvc')
h9 = ccgains.HistoricDataAPI('data', 'btc/dash')
h10 = ccgains.HistoricDataAPI('data', 'btc/knc')
h11 = ccgains.HistoricDataAPI('data', 'btc/mkr')
h12 = ccgains.HistoricDataAPI('data', 'btc/matic')
h13 = ccgains.HistoricDataAPI('data', 'btc/doge')
h14 = ccgains.HistoricDataAPI('data', 'btc/bch')
h15 = ccgains.HistoricDataAPI('data', 'btc/dot')
h16 = ccgains.HistoricDataAPI('data', 'btc/qtum')
h17 = ccgains.HistoricDataAPI('data', 'btc/ren')
h18 = ccgains.HistoricDataAPI('data', 'btc/str')
h19 = ccgains.HistoricDataAPI('data', 'btc/xtz')
h20 = ccgains.HistoricDataAPI('data', 'btc/trx')
h21 = ccgains.HistoricDataAPI('data', 'btc/zec')
h22 = ccgains.HistoricDataAPI('data', 'btc/ltc')
h23 = ccgains.HistoricDataAPI('data', 'btc/xrp')
h24 = ccgains.HistoricDataAPI('data', 'btc/omg')
h25 = ccgains.HistoricDataAPI('data', 'btc/etc')
h26 = ccgains.HistoricDataAPI('data', 'btc/dot')
h27 = ccgains.HistoricDataAPI('data', 'btc/dai')
h28 = ccgains.HistoricDataAPI('data', 'btc/usdc')
h29 = ccgains.HistoricDataAPICoinbase('data', 'cro/eur')
h30 = ccgains.HistoricDataAPIBinance('data', 'btc/uni')
h31 = ccgains.HistoricDataAPIBinance('data', 'avax/eur')
h32 = ccgains.HistoricDataAPIBinance('data', 'btc/dydx')
h33 = ccgains.HistoricDataAPIBinance('data', 'btc/iota')
h34 = ccgains.HistoricDataAPIBinance('data', 'btc/axs')
In h2 bis h28 habe ich die Klasse HistoricDataAPI verwendet, die die öffentliche Poloniex-API verwendet: https://poloniex.com/public?command=returnTradeHistory, da dies die Börse ist, an der diese Paare im Jahr 2023 in diesem Beispiel gehandelt werden.
In h29 habe ich die Klasse HistoricDataAPICoinbase verwendet, die die öffentliche Coinbase-API verwendet: “https://api.pro.coinbase.com/products/:SYMBOL:/candles".
In h30 bis h34 habe ich die Klasse HistoricDataAPIBinance verwendet, die transparent Daten auf Anfrage (get_price) von der öffentlichen Binance-API abruft: https://api.binance.com/api/v1/klines
Um die Ladezeiten bei künftigen Aufrufen zu verkürzen, wird aus den angeforderten Daten eine HDF5-Datei erstellt, die bei der nächsten Anfrage für denselben Tag und dasselbe Paar transparent verwendet wird. Diese HDF5-Dateien werden im Ordner cache_folder gespeichert. Die Einheit muss ein String in der Form “kryptowährung_eins/kryptowährung_zwei” sein, z. B. “NEO/BTC”. Die Daten werden neu abgetastet, indem der gewichtete Preis für die durch interval angegebenen Intervallschritte berechnet wird. Siehe: http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases für mögliche Werte.
prepare_request(dtime) Gibt einen Pandas DataFrame zurück, der die Daten für den angeforderten Zeitpunkt dtime enthält.
Erstellen Sie ein CurrencyRelation-Objekt, das alle angegebenen HistoricData-Währungen in Beziehung setzt, um Wechselkurse für ein beliebiges Paar dieser Währungen zu liefern:
rel = ccgains.CurrencyRelation(h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, h22, h23, h24, h25, h26,h27, h28, h29, h30, h31, h32, h33, h34)
Erstellen Sie das BagQueue-Objekt, das den steuerpflichtigen Gewinn aus Geschäften nach der First-in/First-out-Methode berechnet:
(dieses Objekt muss Ihre native Fiat-Währung und die oben erstellte CurrencyRelation kennen)
bf = ccgains.BagQueue('EUR', rel)
Das TradeHistory-Objekt bietet Methoden zum Laden Ihrer Trades aus CSV-Dateien, die von verschiedenen Börsen oder Anwendungen exportiert wurden.
th = ccgains.TradeHistory()
Exportieren Sie Ihre Trades von Börsen oder Apps als kommagetrennte Dateien und fügen Sie sie an die Liste der Trades an, die vom TradeHistory-Objekt verwaltet werden. Alle Trades werden automatisch sortiert.
Um von einer unterstützten Börse zu laden, verwenden Sie die Methoden namens `append_<exchange_name>_csv` in TradeHistory (siehe trades.py).
th.append_poloniex_csv(
'./data/2020/poloniex_depositHistory_2023.csv',
'deposits')
th.append_poloniex_csv(
'./data/2020/poloniex_tradeHistory_2023.csv',
'trades',
condense_trades=True)
th.append_poloniex_csv(
'./data/2020/poloniex_withdrawalHistory_2023.csv',
'withdr')
th.append_binance_csv(
'./data/2020/binance_depositHistory_2023.csv',
'deposits')
th.append_binance_csv(
'./data/2020/binance_tradeHistory_2023.csv',
'deposits')
th.append_binance_csv(
'./data/2020/binance_withdrawalHistory_2023.csv',
'deposits')
th.append_wirex_csv(
'./data/2020/wirex_btc_tradeHistory_2023.csv',
'trades')
th.append_cro_csv(
'./data/2021/cro_tradeHistory_2023.csv',
'trades')
Wenn Ihre Börse noch nicht unterstützt wird, fügen Sie eine neue Methode in trades.py hinzu. In diesem Beispiel werden die Methoden append_wirex_csv und append_cro_csv im ursprünglichen GitHub-Projekt nicht unterstützt.
Als nächstes werde ich zeigen, wie ich es mit append_cro_csv (Crypto.com) gemacht habe. Importieren Sie zunächst TPLOC_CRO_TRADES, die Bibliothek, die weiß, wie man die CSV-Datei von der Crypto.com-Börse liest.
from .cro_util import (
TPLOC_CRO_TRADES)
def append_cro_csv(
self, file_name, which_data='trades', delimiter=',',
skiprows=1, default_timezone=tz.tzutc()):
wdata = which_data[:5].lower()
if wdata not in ['trade']:
raise ValueError(
'`which_data` must be one of "trades"')
plocs = TPLOC_CRO_TRADES
self.append_csv(
file_name=file_name,
param_locs=plocs,
delimiter=delimiter,
skiprows=skiprows,
default_timezone=default_timezone
)
Erzeugen Sie nun die Datei cro_util.py
from decimal import Decimal
def kind_for(csv_line):
if 'Withdraw' in (csv_line[1].strip('" \n\t')) or ('Transfer' in (csv_line[1].strip('" \n\t')) and 'App' in csv_line[1].strip('" \n\t').split("->")[0]):
return 'Withdrawal'
elif 'Deposit' in (csv_line[1].strip('" \n\t')) or 'Reward' in (csv_line[1].strip('" \n\t')) or ('Transfer' in (csv_line[1].strip('" \n\t')) and 'Exchange' in csv_line[1].strip('" \n\t').split("->")[0]):
return 'Deposit'
elif 'Buy' in (csv_line[1].strip('" \n\t')):
return 'Buy'
elif '->' in csv_line[1].strip('" \n\t'):
return 'Sell'
else:
return None
def get_buy_currency(csv_line):
if not '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Buy' or kind_for(csv_line) == 'Deposit' or 'App' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
elif '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Buy' or kind_for(csv_line) == 'Deposit' or 'App' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
else:
return csv_line[1].strip('" \n\t').split("->")[1]
def get_sell_currency(csv_line):
if not '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Sell' or kind_for(csv_line) == 'Withdrawal' or 'Exchange' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
elif '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Sell' or kind_for(csv_line) == 'Withdrawal' or 'Exchange' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
else:
return csv_line[1].strip('" \n\t').split("->")[0]
#Trade parameters in csv from Crypto.com
TPLOC_CRO_TRADES = {
'kind': lambda cols: kind_for(cols),
'dtime': 0,
'buy_currency': lambda cols: get_buy_currency(cols) if kind_for(cols) == 'Buy' or kind_for(cols) == 'Deposit' else cols[4] if cols[4].strip('" \n\t') != '' else '',
'buy_amount': lambda cols: abs(Decimal(cols[3])) if kind_for(cols) == 'Buy' or kind_for(cols) == 'Deposit' else abs(Decimal(cols[5])) if cols[5].strip('" \n\t') != '' else '',
'sell_currency': lambda cols: get_sell_currency(cols) if kind_for(cols) == 'Sell' or kind_for(cols) == 'Withdrawal' else 'EUR',
'sell_amount': lambda cols: abs(Decimal(cols[3])) if kind_for(cols) == 'Sell' or kind_for(cols) == 'Withdrawal' else cols[7],
'fee_currency': -1,
'fee_amount': -1,
'exchange': 'Crypto.com', 'mark': -1,
'comment': lambda cols: cols[1]
}
Einige Börsen, wie Poloniex, enthalten keine Abhebungsgebühren in ihren exportierten csv-Dateien. Es wird versucht, diese fehlenden Gebühren zu ergänzen, indem die abgehobenen Beträge mit den Beträgen verglichen werden, die kurz nach der Abhebung an anderen Börsen eingezahlt wurden. Rufen Sie dies erst auf, nachdem alle Transaktionen von allen beteiligten Börsen und Wallets importiert wurden.
Da dieser Algorithmus sehr einfach ist, kann nicht garantiert werden, dass er in jedem Fall funktioniert, vor allem, wenn Sie Abhebungen in kurzer Folge an verschiedenen Börsen vorgenommen haben; überprüfen Sie daher bitte die Ausgabe.
th.add_missing_transaction_fees(raise_on_error=False)
Einige Währungen haben seit ihrem ersten Auflistungsdatum ihr Tickersymbol geändert (z. B. AntShares (ANS) -> Neo (NEO)). Dies kann zu Situationen führen, in denen alle historischen Preisdaten das neue Tickersymbol auflisten, die Transaktionshistorie jedoch noch das alte Tickersymbol enthält.
Diese Methode ermöglicht die Umbenennung von Symbolen in der TradeHistory, wenn ein Vorkommen des alten Namens/Tickers gefunden wird.
th.update_ticker_names({'ANS': 'NEO'})
Sie können alle importierten Trades zur späteren Verwendung in eine einzige Datei exportieren, optional gefiltert nach Jahr.
…entweder als kommagetrennte Textdatei (kann in ccgains importiert werden):
th.export_to_csv('transactions2023.csv', year=2023)
…oder als html- oder pdf-Datei, mit der Möglichkeit, Spaltenüberschriften oder Inhalte zu filtern oder umzubenennen:
(Dies ist ein Beispiel für eine Übersetzung ins Deutsche)
my_column_names=[
'Art', 'Datum', 'Kaufmenge', 'Verkaufsmenge', u'Gebühren', u'Börse']
transdct = {'Buy': 'Anschaffung',
'BUY': 'Anschaffung',
'Sell': 'Tausch',
'SELL': 'Tausch',
'Purchase': 'Anschaffung',
'Exchange': 'Tausch', 'Disbursement': 'Abhebung',
'Deposit': 'Einzahlung',
'Withdrawal': 'Abhebung',
'Received funds': 'Einzahlung',
'Withdrawn from wallet': 'Abhebung',
'Create offer fee: a5ed7482': u'Börsengebühr',
'Buy BTC' : 'Anschaffung',
'MultiSig deposit: a5ed7482': 'Abhebung',
'MultiSig payout: a5ed7482' : 'Einzahlung'}
th.export_to_pdf('Transactions2021.pdf',
year=2021, drop_columns=['mark', 'comment'],
font_size=12,
caption=u"Handel mit digitalen Währungen %(year)s",
intro=u"<h4>Auflistung aller Transaktionen zwischen "
"%(fromdate)s und %(todate)s:</h4>",
locale="de_DE",
custom_column_names=my_column_names,
custom_formatters={
'Art': lambda x: transdct[x] if x in transdct else x})
Wenn die Berechnung bereits für frühere Jahre gelaufen ist, können wir hier den Stand der Taschen laden, ohne alles erneut berechnen zu müssen:
bf.load('./status2022.json')
Oder, wenn die aktuelle Berechnung abgestürzt ist (z.B. weil Sie vergessen haben, eine gehandelte Währung in #2 oben hinzuzufügen), wird die Datei ‘precrash.json’ automatisch erstellt. Laden Sie sie hier, um fortzufahren:
bf.load('./precrash.json')
Im Folgenden wird lediglich nachgeschaut, wo mit der Berechnung der Trades begonnen werden soll, falls Sie bereits einige berechnet und durch das Laden von ‘precrash.json’ neu gestartet haben:
last_trade = 0
while (last_trade < len(th.tlist)
and th[last_trade].dtime <= bf._last_date):
last_trade += 1
if last_trade > 0:
logger.info("continuing with trade #%i" % (last_trade + 1))
# Now, the calculation. This goes through your imported list of trades:
for i, trade in enumerate(th.tlist[last_trade:]):
# Most of this is just the log output to the console and to the
# file 'ccgains_<date-time>.log'
# (check out this file for all gory calculation details!):
logger.info('TRADE #%i', i + last_trade + 1)
logger.info(trade)
# This is the important part:
bf.process_trade(trade)
# more logging:
log_bags(bf)
logger.info("Totals: %s", str(bf.totals))
logger.info("Gains (in %s): %s\n" % (bf.currency, str(bf.profit)))
bf.save('status2023.json')
Die im Bericht verwendeten Standard-Spaltennamen sehen nicht sehr schön aus: [‘Art’, ‘bag_spent’, ‘Währung’, ‘bag_date’, ‘sell_date’, ‘exchange’, ‘short_term’, ‘spent_cost’, ‘proceeds’, ‘profit’], also benennen wir sie um:
my_column_names=[
'Type', 'Amount spent', u'Currency', 'Purchase date',
'Sell date', u'Exchange', u'Short term', 'Purchase cost',
'Proceeds', 'Profit']
Hier erstellen wir den pdf-Bericht für Kapitalgewinne im Jahr 2023.
Die Angabe date_precision=’D’ bedeutet, dass wir nur den Tag des Abschlusses erwähnen, nicht die genaue Uhrzeit. Außerdem stellen wir combine=True ein, so dass mehrere Trades, die am selben Tag und an derselben Börse getätigt wurden, im Bericht zu einem einzigen Trade zusammengefasst werden:
my_column_names=[
'Art', 'Verkaufsmenge', u'Währung', 'Erwerbsdatum',
'Verkaufsdatum', u'Börse', u'in\xa0Besitz',
'Anschaffungskosten', u'Verkaufserlös', 'Gewinn']
transdct = {'sale': u'Veräußerung',
'withdrawal fee': u'Börsengebühr',
'deposit fee': u'Börsengebühr',
'exchange fee': u'Börsengebühr'}
convert_short_term=[u'>\xa01\xa0Jahr', u'<\xa01\xa0Jahr']
bf.report.export_report_to_pdf(
'Report2021_de.pdf', year=2023,
date_precision='D', combine=True,
custom_column_names=my_column_names,
custom_formatters={
u'in\xa0Besitz': lambda b: convert_short_term[b],
'Art': lambda x: transdct[x]},
locale="de_DE",
template_file='shortreport_de.html'
)
# If you rather want your report in a spreadsheet, you can export
# to csv:
bf.report.export_short_report_to_csv(
'report_2023.csv', year=2023,
date_precision='D', combine=False,
convert_timezone=True, strip_timezone=True)
Der oben erstellte einfache Kapitalertragsbericht ist nur eine einfache Auflistung aller Trades und der erzielten Gewinne, die für den Steuerbericht ausreicht.
Eine detailliertere Auflistung, in der die Berechnung dargestellt wird, ist ebenfalls verfügbar:
bf.report.export_extended_report_to_pdf(
'Details_2023.pdf', year=2023,
date_precision='S', combine=False,
font_size=10, locale="en_US")
Und noch einmal, übersetzen wir diesen Bericht ins Deutsche: (Wiederum mit transdct von oben, um die Zahlungsart zu übersetzen)
bf.report.export_extended_report_to_pdf(
'Details_2023_de.pdf', year=2023,
date_precision='S', combine=False,
font_size=10, locale="de_DE",
template_file='fullreport_de.html',
payment_kind_translation=transdct)
Jetzt ausführen
python taxReport2023.py
Dies sollte die pdf-Dateien Details_2023.pdf und Details_2023_de.pdf erzeugen, die vom Finanzamt benötigt werden.
Für weitere Informationen zur Erstellung von Krypto-Steuerberichten oder zur Anpassung an Ihre Bedürfnisse kontaktieren Sie uns unter lnsolutions.ee