Chartanalyse mit Python Teil 3: Candlestick-Charts zeichnen

Im letzten Teil habe ich eine Methode vorgestellt, um mit Tickstory lite qualitativ hochwertige historische Daten der wichtigsten Währungspaare und Indizes als Textdatei zur Verfügung zu stellen. Im nächsten Schritt wollen wir nun einige Funktionen entwickeln, um aus diesen Daten Candlestick-Charts (oder auf Deutsch Kerzen-Charts) zu erstellen.

Die Darstellung von Kursverläufen mit Candlesticks hat sich inzwischen beim Trading als weit verbreiteter Standard durchgesetzt, daher setze ich sie auch als bekannt voraus und werde nicht näher auf ihren Aufbau und die Funktion eingehen.

Im Teil 2 dieser Reihe haben wir unter anderem eine CSV-Datei mit Minutenkerzen des DAX der letzten 3 Jahre erzeugt. Das genaue Export-Format lässt sich mit Tickstory sehr detailliert festlegen. Für die weiterer Entwicklung nehmen wir an, dass die Daten wie folgt aussehen:


Date,Timestamp,Open,High,Low,Close,Volume
20130430-09:02:00,7873.5,7928.42,7873.5,7928.42,0
20130430-09:03:00,7928.48,7950.04,7927.78,7947.52,0
.
.
.
20160530-21:57:00,10345.574,10346.545,10344.745,10346.478,0.0100000004749745
20160530-21:58:00,10346.545,10346.545,10345.395,10346.208,0.00475000022561289
20160530-21:59:00,10346.645,10347.978,10342.77,10342.77,0.0127500006055925

Die Zeit wird am Anfang jeder Zeile im Format YYYYMMDD-hh:mm:ss angegeben, danach kommen Eröffnung, Hoch, Tief und Schlusskurs in dieser Minute. Die letzte Spalte enthält Informationen über das Volumen, die wir aber zunächst nicht nutzen wollen und deshalb einfach ignorieren.

Einlesen der Daten

Zunächst müssen die Daten aus der Textdatei natürlich in eine Variable eingelesen werden. Ein dafür gut geeigneter Datentyp ist der DataFrame aus dem Python-Modul pandas. DataFrames sind speziell für die Analyse multivariater großer Datensätze konzipiert und lehnen sich an die Datentypen der Statistik-Programmiersprache R an.  Pandas und DataFrames bieten daher ideale Voraussetzungen, um komplexe Analyseaufgaben umzusetzen.

Wir nehmen an, dass die Daten im Arbeitsverzeichnis liegen und unter dem Namen  „last_3years_minutebarsDEUIDXEUR.csv“ gespeichert sind.

 

Neben den Datenanalysetools aus pandas importieren wir noch das Modul dateutil.parser, um die Datumsrepräsentation in ein Datetime-Objekt umzuwandeln. Dies kann man zwar auch über die Vorgabe eines Formatstrings lösen, aber dann muss das Datum exakt mit dem spezifizierten Format übereinstimmen und jede Abweichung führt zu einem Laufzeitfehler. Der Parser aus dem Modul dateutil ist im Vergleich dazu sehr robust und kann so gut wie alle gängigen Schreibweisen von Kalenderdatum und Uhrzeit umwandeln.

pd.read_csv ist eine Methode des DataFrame-Objekts und macht das was ihr Name vermuten lässt. Wenn  eine Header-Zeile im Datenfile vorhanden ist, dann wählt der CSV-Reader automatisch die Variablennamen der Spalte entsprechend.

Einlesen von Kalenderdatum und Uhrzeit

Die Datumsangaben stehen in der CSV-Datei als String (Zeichenkette). Um die Daten später komfortabel verarbeiten und grafisch darstellen zu können, sollten sie in ein computerlesbare Repräsentation für Datum und Uhrzeit umgewandelt werden. Auch hier bietet Python eine umfangreiche Werkzeugsammlung in Gestalt des Moduls Datetime.

Nach der Umwandlung der Datums-Strings in Datetime-Objekte lässt sich dann das Datum als Zeitachse für die Charts verwenden und außerdem kann man mit dem Datum rechnen. Zum Beispiel lässt sich zu einem Kalenderdatum ein Intervall von 10 Tagen addieren und man erhält das korrekte Datum mitsamt Monats- oder Jahresüberträgen zurück.

