Im vorherigen Kapitel hast du mit den Daten einer Kerze gerechnet. Für die Veränderung des Schlusskurses brauchst du bereits zwei Kerzen: die aktuelle und die vorherige. In diesem Kapitel stellst du die Verbindung zwischen ihnen her.

Dasselbe Programm, eine andere Kerze

Startest du das Programm auf den Demodaten, durchläuft PyneCore die Kerzen in zeitlicher Reihenfolge. main() arbeitet zuerst mit der ersten Kerze, dann mit der zweiten und so weiter. close ist jeweils der Schlusskurs der gerade verarbeiteten Kerze.

Deshalb kann ein einzelner Aufruf plot(close, "Close") eine vollständige Linie zeichnen. Eine Ausführung fügt der Linie einen Punkt hinzu; die Folge der Kerzen ergibt die ganze Linie.

Auch die Zeile midpoint = (high + low) / 2 aus dem vorherigen Kapitel läuft auf jeder Kerze erneut. Die Zuweisung berechnet den Mittelkurs der aktuellen Kerze neu. Der Variablenname bleibt gleich, ihr Wert kann sich ändern.

Die Reihenfolge der Verarbeitung stellt die Laufzeit bereit. Du brauchst keine eigene Schleife, um den gesamten Chart zu durchlaufen.

Mit eckigen Klammern zurückblicken

close[1] ist der Schlusskurs eine Kerze zuvor. Die Zahl in den eckigen Klammern gibt an, wie weit wir zurückblicken.

AusdruckWelcher Schlusskurs ist gemeint?
closeDer der gerade verarbeiteten Kerze
close[0]Ebenfalls der der verarbeiteten Kerze
close[1]Der der vorherigen Kerze
close[2]Der der zwei Kerzen zuvor

Sind drei aufeinanderfolgende Schlusskurse in Tagesdaten 100, 103 und 101, dann ist auf der dritten Kerze close gleich 101, close[1] gleich 103 und close[2] gleich 100.

close - close[1] ist in diesem Fall 101 - 103, also −2. Das ist die Differenz zweier aufeinanderfolgender Schlusskurse. close - open vergleicht Eröffnungs- und Schlusskurs derselben Kerze. Die beiden Berechnungen beantworten unterschiedliche Fragen.

Der Rückblick zählt Kerzen, keine Kalendertage. Bei täglichen Marktdaten kann die vorherige Kerze wegen eines Wochenendes oder handelsfreien Tags mehrere Tage zurückliegen.

Auch dein eigener Wert kann eine Historie haben

Die historischen Werte der eingebauten Kurse sind bereits verfügbar. Möchtest du auf eine eigene Berechnung zurückblicken, kennzeichne sie als Series-Variable:

midpoint: Series[float] = (high + low) / 2

Der Teil nach dem Doppelpunkt ist eine Typangabe. float bezeichnet eine Zahl, die auch Nachkommastellen haben kann. Series[float] fordert die Laufzeit außerdem auf, die Historie der Variablen für jede Kerze aufzubewahren.

Die Zuweisung läuft weiterhin auf jeder Kerze. midpoint ist der aktuell berechnete Wert, midpoint[1] der auf der vorherigen Kerze gespeicherte Wert. Den Namen Series musst du aus dem Modul pynecore importieren.

Zwei Veränderungen im Chart

Lege im Projektordner scripts die Datei history_change.py an:

"""
@pyne edge
"""
from pynecore import Series
from pynecore.lib import close, color, high, low, plot, script


@script.indicator("Changes Between Candles", overlay=False)
def main():
    midpoint: Series[float] = (high + low) / 2
    close_change = close - close[1]
    midpoint_change = midpoint - midpoint[1]
    plot(close_change, "Close change", color=color.blue)
    plot(midpoint_change, "Midpoint change", color=color.orange)

Speichere sie und wähle Run Pyne code sowie die Daten demo. In einem eigenen Panel erscheinen zwei Linien. Die blaue zeigt die Änderung des Schlusskurses, die orangefarbene die Änderung des Mittelkurses. Ein positiver Punkt bedeutet, dass der jeweilige Wert gegenüber der vorherigen Kerze gestiegen ist.

Neben dem Programm history_change.py zeigt der PyneIDE-Chart zwei Linien mit Kursveränderungen.
Die Veränderungen von Schlusskurs und berechnetem Mittelkurs zwischen den Kerzen in einem eigenen Panel.

Bewege den Mauszeiger auf eine Kerze. Die Chartwerte gehören immer zum Zeitpunkt unter dem Zeiger. Du musst diesen Zeitpunkt nicht zusätzlich in der Datei auswählen.

Was passiert auf der allerersten Kerze?

Die erste Kerze hat in der Datendatei keine vorherige Kerze. Dort ist close[1] ein fehlender Wert: na. Die Abkürzung stammt von „not available“.

