Erfahrungen mit der Entwicklung von Handelsstrategien

Schriftsteller:Gutes, Erstellt: 2019-09-05 11:49:31, Aktualisiert: 2023-11-07 20:48:06

img

Der Zweck dieses Artikels ist es, einige Erfahrungen in der Strategieentwicklung sowie einige Tipps zu beschreiben, die es den Lesern ermöglichen, den Schlüsselpunkt der Handelsstrategieentwicklung schnell zu erfassen.

Wenn Sie ähnliche Details bei der Planung einer Strategie finden, können Sie sofort eine vernünftige Lösung finden.

Wir verwenden die FMZ Quant-Plattform als Beispiel für Erläuterungen, Tests und Übungen.

Strategie Programmiersprache werden wir JavaScript verwenden

Für das Handelsziel nehmen wir den Blockchain-Asset-Markt (BTC, ETH usw.) als unser Objekt

Datenerfassung und -verarbeitung

In der Regel, abhängig von der Strategie Logik, kann es die folgenden verschiedenen Schnittstellen verwenden, um Marktdaten zu erhalten, die meisten Strategie Logiken werden von Marktdaten angetrieben (natürlich sind einige Strategien nicht kümmern sich um die Preisdaten, wie eine feste Anlagestrategie).

  • GetTicker: Erhalten Sie Echtzeit-Zitate. Im Allgemeinen verwendet, um schnell den aktuellen letzten Preis zu erhalten, Kauf 1 Preis, Verkauf 1 Preis.

  • Erhalten Sie die Bestelltiefe des Bestellbuchs. Im Allgemeinen verwendet, um den Preis für jede Schicht der Orderbuchtiefe und die Größe der ausstehenden Aufträge zu erhalten.

  • GetTrade: Erhalten Sie die neuesten Transaktionsdaten des Marktes. Im Allgemeinen verwendet, um Marktverhalten in einem kurzen Zeitzyklus zu analysieren und mikroskopische Veränderungen auf dem Markt zu analysieren.

  • GetRecords: Erhalten Sie Markt-K-Line-Daten. Normalerweise für Trendverfolgungsstrategien und zur Berechnung von Indikatoren verwendet.

Fehlertoleranz

Bei der Gestaltung der Strategie ignoriert der Anfänger in der Regel die verschiedenen Fehler und glaubt intuitiv, dass die Ergebnisse jedes Teils der Strategie festgelegt sind.

Einige Marktschnittstellen geben beispielsweise nicht ausgeführte Daten zurück:

var depth = exchange.GetDepth()

// depth.Asks[0].Price < depth.Bids[0].Price "Selling 1" price is lower than "buying 1" price, this situation cannot exist on the market.
// Because the selling price is lower than the buying price, the order must have been executed.
// depth.Bids[n].Amount = 0 Order book buying list "nth" layer, order quantity is 0
// depth.Asks[m].Price = 0 Order book selling list "mth" layer, the order price is 0

Oder direkt exchange.GetDepth() gibt einen Nullwert zurück.

Es gibt viele solche seltsamen Situationen. Daher ist es notwendig, mit diesen vorhersehbaren Problemen umzugehen.

Normalerweise wird mit Fehlern umgehen, indem man Daten wegwirft und wieder aufnimmt.

Zum Beispiel:

function main () {
     while (true) {
         onTick()
         Sleep(500)
     }
}

function GetTicker () {
     while (true) {
         var ticker = exchange.GetTicker()
         if (ticker.Sell > ticker.Buy) { // Take the example of fault-tolerant processing that detects whether the "Selling 1" price is less than the "Buying 1" price.
                                               // Exclude this error, the current function returns "ticker".
             Return ticker
         }
         Sleep(500)
     }
}

function onTick () {
     var ticker = GetTicker() // Make sure the "ticker" you get doesn't exist the situation that "Selling 1" price is less than the "Buying 1" price.
     // ... specific strategy logic
}

Ein ähnlicher Ansatz kann für andere vorhersehbare fehlertolerante Verfahren angewendet werden.

Das Designprinzip ist, dass man niemals die falsche Logik benutzen kann, um die Strategie zu lenken.

Verwendung von K-Liniendaten

K-Linien-Datenerfassung, Anruf:

var r = exchange.GetRecords()

Die erhaltenen K-Liniendaten sind ein Array wie folgt:

