Selbermachen oder in Auftrag geben? Fifo Buchhaltung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

Hallo,

ich brauche euren Rat.
Mit einem „kleinen Projekt“ habe ich mir – so wie es aussieht - zu viel zugemutet. Was meint ihr, kann ich das als „Auftrag“ von einem Python-Programmierer machen lassen?
Ich glaube nicht (mehr) – nach meinen Erfahrungen die ich bis jetzt mit Python gesammelt habe - dass ich es selber mit Hilfestellung in den nächsten ca. 7 Tagen fertig bekomme. Das wäre aber notwendig, da mir das Finanzamt im Nacken sitzt.
Ich selbst bin ganz am Anfang von Python und auch in Buchhaltung eher Amateur. Das kann die Sache doch recht verzwickt (zeitaufwendig) machen!

Versuch einer Beschreibung der Aufgabe:
Es geht um FIFO (First In – First Out) Buchhaltung (Gewinn/Verlustermittlung (G/V)) an Hand von csv Daten. Ich brauche dieses Vorgehen für meine Einkommensteuererklärung.

Wenn in den Datensätzen (daten.csv) ein Datensatz mit „sell“ (Verkauf) auftritt, soll dieser mit dem ältesten „buy“ (Kauf) Datensatz verrechnet werden.
Beispiel (Amount BTC hat acht Nachkommastellen, Rate EUR hat zwei):
Datei: daten.csv

Code: Alles auswählen

DateTime,Typ,Amount (BTC),Rate (EUR)
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:00,buy,1.00000002,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
Amount = Anzahl/Menge von Bitcoin
Rate = der Kurs in EUR (BTC/EUR, ein Bitcoin entspricht x EUR)
buy = Kauf
sell = Verkauf

So wie ich die Fifo Buchhaltung verstanden habe gibt es quasi zwei Teilschritte.

1. Teilschritt Amount BTC, Ermittlung der Anzahl/Menge bei der Verrechnung von Verkauf und Kauf Datensätzen. D.h. wenn die Anzahl/Amount von Verkauf und Kauf Datensätzen unterschiedlich ist und man z.B. gezwungen wird für einen Verkauf zwei(!) unterschiedliche Kauf Datensätze heranzuziehen:

Datensatz: (1. Verkauf) 2017-01-10 16:11:44,sell,0.10000002,290.44
Datensatz: (1. Kauf) 2017-01-08 11:43:00,buy,0.10000001,200.11
1.1 Berechnung Amount: (1. Kauf - 1. Verkauf) 0.10000001 - 0.10000002 = - 0.00000001 BTC (Rest 1. Verkauf)
Der 1. Verkauf hat hier einen größeren Amount als der Kauf, so muss für den Rest des 1. Verkauf (-0.00000001) der nächste (2. Kauf) herangezogen werden.

Datensatz: (2. Kauf) 2017-01-08 11:43:00,buy,1.00000002,210.55
Datensatz: (Rest 1. Verkauf) 2017-01-10 16:11:44,sell,0.00000001,290.44
1.2 Berechnung Amount: (2. Kauf - Rest 1. Verkauf) 1.00000002 - 0.00000001 = 1.00000001 BTC (Rest 2. Kauf)
Nun hat der BTC Amount vom 2. Kauf einen Rest und muss mit dem nächsten 2.Verkauf BTC Amount verrechnet werden. Usw.

Bei den 7 Beispieldatensätzen soll am Ende für BTC Amount 0.00000000 herauskommen.

2. Teilschritt EUR, Kursdifferenz von Kauf/Verkauf, um den G/V in EUR von den sell/buy Datensatzpaaren zu berechnen.
Datensatz: (1. Verkauf) 2017-01-10 16:11:44,sell,0.10000002,290.44
Datensatz: (1. Kauf) 2017-01-08 11:43:00,buy,0.10000001,200.11
2.1 Berechnung EUR: (1. Kauf Amount * (1. Verkauf Rate - 1. Kauf Rate)) 0.10000001 * (290.44-200.11) = 9.03300181 EUR (G/V)

Der 1. Kauf Amount musste zur Berechnung genommen werden, weil er kleiner als der Verkauf Amount ist und ein Rest von - 0.00000001 BTC (Rest 1. Verkauf) übrig bleibt.

Dann käme der (Rest 1. Verkauf), der mit dem (2. Kauf) verrechnet werden muss.
Datensatz: (Rest 1. Verkauf) 2017-01-10 16:11:44,sell,0.00000001,290.44
Datensatz: (2. Kauf) 2017-01-08 11:43:00,buy,1.00000002,210.55
2.2 Berechnung EUR: (Rest 1. Verkauf Amount * (1. Verkauf Rate - 2. Kauf Rate)) 0.00000001 * (290.44-210.55) = 71.90100000 EUR (G/V)
Usw.
Bis hier wären die beiden ersten buy/sell Datensätze komplett bearbeitet.
Datensatz: (1. Verkauf) 2017-01-10 16:11:44,sell,0.10000002,290.44
Datensatz: (1. Kauf) 2017-01-08 11:43:00,buy,0.10000001,200.11

und es würde weitergehen mit 1. Teilschritt Amount BTC bei:
Datensatz: (Rest 2. Kauf) 2017-01-08 11:43:00,buy,1.00000001,210.55

Wäre das ausreichend genug beschrieben? Kann man daran den Aufwand/Kosten abschätzen wenn ich das von einen Programmierer machen lassen will?

Zum Thema FIFO habe ich die letzten Monate das Internet durchforstet und verschiedene Programme, Onlinedienste und Scripte ausprobiert. Für mich habe ich nichts passendes gefunden, dass sich auf die Kernfunktion von FIFO beschränkt. Überall werden noch „Extras“ wie verschiedene Datenformate, Währungsumrechnung und diverse Gebühren miteinbezogen. Und viele sind beta und funktionieren nur eingeschränkt, bzw. sind auch mit erheblichem Lernaufwand verbunden, der dann doch nicht zum gewünschten Ziel führte. Oder bei den Onlinediensten ist das Thema Datenschutz nicht genug berücksichtigt. Die Programme sind nicht Open Source usw.
U.a habe ich mich auch mit ledger cli (hledger, beancount), GnuCash, beschäftigt.

Meine idealistischen Hintergedanken bei der ganzen Sache war die Idee, eine (simple) Open Source Lösung für Fifo via „Gitlab“ etc. auch anderen zur Verfügung zu stellen. Für Leute die z.B. mit Kryptowährungen werkeln aber auch für andere Daten die eine Fifo Berechnung brauchen und sei es, wenn jemand nur einen Vergleich für seine eigenen Methoden braucht. Simpel, offen (Open Source) und offline verwendbar.

Meine Ansätze in Python:
Bisher habe ich mit Python die csv Daten in Listen eingelesen, auf die Elemente der (verschachtelten) Listen zugegriffen und versucht erste Berechnungen zu machen.

Das ist mein zweiter Python-Versuch, hier war die Priorität die ersten Datensätze (Listen) zu erreichen.

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv
"""  daten.csv
row[0],          row[1],  row[2], row[3],
DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:00,buy,1.00000002,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
"""
sID = 0                                     # Zähler für "if" sell Durchläufe
bID = 0                                     # Zähler für "elif" buy Durchläufe
h_array = []                                # history import alle Listen
b_array = []                                # buy Listen
s_array = []                                # sell Listen
amt_diff = 0                                # =SellAmt 0.10000002 -BuyAmt 0.10000001 =0.00000001
rate_diff = 0                               # = rate_s - rate_b
for_id =0                                   # Zähler row[] "for" Durchläufe

with open('daten.csv') as csvDataFile:
    csvList = csv.reader(csvDataFile)
    for row in csvList:
        for_id = for_id+1        
        h_array.append(row)                 # alle Zeilen (Listen) in Array speichern, "anhängen"
        
        if row[1] == "sell":                # Sell Datensätze ermitteln 
            sID = sID +1                    # ID für sell listen
            s_list = row                    # sell Zeilen in Liste
            s_array.append(s_list)          # Sell Listen in Array
            
        elif row[1] == "buy":               # Buy Datensätze ermitteln
            bID = bID +1
            b_list = row                    # analog zu sell
            b_array.append(b_list)