Ein fehlender Kurs ist nicht null. Auch das Ergebnis von close - close[1] fehlt. Deshalb zeichnet das Programm auf der ersten Kerze keine gültige Veränderung. Das ist richtig: Die Differenz zweier Kerzen lässt sich aus einer einzigen Kerze nicht berechnen.

Mit na(value) kannst du prüfen, ob ein Wert fehlt. Den Umgang mit Bedingungen lernst du im Kapitel Bedingungen und Markierungen. Versuche bis dahin nicht, den fehlenden Punkt am Chartanfang durch einen Kurs von null zu „reparieren“.

Zukünftige Kerzen werden durch diese Schreibweise nicht zugänglich. Auch close[-1] bedeutet nicht den nächsten Schlusskurs. Für eine Entscheidung stehen nur Daten zur Verfügung, die bei der jeweiligen Ausführung bekannt sind.

Probiere es selbst aus

Ändere die blaue Linie so, dass sie den Schlusskurs mit dem Schlusskurs fünf Kerzen zuvor vergleicht. Gib den Abstand von fünf Kerzen auch im Titel der Linie an.

Überlege vor der Ausführung: Auf wie vielen Kerzen am Anfang wird das Ergebnis fehlen?

Lösung der Aufgabe
close_change = close - close[5]
plot(close_change, "Five-candle change", color=color.blue)

Auf den ersten fünf Kerzen gibt es keinen Schlusskurs fünf Kerzen zuvor. Auf der sechsten Kerze ist er vorhanden: der Schlusskurs der ersten Kerze der Datendatei.

Die orangefarbene Linie verändert sich dadurch nicht. Sollen beide Veränderungen über fünf Kerzen berechnet werden, musst du auch den Ausdruck midpoint[1] ändern.

Prüfe die Berechnung

Wähle drei aufeinanderfolgende Kerzen. Notiere ihre Schlusskurse und berechne von Hand die Veränderung über eine Kerze für die zweite und dritte Kerze. Die blaue Linie muss dieselben Werte zeigen. Prüfe bei einer Abweichung zuerst die gewählten Zeitpunkte und die Zahl des Rückblicks.

Zusatzaufgabe: ein gespeicherter Wert statt einer Historie

Du kannst einen einzelnen vorherigen Wert auch nutzen, indem du ihn für die nächste Kerze speicherst. Dafür gibt es die Variable Persistent, die du im Kapitel Was das Programm sich merkt kennenlernst. Du kannst diese Aufgabe auch nach dem Lesen dieses Kapitels lösen.

Schreibe history_change.py so um, dass weder close[1] noch midpoint[1] darin vorkommt. Zwei persistente Variablen sollen Schlusskurs und Mittelkurs der vorherigen Kerze aufbewahren. Die Linien sollen dieselben Werte wie im ursprünglichen Programm zeigen; auf der ersten Kerze soll die Veränderung weiterhin fehlen.

Überlege dir die Reihenfolge: Wann musst du den gespeicherten Wert lesen, und wann darfst du ihn durch den aktuellen überschreiben?

Lösung der Aufgabe

Ersetze den Import von Series durch Persistent:

from pynecore import Persistent

Ergänze na im Import aus pynecore.lib. Behalte die Kennzeichnung am Dateianfang und die Indikatoreinstellungen bei und schreibe main() so um:

def main():
    previous_close: Persistent[float] = na
    previous_midpoint: Persistent[float] = na
    midpoint = (high + low) / 2
    close_change = close - previous_close
    midpoint_change = midpoint - previous_midpoint
    plot(close_change, "Close change", color=color.blue)
    plot(midpoint_change, "Midpoint change", color=color.orange)
    previous_close = close
    previous_midpoint = midpoint

Der Anfangswert beider gespeicherten Variablen ist na, weil auf der ersten Kerze noch kein vorheriger Kurs vorhanden ist. Deshalb fehlt auch die erste Differenz. Am Ende der Funktion speichern wir die aktuellen Werte; auf der nächsten Kerze rechnen wir mit ihnen.

Setzt du previous_close = close vor die Subtraktion, ziehst du vom aktuellen Schlusskurs sich selbst ab und erhältst null. Bei der persistenten Lösung musst du dich selbst um die Reihenfolge der Aktualisierung kümmern.

Für einen Rückblick um eine Kerze sind beide Lösungen geeignet. Die Variante mit eckigen Klammern ist kürzer und erreicht auch direkt Werte, die mehrere Kerzen zurückliegen. Diese beiden persistenten Variablen bewahren nur die zuletzt gespeicherten Kurse auf.

Führe beide Varianten auf denselben Demodaten aus und vergleiche die Linien an einigen ausgewählten Kerzen.