Fortsetzung der beiden vorherigen Artikel zu Themen, die beim programmatischen Handel Aufmerksamkeit erfordern:

Harte Trockengüter – Details und Gedanken zum automatisierten Echtzeithandel quantitativer Handelssysteme (1. Probleme und Schwierigkeiten)

Quantitatives Handelssystem – Details und Überlegungen zum automatisierten festen Angebot (2. Zweck des festen Angebots)

Hier werden wir weiterhin über einige detaillierte Handhabungsfähigkeiten im Codedesign sprechen.

Datenbank

Wie in den beiden vorherigen Artikeln erwähnt, ist die Statusaufzeichnung einer komplexeren Strategiekombination sehr wichtig und erfordert den Einsatz einer Datenbank.

Tatsächlich können die meisten Programmierunternehmen in die CRUD-Kategorie eingeordnet werden, d. h. der Kernprozess besteht lediglich aus dem Hinzufügen, Löschen, Ändern und Überprüfen der Datenbank. Handelscodes sind keine Ausnahme. Das Handelsverhalten auf dem Sekundärmarkt mit mittlerer und niedriger Frequenz unterscheidet sich eigentlich nicht wesentlich vom Kauf und Verkauf eines bestimmten Schatzes. Der Schwerpunkt des automatisierten Handels liegt auf der Verwaltung des strategischen Status.

Wenn Sie noch nicht mit relationalen Datenbanken wie SQL vertraut sind, empfiehlt es sich, direkt den Umgang mit NoSQL-In-Memory-Datenbanken wie Redis zu erlernen. Seine Vorteile bestehen darin, dass es einfach zu starten ist, eine hervorragende Leistung aufweist und von Natur aus Single-Threaded ist. Beim Lesen und Schreiben müssen keine Vorgänge auf niedriger Ebene wie das Sperren von Daten berücksichtigt werden. Der Nachteil besteht jedoch darin, dass kein Primärschlüssel vorhanden ist und Funktionen wie die automatische Nummernerhöhung nicht realisiert werden können. Bei Bedarf müssen Sie Code schreiben, um ihn selbst zu implementieren. Allerdings habe ich diese Funktion noch nie so lange im automatisierten Handel genutzt.

Ein weiteres unwichtiges Problem besteht darin, dass bei In-Memory-Datenbanken der Serverspeicher größer sein muss, wenn die zu speichernde Datenmenge relativ groß ist. Für den allgemeinen quantitativen Handel reichen jedoch 4 GB oder sogar 2 GB Speicher aus nicht erforderlich. Speichern Sie so viele Daten.

Redis ist in der Praxis wirklich leistungsstark. Wenn Ihre Strategie hohe Frequenzanforderungen hat, kann es auch das Pub/Sub-Nachrichtenabonnementmodell implementieren, wodurch das Hinzufügen verschiedener zusätzlicher MQ-Module entfällt. Wenn Sie, wie bereits erwähnt, eine relationale Datenbank wie MySQL verwenden, müssen Sie Zeit und Energie in das Erlernen von SQL investieren, einer relativ ekelhaften und schwierigen Programmiersprache, solange Sie diese noch nicht in der Praxis verwendet haben. Beachten Sie, dass jeder hier ist, um quantitativen Handel zu betreiben, und nicht, um das Schreiben von Code zu lernen. Versuchen Sie, eine einfachere Lösung zu verwenden.

Wenn Sie außerdem ein Marktzentrum aufbauen möchten, verwenden Sie unter Berücksichtigung der Leistung auch die Redis-Datenbank und arbeiten aus Bequemlichkeitsgründen mit der Nachrichtenwarteschlange zusammen. Die Lösung ist einfach und für die meisten Szenarien geeignet. Es kann ein Server (oder mehrere Server) verwendet werden.

Code-Design