# Berechnung der ersten Sell und Buy (BTC) AMOUNT Differenz
amt_s = s_array[0][2]                       # Erste Liste mit Sell Amount 
amt_b = b_array[0][2]                       # Erste Liste mit Buy Amount
amt_s = float(amt_s)                        # Umwandlunf in Float (Sell Amount)
amt_b = float(amt_b) 
amt_diff = amt_s - amt_b                    # Erste Differenz von Sell+Buy Amount 
print("1. Berechnung\n",
      "  1. Datensatz:  2017-01-08 11:43:00, buy,  0.10000001, 200.11\n",
      "  3. Datensatz:  2017-01-10 16:11:44, sell, 0.10000002, 290.44")
print("AMOUNT:","SellAmt",amt_s,"-","BuyAmt",amt_b,"=",
      ("%.8f" % amt_diff),"(Sell/Buy Diff=0.00000001)")  # First amt_diff = 0.00000001

# Berechnung der ersten Sell und Buy (EUR) RATE Differenz
rate_s = s_array[0][3]                      # Erster Sell Rate 
rate_b = b_array[0][3]                      # Erster Buy Rate
rate_s = float(rate_s)
rate_b = float(rate_b)
rate_diff = rate_s - rate_b                # Berechnung von Kurs Diff. Sell/Buy (für P/L)
print("RATE:   Sell Rate",rate_s,"-","Buy Rate",rate_b,"=","Diff:",("%.2f" % rate_diff),"(90.33)")

# Berechnung EUR: (1. Datensatz Buy Amt * (Sell Rate - Buy Rate) 0.10000001 * (290.44-200.11)
#                  = 9.03300181 EUR (G/V))
eur_pl = amt_b * (rate_s - rate_b)
print("€ P/L:  Buy Amt",("%.8f" % amt_b),"* (Sell Rate",rate_s," - Buy Rate",rate_b,")=",
      ("%.8f" % eur_pl))
Output:

Code: Alles auswählen

1. Berechnung
   1. Datensatz:  2017-01-08 11:43:00, buy,  0.10000001, 200.11
   3. Datensatz:  2017-01-10 16:11:44, sell, 0.10000002, 290.44
AMOUNT: SellAmt 0.10000002 - BuyAmt 0.10000001 = 0.00000001 (Sell/Buy Diff=0.00000001)
RATE:   Sell Rate 290.44 - Buy Rate 200.11 = Diff: 90.33 (90.33)
€ P/L:  Buy Amt 0.10000001 * (Sell Rate 290.44  - Buy Rate 200.11 )= 9.03300090

Bei meinem ersten Python-Versuch, war die Priorität alle Datensätze (Listen) zu durchlaufen. Die Berechnungen stimmen noch gar nicht.

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import csv
"""  daten.csv
row[0],          row[1],  row[2], row[3],
DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:00,buy,1.00000002,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
"""
sID = 0
bID = 0
h_array = []                                # history
b_array = []                                # buy
s_array = []                                # sell
s1_amt = 0
b1_amt = 0
amt_diff = 0                     
rate_diff = 0
rate_sb = 0
for_id =0                                   # amount (row[2])
with open('daten.csv') as csvDataFile:
    csvList = csv.reader(csvDataFile)
    for row in csvList:
        for_id = for_id+1        
        h_array.append(row)                 # alle Zeilen in Array speichern, "anhängen"

        if row[1] == "sell":
            sID = sID +1                    # ID für sell listen
            s_list = row                    # sell Zeilen in Liste
            s_array.append(s_list)          # Sell Listen in Array
            s1_amt = s_list[2]              # 1 Amount  (nur row, weil schon in[array])
            s1_amt = float(s1_amt)          # Amount als float
            diff_s_amt = b1_amt*s1_amt
            print(sID,"ID","SLD-Liste:",s_list)
            print("                       --> Sell Amount (s1_amt):",("%.8f" % s1_amt))     # ("%.8f" % var) bedeutet Nachkommastellen
            print("        Buy/Sell Amount Diff. (b1_amt - s1_amt):",("%.8f" % b1_amt),"-",
                  ("%.8f" % s1_amt),"=",("%.8f" % diff_s_amt))
            
        elif row[1] == "buy":
            bID = bID +1
            b_list = row
            b_array.append(b_list)
            b1_amt = b_list[2]              # 1 Amount aus b_list[row]
            b1_amt = float(b1_amt)
            diff_b_amt = b1_amt*s1_amt
            print(bID,"ID","BUY-Liste:",b_list)
            print("                       --> Buy Amount (b1_amt):",b1_amt)
            print("       Buy/Sell Amount Diff. (b1_amt - s1_amt):",("%.8f" % b1_amt),"-",
                  ("%.8f" % s1_amt),"=",("%.8f" % diff_b_amt))
    
        print("---------------------------------",for_id,".","Durchlauf--------------------------------------")
Output:

Code: Alles auswählen

1 ID BUY-Liste: ['2017-01-08 11:43:00', 'buy', '0.10000001', '200.11']
                       --> Buy Amount (b1_amt): 0.10000001
       Buy/Sell Amount Diff. (b1_amt - s1_amt): 0.10000001 - 0.00000000 = 0.00000000
--------------------------------- 1 . Durchlauf--------------------------------------
2 ID BUY-Liste: ['2017-01-08 11:43:00', 'buy', '1.00000002', '210.55']
                       --> Buy Amount (b1_amt): 1.00000002
       Buy/Sell Amount Diff. (b1_amt - s1_amt): 1.00000002 - 0.00000000 = 0.00000000
--------------------------------- 2 . Durchlauf--------------------------------------
1 ID SLD-Liste: ['2017-01-10 16:11:44', 'sell', '0.10000002', '290.44']
                       --> Sell Amount (s1_amt): 0.10000002
        Buy/Sell Amount Diff. (b1_amt - s1_amt): 1.00000002 - 0.10000002 = 0.10000002
--------------------------------- 3 . Durchlauf--------------------------------------
3 ID BUY-Liste: ['2017-01-11 18:43:00', 'buy', '0.30000003', '300.88']
                       --> Buy Amount (b1_amt): 0.30000003
       Buy/Sell Amount Diff. (b1_amt - s1_amt): 0.30000003 - 0.10000002 = 0.03000001
--------------------------------- 4 . Durchlauf--------------------------------------
4 ID BUY-Liste: ['2017-01-12 18:55:00', 'buy', '0.40000004', '311.22']
                       --> Buy Amount (b1_amt): 0.40000004
       Buy/Sell Amount Diff. (b1_amt - s1_amt): 0.40000004 - 0.10000002 = 0.04000001
--------------------------------- 5 . Durchlauf--------------------------------------
2 ID SLD-Liste: ['2017-01-14 22:22:11', 'sell', '0.90000000', '444.88']
                       --> Sell Amount (s1_amt): 0.90000000
        Buy/Sell Amount Diff. (b1_amt - s1_amt): 0.40000004 - 0.90000000 = 0.36000004
--------------------------------- 6 . Durchlauf--------------------------------------
3 ID SLD-Liste: ['2018-02-15 09:22:55', 'sell', '0.80000008', '555.77']
                       --> Sell Amount (s1_amt): 0.80000008
        Buy/Sell Amount Diff. (b1_amt - s1_amt): 0.40000004 - 0.80000008 = 0.32000006
--------------------------------- 7 . Durchlauf--------------------------------------

Eure konstruktiven Vorschläge sind sehr willkommen.
Fragen wie: „warum nimmst du keine Dictionaries oder NumPy?“ Kann ich bei meinem Kenntnislevel nicht beantworten, weil ich diese Methoden nicht gut genug kenne.
Und nun läuft mir ja die Zeit davon und meine Kapazitätsgrenzen tauchen am Horizont auf.
Danke.

PS: Wenn es möglich ist meine Idee als Auftrag zu packen, dann wäre das Offtopic Forum dafür richtig?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich denke nicht, dass das Projekt an sich einen erfahreneren Python-Programmierer ueberfordert. Insofern - klar, versuch es zu beauftragen. Das dies wiederum innerhalb der naechsten 7 Tage funktioniert halte ich fuer unwahrscheinlich.

