Les ressources ont été chargées... Je charge...

Application de la fonction "__Thread" dans la conception de stratégie JavaScript

Auteur:FMZ~Lydia, Créé à: 2023-07-07 13:56:17, Mis à jour à: 2024-11-11 22:42:27

img

Application de la fonction __Thread dans la conception de stratégie JavaScript

Dans la conception initiale de la stratégie FMZ, si des opérations asynchrones simultanées sont requises, leexchange.Go()Cette fonction ne peut être utilisée que pour obtenir l'exécution simultanée de l'interface encapsulée FMZ, et il n'est pas possible d'exécuter simultanément certaines opérations personnalisées (fonctions). Bien que cette conception améliore considérablement l'efficacité du programme de stratégie, les étudiants qui ont une expérience dans la conception simultanée dans les langages de programmation natifs se sentent souvent très mal à l'aise.

Même les nouveaux étudiants qui utilisent FMZ pour la négociation quantitative d'introduction peuvent ne pas comprendre l'utilisation de laexchange.Go()fonction.exchange.Go()Dans cet article, nous allons explorer l'utilisation de la fonctionnalité de thread concurrent nouvellement ajoutée dans la plateforme FMZ:__Thread()et autres fonctions connexes, ainsi que la conception asynchrone des programmes stratégiques.

1. conception simultanée simple

Si nous voulons que le fil principal de la stratégie s'exécute simultanément avec un sous-fil exécutant une fonction personnalisée que nous avons écrite, nous pouvons utiliser une conception similaire au code suivant.GetTickerAsync()Cette fonction exécute une boucle infinie et appelle continuellement l'interface FMZ APIGetTicker()pour récupérer des données de marché.

Ensuite, utilisez la déclaration__threadSetData(0, "ticker", t)pour écrire des données dans le fil principal.tickeret la valeur des données estt, qui est la valeur de retour deGetTicker().

__threadSetData(0, "ticker", t)

Après avoir conçu la fonction personnalisée pour l'exécution simultanée de thread, nous pouvons écrire le code dans lemain()Au début de l'annéemain()fonction, nous utilisons:

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

Créez un fil en même temps qui commence l'exécution duGetTickerAsync()La fonctionmain()fonction commence à exécuter sa proprewhileLa fonction de la boucle, dans laquelle il reçoit les données mises à jour par leGetTickerAsync()fonctionne et l'imprime:

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

Exemple de code complet:

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

Test de négociation en direct:

img

C'est l'une des conceptions d'application les plus simples, alors regardons quelques autres conceptions d'exigences.

2. conception du placement simultané des commandes

Nous pouvons concevoir une fonction pour créer 10 threads simultanément, chacun exécutant une fonction de placement de commande.main()fonction, nous pouvons concevoir unwhilela boucle pour détecter les commandes d'interaction de stratégie.placeMultipleOrders, nous appelons la fonction de placement de commande simultanéetestPlaceMultipleOrders().

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

Ajoutez la conception d'interaction de stratégie sur la page d'édition de stratégie en ajoutant un bouton avec la commande: placeMultipleOrders.

img

Exemple de code complet:

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)
    }
}
  • Le test adopte les ordres en attente, augmentant de 80% à 90% du prix actuel, dans un environnement de négociation simulé.

Après avoir cliqué sur le bouton placeMultipleOrders, un message s'affiche: La commande placeMultipleOrders a été envoyée avec succès, veuillez attendre une réponse du trading en direct!

  • Le journal de stratégie affiche les opérations de passation de commandes simultanées:

img

Créer une connexion WebSocket dans une fonction d'exécution de thread en parallèle

Cette exigence a été soulevée par un utilisateur de FMZ qui veut un exemple simple démontrant comment utiliser unWebSocketconnexion dans les threads simultanés et comment transmettre des données à lamain()fonction dans le fil principal.

En fait, c'est assez simple et similaire à la création de threads simultanés dans les exemples précédents.__threadPeekMessage()et__threadPostMessage()Prenant l'appel WebSocket API pour l'échange Binance comme exemple, nous devons également gérer l'opération de fermeture de la connexion WebSocket. L'exemple suivant démontre comment notifier l'arrêt d'un thread concurrent.

Exemple de code complet:

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

Au cours des tests de négociation en direct, nous pouvons voir que lemain()La fonction reçoit continuellement des données de marché des connexions WebSocket créées par des threads concurrents.

Lors de l'arrêt de la stratégie de trading en direct, la fonction finalize commencera à fonctionner.


Relationnée

Plus de