[
    {"Time":1562068800000,"Open":10000.7,"High":10208.9,"Low":9942.4,"Close":10058.8,"Volume":6281.887000000001},
    {"Time":1562072400000,"Open":10058.6,"High":10154.4,"Low":9914.5,"Close":9990.7,"Volume":4322.099},
    ...
    {"Time":1562079600000,"Open":10535.1,"High":10654.6,"Low":10383.6,"Close":10630.7,"Volume":5163.484000000004}
]

Sie können sehen, dass jede lockige Klammer Zeit, Eröffnungspreis, höchsten Preis, niedrigsten Preis, Schließpreis und Volumen enthält.

Dies ist ein K-Linienbalken. Allgemeine K-Liniendaten werden zur Berechnung von Indikatoren wie gleitenden Durchschnitten, MACD usw. verwendet.

Die K-Liniendaten werden als Parameter (Rohstoffdaten) übergeben, und dann werden die Indikatorparameter so eingestellt, dass die Funktion der Indikatordaten berechnet wird, die wir Indikatorfunktion nennen.

Auf der quantitativen Handelsplattform FMZ Quant gibt es viele Indikatorfunktionen.

Zum Beispiel berechnen wir den gleitenden Durchschnittsindikator. Gemäß dem Zyklus der übergebenen K-Liniendaten berechnen wir den gleitenden Durchschnitt des entsprechenden Zyklus.

Zum Beispiel berechnet die passierende K-Liniendaten (eine K-Linienbalke repräsentiert einen Tag), die tägliche Durchschnittslinie, dasselbe, wenn die K-Liniendaten der passierenden Durchschnittsindikatorfunktion ein 1-Stunden-Zyklus sind, dann ist der berechnete Indikator der 1-Stunden- gleitende Durchschnitt.

Wenn ich den 5-tägigen gleitenden Durchschnittsindikator berechnen will, dann bereiten wir zuerst die täglichen K-Liniendaten vor:

var r = exchange.GetRecords(PERIOD_D1) // Pass parameters to the "GetRecords" function "PERIOD_D1" specifies the day K line to be acquired.
                                       // Specific function using method can be seen at: https://www.fmz.com/api#GetRecords

Wenn wir den 5-tägigen gleitenden Durchschnitt berechnen wollen, müssen wir den Indikatorparameter der Indikatorfunktion auf 5 setzen.

var ma = TA.MA(r, 5) // "TA.MA()" is the indicator function used to calculate the moving average indicator. The first parameter sets the daily K-line data r just obtained.
                             // The second parameter is set to 5. The calculated 5-day moving average is the same as the other indicators.

Wir haben ein potenzielles Problem übersehen. Wenn die Anzahl der K-Linienbalken in den K-Liniendaten kleiner als 5 ist, was können wir tun, um einen gültigen gleitenden 5-Tage-Durchschnitt zu berechnen?

Die Antwort ist, dass du nichts tun kannst.

Denn der gleitende Durchschnittsindikator ist der Durchschnitt der Schlusskurse einer bestimmten Anzahl von K-Linienbalken.

img

Vor der Verwendung der K-Liniendaten und der Indikatorfunktion zur Berechnung der Indikatordaten ist daher festzustellen, ob die Anzahl der K-Linienbalken in den K-Liniendaten die Bedingungen für die Indikatorberechnung (Indikatorparameter) erfüllt.

Bevor Sie also den 5-Tage- gleitenden Durchschnitt berechnen, müssen Sie ihn zuerst überprüfen.

function CalcMA () {
     var r = _C(exchange.GetRecords, PERIOD_D1) // _C() is a fault-tolerant function, the purpose is to avoid r being null, you can get more information at: https://www.fmz.com/api#_C
     if (r.length > 5) {
         Return TA.MA(r, 5) // Calculate the moving average data with the moving average indicator function "TA.MA", return it as a function return value.
     }

     Return false
}

function main () {
     var ma = CalcMA()
     Log(ma)
}

img

Anzeige des Rücktests:

[null,null,null,null,4228.7,4402.9400000000005, ... ]

Sie können den berechneten 5-tägigen gleitenden Durchschnittsindikator sehen. Die ersten vier sind null, weil die Anzahl der K-Linienbalken kleiner als 5 ist und der Durchschnitt nicht berechnet werden kann.

Tipps zum Beurteilen der K-Line-Updates