Ich wuerde dir also raten, dass erstmal haendisch zB mit Excel zu machen, und so deinem FA einzureichen. Und das Projekt spaeter zu verfolgen.

Und IMHO wirst du auch keinen finden, der das umsonst macht. Ob *du* den Code danach unter eine freie Lizenz stellst, ist davon natuerlich unbetroffen. Aber ich zahle auch meinen Steuerberater, und genauso wuerde ich auch erwarten bezahlt zu werden, wenn ich deine Steuer mache ;)
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

@__deets__
Danke für deinen Kommentar. Bei Auftrag gibt es eine Bezahlung, das ist mir klar.
Kann man dazu einen Anhaltspunkt geben? Wie viele Stunden á wie viele Euro Stundensatz, oder wie man das bei solchen Projekten abrechnet? Wie beim Steuerberater/Stundensatz? :idea:
Mit Excel/Calc scheint das auch nicht einfacher zu sein, wohl wegen der Unregelmäßigkeit der Amount Größen usw. Für „händisch“ sind es zu viele Datensätze knapp 1000 und das ist seehr Fehleranfällig.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das es anstrengend und doof sein mag glaube ich dir sofort. Nur jede Minute, die du das *nicht* hinbekommst zu delegieren, bringt dich deinem Ziel nicht naeher. Du solltest da fuer den Ernstfall planen, und der heisst, dass du dir nicht handelseinig wirst mit jemanden, oder wenn, dass das in der kuerze der Zeit nicht hin zu bekommen ist. Eine Woche ist halt nicht viel Zeit. Natuerlich arbeitet da niemand eine Woche dran, aber es muessen aller Wahrscheinlichkeit nach Korrekturzyklen eingelegt werden. Da du und der Entwickler sicher auch noch 1-2 andere Sachen im Leben machen, kann das dann knapp werden.

Was den Preis angeht - kA, ich bin da ja am anderen Ende ;) Bei mir sinds 80 die Stunde wenn du ein Angebot haben willst, und 60 wenn ich einfach drauf loslege und mich nicht damit rumschlagen muss, die Buerokratie und das Hick-Hack eines "richtigen" Auftrages mit Aufwandsabschaetzung und natuerlich auch Risikoaufschlages fuer Nachbesserung etc.

Was dann die Stunden angeht: mit allem hin und her, also mit dir zB skypen um die Anforderungen wirklich klar zu kriegen, dran arbeiten, zusammen mit dir das Ergebnis durchgehen, ggf. nachbessern - nicht unter 3, eher mehr.

Aber das bin ich. Du kannst versuchen, dass gut zu beschreiben und auch gerne hier im Offtopic feilzubieten, entweder offen oder mit einer konkreten Preisvorstellung.

Oh, und ich kann's nicht tun. Kunde *hat* mich beauftragt, und meine Zeit fuer so etwas ist dadurch belegt.
lacreature
User
Beiträge: 17
Registriert: Dienstag 5. März 2019, 23:34

Versuche vielleicht mal mehr die starken Python Bibliotheken miteinzubeziehen, mit pandas lassen sich mit relati wenig Code Data Frames erstellen die pandas auch selbst in verschiedene Dateiformate schreibt, auch csv. Ich weiß, dass das jetzt nicht das ist was du hören wolltest.
Aber da du das ja unter freie Lizene stellen würdest, würde ich dir helfen mitzuschreiben, ich kann mit pandas umgehen und könnte die datensätze über sql managen. das ganze projekt in 7 tagen aber nicht.
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

@__deets__
Dein zweiter Beitrag hat mich irgendwie animiert selber dranzubleiben. (nicht wegen deinen Stundensätzen, :) die sind ok.) Ich merke auch, dass es mich ein gutes Stücke weitergebracht hat, das Problem in diesen Einzelschritten zu beschreiben.
Wenn sich jemand angesprochen fühlt, weil ihm die Fragestellung zusagt, der kann sich ja immer noch melden.

Vielleicht würde es auch helfen, wenn mir jemand „nur“ eine Funktion schreibt. Vielleicht ist das Hauptproblem „nur“ die beiden beschriebenen Teilschritte, die man in jeweils eine Funktion packen könnte.

Jetzt mach ich erst mal selber weiter.

@lacreature
Hab mal in meinen Übscripten nachgeschaut, da ist auch ein pandas DataFrame Bsp:

Code: Alles auswählen

"""
daten.csv
row[0],          row[1],  row[2], row[3],
DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:00,buy,1.00000002,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
"""
import pandas as pd
daten = pd.read_csv("daten.csv", sep="," ,decimal=".")
print(daten)

   2017-01-08 11:43:00   buy  0.10000001  200.11
0  2017-01-08 11:43:00   buy         1.0  210.55
1  2017-01-10 16:11:44  sell         0.1  290.44
2  2017-01-11 18:43:00   buy         0.3  300.88
3  2017-01-12 18:55:00   buy         0.4  311.22
4  2017-01-14 22:22:11  sell         0.9  444.88
5  2018-02-15 09:22:55  sell         0.8  555.77
Ich habe nicht das Gefühl, dass es mir die Arbeit (das Verständnis) erleichtern würde. Meine (Daten) Listen sind ja auch an sich nicht kompliziert.

Bei pandas DataFrame fehlen mir Nachkommastellen, um die ich mich erst kümmern müsste.
Mit sql hatte ich im Dezember probiert… bin damit nicht weit gekommen.

Wenn du etwas mit panda und sql hinbekommen würdest, dann würde ich auch etwas dafür bezahlen. Lieber Zweigleisig, als dass ich nachher mit meinem Versuch nicht fertig werde. Und es wäre natürlich auch interessant und nützlich, zu sehen, ob die gleichen Ergebnisse rauskommen.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Zu pandas schriebst du:
Fiffio hat geschrieben: Freitag 22. März 2019, 17:42 Ich habe nicht das Gefühl, dass es mir die Arbeit (das Verständnis) erleichtern würde. Meine (Daten) Listen sind ja auch an sich nicht kompliziert.

Bei pandas DataFrame fehlen mir Nachkommastellen, um die ich mich erst kümmern müsste.
Also ohne pandas würde ich da gar nicht erst drangehen... Mit pandas ist es nicht so schwer. Ich hab mal was probiert, bin mir aber nicht sicher, ob es das ist, was du willst.
Die Nachkommastellen sind auch alle da. Die zeigt pandas aber nicht an. Dadurch bekommt man echt einen viel besseren Überblick über die Daten (geht mir zumindest so).

Die Daten habe ich direkt ins Programm geschrieben, die müsstest du aus der Datei einlesen, aber das kannst du ja.
Die doppelten Zeiten sind garstig. Ich habe mir erlaubt, die eine um eine tausendstel Sekunde zu erhöhen. Bei der Ausgabe könnte man das sicher unterdrücken, wenn es nötig ist.

Wenn du genauer wissen willst, was vor sich geht, kannst du die prints auskommentieren.

Die eigentliche Arbeit passiert in fifo. Dort wird jeder Verkauf angeschaut, und so lange werden Einkäufe damit verrechnet, bis es reicht. Von dem Einkauf muss man sich halt den Rest merken.
Dann kommt der nächste Einkauf dran.

Wenn es genau aufgeht, kann es sein, dass am Schluss wegen float-Ungenauigkeit ein winziger Rest übrigbleibt, den er noch verkaufen will. Deshalb muss man an der einen Stelle etwas tolerant sein und darf nicht auf > 0 vergleichen. Ich habe es mit 1e-10 versucht, was bei den Beispielen locker ausreicht. Wenn es mehr Nachkommastellen bei den amounts geben sollte, müsste man das noch kleiner machen.

Keine Gewähr für irgendwas!

Code: Alles auswählen

import pandas as pd
import io

raw = io.StringIO("""DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:01,buy,1.00000002,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
""")
daten = pd.read_csv(raw, index_col=0, parse_dates=True, 
                    skipinitialspace=True)  # damit die header vernünftig sind

