Aplicación de la función "__Thread" en el diseño de estrategias JavaScript

El autor:- ¿ Por qué?, Creado: 2023-07-07 13:56:17, Actualizado: 2023-09-18 19:31:40

img

Aplicación de la función __Thread en el diseño de estrategias JavaScript

En el diseño inicial de la estrategia FMZ, si se requieren operaciones asíncronas simultáneas, laexchange.Go()Aunque este diseño mejora en gran medida la eficiencia del programa de estrategia, los estudiantes que tienen experiencia en diseño concurrente en lenguajes de programación nativos a menudo se sienten muy incómodos.

Incluso los nuevos estudiantes que utilizan FMZ para la introducción al comercio cuantitativo pueden no entender el uso de laexchange.Go()El uso deexchange.Go()En este artículo, exploraremos el uso de la funcionalidad de hilo concurrente recientemente agregada en la plataforma FMZ:__Thread()y otras funciones relacionadas, así como el diseño asincrónico de programas de estrategia.

1. Diseño simultáneo simple

Si queremos que el hilo principal de la estrategia se ejecute simultáneamente con un sub- hilo ejecutando una función personalizada que hemos escrito, podemos usar un diseño similar al siguiente código.GetTickerAsync()Esta función ejecuta un bucle infinito y llama continuamente a la interfaz FMZ APIGetTicker()para obtener datos de mercado.

Entonces, usa la declaración__threadSetData(0, "ticker", t)El nombre de los datos estickery el valor de los datos est, que es el valor de retorno deGetTicker().

__threadSetData(0, "ticker", t)

Después de diseñar la función personalizada para la ejecución simultánea de hilos, podemos escribir el código en elmain()En el comienzo de lamain()función, 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.

Crear un hilo concurrente que comience a ejecutar elGetTickerAsync()En el caso de lasmain()La función comienza a ejecutar su propiawhileEn el circuito, en el que recibe los datos actualizadosGetTickerAsync()Funciona y lo imprime:

var t = __threadGetData(0, "ticker")
Log(t)

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

Prueba de negociación en vivo:

img

Este es uno de los diseños de aplicaciones más simples, así que vamos a ver algunos otros diseños de requisitos.

2. Diseño de la colocación de pedidos simultáneos

Podemos diseñar una función para crear 10 hilos simultáneamente, cada uno ejecutando una función de orden.main()Función, podemos diseñar unwhilecuando recibimos el comando de interacciónplaceMultipleOrders, llamamos a la función de colocación de órdenes concurrentestestPlaceMultipleOrders().

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

Añadir diseño de interacción de la estrategia en la página de edición de la estrategia mediante la adición de un botón con el comando: placeMultipleOrders.

img

Ejemplo 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)
    }
}
  • La prueba adopta órdenes pendientes, aumentando del 80% al 90% del precio actual, en un entorno de negociación simulado.

Después de hacer clic en el botón placeMultipleOrders, aparece un mensaje: El comando placeMultipleOrders fue enviado con éxito, por favor espere una respuesta del comercio en vivo!

  • El registro de estrategias muestra las operaciones de colocación de pedidos simultáneas:

img

Crear una conexión WebSocket en una función de ejecución de hilo concurrente

Este requisito fue planteado por un usuario de FMZ que desea un ejemplo simple que demuestre cómo utilizar unWebSocket y el sistema operativoconexión en hilos concurrentes y cómo transmitir datos a lamain()función en el hilo principal.

En realidad, es bastante simple y similar a la creación de hilos concurrentes en los ejemplos anteriores.__threadPeekMessage()y__threadPostMessage()Tomando la llamada WebSocket API para el intercambio Binance como ejemplo, también necesitamos manejar la operación de cierre de la conexión WebSocket. El siguiente ejemplo demuestra cómo notificar a un hilo concurrente para detenerse.

Ejemplo 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 las pruebas de comercio en vivo, podemos ver que elmain()La función recibe continuamente datos de mercado de las conexiones WebSocket creadas por hilos concurrentes.

Al detener la estrategia de negociación en vivo, la función de finalización comenzará a funcionar.


Relacionados

Más.