Wenn wir die Strategie schreiben, haben wir oft ein solches Szenario, wie die Strategie, die einige Operationen verarbeiten muss, wenn jeder K-Linie-Zyklus abgeschlossen ist, oder einige Protokolle drucken.

Wie implementieren wir solche Funktionen? Für Anfänger, die keine Programmiererfahrung haben, kann es ein problematisches Problem sein. Hier geben wir Ihnen die Lösungen.

Wie beurteilen wir, ob ein K-Linien-Barzyklus abgeschlossen ist. Wir können mit dem Zeitattribut in den K-Liniendaten beginnen. Jedes Mal, wenn wir die K-Liniendaten erhalten, beurteilen wir, ob sich das Zeitattribut der letzten K-Linien-Bar dieser K-Liniendaten ändert oder nicht. Wenn es geändert wird, bedeutet dies, dass eine neue K-Linien-Bar generiert wurde (was beweist, dass der vorherige K-Linien-Barzyklus der neu generierten K-Linien-Bar abgeschlossen ist), wenn es keine Änderung gibt, bedeutet dies, dass keine neue K-Linien-Bar generiert wird (der aktuelle letzte K-Linien-Barzyklus ist noch nicht abgeschlossen).

Also brauchen wir eine Variable, um die Zeit der letzten K-Linienbalke der K-Liniendaten aufzuzeichnen.

var r = exchange.GetRecords()
var lastTime = r[r.length - 1].Time // "lastTime" used to record the last K-line bar time.

In der Praxis ist dies in der Regel der Fall:

function main () {
     var lastTime = 0
     while (true) {
         var r = _C(exchange.GetRecords)
         if (r[r.length - 1].Time != lastTime) {
             Log ("New K-line bar generated")
             lastTime = r[r.length - 1].Time // Be sure to update "lastTime", this is crucial.

             // ... other processing logic
             // ...
         }

         Sleep(500)
     }
}

img