buys = daten[daten.Typ == "buy"]
sells = daten[daten.Typ == "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():
        #print(f"\nselling {i_sell} (amount {amount_sell:0.8f})")
        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
                i_buy, amount_buy = next(iter_buys)
            amount = min(amount_buy, amount_sell)
            #print(f"  from buy {i_buy}: amount {amount:0.8f}")
            amount_sell -= amount
            amount_buy -= amount
            rate_diff = sells.at[i_sell, "Rate"] - buys.at[i_buy, "Rate"]
            #print(f"  rate diff {rate_diff} * amount {amount:0.8f} = {rate_diff * amount}")
            yield i_sell, i_buy, amount, rate_diff

            
for i_sell, i_buy, amount, rate_diff in fifo(buys, sells):
    print(f"Verkauf am {i_sell} vom Kauf am {i_buy}, Menge: {amount:0.8f}, "
          f"Ratendifferenz: {rate_diff:0.8f}, Wert: {rate_diff * amount:0.8f}")

Da kommt dann raus:

Code: Alles auswählen

Verkauf am 2017-01-10 16:11:44 vom Kauf am 2017-01-08 11:43:00, Menge: 0.10000001, Ratendifferenz: 90.33000000, Wert: 9.03300090
Verkauf am 2017-01-10 16:11:44 vom Kauf am 2017-01-08 11:43:01, Menge: 0.00000001, Ratendifferenz: 79.89000000, Wert: 0.00000080
Verkauf am 2017-01-14 22:22:11 vom Kauf am 2017-01-08 11:43:01, Menge: 0.90000000, Ratendifferenz: 234.33000000, Wert: 210.89700000
Verkauf am 2018-02-15 09:22:55 vom Kauf am 2017-01-08 11:43:01, Menge: 0.10000001, Ratendifferenz: 345.22000000, Wert: 34.52200345
Verkauf am 2018-02-15 09:22:55 vom Kauf am 2017-01-11 18:43:00, Menge: 0.30000003, Ratendifferenz: 254.89000000, Wert: 76.46700765
Verkauf am 2018-02-15 09:22:55 vom Kauf am 2017-01-12 18:55:00, Menge: 0.40000004, Ratendifferenz: 244.55000000, Wert: 97.82000978
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

Interessant. Hab mich damit nun ein paar Stunden beschäftigt.
Wenn du das weiter mit mir durchkauen willst, dann gib Bescheid wegen Gegenleistung.

Fragen:
1) Doppelte Zeiten
Im Prinzip sind die Sekunden eigentlich nicht wichtig. Von daher macht es nichts, sie zu modifizieren. Aber ich habe noch nicht verstanden, warum die Zeit ein Kriterium für die Abfragen ist.

2) Wie du selber zur Funktion fifo schreibst: „fifo. Dort wird jeder Verkauf angeschaut, und so lange werden Einkäufe damit verrechnet, bis es reicht. Von dem Einkauf muss man sich halt den Rest merken. Dann kommt der nächste Einkauf [Verkauf?] dran.“

Meine Logik war, dass man sich „einfach“ immer den ersten Sell/Verkauf aus der Liste holt und wenn dieser abgearbeitet ist, löscht. Insofern würde sich der Rest von Amount Sell/Buy auch immer an dieser ersten Stelle (Index 0) befinden (sich merken sagst du. Wo wird denn der Rest-Wert aktuell gespeichert?).
Ist das bei deinem Script anders?
Hab versuch zu verstehen was „yield“ macht und darüber gelesen. Aber noch nicht ganz verstanden. Hat das mit "sich merken" zu tun?

3) Haltedauer
Hatte das noch nicht beschrieben, aber ich brauche noch die „Haltedauer“ von den Käufen.

Hab das so angefangen:

Code: Alles auswählen

from datetime import timedelta, datetime
week = timedelta(weeks=1)

for i_sell, i_buy, amount, rate_diff in fifo(buys, sells):
    print(f"Verkauf am {i_sell}\n   Kauf am {i_buy}, Menge: {amount:0.8f}\n"
          f"Preisdifferenz: {rate_diff:0.2f}, P/L EUR: {rate_diff * amount:0.2f}\n")
    if i_sell > i_buy + 52 * week:             # Haltedauer größer 1 Jahr?
        print("Haltedauer > 1 Jahr: OK")         # \nBuy = ",i_buy,"\nSell =",i_sell)
        print("Haltedauer = (Sell =",i_sell,") - (Buy",i_buy,") =",i_sell-i_buy)
    elif i_sell < i_buy + 52 * week:             # Haltedauer < 1 Jahr
        print("Haltedauer > 1 Jahr: Nein")        
        print("Haltedauer = (Sell =",i_sell,") - (Buy",i_buy,") =",i_sell-i_buy,"\n")
Sieht ungefähr so aus, will ich noch schöner machen:

Code: Alles auswählen

...gekürzt...
Haltedauer > 1 Jahr: Nein
Haltedauer = (Sell = 2017-01-14 22:22:11 ) - (Buy 2017-01-08 11:43:01 ) = 6 days 10:39:10 


selling  2018-02-15 09:22:55 (amount 0.80000008)
from buy 2017-01-08 11:43:01: amount 0.10000001
   Rate Diff. 345.22 * amount 0.10000001 = 34.52
Verkauf am 2018-02-15 09:22:55
   Kauf am 2017-01-08 11:43:01, Menge: 0.10000001
Preisdifferenz: 345.22, P/L EUR: 34.52

Haltedauer > 1 Jahr: OK
Haltedauer = (Sell = 2018-02-15 09:22:55 ) - (Buy 2017-01-08 11:43:01 ) = 402 days 21:39:54
from buy 2017-01-11 18:43:00: amount 0.30000003
   Rate Diff. 254.89 * amount 0.30000003 = 76.47
Verkauf am 2018-02-15 09:22:55
   Kauf am 2017-01-11 18:43:00, Menge: 0.30000003
Preisdifferenz: 254.89, P/L EUR: 76.47

Haltedauer > 1 Jahr: OK
Haltedauer = (Sell = 2018-02-15 09:22:55 ) - (Buy 2017-01-11 18:43:00 ) = 399 days 14:39:55
from buy 2017-01-12 18:55:00: amount 0.40000004
   Rate Diff. 244.55 * amount 0.40000004 = 97.82
Verkauf am 2018-02-15 09:22:55
   Kauf am 2017-01-12 18:55:00, Menge: 0.40000004
Preisdifferenz: 244.55, P/L EUR: 97.82

Haltedauer > 1 Jahr: OK
Haltedauer = (Sell = 2018-02-15 09:22:55 ) - (Buy 2017-01-12 18:55:00 ) = 398 days 14:27:55
Hab noch nicht ganz kapiert, wie ich die Haltedauer an den richtigen Berechnungsblock ausgeben kann.

4)
Bei mir scheint die Datenübergabe „anfällig“ zu sein. Wenn ich einen Datensatz hinzufüge gibt es Fehlermeldung:
Das passiert wennich einen dritten Buy Datensatz einfüge:

Code: Alles auswählen

raw = io.StringIO("""DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:01,buy,1.00000002,210.55
2017-01-08 11:43:01,buy,0.50000002,203.33
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
""")

Code: Alles auswählen

TypeError: unsupported format string passed to numpy.ndarray.__format__

Bzw. wenn ich den zweiten Datensatz auf Amount 0.00000002 runtersetze:
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:01,buy,0.00000002,210.55

Code: Alles auswählen

RuntimeError: generator raised StopIteration
Woran liegt das?

Die Rechnung geht am Ende nur selten auf (Amount = 0) das ist nur in dem Bsp. so. Es kann je nach Datenimport eine Anzahl/Buy am Ende als Kontostand bestehen bleiben, wenn weniger Verkauft wurde, als gekauft, das ist oft so.
Es müsste also nur eine Anzeige am Ende geben, wie hoch noch der Kontostand/Amount ist.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Nur kurz, vielleicht später mehr.


