Eigene Datensammlungen: Arrays
Du speicherst aktuelle Kurse in einem Array begrenzter Größe und verfolgst die Reihenfolge seiner Elemente.
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.
| Operation | Aufgabe |
|---|---|
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ür Leser mit Python-Kenntnissen: In der Python-Laufzeit von PyneCore wird das Array als Python-Liste gespeichert. Deshalb steht auch list[float] in der Typangabe. Die Elemente müssen dem angegebenen Elementtyp entsprechen; anders als bei einer allgemeinen Python-Liste mischen wir hier keine Zahlen und Texte.
In einem mit @pyne gekennzeichneten Programm, das weitere Python-Möglichkeiten verwendet, kannst du auch die eigenen Listenoperationen nutzen: prices.append(close) fügt ein Element hinzu, prices.pop(0) entfernt das erste. In den @pyne edge-Programmen dieses Buchs verwenden wir dafür array.push und array.shift. Auch statt des direkten Zugriffs prices[0] verwenden wir in Edge array.get(prices, 0). Das Array legen wir beispielsweise mit array.new_float(0) an, nicht mit dem Listenliteral [].
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.

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.