Bei der ursprünglichen Konzeption der FMZ-Strategie, wenn asynchrone gleichzeitige Operationen erforderlich sind, wird dieexchange.Go()
Funktion kann nur zur gleichzeitigen Ausführung der FMZ-verkapselten Schnittstelle verwendet werden, und es ist nicht möglich, einige benutzerdefinierte Operationen (Funktionen) gleichzeitig auszuführen. Obwohl dieses Design die Effizienz des Strategieprogramms erheblich verbessert, fühlen sich Studenten, die Erfahrung mit gleichzeitiger Ausführung in nativen Programmiersprachen haben, oft sehr unwohl.
Selbst neue Studenten, die FMZ für einführende quantitative Handelsmethoden verwenden, können die Verwendung desexchange.Go()
Funktionexchange.Go()
In diesem Artikel werden wir die Verwendung der neu hinzugefügten gleichzeitigen Thread-Funktionalität in der FMZ-Plattform untersuchen:__Thread()
und andere verwandte Funktionen sowie die asynchrone Gestaltung von Strategieprogrammen.
Wenn wir möchten, dass der Hauptthread der Strategie gleichzeitig mit einem Unterthread ausgeführt wird, der eine benutzerdefinierte Funktion ausführt, die wir geschrieben haben, können wir ein Design ähnlich dem folgenden Code verwenden.GetTickerAsync()
Diese Funktion führt eine unendliche Schleife aus und ruft kontinuierlich die FMZ API-SchnittstelleGetTicker()
Um Marktdaten abzurufen.
Dann benutzen Sie die Aussage__threadSetData(0, "ticker", t)
Der Datenname istticker
und der Datenwert istt
, was der Rückgabewert vonGetTicker()
.
__threadSetData(0, "ticker", t)
Nachdem wir die benutzerdefinierte Funktion für die gleichzeitige Ausführung von Threads entworfen haben, können wir den Code in diemain()
In den letzten Jahren hat sich die Zahl dermain()
Funktion, die wir verwenden:
__Thread(GetTickerAsync, 0) // GetTickerAsync is a custom function that needs to be executed concurrently, and 0 is the parameter that is passed to the GetTickerAsync function.
Erstellen Sie einen gleichzeitigen Thread, der die Ausführung desGetTickerAsync()
Diemain()
Funktion beginnt die Ausführung seiner eigenenwhile
Schleife, in der sie die von derGetTickerAsync()
Funktion und druckt es aus:
var t = __threadGetData(0, "ticker")
Log(t)
Beispiel für den vollständigen Code:
function GetTickerAsync(index) {
while (true) {
var t = exchanges[index].GetTicker()
__threadSetData(0, "ticker", t)
Sleep(500)
}
}
function main() {
__Thread(GetTickerAsync, 0)
while(true) {
var t = __threadGetData(0, "ticker")
Log(t)
Sleep(1000)
}
}
Live-Handelstest:
Dies ist eines der einfachsten Anwendungsdesigns, also schauen wir uns einige andere Anforderungendesigns an.
Wir können eine Funktion entwerfen, um 10 Threads gleichzeitig zu erstellen, von denen jeder eine Bestellfunktion ausführt.main()
Wir können eine Funktion entwerfen.while
Wenn wir den Interaktionsbefehl empfangenplaceMultipleOrders
, nennen wir die gleichzeitige BestellfunktiontestPlaceMultipleOrders()
.
if (cmd == "placeMultipleOrders") {
// ...
}
Fügen Sie das Strategieinteraktionsdesign auf der Strategiebearbeitungsseite hinzu, indem Sie eine Schaltfläche mit dem Befehl: placeMultipleOrders hinzufügen.
Beispiel für den vollständigen Code:
function placeOrder(exIndex, type, price, amount) {
var id = null
if (type == "Buy") {
id = exchanges[exIndex].Buy(price, amount)
} else if (type == "Sell") {
id = exchanges[exIndex].Sell(price, amount)
} else {
throw "type error! type:" + type
}
}
function testPlaceMultipleOrders(index, beginPrice, endPrice, step, type, amount) {
Log("beginPrice:", beginPrice, ", endPrice:", endPrice, ", step:", step, ", type:", type, ", amount:", amount)
var tids = []
for (var p = beginPrice; p <= endPrice; p += step) {
var tid = __Thread(placeOrder, index, type, p, amount)
tids.push(tid)
Sleep(10)
}
Sleep(1000)
for (var i = 0; i < tids.length; i++) {
__threadTerminate(tids[i])
}
}
function main() {
while(true) {
LogStatus(_D())
var cmd = GetCommand()
if (cmd) {
if (cmd == "placeMultipleOrders") {
var t = _C(exchange.GetTicker)
var beginPrice = t.Last * 0.8
var endPrice = t.Last * 0.9
var step = t.Last * 0.01
testPlaceMultipleOrders(0, beginPrice, endPrice, step, "Buy", 0.01)
var orders = exchange.GetOrders()
for (var i = 0; i < orders.length; i++) {
Log(orders[i])
}
}
}
Sleep(1000)
}
}
Nach dem Klicken auf die Schaltfläche
Diese Anforderung wurde von einem FMZ-Benutzer gestellt, der ein einfaches Beispiel für die Verwendung einesWebSocketAnschluss in gleichzeitigen Threads und wie Daten an diemain()
Funktion im Hauptfaden.
Eigentlich ist es ziemlich einfach und ähnlich wie das Erstellen von gleichzeitigen Threads in den vorherigen Beispielen.__threadPeekMessage()
und__threadPostMessage()
Wir müssen auch die Schließung der WebSocket-Verbindung verarbeiten. Das folgende Beispiel zeigt, wie man einen gleichzeitigen Thread zum Stoppen benachrichtigt.
Beispiel für den vollständigen Code:
var tid = null
function createWS() {
// wss://stream.binance.com:9443/ws/<streamName> , <symbol>@ticker
var stream = "wss://stream.binance.com:9443/ws/btcusdt@ticker"
var ws = Dial(stream)
Log("Create a WS connection:", stream)
while (true) {
var data = ws.read()
if (data) {
__threadPostMessage(0, data)
}
Log("receiving data pushed by the WS link, data:", data)
// __threadPeekMessage timeout parameter set to -1, no blocking
var msg = __threadPeekMessage(-1)
if (msg) {
if (msg == "stop") {
Log("Concurrent Thread Id:", __threadId(), "Received stop command")
break
}
}
}
Log("Concurrent threads finish execution, close ws connection")
ws.close()
}
function main() {
tid = __Thread(createWS)
Log("Create concurrent threads, thread Id:", tid)
while(true) {
// __threadPeekMessage's timeout parameter is set to 0, blocking for data
var data = __threadPeekMessage(0)
Log("Received from concurrent thread", ", Id:", tid, ", the data sent, data:", data, "#FF0000")
var tbl = {
type : "table",
title : "<symbol>@ticker channel push message",
cols : ["Event Type", "Event Time", "Trading Pairs", "24 Hour Price Change", "24 Hour Price Change %", "Average Price", "Last Traded Price", "Volume in 24 Hours", "Turnover in 24 Hours"],
rows : []
}
try {
data = JSON.parse(data)
tbl.rows.push([data.e, _D(data.E), data.s, data.p, data.P, data.w, data.c, data.v, data.q])
} catch (e) {
Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
}
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
}
}
function onexit() {
Log("Finalize function, send a stop command to the concurrent thread with ID ", tid,"")
__threadPostMessage(tid, "stop")
Log("Wait for the concurrent thread with ID ", tid, " to stop")
__threadJoin(tid)
Log("Finalize function execution completed")
}
Während des Live-Trading-Tests können wir sehen, dass diemain()
Funktion erhält kontinuierlich Marktdaten von WebSocket-Verbindungen, die von gleichzeitigen Threads erstellt werden.
Wenn die Live-Handelsstrategie gestoppt wird, wird die Finalisierungsfunktion funktionieren.