1.) Die Zeitpunkte dürfen nicht doppel sein, weil ich die als index verwende bzw. zum Nachschlagen der zugehörigen Datensätze.
Das empfinde ich auch als natürlich für die Reihenfolge ("ältester zuerst"). Wenn mehrere Käufe zum genau gleichen Zeitpunkt kommen, welcher ist denn dann der ältere? Vermutlich der, der zuerst in der Liste kommt, aber das sieht so willkürlich aus.

Man könnte das natürlich auf die Reihenfolge umstellen, dazu muss man im Wesentlichen beim Einlesen keine Indexspalte angeben, glaube ich (ungestestet).

2.) Der nächste Verkaufs-Wert wird in amount_sell gespeichert und um den tatsächlichen Verkauf reduziert. Genau das gleiche passiert auch mit dem Kauf-Wert: Einlesen nach amount_buy, um den tatsächlichen Verkauf reduzieren.
Wenn der aktuellen Kauf komplett verbraucht wurde, fällt der Wert auf 0 und der nächste Kauf wird eingelesen
Wenn der aktuelle Verkauf komplett abgearbeitet wurde, fällt der Wert auf 0 und der nächste Kauf wird eingelesen (for-Schleife).

3.) Da vermisse ich die konkrete Frage :-) Geht es nur um die Ausgabe? Du kannst meine prints ignorieren, und nur die Datensätze, die in der for-Schleife abgearbeitet werden, für die Ausgabe aufbereiten, wie du willst.

4.) Die Probleme entstehen, wenn du doppelte Zeiten hast, bzw. wenn du mehr verkaufst als du kaufst. Dass du den Restwert (oder die Summe davon?) brauchst, wusste ich nicht.
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

Das geht ja gut voran!
1) Ja, verstehe. Das heißt „Primärschlüssel“ und (Eindeutigkeit) bei Datenbanken, so weit ich erinnere. Eindeutigkeit haben wir dann beim DateTime Attribut nicht.
Könnte man dafür nicht eine eindeutige ID nehmen? Oder bräuchten es einen sog. „zusammengesetzten“ Primärschlüssel aus mehreren Attributen? Ist das dann viel komplizierter für die Auswertung?

3)
3.b) Die Ausgabe:
Ich hatte noch nicht dein Prinzip mit den auskommentierten prints verstanden und dann in die 2. (for-Schleife) Infos eingesetzt, die du in den extra prints schon drinnen hattest.

Also wenn ich deine extra-prints nehme und den Haupt-print 2. (for-Schleife) auskommentiere, dann ist das so wie es mir anschaulich ist.
Plus den amount_sell/amount_buy, den hab ich „ queue“ genannt (für den Rest amount).

Code: Alles auswählen

selling 2017-01-10 16:11:44 (amount 0.10000002 BTC)
                  from sell queue  (0.10000002 BTC)
                         form buy  (0.10000001 BTC)
      from buy 2017-01-08 11:43:00: amount 0.10000001 BTC
           (rate diff) 90.33 EUR * amount 0.10000001 BTC = 9.03 EUR

                  from sell queue  (0.00000001 BTC)
                         form buy  (1.00000002 BTC)
      from buy 2017-01-08 11:43:01: amount 0.00000001 BTC
           (rate diff) 79.89 EUR * amount 0.00000001 BTC = 0.00 EUR


selling 2017-01-14 22:22:11 (amount 0.90000000 BTC)
                  from sell queue  (0.90000000 BTC)
                         form buy  (1.00000001 BTC)
      from buy 2017-01-08 11:43:01: amount 0.90000000 BTC
           (rate diff) 234.33 EUR * amount 0.90000000 BTC = 210.90 EUR


selling 2018-02-15 09:22:55 (amount 0.80000008 BTC)
                  from sell queue  (0.80000008 BTC)
                         form buy  (0.10000001 BTC)
      from buy 2017-01-08 11:43:01: amount 0.10000001 BTC
           (rate diff) 345.22 EUR * amount 0.10000001 BTC = 34.52 EUR

                  from sell queue  (0.70000007 BTC)
                         form buy  (0.30000003 BTC)
      from buy 2017-01-11 18:43:00: amount 0.30000003 BTC
           (rate diff) 254.89 EUR * amount 0.30000003 BTC = 76.47 EUR

                  from sell queue  (0.40000004 BTC)
                         form buy  (0.40000004 BTC)
      from buy 2017-01-12 18:55:00: amount 0.40000004 BTC
           (rate diff) 244.55 EUR * amount 0.40000004 BTC = 97.82 EUR
2.Version
Mit der Haltedauer dazu.
Frage: Wo in den Schleifen muss ich die Haltedauer Berechnung einsetzen?
Am Ende der while Schleife kam noch nicht ganz das raus was ich wollte.

Code: Alles auswählen

            if i_sell > i_buy + 52 * week:             # Haltedauer größer 1 Jahr?
                txf = "Haltedauer > 1 Jahr: OK" ,i_sell-i_buy
                #print(f"  (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = {rate_diff * amount:0.2f} BTC\n {txf}")
                
            elif i_sell < i_buy + 52 * week:             # Haltedauer < 1 Jahr
                tx = "Haltedauer > 1 Jahr: Nein",i_sell-i_buy
                #print(f"  (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = {rate_diff * amount:0.2f} BTC\n {tx}")
Damit die zwei Zeilen „ Haltedauer“ dann beim print als letzte Zeile jeweils unter den Sell/Buy matches stehen?

Code: Alles auswählen

selling 2017-01-10 16:11:44 (amount 0.10000002 BTC)
                  from sell queue  (0.10000002 BTC)
                         form buy  (0.10000001 BTC)
      from buy 2017-01-08 11:43:00: amount 0.10000001 BTC
           (rate diff) 90.33 EUR * amount 0.10000001 BTC = 9.03 BTC
Haltedauer > 1 Jahr: Nein
sell 2017-01-10 16:11:44 - buy 2017-01-08 11:43:00 = 2 days, 4:28:44

                  from sell queue  (0.00000001 BTC)
                         form buy  (1.00000002 BTC)
      from buy 2017-01-08 11:43:01: amount 0.00000001 BTC
           (rate diff) 79.89 EUR * amount 0.00000001 BTC = 0.00 BTC
Haltedauer > 1 Jahr: Nein
sell 2017-01-10 16:11:44 - buy 2017-01-08 11:43:01 = 2 days, 4:28:43

...gekürzt...

                  from sell queue  (0.40000004 BTC)
                         form buy  (0.40000004 BTC)
      from buy 2017-01-12 18:55:00: amount 0.40000004 BTC
           (rate diff) 244.55 EUR * amount 0.40000004 BTC = 97.82 BTC
Haltedauer > 1 Jahr: OK
sell 2018-02-15 09:22:55 - buy 2017-01-11 18:43:00 = 398 days, 14:27:55
PS: Das Script wie es nach meiner Werkelei aussieht:

Code: Alles auswählen

import pandas as pd
import io
from datetime import timedelta, datetime
week = timedelta(weeks=1)

raw = io.StringIO("""DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:01,buy,1.00000002,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
""")
daten = pd.read_csv(raw, index_col=0, parse_dates=True, 
                    skipinitialspace=True)  # damit die header vernünftig sind

buys = daten[daten.Typ == "buy"]
sells = daten[daten.Typ == "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():
        print(f"\nselling {i_sell} (amount {amount_sell:0.8f} BTC)")
        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
                i_buy, amount_buy = next(iter_buys)
            amount = min(amount_buy, amount_sell)
            print(f"                  from sell queue  ({amount_sell:0.8f} BTC)" 
                  f"\n                         form buy  ({amount_buy:0.8f} BTC)"
                  f"\n      from buy {i_buy}: amount {amount:0.8f} BTC")
            amount_sell -= amount
            amount_buy -= amount
            rate_diff = sells.at[i_sell, "Rate"] - buys.at[i_buy, "Rate"]
            print(f"           (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = {rate_diff * amount:0.2f} EUR")
            yield i_sell, i_buy, amount, rate_diff
            if i_sell > i_buy + 52 * week:             # Haltedauer größer 1 Jahr?
                txf = "Haltedauer > 1 Jahr: OK" ,i_sell-i_buy
                #print(f"  (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = {rate_diff * amount:0.2f} BTC\n {txf}")
                
            elif i_sell < i_buy + 52 * week:             # Haltedauer < 1 Jahr
                tx = "Haltedauer > 1 Jahr: Nein",i_sell-i_buy
                #print(f"  (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = {rate_diff * amount:0.2f} BTC\n {tx}")
                            
for i_sell, i_buy, amount, rate_diff in fifo(buys, sells):
    print()
#    print(f"Verkauf am {i_sell} vom Kauf am {i_buy}, Menge: {amount:0.8f}, "
#          f"Ratendifferenz: {rate_diff:0.8f}, Wert: {rate_diff * amount:0.8f}")
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

EDIT: 3) Frage, wie es aussieht, gelöst.