Da für die Analyse von Finanzdaten die Verarbeitung von Zeiten und Kalenderdaten unverzichtbar ist, wollen wir schon beim Einlesen der Daten alles im Datetime Format speichern.

Dies geschieht über das Schlüsselwort converters, das beim Aufruf des CSV-Readers mit übergeben wird. Hier kann der Anwender eine Funktion angeben, die dann auf die Eingabedaten automatisch angewendet wird. In unserem Fall wenden wir einfach den oben erwähnten Datums-Parser auf den Datumsstring an.

Die dafür verwendete Lambda-Konstruktion ist eine weitere sehr interessante Eigenheit von Python. Lambda gestattet Funktionsdefinitionen wie eine Variable zu behandeln und führt damit Konzepte der funktionalen Programmierung in Python ein.

Die Codezeile ist also so zu lesen: „Lies die CSV-Daten in einen DataFrame.  Bei der Spalte mit dem Namen „Datetime“ wende vorher auf jeden Einzelwert die Funktion parser.parse  an.“

Jetzt können wir die Daten einlesen und weiterverarbeiten, zum Beispiel interaktiv in der Python-Shell:

>>>DAX=fp_read_data('last_3years_minutebarsDEUIDXEUR.csv')
>>>print DAX.Open[0], DAX.Close[0] 8396.0 8399.0

>>>DAX.Open[0:10] 0 8396
1 8398
2 8398
3 8399
4 8399
5 8399
6 8399
7 8399
8 8400
9 8399
Name: Open, dtype: float64
>>>DAX.Datetime[0] Timestamp(‚2013-05-24 02:00:00‘, tz=None)

usw. Einfache Analysen lassen sich damit bereits durchführen, denn es steht das gesamte Methoden-Arsenal des pandas-DataFrame zur Verfügung. Darauf will ich aber an dieser Stelle nicht weiter eingehen, denn es würde den Rahmen sprengen.

Zeitintervalle definieren

Die komplette CSV-Datei mit Minutenkerzen der letzten 3 Jahre hat etwa 800 000 Zeilen. Um Charts zu plotten, müssen wir natürlich den Datenbestand reduzieren. Die am häufigsten benötigte Aufgabe ist, Minutenkerzen zwischen einer vorgegebenen Startzeit und Endzeit herauszuschneiden. Dies leistet die folgende Funktion:

Beim Aufrufen der Funktion kann der Benutzer entweder Start- und Enddatum als Zeichenkette übergeben, oder aber als Datetime-Objekt. Letzteres wird meist passieren, wenn die Funktion von anderen Funktionen aufgerufen wird, während beim Aufruf durch einen menschlichen Benutzer eher die erste Variante in Frage kommt.

Dafür wird zunächst der Typ von Start und Endzeit abgefragt. Wenn es sich um Strings handelt, dann wandelt die Funktion diese in ein Datetime-Objekt um. Das geschieht über die Funktion  strptime aus dem Modul datetime, die ein Datum aus einer Zeichenkette nach einem vorgegebenen Formatstring auswertet.

Anschließend werden einfach die Daten aus dem Zeitintervall zurückgegeben. Damit ließe sich jetzt ein einzelner Handelstag aus den 3-Jahresdaten herausschneiden, in diesem Beispiel der 23. Mai 2016:
>>>day0523=fp_timeslice(DAX,'20160523-070000','20160523-230000')

Der Frame day0523 enthält nun nur die Kerzen des 23. Mai zwischen 07:00 Uhr und 23:00 Uhr.
Um die Daten zu überprüfen, können wir schon mal die Schlusskurse mit der pandas-eigenen Plot-Funktion anzeigen lassen:

>>>day0523.Close.plot()

figure_1

Der Kursverlauf des Handelstages ist bereits deutlich zu erkennen, aber die Zeitachse stimmt natürlich noch nicht. Jedoch ist immerhin zu erkennen, dass das herausschneiden der Daten korrekt funktioniert.

Damit können wir zum nächsten Schritt übergehen und die Daten mit korrekter Zeitachse als Candlestick-Chart zeichnen.

Das Plotten von Candlesticks

