Aplicação da função "__Thread" no projeto de estratégia JavaScript

Autora:Lydia., Criado: 2023-07-07 13:56:17, Atualizado: 2023-09-18 19:31:40

img

Aplicação da função __Thread no projeto de estratégia JavaScript

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.

1. Design simultâneo simples

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 étickere 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ópriawhileO 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:

img

Este é um dos designs de aplicativos mais simples, então vamos olhar para alguns outros designs de requisitos.

2. Projeto de colocação simultânea de pedidos

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 umwhilequando 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.

img

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)
    }
}
  • O teste adota ordens pendentes, aumentando de 80% para 90% do preço atual, em um ambiente de negociação simulado.

Após clicar no botão placeMultipleOrders, aparece uma mensagem: O comando placeMultipleOrders foi enviado com êxito, espere uma resposta da negociação ao vivo!

  • O log da estratégia exibe as operações de colocação de ordens simultâneas:

img

3. Crie uma conexão WebSocket em uma função de execução de thread simultânea

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.


Relacionados

Mais.