Code: Alles auswählen

import pandas as pd
import io
from datetime import timedelta, datetime
week = timedelta(weeks=1)
sid = 0
raw = io.StringIO("""DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:01,buy,1.00000002,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
""")
daten = pd.read_csv(raw, index_col=0, parse_dates=True, 
                    skipinitialspace=True)  # damit die header vernünftig sind

buys = daten[daten.Typ == "buy"]
sells = daten[daten.Typ == "sell"]

def fifo(buys, sells):
    iter_buys = buys.Amount.iteritems()  # enumerate(buys)
    i_buy, amount_buy = None, 0.0
    sid = 0
    for i_sell, amount_sell in sells.Amount.iteritems():
        sid = sid +1
        print(f"\n({sid}) Sell {i_sell} (amount {amount_sell:0.8f} BTC)")
        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
                i_buy, amount_buy = next(iter_buys)
            amount = min(amount_buy, amount_sell)
            print(f"                   from sell queue  ({amount_sell:0.8f} BTC)" 
                  f"\n                          form buy  ({amount_buy:0.8f} BTC)"
                  f"\n      from buy {i_buy}: amount {amount:0.8f} BTC")
            amount_sell -= amount
            amount_buy -= amount
            rate_diff = sells.at[i_sell, "Rate"] - buys.at[i_buy, "Rate"]
            if i_sell > i_buy + 52 * week:             # Haltedauer größer 1 Jahr?
                print(f"           (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = "
                      f"{rate_diff * amount:0.2f} EUR \n Haltedauer > 1 Jahr: OK {i_sell-i_buy}")
                
            elif i_sell < i_buy + 52 * week:             # Haltedauer < 1 Jahr
                print(f"           (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = "
                      f"{rate_diff * amount:0.2f} EUR \n Haltedauer < 1 Jahr: Nein {i_sell-i_buy}")
            yield i_sell, i_buy, amount, rate_diff
       
for i_sell, i_buy, amount, rate_diff in fifo(buys, sells):
    print()
#    print(f"Verkauf am {i_sell} vom Kauf am {i_buy}, Menge: {amount:0.8f}, "
#          f"Ratendifferenz: {rate_diff:0.8f}, Wert: {rate_diff * amount:0.8f}")

Code: Alles auswählen

(1) Sell 2017-01-10 16:11:44 (amount 0.10000002 BTC)
                   from sell queue  (0.10000002 BTC)
                          form buy  (0.10000001 BTC)
      from buy 2017-01-08 11:43:00: amount 0.10000001 BTC
           (rate diff) 90.33 EUR * amount 0.10000001 BTC = 9.03 EUR 
 Haltedauer < 1 Jahr: Nein 2 days 04:28:44

                   from sell queue  (0.00000001 BTC)
                          form buy  (1.00000002 BTC)
      from buy 2017-01-08 11:43:01: amount 0.00000001 BTC
           (rate diff) 79.89 EUR * amount 0.00000001 BTC = 0.00 EUR 
 Haltedauer < 1 Jahr: Nein 2 days 04:28:43


(2) Sell 2017-01-14 22:22:11 (amount 0.90000000 BTC)
                   from sell queue  (0.90000000 BTC)
                          form buy  (1.00000001 BTC)
      from buy 2017-01-08 11:43:01: amount 0.90000000 BTC
           (rate diff) 234.33 EUR * amount 0.90000000 BTC = 210.90 EUR 
 Haltedauer < 1 Jahr: Nein 6 days 10:39:10


(3) Sell 2018-02-15 09:22:55 (amount 0.80000008 BTC)
                   from sell queue  (0.80000008 BTC)
                          form buy  (0.10000001 BTC)
      from buy 2017-01-08 11:43:01: amount 0.10000001 BTC
           (rate diff) 345.22 EUR * amount 0.10000001 BTC = 34.52 EUR 
 Haltedauer > 1 Jahr: OK 402 days 21:39:54

                   from sell queue  (0.70000007 BTC)
                          form buy  (0.30000003 BTC)
      from buy 2017-01-11 18:43:00: amount 0.30000003 BTC
           (rate diff) 254.89 EUR * amount 0.30000003 BTC = 76.47 EUR 
 Haltedauer > 1 Jahr: OK 399 days 14:39:55

                   from sell queue  (0.40000004 BTC)
                          form buy  (0.40000004 BTC)
      from buy 2017-01-12 18:55:00: amount 0.40000004 BTC
           (rate diff) 244.55 EUR * amount 0.40000004 BTC = 97.82 EUR 
 Haltedauer > 1 Jahr: OK 398 days 14:27:55
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Ist dann jetzt alles OK?

Ansonsten würde ich noch folgendes anbieten. Dabei sind die Berechnungen in der Funktion, und die Ausgabe (und man könnte es dort auch weiterverarbeiten) in der Schleife außerhalb.
(Statt mit Datum wird jetzt mit Reihenfolge gearbeitet, und nur für die Zeitabstandsberechnung wird das Datum verwendet.)

Code: Alles auswählen

import pandas as pd
import io
from datetime import timedelta, datetime
week = timedelta(weeks=1)

raw = io.StringIO("""DateTime,           Typ,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:00,buy,1.00000002,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
""")
daten = pd.read_csv(raw, parse_dates=[0], 
                    skipinitialspace=True)  # damit die header vernünftig sind

