Применение функции "__Thread" в дизайне стратегии JavaScript

Автор:Лидия., Создано: 2023-07-07 13:56:17, Обновлено: 2023-09-18 19:31:40

img

Применение функции __Thread в дизайне стратегии JavaScript

В первоначальном дизайне стратегии FMZ, если требуются асинхронные одновременные операции,exchange.Go()Функция может использоваться только для достижения одновременного выполнения FMZ-инкапсулированного интерфейса, и одновременное выполнение некоторых пользовательских операций (функций) невозможно.

Даже новые студенты, которые используют FMZ для вводного количественного трейдинга, могут не понимать использованияexchange.Go()Использованиеexchange.Go()В этой статье мы рассмотрим использование недавно добавленной функциональности параллельных потоков в платформе FMZ:__Thread()и другие связанные функции, а также асинхронное проектирование стратегических программ.

1. Простой параллельный дизайн

Если мы хотим, чтобы основная нить стратегии работала одновременно с подниткой, выполняющей выполненную нами пользовательскую функцию, мы можем использовать дизайн, похожий на следующий код.GetTickerAsync()Эта функция выполняет бесконечную петлю и непрерывно вызывает интерфейс FMZ APIGetTicker()для получения данных о рынке.

Тогда используйте утверждение__threadSetData(0, "ticker", t)чтобы записать данные в основную нить.tickerи значение данныхt, что является возвращаемым значениемGetTicker().

__threadSetData(0, "ticker", t)

После разработки пользовательской функции для одновременного выполнения потока, мы можем написать код вmain()В началеmain()функция, мы используем:

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

Создать параллельную нить, которая начнет выполнятьGetTickerAsync()Затем,main()Функция начинает выполнять свою собственнуюwhileцикл, в котором он получает обновленные данныеGetTickerAsync()Функционирует и печатает:

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

Полный пример кода:

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

Тест на прямую торговлю:

img

Это один из самых простых дизайнов приложений, так что давайте посмотрим на некоторые другие требования дизайн.

2. Конструкция одновременного размещения заказов

Мы можем спроектировать функцию для создания 10 потоков одновременно, каждый из которых выполняет функцию размещения заказов.main()функция, мы можем спроектироватьwhileкогда мы получаем команду взаимодействияplaceMultipleOrders, мы называем функцию одновременного размещения заказовtestPlaceMultipleOrders().

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

Добавьте дизайн взаимодействия стратегии на странице редактирования стратегии, добавив кнопку с командой: placeMultipleOrders.

img

Полный пример кода:

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)
    }
}
  • Тест принимает ожидающие ордера, увеличиваясь с 80% до 90% текущей цены, в моделируемой торговой среде.

После нажатия кнопки placeMultipleOrders появляется сообщение: команда placeMultipleOrders была отправлена успешно, пожалуйста, ждите ответа от торгового центра!

  • Журнал стратегии отображает одновременные операции размещения заказов:

img

3. Создать соединение WebSocket в одновременной функции выполнения потока

Это требование было поднято пользователем FMZ, который хочет простой пример, демонстрирующий, как использоватьВеб-сокетсоединение в одновременных потоков и как передать данные наmain()Функция в основной нить.

На самом деле, это довольно просто и похоже на создание одновременных потоков в предыдущих примерах.__threadPeekMessage()и__threadPostMessage()В следующем примере показано, как уведомить одновременную нить об остановке.

Полный пример кода:

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

Во время тестирования торговли в режиме реального времени, мы можем видеть, чтоmain()функция непрерывно получает данные рынка от соединений WebSocket, созданных одновременными потоками.

При остановке стратегии ведения торговли функция финализации начнет работать.


Связанные

Больше