Der Zweck dieses Artikels ist es, einige Erfahrungen in der Strategieentwicklung zu erzählen, sowie kleine Tipps, die den Lesern eine schnelle Einsicht in die Entwicklung von Handelsstrategien geben. Wenn man auf ähnliche Detailprobleme bei der Strategieentwicklung trifft, kann man sofort eine vernünftige Lösung finden. Es wird eine Plattform zur Erzählung, zum Testen und zum Üben von Quantitative Trading Plattformen verwendet. Strategische Programmiersprache: JavaScript Handelsmärkte: Blockchain-Assetmärkte (BTC, ETH usw.)
Es ist möglich, Marktdaten anhand von folgenden verschiedenen Interfaces zu erhalten, da die Handelslogik der üblichen Strategien von Marktdaten angetrieben wird (aber natürlich gibt es auch Strategien, die unabhängig von den Märkten sind, z. B. die Platzierung).
GetTicker: Erhalten Sie Echtzeit-Tick-Markt. Es wird in der Regel verwendet, um schnell auf die aktuellsten Preise zuzugreifen, einen Preis zu kaufen, einen Preis zu verkaufen.
GetDepth: Erhalten Sie tiefe Bestellungen. Es wird in der Regel verwendet, um die Preise für jede Reihe, die Menge der Bestellungen und die Anzahl der Bestellungen zu erhalten. Sie werden für Hedging-Strategien, Marktstrategien usw. verwendet.
GetTrade: Zugang zu den letzten Transaktionen auf dem Markt. Es wird in der Regel verwendet, um Marktverhalten in kurzer Zeit zu analysieren und Mikro-Veränderungen des Marktes zu analysieren. Häufig verwendet für Hochfrequenzstrategien, Algorithmusstrategien.
GetRecords: Erhalten Sie K-Line-Daten über den Markt. Es wird häufig als Trend-Tracking-Strategien verwendet. Das ist ein Beispiel für die Berechnung der Indikatoren.
Bei der Konzeption von Strategien werden häufig Fehler ignoriert und die Ergebnisse der einzelnen Schritte der Strategie intuitiv als festgesetzt angesehen. In Wirklichkeit ist dies jedoch nicht der Fall. Bei der Durchführung von Strategien werden auch unerwartete Situationen beim Anfordern von Marktdaten auftreten. Einige Brancheninterfaces lieferten beispielsweise außergewöhnliche Daten:
var depth = exchange.GetDepth()
// depth.Asks[0].Price < depth.Bids[0].Price 卖一价格低于了买一价格,这种情况不可能存在于盘面上,
// 因为卖出的价格低于买入的价格,必定已经成交了。
// depth.Bids[n].Amount = 0 订单薄买入列表第n档,订单量为0
// depth.Asks[m].Price = 0 订单薄卖出列表第m档,订单价格为0
Oder direkt exchange.GetDepth ((() gibt einen null Wert zurück.
Es gibt viele seltsame Situationen wie diese. Es ist daher notwendig, diese vorhersehbaren Probleme entsprechend zu behandeln, und diese Art von Behandlung nennt sich Fehlerbehandlung.
Die übliche Art und Weise, Fehler zu beheben, ist, die Daten zu verwerfen und zurückzuholen.
Zum Beispiel:
function main () {
while (true) {
onTick()
Sleep(500)
}
}
function GetTicker () {
while (true) {
var ticker = exchange.GetTicker()
if (ticker.Sell > ticker.Buy) { // 以 检测卖一价格是不是小于买一价这个错误的容错处理为例,
// 排除这个错误,当前函数返回 ticker 。
return ticker
}
Sleep(500)
}
}
function onTick () {
var ticker = GetTicker() // 确保获取到的 ticker 不会存在 卖一价格小于买一价格这种数据错误的情况。
// ... 具体的策略逻辑
}
Andere, vorhersehbare Fehlerbehebungen können in ähnlicher Weise durchgeführt werden. Das Designprinzip lautet, dass falsche Daten niemals die strategische Logik lenken dürfen.
K-Line-Daten erhalten und aufrufen:
var r = exchange.GetRecords()
Die gewonnenen K-Linien-Daten sind eine Array, die zum Beispiel so aussieht:
[
{"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 jede Klammer sehen.{}
In der Mitte befinden sich: Zeit, Öffnungspreis, Höchstpreis, Höchstpreis, Tiefpreis, Schließpreis, Volumen.
Dies ist ein K-Linien-Säulen. Allgemeine K-Linien-Daten werden verwendet, um Indikatoren zu berechnen, z. B.: Durchschnittliche MA, MACD usw.
Die K-Liniendaten als Parameter eingeben (Rohdaten) und dann die Indikatorparameter setzen, um eine Funktion für die Indikatordaten zu berechnen, die wir als Indikatorfunktion bezeichnen.
Es gibt viele Indikatorfunktionen auf der Quantifizierungsplattform der Erfinder.
Zum Beispiel berechnen wir die Durchschnittsindikatoren, die je nach Periode der von uns übertragenen K-Daten unterschiedlich sind, um die Durchschnittslinie der entsprechenden Periode zu berechnen. Zum Beispiel, wenn die Daten der K-Tageslinie (ein K-Säule steht für einen Tag) übertragen werden, wird die Tagesmittellinie berechnet. Wenn die Daten der K-Tageslinie für die Indikatorfunktion der K-Tageslinie übertragen werden, sind die Indikatoren für die 1st-Stunden-Medaille berechnet.
Wenn ich einen 5-tägigen Durchschnittsindikator berechnen will, dann bereite ich zuerst die K-Tagesdaten vor:
var r = exchange.GetRecords(PERIOD_D1) // 给GetRecords 函数传入参数 PERIOD_D1就是指定获取日K线,
// 具体函数使用可以参看:https://www.fmz.com/api#GetRecords
Mit den K-Tage-Daten können wir den Mittelwert berechnen. Wenn wir den 5-Tage-Mittelwert berechnen wollen, dann müssen wir den Indikatorparameter der Indikatorfunktion auf 5 setzen.
var ma = TA.MA(r, 5) // TA.MA() 就是指标函数,用来计算均线指标,第一个参数设置刚才获取的日K线数据r,
// 第二个参数设置5,计算出来的就是5日均线,其它指标函数同理。
Wir haben ein potenzielles Problem übersehen, wenn die Anzahl der K-Säulen in den Daten der r-Tage-K-Linie weniger als 5 ist, was tun, um einen effektiven 5-Tage-Durchschnitt zu berechnen? Die Antwort lautet: Nein. Denn ein Mittelwert ist der Durchschnittswert des Schlusskurses für eine bestimmte Anzahl von K-Säulen.
Vor der Verwendung von K-Linien-Daten, die als Indikatorfunktionen berechnet werden, muss also entschieden werden, ob die Anzahl der K-Linien-Säulen in den K-Linien-Daten die Voraussetzungen für die Berechnung der Indikatoren erfüllt (Indikatorparameter).
Vor der Berechnung der 5-Tage-Durchschnittslinie ist es also wichtig zu beurteilen, dass der vollständige Code folgendermaßen lautet:
function CalcMA () {
var r = _C(exchange.GetRecords, PERIOD_D1) // _C() 是容错函数,目的就是避免 r 为 null , 具体可以查询文档:https://www.fmz.com/api#_C
if (r.length > 5) {
return TA.MA(r, 5) // 用均线指标函数 TA.MA 计算出均线数据,做为函数返回值,返回。
}
return false
}
function main () {
var ma = CalcMA()
Log(ma)
}
Die Ergebnisse zeigen: [null, null, null, null, 4228.7, 4402.9400000000005,... ]
Man kann sehen, dass die berechneten 5-tägigen Durchschnittswerte, die ersten 4 sind null, weil die Anzahl der K-Säulen unter 5 ist, nicht berechnet werden können.
Es gibt häufig Szenarien, in denen wir Strategien schreiben, in denen wir bei jedem K-Linienzyklus einige Operationen bearbeiten oder einige Logs drucken müssen. Wie können wir das erreichen? Für Anfänger ohne Programmiererfahrung, die vielleicht nicht wissen, mit welchem Mechanismus sie es zu tun haben, geben wir hier direkt Tipps.
Wir entscheiden, dass ein K-Säulenzyklus abgeschlossen ist, und wir können von der Zeitattribute aus den K-Säulendaten ausgehen, und jedes Mal, wenn wir eine K-Säulendaten erhalten, entscheiden wir, ob sich der Time-Wert in den Daten des letzten K-Säulenzyklus dieser K-Säulendaten geändert hat. Wenn dies der Fall ist, bedeutet dies, dass ein neuer K-Säulenzyklus erzeugt wird (belegt, dass der vorherige K-Säulenzyklus des neu erzeugten K-Säulens abgeschlossen ist), wenn nichts passiert, bedeutet dies, dass kein neuer K-Säulenzyklus erzeugt wird).
Also müssen wir eine Variable haben, um die Zeit der letzten K-Säule der K-Liniendaten zu erfassen.
var r = exchange.GetRecords()
var lastTime = r[r.length - 1].Time // lastTime 用来记录最后一根K线柱的时间。
In der Praxis ist die Struktur meistens wie folgt:
function main () {
var lastTime = 0
while (true) {
var r = _C(exchange.GetRecords)
if (r[r.length - 1].Time != lastTime) {
Log("新K线柱产生")
lastTime = r[r.length - 1].Time // 一定要更新 lastTime ,这个至关重要。
// ... 其它处理逻辑
// ...
}
Sleep(500)
}
}
Wie man sehen kann, ist der K-Zeilzyklus bei der Wiederholung als Tag eingestellt (exchange.GetRecords-Funktion gibt keine Parameter an, sondern als Standard-Parameter für die wiederholte K-Zeilzyklus). Jedes Mal, wenn ein neuer K-Zeilzyklus erscheint, wird ein Log gedruckt.
Wenn Sie eine bestimmte Anzeige oder Kontrolle über die Zeit, die die Schnittstellen der strategischen Börsen nutzen, haben möchten, 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() 函数耗时:", endTime - beginTime, "毫秒")
Sleep(1000)
}
}
Einfach ausgedrückt, wird der Zeitfenster, der nach dem Aufruf der GetTicker-Funktion aufgezeichnet wurde, minus der Zeitfenster, der vor dem Aufruf aufgezeichnet wurde, berechnet, um die Anzahl der Millisekunden zu berechnen, die die GetTicker-Funktion von der Ausführung bis zur Rückgabe der Ergebnisse benötigt.
Wenn ein Wert eine Obergrenze hat, wird die Math.min-Beschränkung verwendet.
Bei einem Verkaufsauftrag darf z. B. die Verkaufsmenge nicht größer sein als die Anzahl der Münzen auf dem Konto. Wenn die Anzahl der verfügbaren Münzen größer ist als die Anzahl der in einem Konto verfügbaren Münzen, wird eine Fehlermeldung gemacht.
Das ist normalerweise wie folgt: So ist beispielsweise geplant, einen Verkauf von 0.2 Münzen zu planen.
var planAmount = 0.2
var account = _C(exchange.GetAccount)
var amount = Math.min(account.Stocks, planAmount)
So wird sichergestellt, dass der Betrag, der für die Anforderung verwendet wird, die Anzahl der verfügbaren Münzen im Konto nicht übersteigt.
Ähnlich wird Math.max verwendet, um die Untergrenze eines Zahlenwerts zu sichern. Was für Szenarien wird das normalerweise angewendet? Im Allgemeinen haben die Börsen für bestimmte Paare eine Mindestaufnahmegröße, und wenn diese unterhalb dieser Mindestaufnahmegröße liegt, werden Aufträge abgelehnt. Auch diese Aufträge scheitern. Nehmen wir an, dass BTC normalerweise eine minimale Einheitsmenge von 0.01 hat. Es ist manchmal möglich, durch die Berechnung weniger als 0.01 Einheiten zu ergeben, so dass wir mit Math.max sicherstellen können, dass es die kleinste Einheit ist.
Die Präzisionskontrolle kann mit der _N(-Funktion oder der SetPrecision-Funktion durchgeführt werden.
Die SetPrecision-Funktion (() wird automatisch abgeschnitten, wenn die Anzahl der Einzelmengen und Preise überschüssig ist.
Die _N() -Funktion ist eine Funktion, bei der ein bestimmter Wert mit einer kleinen Zahl abgeschnitten wird (genauigkeitskontrolle).
Zum Beispiel:
var pi = _N(3.141592653, 2)
Log(pi)
Der Wert von pi wird durch eine kleine Zahl unterbrochen, wobei zwei kleine Stellen erhalten bleiben, also: 3.14
Weitere Informationen finden Sie in der API-Dokumentation.
Mit einem solchen Mechanismus kann der aktuelle Zeitrahmen abzüglich des Zeitrahmens des letzten Terminums der Ausführung einer Aufgabe mit der Methode der Zeitstrahmen-Detektion bestimmt werden.
Sie werden z.B. für Investitionsstrategien verwendet.
var lastActTime = 0
var waitTime = 1000 * 60 * 60 * 12 // 一天的毫秒数
function main () {
while (true) {
var nowTime = new Date().getTime()
if (nowTime - lastActTime > waitTime) {
Log("执行定投")
// ... 具体的定投操作,买入操作。
lastActTime = nowTime
}
Sleep(500)
}
}
Das ist ein einfaches Beispiel.
Mit der von den Erfindern quantifizierten _G() -Funktion und der Abbruch-Speicherfunktion ist es praktisch, eine Strategie zu entwerfen, um den Speicherfortschritt zu verlassen und die Funktion für 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("恢复 hold:", hold)
}
var count = 1
while (true) {
// ... 策略逻辑
// ... 策略运行中,可能开仓,交易,把开仓的持仓价格赋值给 hold.price ,开仓的数量赋值给 hold.amount,用以记录持仓信息。
hold.price = count++ // 模拟一些数值
hold.amount = count/10 // 模拟一些数值
Sleep(500)
}
}
function onexit () { // 点击机器人上的停止按钮,会触发执行这个函数,执行完毕机器人停止。
_G("hold", hold)
Log("保存 hold:", JSON.stringify(hold))
}
Man kann sehen, dass jedes Mal, wenn der Roboter gestoppt wird, die Daten im Hold-Objekt gespeichert werden, und jedes Mal, wenn er neu gestartet wird, die Daten gelesen werden, und der Wert des Holds wieder in den Zustand gebracht wird, in dem er vor dem Stoppen war. Dies ist natürlich ein einfaches Beispiel, wenn es in einer praktischen Strategie verwendet wird, sollte es nach den wichtigen Daten, die in der Strategie wiederhergestellt werden müssen, entworfen werden (in der Regel Informationen über Kontoinformationen, Haltungen, Gewinnwerte, Handelsrichtung usw.). Natürlich kann man auch Bedingungen setzen, ob es wiederhergestellt wird.
Hier sind einige wenige Tipps für die Entwicklung von Strategien, die für Anfänger und Entwickler hilfreich sein werden. Ich wünsche Ihnen viel Glück und viel Glück für die Zukunft.
Weix1aoDanke, dass du es mit mir geteilt hast. Es ist ideal für Anfänger, die nicht wissen, wie man API schreibt.
- Ich weiß nicht.Danke Drehmann! Drehmann-Lehrer, das ist wirklich ein ganzes Buch, die Programmiertechnik ist hoch, der Artikel ist gut geschrieben und bewundernswert!
Die Erfinder quantifizieren - Kleine TräumeHallo, es wird derzeit ES8-Standard unterstützt.
Die Erfinder quantifizieren - Kleine TräumeDanke für die Unterstützung von FMZ Quantity!