buys = daten[daten.Typ == "buy"]
sells = daten[daten.Typ == "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
                i_buy, amount_buy = next(iter_buys)
            amount = min(amount_buy, amount_sell)
            amount_sell -= amount
            amount_buy -= amount
            rate_diff = sells.at[i_sell, "Rate"] - buys.at[i_buy, "Rate"]
            time_diff = sells.at[i_sell, "DateTime"] - buys.at[i_buy, "DateTime"]
            yield i_sell, i_buy, amount, rate_diff, time_diff
                            

for i_sell, i_buy, amount, rate_diff, time_diff in fifo(buys, sells):
    print(f"\nselling {i_sell} (amount {amount:0.8f} BTC)")
    print(f"from buy {i_buy}: amount {amount:0.8f} BTC")
    print(f"    (rate diff) {rate_diff:0.2f} EUR * amount {amount:0.8f} BTC = {rate_diff * amount:0.2f} EUR")
    if time_diff.days >= 365:
        print(f"    Haltedauer > 1 Jahr: OK ({time_diff.days} days)")
    else:
        print(f"    Haltedauer > 1 Jahr: Nein ({time_diff.days} days)")
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

Ich musste gestern Pause machen. Als Anfänger ist das jetzt, als müsste ich nach 1,5 Tagen wieder bei null anfangen, hätte alles vergessen.

Du hast bei der Ausgabe zu viel gekürzt. Ich brauch das Datum als Orientierung :wink: Die Uhrzeit bei Haltedauer weg war gut.

Hab das so gemacht. Hoffe es spricht aus pythonistischer Sicht nichts dagegen?

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,200.11
2017-01-08 11:43:00,buy,1.00000002,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
""")
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
                i_buy, amount_buy = next(iter_buys)
            amount = min(amount_buy, amount_sell)
            amount_sell -= amount
            amount_buy -= amount
            rate_diff = sells.at[i_sell, "Rate"] - buys.at[i_buy, "Rate"]
            time_diff = sells.at[i_sell, "DateTime"] - buys.at[i_buy, "DateTime"]
            yield i_sell, i_buy, amount, rate_diff, time_diff
                            
for i_sell, i_buy, amount, rate_diff, time_diff in fifo(buys, sells):
    sell_t = sells.at[i_sell, "DateTime"]
    buy_t = buys.at[i_buy, "DateTime"]
    sell_r = sells.at[i_sell, "Rate"]
    buy_r = buys.at[i_buy, "Rate"]
    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")
    if time_diff.days >= 365:
        print(f"              Haltedauer > 1 Jahr: OK ({time_diff.days} days)")
    else:
        print(f" Haltedauer > 1 Jahr: Nein ({time_diff.days} days)")
Noch eine Frage:
Wie könnte diese Fehlermeldung abgefangen werden?

Code: Alles auswählen

RuntimeError: generator raised StopIteration
Das passiert, wenn mehr verkauft werden soll als vorhanden ist. Beispiel:

Code: Alles auswählen

raw = io.StringIO("""DateTime,           Type,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:00,buy,1.00000001,210.55                   # statt 1.00000002
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                  # Achtung es sind nur 0.80000007 zum Verkauf da!
""")
Könnte man da eine Ausgabe machen, dass erst am Ende (7. Datensatz) die Meldung kommt, dass nur 0.80000007 verkauft werden können anstatt die 0.80000008? Und dass das aber ganz normal gerechnet wird mit eben der Anzahl die da ist, in dem Fall eben 0.80000007

Es kann tatsächlich bei den realen Daten der Fall sein, dass unter gewissen Umständen ein Verkauf auftritt, dem nicht genug aus einem Kauf zur Verfügung steht.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nur mal zum Verständnis: Die Verkäufe sollen chronologisch abgearbeitet werden (ältester zuerst), wobei diese Reihenfolge schon durch die vorliegenden Daten garantiert wird (älteste Transaktion steht oben), richtig? Und nach jedem Verkauf soll freigewordenes Kapital immer soweit wie möglich durch neue Käufe "aufgebraucht" werden. Anschließend wird der nächste Verkauf verarbeitet, usw. Alles soweit korrekt?

Und du richtest dich dabei nach § 256 HGB (sog. Verbrauchsfolgeverfahren), um dein Kapital halt mittels der FIFO-Methode bewerten zu können, oder? Mir geht es bloß darum, dass wir über die selbe Sache sprechen, da deine Erklärungen etwas kompliziert sind.
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

snafu hat geschrieben: Dienstag 26. März 2019, 06:27 Nur mal zum Verständnis: Die Verkäufe sollen chronologisch abgearbeitet werden (ältester zuerst), wobei diese Reihenfolge schon durch die vorliegenden Daten garantiert wird (älteste Transaktion steht oben), richtig?
Ja.
snafu hat geschrieben: Dienstag 26. März 2019, 06:27 Und nach jedem Verkauf soll freigewordenes Kapital immer soweit wie möglich durch neue Käufe "aufgebraucht" werden.
Nein. Es wird beim Verkauf ermittelt, ob der Verkauf einen Gewinn (EUR) erbracht hat, oder ob es ein Verlustgeschäft ergab. (Gewinn-Verlustrechnung)
Dabei wird auch geschaut, ob die Haltedauer (der Käufe) länger als ein Jahr war, weil dann der Verkauf (falls er einen Gewinn abwirft) steuerfrei ist.
Was "aufgebraucht" werden soll sind die BTC Beträge (Amounts). Verkäufe und Käufe (BTC Beträge) müssen gegeneinander verrechnet werden.
Jede Verkauf braucht entsprechend(e) vorhergehende Einkäufe.
Bsp:

Code: Alles auswählen

DateTime,           Type,  Amount,  Rate
2017-01-08 11:43:00, buy,  1.00, 200.11
2017-01-08 11:43:00, buy,  1.00, 210.55
2017-01-10 16:11:44, sell, 2.00, 290.44
buy 1.00 - sell 2.00 = −1 BTC
(Das geht nicht. Der Kauf ist zu klein. Man kann nicht zwei Äpfel verkaufen, wenn man nur einen hat.
Also muss man den zweiten Kauf dazu nehmen um den Verkauf komplett durchzuführen.
Der zweite Verkauf hat aber eine andere Preisbasis (200.11 versus 210.55). Das muss man berücksichtigen.
snafu hat geschrieben: Dienstag 26. März 2019, 06:27 Anschließend wird der nächste Verkauf verarbeitet, usw.
Ja.
snafu hat geschrieben: Dienstag 26. März 2019, 06:27 Und du richtest dich dabei nach § 256 HGB (sog. Verbrauchsfolgeverfahren), um dein Kapital halt mittels der FIFO-Methode bewerten zu können, oder? Mir geht es bloß darum, dass wir über die selbe Sache sprechen, da deine Erklärungen etwas kompliziert sind.
Ich bin kein Buchalter, darum ohne Gewähr. Es geht hier nicht um Bilanz/Kapitalermittlung, sondern um die Ermittlung von privaten Veräußerungsgewinnen (§ 256 HGB sagt dazu glaube ich nicht wirklich etwas aus.). https://de.wikipedia.org/wiki/Ver%C3%A4 ... ungsgewinn
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Was soll eigentlich passieren, wenn z.B. 0,8 BTC durch die Käufe vorhanden sind und der nächste Sell 0,3 BTC vorgibt? Also was passiert mit der Differenz von 0,5 BTC, die dabei entsteht? Ist die einfach weg oder bleibt die trotz Verkauf irgendwie doch vorhanden und kann für den nächsten Verkauf mitgenutzt werden? Ich denke mal eher letzteres, also dass der letzte Einkauf nur zum Teil verkauft wird, oder?

Ich habe hier etwas gebastelt, wie ich an die Sache herangehen würde:
https://gist.github.com/seblin/bbf61cb8 ... 226ea972e8

Allerdings ist die Verrechnung der Käufe noch nicht korrekt implementiert, da Einkäufe zum Teil schon als Gewinn verbucht werden, obwohl sie noch nicht bzw noch nicht komplett durch einen Verkauf gedeckt wurden.
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

snafu hat geschrieben: Dienstag 26. März 2019, 21:50 Was soll eigentlich passieren, wenn z.B. 0,8 BTC durch die Käufe vorhanden sind und der nächste Sell 0,3 BTC vorgibt? Also was passiert mit der Differenz von 0,5 BTC, die dabei entsteht? Ist die einfach weg oder bleibt die trotz Verkauf irgendwie doch vorhanden und kann für den nächsten Verkauf mitgenutzt werden? Ich denke mal eher letzteres, also dass der letzte Einkauf nur zum Teil verkauft wird, oder?
Ja genau. bords0 der das Script gemacht hat hat das hier beschrieben.
bords0 hat geschrieben: Freitag 22. März 2019, 21:47 ...Die eigentliche Arbeit passiert in fifo. Dort wird jeder Verkauf angeschaut, und so lange werden Einkäufe damit verrechnet, bis es reicht. Von dem Einkauf muss man sich halt den Rest merken.
Dann kommt der nächste Einkauf dran. ...
Das muss wohl in diesem Teil des Script sein? Wo der übrig geblieben Teil von z.B. 0,5 BTC gespeichert wird. Ichhabs noch nicht kapiert. :)

Code: Alles auswählen

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
                i_buy, amount_buy = next(iter_buys)
            amount = min(amount_buy, amount_sell)
            amount_sell -= amount
            amount_buy -= amount
An der Börse kann das so aussehen:
Im Depo sind z.B. die Anzahl von 0,8 BTC durch Kauftrades vorhanden. Sagen wir gekauft bei Kurs zu 2000.- EUR. Dann geht der Kurs weiter hoch zu 2500.- EUR. Man möchte verkaufen und stellt eine Limitorder mit Verkaufspreis z.B. bei 2520.- ein. Doch der Kurs geht nicht höher und es wird nur ein Teil (Sell 0,3 BTC) bei dem Kurs von 2520.- verkauft. Der Rest 0,5 BTC bleibt als Limitorder stehen und der Kurs fällt wieder nach unten. Die 0,5 BTC müssen dann also zu einem anderen Zeitpunkt (und Kurs) verkauft werden. Usw.
Fiffio
User
Beiträge: 33
Registriert: Donnerstag 21. Februar 2019, 21:20

snafu hat geschrieben: Dienstag 26. März 2019, 21:50 Ich habe hier etwas gebastelt, wie ich an die Sache herangehen würde:
https://gist.github.com/seblin/bbf61cb8 ... 226ea972e8
Hab mal getestet ob dein Script meckert, wenn man von den Käufen etwas wegnimmt.
Summ der Käufe und Verkäufe ist ja:
buy 1.80000010
sell -1.80000010
also ist das Depo am Ende bei null BTC.

Das Script müsste schon hier meckern. Bsp:
2017-01-08 11:43:00,buy,1.00000001,210.55 (manipuliert)
2017-01-08 11:43:00,buy,1.00000002,210.55 (original)

Code: Alles auswählen

----- Verkauf #1 -------------------------
Verbleibende Bitcoins: 1.0000000100000002
Gesamtsaldo (€):       88.92

Verbleibende Käufe:
             DateTime Type  Amount    Rate
3 2017-01-11 18:43:00  buy     0.3  300.88
4 2017-01-12 18:55:00  buy     0.4  311.22

----- Verkauf #2 -------------------------
Verbleibende Bitcoins: 0.40000004
Gesamtsaldo (€):       132.12

Verbleibende Käufe:
             DateTime Type  Amount    Rate
4 2017-01-12 18:55:00  buy     0.4  311.22

----- Verkauf #3 -------------------------
Verbleibende Bitcoins: 0.700000079
Gesamtsaldo (€):       229.94

Verbleibende Käufe:
Keine
Es meckert nicht.

Es müsste "Need" 0.00000001 heißen.

Erst wenn man den buy Datensatz von 1.00000002 bis auf 0.50000000 minimiert
2017-01-08 11:43:00,buy,0.50000000,210.55
heißt es:

Code: Alles auswählen

ValueError: Need 0.10000000099999999 BTC, have 0.30000006 BTC
Die Zahlen stimmen irgendwie nicht? Es müsste nach meiner Rechnung Need -0.50000002 lauten.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich schau da morgen nochmal drüber. Habe ja angemerkt, dass es noch fehlerhaft ist.

Mein Code geht u.a. davon aus, dass für jeden Verkauf mindestens ein gekauftes Paket genutzt wird. Das ist natürlich falsch, da manchmal genug Reserven aus den Resten eines zuvor gekauften und nicht komplett ausgeschöpften Pakets vorhanden sind, um den Verkauf vollständig abwickeln zu können. Umgekehrt können Verkäufe aus Mangel an Bitcoins ab und zu auch gar nicht stattfinden.

Abläufe aus dem Finanzwesen nachzuprogrammieren und halt komplex und fehleranfällig. Ich an deiner Stelle hätte da schon längst einen Experten beauftragt - auch wenn der ein paar Taler kostet, aber das soll jeder selbst entscheiden...
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Wie könnte diese Fehlermeldung abgefangen werden?

RuntimeError: generator raised StopIteration

Das passiert, wenn mehr verkauft werden soll als vorhanden ist. Beispiel:

Code: Alles auswählen

raw = io.StringIO("""DateTime,           Type,  Amount,  Rate
2017-01-08 11:43:00,buy,0.10000001,200.11
2017-01-08 11:43:00,buy,1.00000001,210.55                   # statt 1.00000002
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                  # Achtung es sind nur 0.80000007 zum Verkauf da!
""")
StopIteration ist eine Exception. Die tritt hier auf, weil mit

Code: Alles auswählen

i_buy, amount_buy = next(iter_buys)
versucht wird, noch einen Kauf aus iter_buys herauszubekommen. Alles von iter_buys ist aber schon verbraucht, und deshalb wirft iter_buys (ein generator) diese Exception: "Stop jetzt, ich kann nicht mehr iterieren".
Abfangen kann man das mit try: except:, mit dem man Ausnahmen (Exceptions) abfangen kann.

Das habe ich gemacht im folgenden Code. Der hat jetzt alle Berechnungen außerhalb der Funktion fifo (die eigentlich eine generator function ist), in der Schleife, in der du auch deinen eigenen Berechnungen und Ausgaben eingebaut hast. (Das rettet wenigstens ein wenig die Struktur, die inzwischen nicht so schön geworden ist.)
Im Fall, dass nicht genug Käufe vorhanden sind, gibt fifo jetzt None für die Nummer des Kaufs zurück, und die Ausgabe in der Schleife habe ich entsprechend angepasst.
Außerdem habe ich einen zusätzlichen Verkauf eingebaut, damit man sieht, was passiert, wenn mehrere Verkäufe nicht bedient werden können.

Wenn deine Daten nicht konsistent sind, musst du evtl. auch aufpassen, dass keine Verkäufe mit Käufen verrechnet werden, die erst später kommen - aber dazu habe ich nichts eingebaut.

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,200.11
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
""")
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
                try:
                    i_buy, amount_buy = next(iter_buys)
                except StopIteration:
                    yield i_sell, None, amount_sell
                    break
            amount = min(amount_buy, amount_sell)
            amount_sell -= amount
            amount_buy -= amount
            yield i_sell, i_buy, amount


