Portfolio-App: Vorgehen bei zeilenweiserr Query-Analyse - View-Erstellung

Django, Flask, Bottle, WSGI, CGI…
Antworten
hoppel
User
Beiträge: 4
Registriert: Samstag 5. Dezember 2020, 16:37

Ich bin gerade ein bisschen lost mit meiner erste Django-App. Ich möchte so etwas wie eine Portfolioübersicht für Börsenanlagen erstellen. Also jedes Mal, wenn ich eine Order zu meiner Tabelle hinzufüge, ändern sich die Statistiken etc. Im Moment habe eigentlich nur meine Order-Tabelle. Die Orders sollten alle Informationen enthalten, die für weitere Analysen benötigt werden. Dies ist das Modell:

Code: Alles auswählen

class Order(models.Model):
    name = models.CharField(max_length=100)
    ko_identifier = models.BooleanField()
    order_price = models.FloatField()
    quantity = models.FloatField()
    order_value = models.FloatField()
    order_fees = models.DecimalField(decimal_places=2,max_digits=5,default=0.0, null=True)
    order_commission = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    stock_exchange_fees = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    courtage_fee = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    own_fees = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    transaction_fee = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    transaction_fee_sum = models.FloatField()
    order_date = models.DateTimeField('order date')
    #order_date = models.DateTimeField(auto_add_now=true)
    order_wkn = models.CharField(max_length=6)
    order_isin = models.CharField(max_length=12)
    order_direction = models.ForeignKey(OrderDirection, null=True, on_delete= models.SET_NULL)
    order_place = models.ForeignKey(OrderPlace, null=True, on_delete= models.SET_NULL)
und hier eine vereinfachte Importdatei:

Bild

Später wird die Tabelle natürlich Hunderte / Tausende von Einträgen enthalten.

wo ich Schwierigkeiten habe:

Ich muss mindestens zwei Sichten auf diese Tabelle erstellen
  • Aktuelles Portfolio
  • abgeschlossene "Geschäfte"
also so etwas für das aktuelle Portfolio:

Bild

und so etwas für verkaufte Positionen (Weite Daten wie Verkaufszeitpunkt etc. sind sicherlich auch noch hinzuzufügen):

Bild

Was mich umtreibt:
  • Wie kann ich diese Sichten optimalerweise und auch in Hinblick auf Geschwindigkeitsaspekte umsetzen?
  • aktuelle versuche ich einen View zu generieren auf meine gesamte Order-Tabelle, was sich aber schwierig gestaltet, da ich ja über ggf. mehrere Orders Durchschnitte addieren oder subtrahieren muss... und dafür muss ich ja auch erstmal wissen wie viele und welcher Art und und und :). Eine georndete Tabelle wäre zumindest einfach zu generieren: orders = Order.objects.order_by('order_wkn', 'order_date'). Jetzt konnte ich von oben nach unten durchgehen und Operationen durchführen... auch wenn ich noch nicht weiß wie, erscheint mir das erstmal nicht optimal...
  • wäre das Umwandeln in eine Liste zu durchdenken?
  • Sind ggf. zwei weitere Tabellen zu erstellen, wo dann immer neue Orders reingeuptadet werden? Vorschläge/Beispiele zur Umsetzung?
Ich hoffe die Frage ist einigermaßen verständlich.

Gesamtauswertungen wie:

Code: Alles auswählen

total_ko = orders.filter(ko_identifier=1).count()
total_buy = orders.filter(order_direction=4).count()
total_sell = orders.filter(order_direction=3).count()
total_sum_buy = orders.filter(order_direction=4).aggregate(Sum('order_value')).get('order_value__sum', 0.00)
total_sum_sell = orders.filter(order_direction=3).aggregate(Sum('order_value')).get('order_value__sum', 0.00)
sind soweit klar
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