Grundsätzlich ist beim Schreiben von Code die Kerndatenstruktur am wichtigsten. Das Design der Datenstruktur ist nicht vernünftig genug, und der Code wird umständlich geschrieben, da dies zwangsläufig dazu führt, dass die verschiedenen Module miteinander gekoppelt werden, was Änderungen sehr mühsam macht. Aber um es richtig zu gestalten, braucht man etwas Handelserfahrung, also Geschäftserfahrung. Hier dreht sich alles um das Schreiben von Code, dazu gibt es nicht viel zu sagen. Die Strategien jedes Einzelnen sind unterschiedlich und können nicht gleich behandelt werden. Einige Prinzipien sind jedoch wahrscheinlich dieselben.

Beispielsweise gibt es nach der Übermittlung einer Order keine Erfolgsgarantie, auch wenn es sich um eine Market Order handelt, da diese von der Börse abgelehnt werden kann. Beispielsweise ist die Vermittlungsstelle zu ausgelastet oder es kommt zu einem vorübergehenden Verlust von Netzwerkdatenpaketen. Dann ist es am besten, einige Zwischenzustände zu entwerfen, die dem 2-Phasen-Commit ähneln. Wenn es fehlschlägt, versuchen Sie es weiter (natürlich nicht zu oft, sonst wird es gesperrt, wenn es das Limit überschreitet. Dafür gibt es einen speziellen Wiederholungs-Dekorator). , oder fügen Sie weitere hinzu Eine Methode zum Korrigieren des Fehlerstatus.

Unter normalen Umständen wird sich die Börse selbst bei einem Ausfall in kurzer Zeit erholen. Wenn Sie keine Wiederherstellung durchführen, ist eine Partei vollständig ausgefallen, entweder die Vermittlungsstelle oder Ihr eigener Codeserver. Dies muss überwacht und gewarnt werden. Es ist unmöglich, dass automatisierter Code alles abdeckt, wenn er nicht automatisch verarbeitet werden kann, ist ein manueller Eingriff erforderlich. Wenn die manuelle Verarbeitung nicht rechtzeitig erledigt wird, wird das Problem nicht allzu groß sein, solange wir nicht weiterhin Positionen eröffnen, um das Engagement zu erhöhen, da es algorithmische Stop-Loss-Orders gibt, um den Boden abzudecken.

Das Folgende ist eine Strategie-Eröffnungslogik, die ich selbst geklärt habe:

Grundsätzlich wird der Code durch das Zeichnen eines ähnlichen Flussdiagramms viel besser organisiert und die Anzahl potenzieller Fehler verringert. Daher ist es am besten, vor dem Schreiben von Code ein Flussdiagramm zu zeichnen oder es beim Schreiben zu sortieren, damit die Logik klar ist und Sie eine Idee haben.

Die Logik des Schließens einer Position ist viel komplizierter, da es mehr Bedingungen für das Schließen einer Position gibt, wie z. B. Stop-Profit, Stop-Loss und Ausstiegssignale verschiedener Strategien, die das Schließen der Position auslösen. Kurz gesagt, die Bedeutung des Ausstiegs ist höher als die des Einstiegs, und das tatsächliche Angebot ist auch etwas problematischer.

Da die Strategielogik definitiv bei jedem anders ist, werde ich hier nicht auf Details eingehen. Das Wichtigste ist, Ihre strategische Logik zu korrigieren und mögliche Fehler zu vermeiden.

Diese scheinen jedoch kompliziert zu sein, und es handelt sich lediglich um eine Ansammlung anderer Dinge (Python verfügt nicht einmal über eine switch-Anweisung). Wenn die Bedingungen erfüllt sind, fahren Sie mit dem nächsten Schritt fort. Wenn nicht, beenden Sie den Vorgang.

Zeitkontrolle

Bei Transaktionen ist das Timing zweifellos sehr wichtig. Hier werde ich einige weitere meiner Fähigkeiten zur Zeitkontrolle teilen.

Wenn es in der allgemeinen Programmierung Aufgaben gibt, die regelmäßig ausgeführt werden müssen, werden normalerweise Cron-Job-Pakete wie Apscheduler verwendet. Planen Sie beispielsweise eine geplante Aufgabe, um zu erkennen, ob der K-Line-Preis eine Position eröffnen oder schließen muss, sobald die Stunde erreicht ist.

