Dagoberts Geldspeicher (Linux-Magazin, Februar 2018)

Für Nutzer von APIs, die Aktienkurse einholen, hängt der Brotkorb seit neuestem höher als gewohnt. Erst stellte Google seinen kostenlosen Webservice zu Echtzeitbörsendaten ein, dann zog auch kürzlich Yahoo den Stecker zur undokumentierten aber weiträumig genutzten Aktienkurs-Schnittstelle im CSV-Format ([2]).

Letztere Kurzschlusshandlung riss einige Open-Source-Projekte wie das Perl-CPAN-Modul Yahoo::Finance oder das Python-Paket yahoo-finance und darauf aufbauende Börsen-Applikationen mit rein in den Abflußstrudel und auf den Github-Seiten raufen sich die User nun unter den "Issues"-Reitern die Haare und wringen die Hände auf Hoffnung nach Ersatz für die gewohnt kostenlosen Echtzeit- oder zumindest zeitverzögerten Börsenkursdaten.

Abbildung 1: Googles Finanzseite zur Portfolioermittlung war auch schon mal besser ([3]).

Umsonst ist billig genug

Gegen ein happiges monatliches Entgeld finden sich natürlich dutzende professionelle Anbieter von Börsendaten wie Bloomberg, doch kostenlose Kurse bieten nur wenige Unternehmen an, und oft auch nur gegen Registrierung und nach der Herausgabe eines dann bei jedem Request beizulegenden API-Keys. Es ist wohl nur eine Frage der Zeit, bis auch die heute vorgestellte freie Quelle versiegen wird, doch auch in Zukunft werden sich immer wieder Möglichkeiten auftun, die Daten ohne Gebühr einzusammeln.

Abbildung 2: Das Inventurskript zählt das Gesamtvermögen auf mehreren Bankkonten zusammen.

Entwickler sollten sich also darauf einstellen, dass sich der Daten-Backend einer Applikation kurzfristig ändern kann. Dank Design mit schöner Abstraktion der Kursquelle sollte dies jedoch nach einem simplen Upgrade der genutzten Quote-Bibliothek für Applikationen erledigt sein, und die Karawane durstiger Kamele, die an der alten Oase nur noch ausgedörrte Wasserlöcher findet, zieht zu erquickenderen Zielen weiter.

Listing 1: myquote.py

    01 #!/usr/bin/env python
    02 import requests
    03 import json
    04 
    05 def quote(symbol):
    06     r = requests.get(
    07       'https://query1.finance.yahoo.com'+
    08       '/v7/finance/quote?symbols=%s'
    09       % symbol)
    10     data = json.loads(r.text)
    11     return (data['quoteResponse']
    12             ['result'][0]
    13             ['regularMarketPrice'])

Listing 1 nutzt eine nach wie vor offene Yahoo-Quelle zum Einholen der aktuellen Marktpreise von Aktien an den Haupthandelsplätzen der Welt. Den Tageswert der Amazon-Aktie an der New Yorker Börse fördert das Ticker-Symbol "amzn" in Dollars zutage, wer statt dessen den Kurs von Amazon an der deutschen Xetra-Börse in Euro möchte, gibt "amz.de" an. Dazu erwartet die Funktion quote() das Ticker-Symbol und setzt einen Request an die Web-API ab, die eine in Json kodierte Datenstruktur zurückliefert. Unter dem Schlüssel regularMarketPrice steht dort der Zahlenwert für den Preis in der am Handelsplatz üblichen Währung.

Inventur im Geldspeicher

Banken und Plattformen für den Aktienhandel rechnen für ihre Kunden natürlich aus, wie hoch der Netto-Wert des Depots gerade ist. Auch Google und Yahoo bieten Portfolios an, die sich aber ebenfalls gerade im Wandel befinden ([3]), scheinbar wollen beide neue Wege der Monetisierung beschreiten. Der Vorteil eines selbstgestrickten Skripts ist, dass es kontoübergreifend alle Habseligkeiten aufaddiert. Hierzu muss der User zwar selbständig eine Yaml-Datei mit den Posten im Portfolio wie in Listing 2 auf dem neuesten Stand halten, aber der Ansatz wahrt die Privatsphäre des Anlegers zuverlässiger als eine Applikation eines Drittanbieters, den die Vermögensverhältnisse eines Privatmanns eigentlich nichts angehen.

