Fiffio hat geschrieben: Mittwoch 27. März 2019, 10:23
Bords0 und snafu,
was meint ihr, welche Möglichkeiten sind sinnvoll weiter vorzugehen?
Also ich glaube, dass du es eigentich so gut wie fertig hast... Aber das hängt natürlich ab, was du noch alles brauchst. Es war zum Beispiel ein Überraschung für mich, dass deine Daten nicht "sauber" sind.
Fiffio hat geschrieben: Mittwoch 27. März 2019, 10:23
Bords0 würde es Sinn machen dein Script mit Git (jetzt) online zu stellen?
Glaub ich nicht, man kann ja auf das Forum verweisen.
Fiffio hat geschrieben: Mittwoch 27. März 2019, 10:23
Was meinst du wie ich vorgehen soll? Was denkst du von deiner Seite was das Script noch bräuchte, außer dass es getestet werden muss? Kannst du das noch einbauen, „Sperre für ungewollte Verrechnung von früheren Verkäufen mit späteren Käufen“?
Ja, ich habs eingebaut, siehe unten. Ich rate aber dringend dazu, die Funktion fifo nur die Tupel (sell_id, buy_id, amount) ausgeben zu lassen, und nur in der Schleife im Hauptprogramm die Ausgabe zu machen.
Fiffio hat geschrieben: Mittwoch 27. März 2019, 10:23
Ich erwarte nicht dich ewig kostenlos verpflichten zu können.
Danke, das ist nett, und ich weiß das zu schätzen. Wenn du willst, spende einen Betrag, den du für angemessen hältst, z.B. an Spyder (
www.spyder-ide.org), damit "arbeite" ich meistens.
Ich selbst möchte nichts.
Fiffio hat geschrieben: Mittwoch 27. März 2019, 10:23
Ich habe angefangen von den Auswertungen etwas in eine Datei schreiben zu lassen.
Code: Alles auswählen
output_pl.write(f"{sell_t}\t{rate_diff * amount:0.2f}\t{holdingNO}{holdingOK}\n")
Das klappt mit der Berechnung der Zeiten noch nicht. (Haltedauer heißt jetzt holdingOK/ holdingNO)
Ja, das sieht seltsam aus. Du willst sowohl holdingNO als auch holdingOK ausgeben, es wird pro Schleifendurchlauf aber nur einer der Werte berechnet, und auch erst, nachdem du den Wert ausgegeben hast.
Vielleicht möchtest du folgendes: Es wird einfach nur ausgegeben, ob es OK ist. Das könnte man in einer Variaben "is_holding_OK" speichern oder so.
Ich habe das Beispiel noch etwas erweitet, damit man die Verkäufe ohne passende Käufe besser sieht.
Code: Alles auswählen
import pandas as pd
import io
from datetime import timedelta, datetime
week = timedelta(weeks=1)
raw = io.StringIO("""DateTime, Type, Amount, Rate
2017-01-08 11:43:00,buy,0.10000001,777.33
2017-01-08 11:43:00,buy,1.00000001,210.55
2017-01-10 16:11:44,sell,0.10000002,290.44
2017-01-11 18:43:00,buy,0.30000003,300.88
2017-01-12 18:55:00,buy,0.40000004,311.22
2017-01-14 22:22:11,sell,0.90000000,444.88
2018-02-15 09:22:55,sell,0.80000008,555.77
2018-02-16 09:22:55,sell,1.00000008,445.55
2018-02-15 18:55:00,buy,0.40000004,311.22
""")
file = r'bitstamp1.csv'
daten = pd.read_csv(raw, parse_dates=[0],
skipinitialspace=True) # damit die header vernünftig sind
buys = daten[daten.Type == "buy"]
sells = daten[daten.Type == "sell"]
def fifo(buys, sells):
iter_buys = buys.Amount.iteritems() # enumerate(buys)
i_buy, amount_buy = None, 0.0
for i_sell, amount_sell in sells.Amount.iteritems():
while amount_sell > 1e-10: # Falls es am Schluss genau aufgeht, kann die Rechengenauigkeit sonst ein Problem machen
if amount_buy == 0.0: # nächster Kauf wird benötigt
# gibt es noch einen?
try:
i_buy, amount_buy = next(iter_buys)
except StopIteration:
yield i_sell, None, amount_sell
break
# wenn der nicht in der Vergangenheit liegt,
# dann kann er auch nicht verwendet werden.
if buys.at[i_buy, "DateTime"] > sells.at[i_sell, "DateTime"]:
yield i_sell, None, amount_sell
break
# verkaufen kann ich so viel, wie beim Kauf und beim Verkauf vorhanden ist
amount = min(amount_buy, amount_sell)
amount_sell -= amount
amount_buy -= amount
yield i_sell, i_buy, amount
# Ausgabedateien öffnen - und dafür sorgen, dass sie automatisch wieder geschlossen werden
with open("output_pl.txt","w") as output_pl:
with open("output.txt","w") as output:
# Jetzt über alle Verkaufs/Kaufs-Paare iterieren
for i_sell, i_buy, amount in fifo(buys, sells):
# Verkaufsinfos bestimmen
sell_t = sells.at[i_sell, "DateTime"]
sell_r = sells.at[i_sell, "Rate"]
# Ausgeben und diesen Schleifendurchlauf beenden, wenn kein Verkauf zustande kam
if i_buy is None:
print(f"\nSELL id {i_sell} {sell_t} (amount {amount:0.8f} BTC) {sell_r} EUR")
print("no matching buy found")
continue
# Kaufinfos bestimmen
buy_t = buys.at[i_buy, "DateTime"]
buy_r = buys.at[i_buy, "Rate"]
# Relevante berechnete Werte bestimmen
rate_diff = sell_r - buy_r
time_diff = sell_t - buy_t
is_holding_OK = "OK" if time_diff.days >= 365 else "not OK"
# Ausgabe auf Bildschirm
print(f"\nSELL id {i_sell} {sell_t} (amount {amount:0.8f} BTC) {sell_r} EUR")
print(f" BUY id {i_buy} {buy_t} {amount:0.8f} BTC {buy_r} EUR")
print(f" Rate Diff {rate_diff:0.2f} EUR * {amount:0.8f} BTC = {rate_diff * amount:0.2f} EUR")
# Ausgabe in Datei
output_pl.write(f"{sell_t}\t{rate_diff * amount:0.2f}\tholding time is {is_holding_OK} ({time_diff.days} days)\n")
output.write(f"\nSELL id {i_sell} {sell_t} (Amount -{amount:0.8f} BTC) {sell_r} EUR\n"
f" BUY id {i_buy} {buy_t} {amount:0.8f} BTC {buy_r} EUR\n"
f" Rate Diff {rate_diff:0.2f} EUR * {amount:0.8f} BTC = "
f"{rate_diff * amount:0.2f} EUR\n")
Anmerkung: Ich weiß nicht, ob das steuerlich wirklich i.O. mit den 365 Tagen. Wahrscheinlich eine sehr gute Näherung. Falls es Fälle gibt, wo es genau 365 Tage sind, müsste man das aber überprüfen.
Anmerkung 2: Der Code ist nicht schön. Ich wollte aber nicht zu viel ändern, du sollst ihn ja noch wiedererkennen...