Der Umgang mit Zeitdaten beim Plotten ist leider ein wenig mühsam, nicht nur in Python sondern in allen Programmiersprachen. Das liegt daran, dass Zeitangaben sehr unregelmäßig sind und viele Sonderfälle zu berücksichtigen sind und man die Überträge von Monaten oder Jahren jeweils gesondert berücksichtigen muss . Glücklicherweise stellt matplotlib auch hier bereits einige vordefinierte Funktionen zur Datumsformatierung zur Verfügung. Ich werde versuchen, mich weitgehend auf diese zu beschränken, auch wenn sie nicht immer die ästhetisch ansprechendsten Ergebnisse liefert. Dies führt schließlich zu folgendem Code:

 

Wir erkennen zunächst, dass wir die Candlesticks nicht selbst erzeugen müssen. Auch hierfür stellt das Modul matplotlib.finance glücklicherweise bereits eine Funktion zur Verfügung. Der erste Teil der Routine besteht aus einer For-Schleife, deren Aufgabe lediglich eine Umsortierung der Daten ist. Dafür wird eine einfache Liste namens quotes angelegt. Die Funktion  iterrows() ist ein sogenannter Iterator. In perfekter Zusammenarbeit mit der For-Schleife liefert der Iterator mit jedem Bearbeitungsschritt eine Zeile des DataFrames zurück.
Die candlestick-Funktion erwartet für das Datum einen sogenannten Timestamp. Dieses Format haben wir im letzten Teil bereits kurz angesprochen. Hier nutzen wir date2num um den Timestamp aus dem Datetime-Objekt zu erzeugen.
Dann wird die Plot-Achse definiert.

Mit ax=plt.gca  (get current axis) wird der Variablen ax die Plotachse zugewiesen.

Die Funktion DateFormatter sorgt dafür,  die Timestamps in einem lesbaren Datumsformat an der Achse aufzutragen. Außerdem drehen wir die Beschriftung um 25 Grad, weil sie sonst horizontal geschrieben würde und sich dann die langen Datums-Ausdrücke damit überlappen würden:

Danach rufen wir mit der so definierten Achse die candlestick-Funktion auf. Die Farben für up- und down-Kerzen lassen sich hier noch umdefinieren, ich bevorzuge eine klassische Darstellung mit Rot und Grün. Die abschließende Zeile

teilt dem Interpreter mit, dass es sich bei der x-Achse um eine Datumsachse handelt. Lässt man diese weg, kann es hier zu Fehlermeldungen kommen.

Damit hätten wir alles beisammen. In der Shell genügt nun ein Aufruf der Funktion fp_chart, um den Candlestick-Chart darzustellen, zum Beispiel so:

>>fp_chart(day0523)

Die Ausgabe zeigt den gesamten Handelstag mit korrekter Zeitachse.
candlesick1

Die Zeitachse stimmt zwar,  aber aufmerksame Beobachter erkennen vielleicht einen Schönheitsfehler:  Matplotlib ordnet die Achsenbschriftung linksbündig an die Ticks an. Da das linke Ende aber wegen der gedrehten Labels nach unten geklappt ist, läuft die Beschriftung auf den folgenden Tick an der Achse zu. Für das Auge sieht es so aus, als ob die Ticks um eins verschoben sind. Das Problem beheben wir, indem wir die Ticklabels rechtsbündig machen:

candlestick_tickcorr

Jetzt stimmen die Enden der Labels mit den Ticks überein, wie man es erwartet. Dass dabei die erste Beschriftung am Rand abgeschnitten wird, nehmen wir in Kauf.

Ein mit matplotlib.pyplot gezeichneter Chart ist automatisch zoombar und verschiebbar.  Eine Werkzeugleiste mit diesen Funktionen erscheint automatisch beim Erzeugen des Plot-Windows.

Damit können wir weiter in den Chart hineinzoomen und Ausschnitte des DAX-Verlaufs innerhalb des Handelstages anschauen:

candlesick2

 

Das Fundament ist gelegt

Wir haben also nun den Werkzeugkasten um drei grundlegende Funktionen erweitert:

  • Einlesen der Daten aus einer CSV-Datei in einen pandas-Dataframe
  • Ausschneiden von bestimmten Zeitintervallen aus dem Gesamtdatensatz
  • Darstellung dieser Zeitintervalle als Candlestick-Plot

Damit sind die wichtigsten Grundlagen für eine Datenanalyse bereits gelegt. Zum Abschluss hier nochmal der gesamte in diesem Artikel behandelte Code:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.