Diese Art von Paket öffnet tatsächlich sofort zum festgelegten Zeitpunkt einen neuen Thread (kann auf die zweite Ebene genau sein) und führt dann die angegebene Aufgabe aus. Das Problem besteht darin, dass die nächste Aufgabe ausgeführt wird, wenn die Ausführungszeit dieser Aufgabe zu lang ist Es wird wieder Probleme geben, die jedoch gelöst werden können.

Normalerweise verwende ich solche geplanten Aufgaben, wenn ich regelmäßig Protokollinformationen ausgeben und die Selbstkorrektur und den Selbsttest des Programms durchführen muss. Dabei handelt es sich um Funktionen mit geringer Häufigkeit, die schnell ausgeführt werden können. Diese Funktionen lesen nur die Daten in der Datenbank und es gibt keine Schreib- oder Aktualisierungsvorgänge. Daher kann es nicht schaden, Apscheduler einen anderen Thread zur Verarbeitung öffnen zu lassen.

Allerdings ist eine Logik, die eine ständige und häufige Abfrage der Marktpreise oder des lokalen Richtlinienstatus erfordert, für ein solches Timing-Paket nicht geeignet und muss durch eine While-Schleife gesteuert werden.

Wenn die Strategie beispielsweise Signale innerhalb des Balkens der K-Linie verwendet, bedeutet dies, dass das Signal jederzeit erscheinen kann und Sie ständig den zugrunde liegenden Preis oder das Handelsvolumen überprüfen müssen, um festzustellen, ob entsprechende Operationen durchgeführt werden müssen. Wenn Sie zu diesem Zeitpunkt beispielsweise eine genauere Zeitsteuerung benötigen, führen Sie die Serienlogik zum Eröffnen einer Position nur 10 Sekunden vor dem Ende der K-Linien-Stunde aus. Wie können Sie also einfach beurteilen, ob es die letzten 10 Sekunden sind?

Den Rest von 3600 habe ich mithilfe des Zeitstempels erfasst.

(Wenn Sie mit dem Zeitstempel auf dem Computer nicht vertraut sind, d Mikrosekundenebene.)

Nach Abzug des Rests von 3600 sind es die letzten zehn Sekunden, wenn der Rest größer als 3590 Sekunden ist. Der Fehler kann bis in den Millisekundenbereich reichen. Wie bereits erwähnt, ist es am besten, die Haupttransaktionsvorgänge nacheinander in einem Thread auszuführen. Auf diese Weise kann die Ausführungszeit grob gesteuert oder der Zeitraum verwischt werden, was kein Problem darstellt.

Diese Art der Steuerung setzt voraus, dass die Zeiteinstellung des eigenen Servers nicht stark von der Standardzeit abweicht. Allerdings wird diese Art der Steuerung nicht sehr präzise sein, sie kann nur die zweite Ebene erreichen. Allerdings kann Python die Zeit nicht sehr genau steuern und diese Schlaffunktionen verursachen Fehler von etwa Mikrosekunden.

Reduzieren Sie die Häufigkeit des API-Zugriffs

Wenn Sie ein unabhängiges Marktzentrum auf WebSocket-Basis eingeführt haben, um öffentliche Marktinformationen wie K-Linien zwischen verschiedenen Strategien oder sogar verschiedenen Handelscodes auszutauschen, besteht in dieser Hinsicht kein Grund zur Besorgnis über API-Frequenzbeschränkungen.

Aber wir müssen auch zeitnah Kontoinformationen erhalten, also drei Arten von Informationen: Gelder, Positionen und Aufträge. Obwohl die Kontoinformationen auch Websocket verwenden und darauf warten können, dass der Exchange-Server sie aktiv pusht, ist es aus drei Gründen einfacher, die restliche API direkt zu verwenden.

Erstens: Um die Belastung der vom Websocket übertragenen Kontoinformationen zu verringern, muss die Börse von Zeit zu Zeit eine erneute Verbindung herstellen oder den ListenKey aktualisieren (Binance dauert 60 Minuten). Es ist offensichtlich schwieriger, diese Situation aufrechtzuerhalten. Auch wenn es kein großer Aufwand ist, müssen Sie, wenn Sie API-Hosting betreiben und mehrere Konten gleichzeitig handeln, ein separates Programm aktivieren, um die Echtzeitgenauigkeit der Informationen sicherzustellen, und die Logik wird viel komplizierter.

