Na concepção inicial da estratégia FMZ, se forem necessárias operações simultâneas assíncronas, oexchange.Go()
Embora este design melhore muito a eficiência do programa de estratégia, os alunos que têm experiência em design simultâneo em linguagens de programação nativas muitas vezes se sentem muito desconfortáveis.
Mesmo os novos estudantes que usam o FMZ para negociação quantitativa introdutória podem não compreender o uso do FMZ para a negociação quantitativa.exchange.Go()
Função.exchange.Go()
Neste artigo, vamos explorar o uso da funcionalidade de thread simultâneo recém-adicionado na plataforma FMZ:__Thread()
e outras funções conexas, bem como a concepção assíncrona de programas estratégicos.
Se quisermos que o thread principal da estratégia seja executado simultaneamente com um sub-thread executando uma função personalizada que escrevemos, podemos usar um design semelhante ao seguinte código.GetTickerAsync()
Esta função executa um loop infinito e chama continuamente a interface FMZ APIGetTicker()
para obter dados de mercado.
Então, use a declaração__threadSetData(0, "ticker", t)
O nome dos dados éticker
e o valor dos dados ét
, que é o valor de retorno deGetTicker()
.
__threadSetData(0, "ticker", t)
Depois de projetar a função personalizada para execução de thread simultânea, podemos escrever o código nomain()
No início do período de transiçãomain()
função, usamos:
__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.
Crie um thread simultâneo que comece a executar oGetTickerAsync()
A funçãomain()
função começa a executar a sua própriawhile
O ciclo, no qual recebe os dados actualizados peloGetTickerAsync()
função e imprime-lo:
var t = __threadGetData(0, "ticker")
Log(t)
Exemplo de código completo:
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)
}
}
Teste de negociação ao vivo:
Este é um dos designs de aplicativos mais simples, então vamos olhar para alguns outros designs de requisitos.
Podemos projetar uma função para criar 10 tópicos simultaneamente, cada um executando uma função de colocação de pedidos.main()
função, podemos projetar umwhile
quando recebemos o comando de interaçãoplaceMultipleOrders
, chamamos a função de colocação de ordem simultâneatestPlaceMultipleOrders()
.
if (cmd == "placeMultipleOrders") {
// ...
}
Adicione o design de interação da estratégia na página de edição da estratégia adicionando um botão com o comando: placeMultipleOrders.
Exemplo de código completo:
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)
}
}
Após clicar no botão
Este requisito foi levantado por um utilizador de FMZ que quer um exemplo simples que demonstre como utilizar umWebSocketConexão em threads simultâneos e como passar dados para omain()
função no fio principal.
Na verdade, é bastante simples e semelhante à criação de tópicos simultâneos nos exemplos anteriores.__threadPeekMessage()
e__threadPostMessage()
Tomando a chamada WebSocket API para a troca Binance como exemplo, também precisamos lidar com a operação de fechamento da conexão WebSocket. O exemplo a seguir demonstra como notificar um thread concorrente para parar.
Exemplo de código completo:
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")
}
Durante os testes de negociação ao vivo, podemos ver que omain()
função recebe continuamente dados de mercado de conexões WebSocket criadas por threads concorrentes.
Ao parar a estratégia de negociação ao vivo, a função finalize começará a funcionar.