hoppel hat geschrieben: Samstag 5. Dezember 2020, 17:02
Was mich umtreibt:
  • Wie kann ich diese Sichten optimalerweise und auch in Hinblick auf Geschwindigkeitsaspekte umsetzen?
  • aktuelle versuche ich einen View zu generieren auf meine gesamte Order-Tabelle, was sich aber schwierig gestaltet, da ich ja über ggf. mehrere Orders Durchschnitte addieren oder subtrahieren muss... und dafür muss ich ja auch erstmal wissen wie viele und welcher Art und und und :). Eine georndete Tabelle wäre zumindest einfach zu generieren: orders = Order.objects.order_by('order_wkn', 'order_date'). Jetzt konnte ich von oben nach unten durchgehen und Operationen durchführen... auch wenn ich noch nicht weiß wie, erscheint mir das erstmal nicht optimal...
  • wäre das Umwandeln in eine Liste zu durchdenken?
  • Sind ggf. zwei weitere Tabellen zu erstellen, wo dann immer neue Orders reingeuptadet werden? Vorschläge/Beispiele zur Umsetzung?
Du hast jetzt hier nur das Modell für die Order. Ich würde das um Modelle für das Depot und die Positionen ergänzen. Vielleicht handelst du ja auch irgendwann über zwei Depots, spätestens dann musst du eh unterscheiden. Das Depot Modell bringt den Vorteil, dass du dort eine Position mit einer Order eröffnen kannst. Dann hast du die aktuellen Daten für den Depotbestand im System und musst sie nicht immer aus den Orders herausfiltern. Auch die Durchschnitte etc. kannst du über das Position-Modell komfortabel pflegen. Du hättest also ein Depot, dort liegen Positionen drin. Die Positionen haben Orders im Bauch für Kauf, Zukauf, Teilverkauf, Schließen der Position.

Du hast dann quasi eine Ansicht für das Depot in der alle aktiven oder geschlossenen Positionen angezeigt werden. Das würde ich dann über ein Boolean-Field in der Position steuern. Und dann kannst du auf die Positionen verlinken und dort die einzelnen Aufträge anzeigen.

Ich hatte damals das Tool divipedia.de online. Damit konnte man sein Depot zur Dividendenstrategie verwalten. Der oben beschriebene Ansatz hat super funktioniert. Auch für große Depots mit vielen Positionen. Und ich hatte ja auch ca. 250 User auf dem System, die auch alle ihre Depots dort verwaltet haben. ... Allerdings ist die Dividendenstrategie ziemlich statisch und wenn es jetzt Sekundenhandel oder sowas sein soll muss man vielleicht andere Wege gehen.
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Und ich habe mein Depot in meiner eigenen Finanzverwaltung so abgebildet...

Hier die Depotübersicht:
Bild

Und dann die Details zur Position:
Bild
Bild
hoppel
User
Beiträge: 4
Registriert: Samstag 5. Dezember 2020, 16:37

Huhu,

also deine APP sieht ja mal super aus, da möchte ich auch ma hinkommen, wird aber noch ein recht langer Weg...
Danke auf jeden Fall für den Input, hat mich schon mal weitergebracht!

