Aplicação da função _Thread no design da política JavaScript

Autora:Sonhos pequenos, Criado: 2023-07-04 16:35:42, Atualizado: 2023-09-18 19:32:51

img

Aplicação da função _Thread no design da política JavaScript

No projeto original da política FMZ, as operações de sincronia não-sincronizada só podiam ser usadas se fosse necessário.exchange.Go()A função para realizar a concomitância da interface de envelopamento FMZ não pode executar algumas operações personalizadas (funções) simultaneamente. Embora esse design faça com que o programa de estratégia seja executado de forma muito mais eficiente, os alunos que já tiveram experiência com o design de concomitância em linguagens nativas não estão acostumados com a sensação geral.

Até mesmo os novos alunos que usam o FMZ para transações quantitativas de entrada não entendem.exchange.Go()Funções usadasexchange.Go()Parece que ainda há uma execução de uma frase por outra no código executado em sequência. Então, neste artigo, vamos explorar a nova função de thread de concomitância da plataforma FMZ:__Thread()O uso de funções de série, por exemplo, é desenhado de forma asynchronous com o programa de estratégia.

1o, simples design paralelo

Se quisermos executar um thread principal da política ao mesmo tempo que executamos um sub-thread para executar a função customizada que escrevemos, podemos usar um design semelhante ao seguinte código.GetTickerAsync()A função executa um ciclo morto, em que a função é executada em um ciclo morto.whileA interface API do FMZ, que está sempre a ligar para o circuito:GetTicker()O Facebook é um dos principais meios de comunicação do mundo.

E depois usá-lo novamente.__threadSetData(0, "ticker", t)A frase escreve um dado para a linha principal, que é chamado de nome de dados.tickerO valor de dados étOu seja,GetTicker()O valor de retorno de.

__threadSetData(0, "ticker", t)

Depois de concebermos funções personalizadas para serem executadas em simultâneo, podemos escrevermain()Então, o código da função está nomain()Para começar a função, usamos:

__Thread(GetTickerAsync, 0)   // GetTickerAsync为需要并发执行的自定义函数,0为这个传入GetTickerAsync函数的参数

Criamos um thread paralelo que começa a executar.GetTickerAsync()Funções.main()A função começa a executar a sua própria função.whileO ciclo, recebido no cicloGetTickerAsync()A função atualiza os dados e imprime:

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)
    }
}

Testes em disco real:

img

Este é um dos mais simples projetos de aplicativos, e vamos ver em seguida alguns outros projetos de demanda.

2o, distribuição simultânea

Uma função pode ser projetada para criar 10 threads simultaneamente, cada um executando uma função de subordinação.main()Desenhe uma funçãowhileO ciclo, a detecção da política, as instruções de interação.placeMultipleOrdersEntão, se você quer que a função funcione de uma maneira diferente, você pode usar a função função de uma forma diferente.testPlaceMultipleOrders()

if (cmd == "placeMultipleOrders") {
    // ...
}

Adicione o design interativo da política na página de edição da política, configure 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)
    }
}
  • Testar usando o modo pendente, incrementando de 80% a 90% do preço atual, usando o teste de ambiente de disco analógico, clicando no botão interativo para desencadear o teste:

    img

  • O botão "placeMultipleOrders" é clicado e a mensagem é sugerida:

    img

  • O log da estratégia mostra a seguinte operação em simultâneo:

    img

3. Crie uma conexão WebSocket em funções executadas em linhas paralelas

Esta exigência foi feita por um usuário do FMZ, que esperava um exemplo simples para demonstrar como usar em linhas paralelas.WebSocketA partir de então, a rede de computadores foi criada para fornecer uma rede de computadores de computadores de computadores de computadores de computadores.main()Função.

É muito simples, como o exemplo anterior, criar fios em simultâneo.__threadPeekMessage()Funções e__threadPostMessage()Função. Como exemplo da chamada da API do WebSocket da Bitcoin Exchange, também precisamos prestar atenção no design para a operação de fechamento da conexão do WebSocket. O exemplo a seguir também mostra como notificar um fio paralelo e fazê-lo 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("创建WS连接:", stream)
    
    while (true) {
        var data = ws.read()
        if (data) {            
            __threadPostMessage(0, data)
        }
        Log("接收到WS链接推送的数据,data:", data)
        
        // __threadPeekMessage 超时参数设置-1,不阻塞
        var msg = __threadPeekMessage(-1)
        if (msg) {
            if (msg == "stop") {
                Log("并发线程Id:", __threadId(), "接收到stop指令")
                break
            }
        }
    }

    Log("并发线程执行完毕,关闭ws连接")
    ws.close()
}

function main() {
    tid = __Thread(createWS)
    Log("创建并发线程,线程Id:", tid)

    while(true) {
        // __threadPeekMessage 的超时参数设置为0,阻塞等待数据
        var data = __threadPeekMessage(0)
        Log("接收到并发线程", ", Id:", tid, ", 发送的数据,data:", data, "#FF0000")
        
        var tbl = {
            type : "table", 
            title : "<symbol>@ticker频道推送消息",
            cols : ["事件类型", "事件时间", "交易对", "24小时价格变化", "24小时价格变化百分比", "平均价格", "最新成交价格", "24小时内成交量", "24小时内成交额"],
            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("扫尾函数,向Id为", tid, "的并发线程发送stop指令")
    __threadPostMessage(tid, "stop")
    Log("等待Id为", tid, "的并发线程停止")
    __threadJoin(tid)
    Log("扫尾函数执行完毕")
}

Testes em disco real:

img

É possível vermain()A função recebe continuamente dados de transação recebidos a partir de conexões WebSocket criadas em simultâneo.

Quando a política é interrompida no disco real, a função de varredura começa a funcionar:

img


Relacionados

Mais.

Esparda joga quantidadeUm último exemplo, se houver um monte de threads ws e subscrever vários tópicos, qual é o melhor desempenho para a comunicação entre os threads usando o get/set ou o peek/post?

Esparda joga quantidadeA implementação básica das variáveis compartilhadas entre os threads é que não suporta referências de variáveis, que precisam ser reiniciadas a cada atualização, o que é muito pouco eficiente.

Sonhos pequenosA partir daí, o blogueiro e o blogueiro se tornaram amigos.