for i_sell, i_buy, amount in fifo(buys, sells):
    sell_t = sells.at[i_sell, "DateTime"]
    sell_r = sells.at[i_sell, "Rate"]
    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
    
    buy_t = buys.at[i_buy, "DateTime"]
    buy_r = buys.at[i_buy, "Rate"]
    rate_diff = sell_r - buy_r
    time_diff = sell_t - buy_t
    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")
    if time_diff.days >= 365:
        print(f"              Haltedauer > 1 Jahr: OK ({time_diff.days} days)")
    else:
        print(f" Haltedauer > 1 Jahr: Nein ({time_diff.days} days)")
Ausgabe:

Code: Alles auswählen

SELL id 2 2017-01-10 16:11:44 (amount 0.10000001 BTC) 290.44 EUR
 BUY id 0 2017-01-08 11:43:00         0.10000001 BTC  200.11 EUR
              Rate Diff  90.33 EUR * 0.10000001 BTC = 9.03 EUR
 Haltedauer > 1 Jahr: Nein (2 days)

SELL id 2 2017-01-10 16:11:44 (amount 0.00000001 BTC) 290.44 EUR
 BUY id 1 2017-01-08 11:43:00         0.00000001 BTC  210.55 EUR
              Rate Diff  79.89 EUR * 0.00000001 BTC = 0.00 EUR
 Haltedauer > 1 Jahr: Nein (2 days)

SELL id 5 2017-01-14 22:22:11 (amount 0.90000000 BTC) 444.88 EUR
 BUY id 1 2017-01-08 11:43:00         0.90000000 BTC  210.55 EUR
              Rate Diff  234.33 EUR * 0.90000000 BTC = 210.90 EUR
 Haltedauer > 1 Jahr: Nein (6 days)

SELL id 6 2018-02-15 09:22:55 (amount 0.10000000 BTC) 555.77 EUR
 BUY id 1 2017-01-08 11:43:00         0.10000000 BTC  210.55 EUR
              Rate Diff  345.22 EUR * 0.10000000 BTC = 34.52 EUR
              Haltedauer > 1 Jahr: OK (402 days)

SELL id 6 2018-02-15 09:22:55 (amount 0.30000003 BTC) 555.77 EUR
 BUY id 3 2017-01-11 18:43:00         0.30000003 BTC  300.88 EUR
              Rate Diff  254.89 EUR * 0.30000003 BTC = 76.47 EUR
              Haltedauer > 1 Jahr: OK (399 days)

SELL id 6 2018-02-15 09:22:55 (amount 0.40000004 BTC) 555.77 EUR
 BUY id 4 2017-01-12 18:55:00         0.40000004 BTC  311.22 EUR
              Rate Diff  244.55 EUR * 0.40000004 BTC = 97.82 EUR
              Haltedauer > 1 Jahr: OK (398 days)

SELL id 6 2018-02-15 09:22:55 (amount 0.00000001 BTC) 555.77 EUR
no matching buy found

SELL id 7 2018-02-16 09:22:55 (amount 1.00000008 BTC) 445.55 EUR
no matching buy found
Antworten