Series speichert eine den Kerzen zugeordnete Historie. Manchmal möchtest du aber selbst festlegen, welche Werte das Programm sammelt, in welcher Reihenfolge und wann es sie entfernt. Dafür kannst du ein Array verwenden.

Was speichert ein Array?

Ein Array besteht aus aufeinanderfolgenden Elementen. Jedes Element hat einen Index; der erste ist null.

Ein Array speichert Elemente desselben Typs. Du kannst beispielsweise ein Array für Zahlen oder für Texte haben, aber in ein Zahlenarray schreiben wir keinen Text. Gleicher Typ bedeutet nicht gleicher Wert: 100, 103 und 101 sind unterschiedliche Zahlen im selben Array.

Kommen 100, 103 und 101 in dieser Reihenfolge in ein Array, ist das Element mit Index 0 gleich 100, das mit Index 1 gleich 103 und das mit Index 2 gleich 101. Der Index bezeichnet hier den Speicherplatz. Er bedeutet nicht automatisch einen Wert entsprechend viele Kerzen zuvor.

close[1] ist der Schlusskurs der vorherigen Kerze. array.get(prices, 1) ist das zweite Element des Arrays prices. Wie alt das Element ist, hängt davon ab, wie du das Array gefüllt hast.

Der Namensraum array

array.new_float(0) erstellt ein anfangs leeres Array für Zahlen. Null ist die anfängliche Elementanzahl, kein Anfangskurs.

OperationAufgabe
array.push(prices, close)Fügt am Ende ein Element hinzu
array.size(prices)Gibt die Anzahl der Elemente an
array.shift(prices)Entfernt das erste Element und gibt es zurück
array.get(prices, 0)Liest das erste Element
array.avg(prices)Berechnet den Durchschnitt der Zahlen

Der Index von array.get muss auf ein vorhandenes Element zeigen. Bei drei Elementen sind 0, 1 und 2 gültig; 3 ist es nicht mehr.

Fünf aktuelle Kurse speichern

Lege die Datei recent_prices.py an:

"""
@pyne edge
"""
from pynecore import Persistent
from pynecore.lib import array, close, color, plot, script, ta


@script.indicator("Recent Prices", overlay=True)
def main():
    prices: Persistent[list[float]] = array.new_float(0)
    array.push(prices, close)
    if array.size(prices) > 5:
        array.shift(prices)
    stored_average = array.avg(prices)
    full_average = ta.sma(close, 5)
    plot(stored_average, "Stored average", color=color.blue, linewidth=2)
    plot(full_average, "SMA 5", color=color.orange)

list[float] bezeichnet den Typ eines Zahlenarrays. Persistent stellt sicher, dass das Array auf der nächsten Kerze noch vorhanden ist. Es wird nicht auf jeder Kerze neu angelegt.

Wir bearbeiten das Array mit dem Namensraum array. Dafür brauchst du keine allgemeine Python-Bibliothek zu importieren und kein eigenes Listenliteral zu schreiben.

Führe das Programm auf den Demodaten aus. Die blaue Linie zeichnet den Durchschnitt der bereits gesammelten Kurse. Auf der ersten Kerze ist einer enthalten, auf der zweiten zwei, dann drei und vier. Ab der fünften Kerze bleiben fünf Elemente erhalten.

Der Chart von recent_prices.py zeigt den blauen Durchschnitt der gespeicherten Kurse und den orangefarbenen SMA mit Länge fünf.
Wir vergleichen den Durchschnitt des eigenen Arrays mit dem SMA aus einem vollständigen Fenster von fünf Werten.

Die Reihenfolge von Hinzufügen und Entfernen

Auf der sechsten Kerze fügen wir zuerst den sechsten Schlusskurs hinzu. Das Array hat dann sechs Elemente. Die Bedingung von if ist wahr, deshalb entfernen wir das erste, älteste Element. Bei der Durchschnittsberechnung enthält es nur noch die fünf Schlusskurse der zweiten bis sechsten Kerze.

In diesem Programm steht am Anfang des Arrays der älteste verbleibende Kurs und am Ende der neueste. Ab fünf Elementen gibt array.get(prices, 0) daher den Kurs vier Kerzen zuvor zurück. Es entspricht nicht dem aktuellen Kurs.

Möchtest du den neuesten auslesen, ist der letzte Index array.size(prices) - 1. Elementanzahl und letzter Index unterscheiden sich wegen der bei null beginnenden Nummerierung um eins.

Teilweise und vollständige Fenster

Die beiden dargestellten Durchschnitte verhalten sich anfangs verschieden. Der Array-Durchschnitt lässt sich auch aus den tatsächlich gesammelten, höchstens vier Kursen berechnen. ta.sma(close, 5) liefert erst für ein vollständiges Fenster mit fünf Werten ein Ergebnis.

Ab der fünften Kerze mitteln beide dieselben fünf Schlusskurse. Von da an müssen die Linien innerhalb der Genauigkeit der Zahlendarstellung übereinstimmen.

Ein Array-Durchschnitt ersetzt deshalb nicht automatisch den fertigen gleitenden Durchschnitt. Die Regel für das anfängliche Fenster musst du selbst festlegen.

Warum begrenzen wir die Größe?

Fügst du auf jeder Kerze nur ein Element hinzu, wächst das Array mit der Datenlänge. Am Programmende enthielte es alle verarbeiteten Schlusskurse.

Hier brauchen wir nur die letzten fünf Kurse und entfernen deshalb ältere Elemente. Zum Berechnungszeitpunkt ist der Speicher damit höchstens fünf Elemente groß. Lege auch bei echten Sammelaufgaben fest, welche Daten wie lange erhalten bleiben sollen.

Probiere es selbst aus

Ändere das Programm so, dass das Array drei Kurse behält. Stelle auch die Länge des fertigen SMA auf drei. Zeichne anschließend das älteste verbleibende Array-Element als dritte Linie.

Lösung der Aufgabe

Die Bedingung zum Entfernen:

if array.size(prices) > 3:
    array.shift(prices)

Der fertige Durchschnitt und die neue Linie:

full_average = ta.sma(close, 3)
oldest_price = array.get(prices, 0)
plot(oldest_price, "Oldest stored price", color=color.gray)

array.push steht auf jeder Kerze vor dem Lesen, deshalb enthält das Array dann mindestens ein Element. Sobald es drei Elemente umfasst, ist der älteste Kurs zwei Kerzen alt.

Notiere den Array-Inhalt

Verwende drei statt fünf verbleibende Elemente und die Kursfolge 100, 103, 101, 105. Notiere den Array-Inhalt nach jeder der vier Kerzen. Auf der vierten muss es 103, 101 und 105 enthalten, in dieser Reihenfolge.