Listing 2: portfolio.yaml

    01 - account: Deutsche Bank
    02   holdings:
    03     - type: stock
    04       ticker: amz.de
    05       shares: 100
    06     - type: cash
    07       amount: 5170.99
    08 
    09 - account: Sparkasse
    10   holdings:
    11     - type: stock
    12       ticker: abea.f
    13       shares: 50
    14     - type: cash
    15       amount: 1234.56

Listing 2 zeigt zwei fiktive Konten, eines bei der Deutschen Bank und eines bei der Sparkasse. Dort liegen 100 Amazon-Aktien und 50 Google-Aktien, letztere laufen ja unter dem Namen "Alphabet" und das Ticker-Symbol der Firma an der Frankfurter Börse ist "abea.f". Beide Konten verfügen außerdem über eine cash genannte Bargeld-Position. Beim Zusammenzählen addiert das Skript mymoney.py in Listing 3 letzere Eins zu Eins auf, während es bei den Aktien-Posten den aktuellen Tageswert ermittelt und mit der im Depot liegenden Anzahl multipliziert.

Listing 3: mymoney.py

    01 #!/usr/bin/env python
    02 import requests
    03 import yaml
    04 import myquote
    05 
    06 def pf_read(filename):
    07     with open(filename, 'r') as stream:
    08         return yaml.load(stream)
    09 
    10 def amount_fmt(amount):
    11     return "%10.2f" % amount
    12 
    13 def stock_dump(ticker, shares):
    14     price=myquote.quote(ticker)
    15     return("%d x %s" % (shares, ticker),
    16            price*shares)
    17 
    18 def cash_dump(amount):
    19     return "Cash", amount
    20 
    21 def pos_dump(pos):
    22     if pos['type'] == 'stock':
    23         return stock_dump(pos['ticker'],
    24                           pos['shares'])
    25     elif pos['type'] == 'cash':
    26         return cash_dump(pos['amount'])
    27 
    28 total=0
    29 
    30 for account in pf_read("portfolio.yaml"):
    31     print(account['account'])
    32     for pos in account['holdings']:
    33         (name, amount) = pos_dump(pos)
    34         total += int(amount*100)
    35         print("%15s: %s" % 
    36                 (name, amount_fmt(amount)))
    37 
    38 print("\n%15s: %s" % 
    39         ("Total", amount_fmt(total/100.0)))

Listing 3 zieht in Zeile 3 das PyYaml-Modul herein, das der Admin vorher mit pip install --user pyyaml installiert hat. Es bietet die Methode load(), die Zeile 8 nutzt, um die Kontodaten aus der Portfolio-Datei aus Listing 1 einzulesen. Zeile 30 iteriert über die dort gefundenen Konten, Zeile 32 über die dort jeweils gehorteten Posten. In der abgedruckten Version unterstützt das Skript Bargeld ("cash") und Aktien ("stock"), ließe sich aber bei Bedarf leicht um Pfandbriefe, Optionen, oder Posten in ausländischen Währungen erweitern, deren Kurs das Skript dann zur Laufzeit einholt. Zur Wertermittlung eines Bargeldpostens dient die Funktion cash_dump() ab Zeile 18, die lediglich einen Tupel mit dem Namen "Cash" und dem Betrag zurückgibt.

Zur Wertbestimmung eines Aktienposten nutzt Listing 3 das Modul myquote.py aus Listing 2 und ruft dessen Funktion quote() mit dem Tickersymbol als Parameter auf. Den zurückkommenden Tageswert multipliziert es mit der Anzahl der im Depot liegenden Aktien und gibt diesen mitsamt einem Tabellenschlüssel als Tupel ans Hauptprogramm zurück. Letzteres braucht nur noch die Einzelposten über alle Konten aufzuaddieren und den Gesamtnettowert des Users auszugeben (Abbildung 2).