Sie können sehen, dass im Backtest der K-Linienzyklus auf den täglichen Satz gesetzt wird (der Parameter wird nicht angegeben, wenn derexchange.GetRecordsWenn die neue K-Line-Bar erscheint, druckt sie ein Protokoll.

Berechnungen des Zahlenwerts

  • Berechnen Sie die Zeit für den Zugriff auf die Austauschoberfläche

Wenn Sie eine bestimmte Anzeige oder Kontrolle über die Zeit haben möchten, die für die Strategie benötigt wird, um auf die Schnittstelle der Börse zuzugreifen, können Sie den folgenden Code verwenden:

function main () {
     while (true) {
         var beginTime = new Date().getTime()
         var ticker = exchange.GetTicker()
         var endTime = new Date().getTime()

         LogStatus(_D(), "GetTicker() function time-consuming:", endTime - beginTime, "millisecond")
         Sleep(1000)
     }
}

Einfach ausgedrückt, der Zeitstempel, der nach dem Anrufen derGetTickerDie Funktion wird vom Zeitstempel vor dem Anruf abgezogen und die Anzahl der erlebten Millisekunden berechnet, d. h. die Zeit, die derGetTickerFunktion von der Ausführung bis zur Rückgabe.

  • Verwenden Sie Math.min / Math.max, um die oberen und unteren Grenzen des Wertes zu begrenzen

Zum Beispiel darf der Betrag des Verkaufsorders beim Auftragen eines Verkaufsorders nicht größer sein als die Anzahl der Münzen auf dem Konto. Denn wenn es mehr ist als die Anzahl der auf dem Konto verfügbaren Münzen, wird die Reihenfolge Fehler verursachen.

Wir steuern es so:

Zum Beispiel planen wir, kurz zu verkaufen 0,2 Münzen.

var planAmount = 0.2
var account = _C(exchange.GetAccount)
var amount = Math.min(account.Stocks, planAmount)

Dadurch wird sichergestellt, dass die Anzahl der auf dem Konto verfügbaren Münzen nicht übersteigt.

Aus demselben Grund,Math.maxwird verwendet, um die untere Grenze eines Wertes sicherzustellen.

  • Auf welche Art von Szene bezieht sich das gewöhnlich?

Im Allgemeinen hat ein normaler Austausch ein Mindestlimit für den Versand von Bestellungen für bestimmte Handelspare. Wenn es unter dem Mindestbetrag liegt, wird die Bestellung abgelehnt. Dies führt auch zum Ausfall des Programms.

Unter der Annahme, dass der BTC normalerweise eine Mindestbestellmenge von 0,01 hat.

Handelsstrategien können manchmal zu weniger als 0,01 Bestellmengen führen, so dass wir verwenden könnenMath.maxum die Mindestbestellmenge zu gewährleisten.

  • Bestellmenge, Präzisionskontrolle der Preise

Die Präzision kann mit Hilfe der_N()Funktion oderSetPrecision function.

DieSetPrecision()Die Funktion muss nur einmal eingestellt werden, und die Anzahl der Dezimalstellen in der Bestellmenge und im Preiswert wird automatisch im System abgeschnitten.

Die_N()Die Funktion besteht darin, für einen bestimmten Wert einen Dezimalpunkt zu verkürzen (Genauigkeitskontrolle).

Zum Beispiel:

var pi = _N(3.141592653, 2)
Log(pi)

Der Wert von pi wird durch den Dezimalpunkt abgeschnitten und 2 Dezimalpunkte sind reserviert, das ist: 3.14

Siehe API-Dokumentation für weitere Informationen.

Einige logische Einstellungen

  • Zeitplanung, Durchführung bestimmter Operationen für einen bestimmten Zeitraum

Sie können einen solchen Mechanismus verwenden, um die Zeitstempel-Erkennungsmethode zu verwenden, um den aktuellen Zeitstempel abzüglich des Zeitstempels des letzten Males zu bestimmen, als die geplante Aufgabe ausgeführt wurde, und die vergangene Zeit in Echtzeit zu berechnen. Wenn die vergangene Zeit eine bestimmte festgelegte Zeit überschreitet. Danach wird eine neue Operation durchgeführt.

Zum Beispiel in einer Anlagestrategie für feste Anlagen.

var lastActTime = 0
var waitTime = 1000 * 60 * 60 * 12 // number of milliseconds a day
function main () {
     while (true) {
         var nowTime = new Date().getTime()
         if (nowTime - lastActTime > waitTime) {
             Log ("Execution Fixed")
             // ... specific fixed investment operation, buying operation.


             lastActTime = nowTime
         }

         Sleep(500)
     }
}

Das ist ein einfaches Beispiel.

  • Entwurf eines automatischen Wiederaufnahmemechanismus für die Strategie

Verwendung des FMZ-Quants_G()Wenn Sie die Speicherfunktion verlassen, ist es praktisch, eine Strategie zu entwickeln, um den Speicherfortschritt zu beenden und den automatischen Wiederherstellungszustand neu zu starten.

var hold = {
     Price : 0,
     Amount : 0,
}

function main () {
     if (_G("hold")) {
         var ret = _G("hold")
         hold.price = ret.price
         hold.amount = ret.amount
         Log("restore hold:", hold)
     }

     var count = 1
     while (true) {
         // ... strategy logic
         // ... In the strategy operation, it is possible that when opening a position, then assign the position price of the open position to "hold.price", and the amount of open positions is assigned to "hold.amount" to record the position information.

         hold.price = count++ // simulate some values
         hold.amount = count/10 // Simulate some values

         Sleep(500)
     }
}

function onexit () { // Click the stop button on the robot to trigger the execution of this function. After the execution, the robot stops.
     _G("hold", hold)
     Log("save hold:", JSON.stringify(hold))
}

img

Es ist zu sehen, daß die Daten in derholdObjekt wird jedes Mal gespeichert, wenn der Roboter angehalten wird. und wenn jedes Mal die Daten neu gestartet werden, werden die Daten gelesen und der Wert derholdwird wieder in den Zustand vor dem Stopp gebracht.

Natürlich ist das obige ein einfaches Beispiel. Wenn es in einer tatsächlichen Handelsstrategie verwendet wird, sollte es entsprechend den Schlüsseldaten, die in der Strategie wiederhergestellt werden müssen (im Allgemeinen sind Kontoinformationen, Position, Gewinnwert, Handelsrichtung usw.) konzipiert werden.

Darüber hinaus können Sie auch einige andere Bedingungen festlegen, um wiederherzustellen.

Dies sind einige Tipps für die Entwicklung einer Handelsstrategie, und ich hoffe, es könnte Anfängern helfen!

Praxis-Training ist der schnellste Weg, sich zu verbessern! Ich wünsche euch allen viel Glück.


Verwandt

Mehr