Ich habe mal meine Modelle angepasst, aber konnte noch nicht alles abschließend durchdenken... Einfach zu viel um die Ohren in der Weihnachtszeit :(
  • Ich habe einige Felder in "Position" auskommentiert, da es wohl kien Sinn ergibt, dsowas in der Tabelle zu speichern... viel eher wird hier zur Laufzeit berechnet, oder?
    • Ähnlich wird es ja auch mit Finanzdaten sein... kann ich ja nicht alle in mein Model mit reinkloppen
Wo ich jetzt noch ein bisschen Gehirnschmalz reinsteken muss:
  • Ich lade aktuell, wie gesagt, nur Orders ins System. Zumeist per Excel-Import
    • Ich muss dann also für jede Excel-Zeile gucken, ob es schon eine Position gibt
      • Wenn ja, dann hinzufügen
      • Wenn nein, neue Position erstellen mit der neuen Order und dem DEpot hinzufügen
Soweit grob korrekt oder gibt es schnelle,schönere Wege als über den ganzen Import und alle Positionen zu loopen?

Code: Alles auswählen

class Order(models.Model):

    ORDER_PLACES = (
        ('TRADEGATE', 'Tradegate'),
        ('FRANKFURT', 'Frankfurt'),
        ('STUTTGART', 'Stuttgart'),
    )

    ORDER_TYPE = (
        ('BUY', 'buy'),
        ('SELL', 'sell'),
    )

    name = models.CharField(max_length=100)
    ko_identifier = models.BooleanField()
    order_price = models.FloatField()
    quantity = models.FloatField()
    order_value = models.FloatField()
    order_fees = models.DecimalField(decimal_places=2,max_digits=5,default=0.0, null=True)
    order_commission = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    stock_exchange_fees = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    courtage_fee = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    own_fees = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    transaction_fee = models.DecimalField(decimal_places=2,max_digits=5,default=0.0)
    transaction_fee_sum = models.FloatField()
    order_date = models.DateTimeField('order date')
    #order_date = models.DateTimeField(auto_add_now=true)
    order_wkn = models.CharField(max_length=6)
    order_isin = models.CharField(max_length=12)
    order_TYPE = models.CharField(max_length=100, choices=ORDER_TYPE)
    order_place = models.CharField(max_length=100, choices=ORDER_PLACES)

    def __str__(self):
        return self.name

class Position(models.Model):
    name = models.CharField(max_length=100)
    status = models.BooleanField()
    shares = models.FloatField(default=0.0)
    average_price = models.FloatField(default=0.0)

    #growth_total = models.FloatField(default=0.0)
    #growth_percentage = models.FloatField(default=0.0)
    #current_price = models.FloatField(default=0.0)
    #type = models.CharField(max_length=100)
    
    orders = models.ForeignKey("Order", on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class Depot(models.Model):
     name = models.CharField(max_length=100)
     broker = models.CharField(max_length=100)
     cash_balance = models.FloatField(default=0.0)
     position = models.ForeignKey("Position", blank=True, null=True, on_delete=models.CASCADE)

     def __str__(self):
         return self.name
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Sieht soweit okay aus. Ja, die auskommentierten Dinge kann man zur Laufzeit berechnen. Oder, wenn du mit EOD Kursen arbeitest, dann eben zum EOD Kurs.

Genau, du musst dir überlegen, welche Änderung an der Position durch welcher Order ausgelöst wird und das dann umsetzen.
hoppel
User
Beiträge: 4
Registriert: Samstag 5. Dezember 2020, 16:37

Huhu,

würde das Thema gerne nochmal rausholen, da ich bisher zu keiner Lösung gekommen bin, die sich irgendwie clean/clever anfühlt:

Ich würde natürlich sehr gerne diverse Auswertungen auf die jeweiligen Aktien im Depot ausführen:

Tagesperformance
Bester Tageswert
Wochenperformance
Monatsperformance
Jahresperformance
... und noch ganze viele anderen...

Da das zu Laufzeit alles allein schon aufgrund der beschänkten APIs nichts wird, muss ich wohl Tageskurswerte abspeichern... und hier beginnen die Probleme...

Was ist hier ein gutes Vorgehen... habe bei meiner Recherche sowas wie:
  • django-simple-history
    PyTables
    einfach so in ein Model schreiben
    anderweitig speichern (Json)
Vorschläge? Erfahrungswerte?
Bin auch noch nicht ganz sicher ob ich bur Tagesentwerde nehmen oder mehrere Tageswerte - aktuell aktualisiere ich so oft es der API-Zugang zulässt.

Danke schon mal
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Das hängt von deinem Anwendungsfall ab. Als Daytrader brauchst du Intraday-Kurse. Als langfristiger Investor reichen Tagesendkurse aus meiner Sicht.
Komplex wird das schnell genug. ZB alle Kurse in Euro speichern, sind denn auch alle anderen Kennzahlen in EUR verfügbar? Was wenn für ein Unternehmen keine, begrenzte oder veraltete Zahlen in EUR gibt?

Ich würde die Kurse nachts aktualisieren, wenn die Tagesendkurse verfügbar sind und danach einen Analyse-Job laufen lassen, der die Kennzahlen berechnet und sie in Extra-Tabellen schreibt.
Antworten