Zweitens verfügen einige Börsen nicht über einen Websocket-Push für die Aktualisierung von Kontoinformationen. In diesem Fall ist die Handelslogik nicht universell und es ist schwieriger, echte Handelscodes zwischen verschiedenen Börsen zu wechseln. Natürlich werden die meisten Menschen nicht an mehreren Börsen handeln und werden nicht in eine solche Situation geraten.

Drittens, wenn die WebSocket-Verbindung unterbrochen ist oder Probleme wie die zuvor erwähnte ListenKey-Aktualisierung oder der Ablauf auftritt, das Programm sie nicht rechtzeitig erkennt und zu diesem Zeitpunkt zufällig eine Transaktion stattfindet, dann, wenn Sie sich nur auf WebSocket verlassen, Dies führt zu einem großen Vergleichsproblem, da verpasste Kontoaktualisierungsinformationen nicht erneut übertragen werden. Um die Möglichkeit solcher potenziellen Probleme zu vermeiden, müssen Sie sich auch auf die Rest-API verlassen, um bestimmte Kontoinformationen zu erhalten. Am Ende muss man sich also auf die restliche API verlassen, ist das nicht unnötig?

Zusammenfassend lässt sich sagen, dass es für Transaktionen mit mittlerer und niedriger Frequenz besser ist, die Rest-API direkt zu verwenden, um Kontoinformationen abzurufen. Für wichtige Datenquellen ist es am besten, SSOT (Single Source Of Truth) zu befolgen, da dies sonst zu Verwirrung führen kann. Dieses Konzept kann von Ihnen selbst gegoogelt werden und ist bei der Programmierung, die auf Datenverarbeitung basiert, sehr nützlich.

Wenn Sie dann nur die REST-API verwenden, um Kontoinformationen abzurufen, können Sie eine temporäre Kontoinformationstabelle im lokalen Codespeicher verwalten, insbesondere die verfügbaren Mittel. Dies kann häufige Besuche an der Börse reduzieren Sie können alle Bestellungen auf einmal senden, ähnlich wie bei der stapelweisen Auftragserteilung und der anschließenden langsamen Verarbeitung der Logik hinter der Aktualisierung. Je schneller die Bestellung aufgegeben wird, desto geringer ist natürlich die Abweichung.

Um festzustellen, ob die algorithmische Stop-Loss-Order ausgeführt wurde, können Sie außerdem die aktuellen Höchst- und Tiefstkurse verwenden, anstatt direkt den Status der ausstehenden Order abzurufen, da Sie eine Abfrage durchführen müssen, um festzustellen, ob die Order ausgeführt wurde kontinuierlich, was relativ häufig vorkommt und viele ungültige API-Zugriffe verursacht. Die K-Line-Preisaktualisierung von Websocket erfolgt sehr zeitnah und belegt nicht die API-Frequenzbegrenzung.

Auf die gleiche Weise können auch einige Ausstiegsaufträge so lauten. Wenn Ihr Ausstiegssignal auf dem Preis innerhalb eines Balkens beruht, ist es möglicherweise besser, die aktuellen Höchst- und Tiefstkurse zu verwenden. Da der Preis manchmal ausgelöst wird und sofort zurückkehrt, kann es sein, dass Sie ihn verpassen, wenn Sie nicht zu häufig prüfen. Um die Konsistenz Ihrer Handelsstrategie zu gewährleisten, überprüfen Sie die Höchst- und Tiefststände, damit Ihnen die Preise nicht entgehen. Dieser Ansatz hat den zusätzlichen Vorteil, dass der tatsächliche Transaktionspreis günstiger sein kann als der tatsächliche Auslösepreis.

Ich weiß nicht, ob die beiden oben genannten Punkte leicht zu verstehen sind. Es erfordert möglicherweise etwas Erfahrung aus dem wirklichen Leben.

Ich möchte einige meiner Erfahrungen bei der Entwicklung von echtem Code teilen und hoffe, dass sie für alle hilfreich sind.