Runden aber richtig

Computer sind ja bekanntlich grottenschlecht beim Addieren von Fließkommazahlen. Wer 1.23 und 4.56 zusammenzählt, bekommt unter Umständen ein Ergebnis, das vom erwarteten Wert 5.79 abweicht, weil der Prozessor intern 1.23 nicht genau als eins und 23 Hundertstel darstellt, sondern im Binärformat approximiert. Vor einiger Zeit hat sich diese Kolumne ja bekanntlich dem Thema gewidmet, dass selbst Ebay nicht richtig rechnen kann und die monatliche Abrechnung regelmäßig um ein paar Pfennige verhaut ([6]). Beim Rechnen mit Geldbeträgen ist es schlauer, statt mit Euros in Cents zu rechnen, krumme Beträge also einfach mal Hundert zu multiplizieren, als gerundete Integer aufzuaddieren, und beim Abschließenden Anzeigen des Ergebnisses dann vor die letzten zwei Ziffern ein Komma reinzuhauen. Listing 3 tut genau dies.

Zukunft vorhersagen

Mit den relativ einfach verfügbaren Tageskursdaten bekannter Aktien könnte man freilich auf den Gedanken verfallen, ein AI-Netzwerk mit historischen Kursdaten zu füttern, zukünftige Kurssprünge vorauszusagen, um dann mit diesem Wissen gewappnet dick einzukaufen und gehörig abzukassieren -- wären da nicht die schon die nicht mehr ganz frischen aber zeitlosen Argumente aus dem Bestseller "A Random Walk down Wall Street" ([4]), die belegen, dass es in diesem Fall hunderte Markteilnehmer mit ähnlichen Ideen gibt, die solche Wurmlöcher im Zeitgefüge, wenn es sie tatsächlich gäbe, schnell schließen würden, weil sie zur gleichen Zeit um etwaige Preissprünge wüssten und den Gewinn schon lange eingesackt hätten, bevor ein Einzelner überhaupt eine Chance auf den Pott hätte. Das ganze Weltbörsenkasino ist eben, aus der Sicht eines einzelnen Teilnehmers, ein einziger "Random Walk" ([5]), weil unvorhersehbar. Oder sollte man es lieber mit Monaco Franze halten, nach dem immer "a bisserl was" geht? Ein Versuch könnte sich lohnen.

Infos

[1]

Listings zu diesem Artikel: http://www.linux-magazin.de/static/listings/magazin/2018/02/snapshot/

[2]

"Has Yahoo finance web service disappeared?", https://stackoverflow.com/questions/38355075

[3]

"Google Finance as you know it is going away", https://www.marketwatch.com/story/google-finance-as-you-know-it-is-going-away-here-is-what-will-remain-2017-09-27

[4]

"A Random Walk down Wall Street: The Time-tested Strategy for Successful Investing", 2016, https://www.amazon.com/Random-Walk-down-Wall-Street/dp/0393352242

[5]

"Random Walk", Wikipedia, https://de.wikipedia.org/wiki/Random_Walk

[6]

Michael Schilli, "Ladenhüter": Linux-Magazin 06/16, S.XXX, <U>http://www.linux-magazin.de/Ausgaben/2016/06/Perl-Snapshot<U>

http://www.linux-magazin.de/Ausgaben/2016/06/Perl-Snapshot

Michael Schilli

arbeitet als Software-Engineer in der San Francisco Bay Area in Kalifornien. In seiner seit 1997 laufenden Kolumne forscht er jeden Monat nach praktischen Anwendungen verschiedener Programmiersprachen. Unter mschilli@perlmeister.com beantwortet er gerne Ihre Fragen.

POD ERRORS

Hey! The above document had some coding errors, which are explained below:

Around line 5:

Unknown directive: =desc