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

Instructions de l'API FMZ

Auteur:Nul, Créé: 2020-04-20 10:19:00, Mis à jour: 2023-04-12 14:44:56

l'adresse IP est10.0.3.15 }


#### exchange.SetTimeout(...)

```exchange.SetTimeout(Millisecond)```, in which the parameter **Millisecond** is a millisecond value.

Only for the ```rest``` protocol, it is used to set the time-out period for ```rest``` requests, and it takes effect only by setting it once.
For example: ```exchange.SetTimeout(3000)```, set the timeout time of the ```rest``` request of the exchange object ```exchange```, if it exceeds 3 seconds, timeout will return ```null```.

Note:
* The parameter ```Millisecond``` is millisecond, and 1,000 milliseconds equals 1 second. 
* Only need to set once.
* Only for the **rest** protocol.
* ```SetTimeout``` is not a global function, but an exchange object method. 

### Special Requirements for C++ Written Strategies   
The main difference between ```C++``` written strategy and ```JavaScript``` written strategy is the returned data differences of **FMZ API** interface. For example, the ```exchange.GetTicker()``` function.

- JavaScript
```exchange.GetTicker()``` returns an object if the call succeeds, or returns ```null``` if the call fails (due to the exchange server problems or network problems, etc.).

```javascript
function main() {
    var ticker = exchange.GetTicker()
    // Determine if the call to "exchange.GetTicker" function failed, and return "null" when it failed
    if (ticker){
        Log(ticker)
    }
}
  • C++exchange.GetTicker()renvoie un objet, lorsque l'appel réussit. Si l'appel échoue, l'objet renvoyé est toujours un objet, qui se distingue de l'objet renvoyé normal par l'attributValid.

    void main() {
        auto ticker = exchange.GetTicker();
        // Determine if the call to "exchange.GetTicker()" function failed and if the "Valid" attribute of the returned object is "false"
        if (ticker.Valid) {
            Log(ticker);
        }
    }
    

La différence entremain()fonction dans leC++stratégie écrite et lamain()fonction dans la norme C11: La valeur de rendement de laC++fonction d'entrée du programmemain()dans C11 est deintDans le domaine de laC++la stratégie écrite sur la plateforme FMZ, la fonction de démarrage de la stratégie est également la fonctionmain(), mais ces deux ne sont pas la même fonction, juste avec le même nom.main()fonction dans leC++La stratégie est devoid type.

void main() {
    // Use "Test" function to test
    if (!Test("c++")) {
        // Show an exception to stop the program
        Panic("Please download the latest-versioned docker");
    }

    // Determine if the return of all objects is valid with "Valid" 
    LogProfitReset();
    LogReset();
    Log(_N(9.12345, 2));
    Log("use _C", _C(exchange.GetTicker), _C(exchange.GetAccount));
}

Questions spéciales JavaScript

Pour des raisons de langage JavaScript (le langage JavaScript prend en charge les chaînes intégréesasciietutf-16En cas de défaillance de la connexion, le codeur de la connexion ne doit pas être encodé (seulement, afin de ne pas perdre de données), quand il a rencontré une chaîne qui ne peut pas être encodée, il renverra leArrayBufferToutes les interfaces API qui peuvent passer des paramètres de chaîne prennent également en charge le passage de laArrayBuffer type.

JavaScript multi-threading

Il supporte vraiment la fonction multi-threading duJavaScriptstratégie de langage depuis le bas du système, y compris: exécution simultanée de fonctions d'exécution personnalisées; prise en charge de la communication entre les threads simultanés, prise en charge de la communication entre les threads simultanés et le thread principal; stockage, partage de variables dans l'environnement du thread et autres fonctions.https://www.fmz.com/bbs-topic/9974.

__Flèche

Le__Thread(function, arguments...)fonction crée un thread qui s'exécute simultanément. Il ne prend pas en charge la référence directe à des variables autres que la fonction d'exécution du thread (exécutée en environnement isolé). Les références à des variables externes ne seront pas compilées. Les références à d'autres fonctions de fermeture ne sont pas non plus prises en charge. Toutes les API de la plate-forme peuvent être appelées à l'intérieur du thread, mais d'autres fonctions définies par l'utilisateur ne peuvent pas être appelées. Le paramètrefunctionLe paramètre peut être une référence de fonction ou une fonction anonyme.argumentsest le paramètre dufunctionfonction (le paramètre réel transmis), etarguments...signifie que plusieurs paramètres peuvent être passés.

function testFunc(n) {
    Log("Execute the function testFunc, parameter n:", n)
}

function main() {
    var testThread1 = __Thread(function () {
        Log("Executes an anonymous function with no parameters.")
    })

    var testThread2 = __Thread(testFunc, 10)   // parameter n : 10
    
    __threadJoin(testThread1)                  // You can use the __threadJoin function to wait for concurrent threads to complete
    __threadJoin(testThread2)                  // If you don't wait for the execution of testThread1 and testThread2 to complete, the main thread will automatically release the concurrent thread after the execution is completed first, and terminate the execution function of the concurrent thread
}

Il prend en charge la méthode d'appel de__Thread([function, arguments...], [function, arguments...], ...), c'est-à-dire que plusieurs fonctions d'exécution de thread sont exécutées séquentiellement dans les threads créés.

function threadTestFuncA(a) {
    Log(a)
    threadTestFuncC(4)
    
    // The threadTestFuncC function can be called, but the threadTestFuncB function cannot be called

    // this.d
    Log(d)
}

function threadTestFuncB(b) {
    Log(b)
    threadTestFuncC(2)

    this.d = 5
}

function main() {
    // Execute the threadTestFuncB function first, and then execute the threadTestFuncA function
    // threadTestFuncC will not be executed automatically, but it can be called by other thread execution functions
    var threadId = __Thread([threadTestFuncA, 3], [threadTestFuncB, 1], ["function threadTestFuncC(c) {Log(c)}"])
    __threadJoin(threadId)
}

La fonction d'exécution simultanée a été transférée au__ThreadL'exemple ci-dessus utilise leLogfonction à imprimer1 ~ 5Les variables partagées entre différentes fonctions d'exécution de thread sont prises en charge.this.dLa variable dans l'exemple ci-dessus peut être attribuée dans lethreadTestFuncBfonction et utilisé dans lethreadTestFuncAIl prend en charge le passage de chaînes de fonctions, telles que"function threadTestFuncC(c) {Log(c)}"dans l'exemple ci-dessus, qui permet aux threads d'exécuter des appels de fonctions vers des fonctions externes et des bibliothèques importées par cette méthode.

Pour l'importation de bibliothèques externes, un exemple d'utilisation spécifique est le suivant:

function ml(input) {
    const net = new brain.NeuralNetwork();
    net.train([
        { input: [0, 0], output: [0] },
        { input: [0, 1], output: [1] },
        { input: [1, 0], output: [1] },
        { input: [1, 1], output: [0] },
    ]);
    return net.run(input);
}

function main() {
    Log(__threadJoin(__Thread([ml, [1, 0]], [HttpQuery("https://unpkg.com/brain.js")])))
}

__threadPeekMessage Je suis désolé

Le__threadPeekMessage(threadId, timeout)la fonction lit les données du canal de communication du fil, le paramètrethreadIdest l'Id renvoyée par le__Thread()fonction, réglage du paramètrethreadIdsignifie recevoir les données envoyées par le thread représenté par le threadId. Lorsqu'il est défini à 0, il signifie recevoir les données envoyées par le thread principal, c'est-à-dire la fonction principale actuelle (le paramètre threadId est défini à 0, qui n'est pris en charge que dans les fonctions d'exécution de thread simultanées). Le paramètretimeoutest un paramètre de temps d'arrêt, qui bloque et attend selon le nombre de millisecondes défini par ce paramètre.timeoutest réglée sur-1, cela signifie bloquer et attendre que les données du canal soient reçues.__threadPeekMessageLa fonction renvoie immédiatement une valeur nulle.

Lorsque vous écrivez des programmes, vous devez prêter attention au problème de blocage des threads.testFuncde la chaîne concomitante créée et dumainfonction du fil principal et fonction d'exécution du filtestFuncseront exécutés en premier.

function testFunc() {
    for(var i = 0 ; i < 5 ; i++) {                // 0 ~ 5, after sending to the main thread 5 times, the execution of the thread function is completed, and the __threadPeekMessage function in the main function fetches all the data, it will not block again, and returns a null value immediately
        __threadPostMessage(0, i)                 // Send data to the main thread
        var msg = __threadPeekMessage(0, -1)      // Listen for data from the main thread
        Log("from main msg:", msg)
        Sleep(500)
    }
    Log("testFunc execution is complete")
}

function main() {
    var testThread = __Thread(testFunc)           // Create a thread with an Id of 1 
    
    for (var i = 0 ; i < 10 ; i++) {
        __threadPostMessage(1, i)                 // Send data to the thread whose Id is 1, that is, the thread that executes the testFunc function in this example
        var msg = __threadPeekMessage(1, -1)      // Listen to the data sent by the thread whose Id is 1, that is, the data sent by the thread that executes the testFunc function in the example
        Log("from testFunc msg:", msg)
        Sleep(500)
    }
}

__threadPostMessage Je suis désolé.

Le__threadPostMessage(threadId, data)la fonction écrit des données sur le canal de communication du fil, le paramètrethreadIdest l'Id renvoyée par le__Thread()fonction, définir le paramètrethreadIdsignifie envoyer des données au fil représenté par le threadId, et lorsqu'il est défini à 0, il signifie envoyer des données au fil principal, c'est-à-dire à la fonction principale actuelle (le paramètre threadId est défini à 0, qui n'est pris en charge que dans les fonctions d'exécution de fil concurrentes). Le paramètredatapeut transmettre des valeurs, des chaînes, des valeurs booléennes, des objets, des tableaux et d'autres types de données.

Lorsque le__threadPostMessagefonction est appelée dans la fonction d'exécution d'un thread pour envoyer des signaux et des données, un événement de message sera également généré.EventLoop()fonction de réception des notifications de messages.

function testFunc() {
    for(var i = 0 ; i < 10 ; i++) {
        Log("post msg, i:", i)
        __threadPostMessage(0, {msg: "testFunc", i: i})
        Sleep(100)
    }
}

function main() {
    var testThread = __Thread(testFunc)
    
    for (var i = 0 ; i < 10 ; i++) {
        var e = EventLoop()
        Log("e:", e)
        // e: {"Seq":1,"Event":"thread","Index":1,"Nano":1677745512064773600,"Deleted":0,"Symbol":"","Ticker":{"Info":null,"High":0,"Low":0,"Sell":0,"Buy":0,"Last":0,"Volume":0,"OpenInterest":0,"Time":0}}
        if (e.Event == "thread") {
            var msg = __threadPeekMessage(testThread, -1)
            Log("msg:", msg, "#FF0000")
        }
        Sleep(500)
    }
    
    var retThreadJoin = __threadJoin(testThread)
    Log("retThreadJoin:", retThreadJoin)
}

Je vous rejoins.

Le__threadJoin(threadId, timeout)fonction est utilisée pour attendre que le thread avec l'ID spécifié pour sortir et récupérer les ressources du système.threadIdest l'Id renvoyée par le__Thread()fonction, et le paramètretimeoutest le temps d'attente pour attendre la fin du fil, en millisecondes. Si le temps d'attente n'est pas défini, cela signifie attendre la fin de l'exécution du fil. Valeur de retour: Le type est un objet, indiquant le résultat de l'exécution. S'il est temps d'expiration, retournerundefined.

Structure de la valeur du rendement, par exemple:

{
    "id":1,                 // Thread Id
    "terminated":false,     // Whether the thread is terminated forcibly
    "elapsed":2504742813,   // The running time of the thread (nanoseconds)
    "ret": 123              // The return value of the thread function
}

__threadTerminé

Le__threadTerminatefonction est utilisée pour terminer le thread de force et libérer les ressources matérielles utilisées par le thread créé (le __threadJoin ne peut plus être utilisé pour attendre la fin). Le paramètrethreadIdest l'Id renvoyée par le__Thread()valeur de retour: valeur booléenne, indiquant le résultat d'exécution.

function testFunc() {
    for(var i = 0 ; i < 10 ; i++) {
        Log("i:", i)
        Sleep(500)
    }
}

function main() {
    var testThread = __Thread(testFunc)
    
    var retThreadTerminate = null 
    for (var i = 0 ; i < 10 ; i++) {
        Log("main i:", i)
        if (i == 5) {
            retThreadTerminate = __threadTerminate(testThread)
        }
        Sleep(500)
    }
    
    Log("retThreadTerminate:", retThreadTerminate)
}

__threadGetData Il est temps de le faire.

__threadGetData(threadId, key), la fonction est utilisée pour accéder aux variables partagées entre les threads.__threadJoinfonction (en attente d'une sortie réussie) et n'a pas exécuté le__threadTerminateLe paramètrethreadIdest l'Id de fil, et le paramètrekeyest le nom de la clé du fichier stockékey-valueRetourne la valeur de clé correspondant à:keydans lekey-value pair.

threadIdest égal à 0 pour indiquer le fil principal (c'est-à-dire le fil oùmainfonction est située), vous pouvez utiliser__threadId()fonction pour obtenir l'Id du fil courant, définir le paramètrethreadIdVous pouvez également lire les variables dans l'environnement du thread de l'id spécifié.

function main() {
    var t1 = __Thread(function() {
        Sleep(2000)
        var id = __threadId()                                                   // Get the Id of the current thread
        Log("id:", id, ", in testThread1 print:", __threadGetData(id, "msg"))   // Retrieve the key value corresponding to the key name msg in the current thread, i.e. "testThread2"
        Log("id:", 2, ", in testThread1 print:", __threadGetData(2, "msg"))     // Read the key value corresponding to the key name msg in the thread with thread Id 2, i.e. 99
    })

    var t2 = __Thread(function(t) {
        __threadSetData(t, "msg", "testThread2")                                // Set a key-value pair to the thread with Id t1 (Id 1), with the key name msg and the key value "testThread2"
        __threadSetData(__threadId(), "msg", 99)                                // Set the key-value pair in the current thread (Id is 2) with the key name msg and the key value 99
        __threadSetData(0, "msg", 100)                                          // Set up a key-value pair in the main thread, with the key name msg and the key value 100
    }, t1)
    
    __threadJoin(t1)   // You can check the __threadJoin(threadId, timeout) function, which is used to wait for the end of thread execution
    Log("in main, get msg:", __threadGetData(0, "msg"))
}

__threadSetDonnées

__threadSetData(threadId, key, value), qui est utilisé pour stocker des variables dans l'environnement du thread.threadIdest l'ID du fil, le paramètrekeyest le nom de la clé du fichier stockékey-valuela paire et le paramètrevalueest la valeur clé. La fonction ne renvoie aucune valeur.

threadIdest égal à 0 pour indiquer le fil principal (c'est-à-dire le fil oùmainfonction est située), et vous pouvez utiliser le__threadId()fonction pour obtenir l'ID du fil actuel.valueMéthodes non spécifiées de suppressionkey. Il prend en charge l'accès mutuel aux variables partagées entre les threads. Les données sont valides lorsque le thread n'a pas exécuté le__threadJoinfonction (en attente d'une sortie réussie) et n'a pas exécuté le__threadTerminatefonction (terminer le fil de force). La valeur du paramètrevaluedoit être une variable sérialisable.

function testFunc() {
    var id = __threadId()                  // Get the current thread Id
    __threadSetData(id, "testFunc", 100)   // Stored in the current thread environment
    __threadSetData(0, "testFunc", 99)     // Stored in the main threaded environment
    Log("testFunc execution is complete")
}

function main() {
    // threadId is 1, the created thread with threadId 1 will be executed first, as long as the thread resources are not recycled, the variables stored locally in the thread will be valid
    var testThread = __Thread(testFunc)
    
    Sleep(1000)

    // Output in main, get testFunc: 100
    Log("in main, get testFunc:", __threadGetData(testThread, "testFunc"))

    // Output in main, get testFunc: 99
    Log("in main, get testFunc:", __threadGetData(0, "testFunc"))

    // Delete the testFunc key-value pair in the thread environment with Id testThread
    __threadSetData(testThread, "testFunc")

    // After deleting and reading again, the __threadGetData function returns undefined
    Log("in main, get testFunc:", __threadGetData(testThread, "testFunc"))
}

- Le fil.

__threadId(), qui est utilisé pour obtenir l'Id du fil courant, sans paramètres.threadIddu fil actuel.

function testFunc() {
    Log("in testFunc, __threadId():", __threadId())
}

function main() {
    __Thread(testFunc)

    // If the execution of the main thread is completed, the created child thread will stop executing, so here Sleep(1000), wait for 1 second
    Sleep(1000)
    Log("in main, __threadId():", __threadId())
}

Soutenir le codage wasm

Dans leJavaScriptDans la stratégie de langage, le code hexadecimal du fichier wasm peut être chargé, instancié, et le code qui s'y trouve exécuté.JavaScriptCode, il a un certain avantage de vitesse.

wasm.parseModule

wasm.parseModule(data), qui analyse un modèle de chaîne hexagonale.dataParamètre est l'encodage de wasm qui a été converti en une chaîne hexagonale.Exemple de stratégie.

Par exemple, le code de fonction c++ suivant peut être compilé en code wasm, puis converti en une chaîne hexagonale, qui peut être utilisée comme ledataparamètre duwasm.parseModule(data) function.

// Recursive Algorithm for Fibonacci Numbers
int fib(int f) {
    if (f < 2) return f;
    return fib(f - 1) + fib(f - 2);   
}

wasm.buildInstance

wasm.buildInstance(module, opt), qui crée une instance de modèle de guêpe.moduleParamètre est le modèle wasm, et leoptparamètre est l'information de configuration, qui est utilisée pour définir l'espace de pile alloué au programme d'instance wasm.

optExemple de réglage de paramètres:

{
    stack_size: 65*1024*1024,
}

appelFonction

callFunction(funcName, param1, ...), qui est une méthode de l'instance du modèle wasm, utilisée pour exécuter la fonction dans l'instance du modèle wasm.funcNameparamètre est le nom de la fonction à exécuter, et leparam1paramètre est le paramètre passé lors de l'exécution de la fonction (spécifié par le paramètrefuncName).

La chaîne de blocs

La plateforme FMZ Quant Trading est officiellement accessible pour soutenir l'appelweb3Le contrat sur la chaîne, qui peut accéder à ladefiéchange facilement.

Éthereum

Configuration

Sur la plateforme de trading FMZ Quant, écrivez un code de stratégie pour implémenter l'appel de méthode du contrat intelligent sur la chaîne Ethereum via leexchange.IOLes nœuds d'accès peuvent être des nœuds auto-construits ou utiliser des services tiers, tels queinfura.

Sur la page deÉchange FMZ Quant trading plate-forme, sélectionnez le protocole: crypto-monnaie, puis sélectionnez l'échangeWeb3. ConfigurerRpc Address(adresse de service du nœud d'accès) etPrivate KeyIl prend en charge le déploiement local de clés privées, voirLa sécurité est essentielle].

Enregistrer l'ABI

Appeler un contrat qui est une normeERC20L'appel des méthodes autres que le contrat standard nécessite l'enregistrement du contenu ABI:exchange.IO("abi", tokenAddress, abiContent). Pour obtenir le contenu ABI d'un contrat, vous pouvez utiliser l'URL suivante pour l'obtenir, en prenant le champ de résultat seulement.

https://api.etherscan.io/api?module=contract&action=getabi&address=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45

Méthode d'appel d'Ethereum RPC

Lorsque le deuxième paramètre duexchange.IOla fonction est"eth", vous pouvez appeler les méthodes RPC disponibles pour le serveur de nœud directement, par exemple:

  • Rechercher le solde d'ETH dans le portefeuille

    function main() {
        // "owner" needs to be replaced with a specific wallet address
        // "latest" parameter labels for string position: 'latest', 'earliest' or 'pending', please refer to https://eth.wiki/json-rpc/API#the-default-block-parameter
        // The return value ethBalance is a hexadecimal string: 0x9b19ce56113070
        var ethBalance = exchange.IO("api", "eth", "eth_getBalance", "owner", "latest")
    
        // ETH has a precision unit of 1e18
        var ethDecimal = 18
    
        // Because of the JavaScript language precision, it is necessary to use the system underlying encapsulated function BigInt, BigDecimal to process.
        // Convert ethBalance to readable quantity, 0x9b19ce56113070 to 0.043656995388076145.
        Log(Number((BigDecimal(BigInt(ethBalance))/BigDecimal(Math.pow(10, ethDecimal))).toString()))
    }
    
  • Transfert de l'ETH

    function mian() {
        // ETH has a precision unit of 1e18
        var ethDecimal = 18
    
        // Number of transfers, readable quantity e.g. 0.01 ETH
        var sendAmount = 0.01
    
        // Because of the JavaScript language precision, it is necessary to use the system underlying encapsulated function BigInt, BigDecimal to process, and converts readable quantities into data for processing on the chain.
        var toAmount = (BigDecimal(sendAmount)*BigDecimal(Math.pow(10, ethDecimal))).toFixed(0)
        
        // "toAddress" is the address of the recipient's ETH wallet at the time of the transfer, which needs to be filled in specifically, and toAmount is the number of transfers.
        exchange.IO("api", "eth", "send", "toAddress", toAmount)
    }
    
  • Renseignez-vous sur le prix du gaz

    function toAmount(s, decimals) {
        return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
    }  
    
    function main() {
        var gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
        Log("gasPrice:", toAmount(gasPrice, 0))   // 5000000000 , in wei (5 gwei)
    }
    
  • Demande d'éth_estimationGas

    function toAmount(s, decimals) {
        // The toAmount function can convert the hex-encoded value to a decimal value
        return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
    }  
    
    function main() {
        // Encoding the call to the approve method
        var data = exchange.IO("encode", "0x111111111117dC0aa78b770fA6A738034120C302", "approve", "0xe592427a0aece92de3edee1f18e0157c05861564", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
        Log("data:", data)
        var gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
        Log("gasPrice:", toAmount(gasPrice, 0))
        var obj = {
            "from" : "0x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",   // walletAddress
            "to"  : "0x111111111117dC0aa78b770fA6A738034120C302",
            "gasPrice" : gasPrice,
            "value" : "0x0",
            "data" : "0x" + data,
        }
        
        var gasLimit = exchange.IO("api", "eth", "eth_estimateGas", obj)
        Log("gasLimit:", toAmount(gasLimit, 0))
        Log("gas fee", toAmount(gasLimit, 0) * toAmount(gasPrice, 0) / 1e18)
    }
    

Prise en charge du codage

La fonctionexchange.IOencapsule leencodeméthode, qui peut renvoyer le codage d'appel de fonction àhexVous pouvez vous référer aux plateformes accessibles au public Uniswap V3 Bibliothèque de classes de négociation modèlel'appel du codeunwrapWETH9la méthode est utilisée ici à titre d'exemple:

function main() {
    // Main network address of ContractV3SwapRouterV2: 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
    // To call the unwrapWETH9 method, you need to register the ABI first, omit the registration here.
    // "owner" represents the wallet address, it needs to fill in the specific, 1 represents the number of unwrapping, unwrap a WETH into ETH
    var data = exchange.IO("encode", "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", "unwrapWETH9(uint256,address)", 1, "owner")
    Log(data)
}

Lorsque vous appelez leexchange.IO("encode",...)fonction, si le deuxième paramètre (type de chaîne) commence par0x, il s'agit de l'appel à la méthode sur le code (encodeLe contrat intelligent ne commence pas par un0x, il est utilisé pour coder l'ordre de type spécifié.abi.encodedans lesolidity. Consultez l'exemple suivant.

function main() {
    var x = 10 
    var address = "0x02a5fBb259d20A3Ad2Fdf9CCADeF86F6C1c1Ccc9"
    var str = "Hello World"
    var array = [1, 2, 3]
    var ret = exchange.IO("encode", "uint256,address,string,uint256[]", x, address, str, array)   // uint i.e. uint256 , the type length needs to be specified on FMZ
    Log("ret:", ret)
    /*
    000000000000000000000000000000000000000000000000000000000000000a    // x
    00000000000000000000000002a5fbb259d20a3ad2fdf9ccadef86f6c1c1ccc9    // address
    0000000000000000000000000000000000000000000000000000000000000080    // offset of str
    00000000000000000000000000000000000000000000000000000000000000c0    // offset of array
    000000000000000000000000000000000000000000000000000000000000000b    // the length of str
    48656c6c6f20576f726c64000000000000000000000000000000000000000000    // str data
    0000000000000000000000000000000000000000000000000000000000000003    // the length of the array
    0000000000000000000000000000000000000000000000000000000000000001    // array the first data
    0000000000000000000000000000000000000000000000000000000000000002    // array the second data
    0000000000000000000000000000000000000000000000000000000000000003    // array the third data
    */
}

Prise en charge de l'encodage séquentiel de tuples ou de types contenant des tuples:

function main() {
    var types = "tuple(a uint256,b uint8,c address),bytes"
    var ret = exchange.IO("encode", types, {
        a: 30,
        b: 20,
        c: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    }, "0011")
    Log("encode: ", ret)
}

Cet ordre de type est composé de:tupleetbytes, donc deux paramètres doivent être passés en appelantexchange.IOàencode:

    1. Variables correspondant au typetuple:
    {
        a: 30,
        b: 20,
        c: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    }
    

    Les paramètres transmis doivent également être conformes à la structure et au type detuple, au sens de la définitiontypesparamètre:tuple(a uint256, b uint8, c address).

    1. Variables correspondant au typebytes:
    "0011"
    

Prise en charge du codage séquentiel de tableaux ou de types contenant des tableaux:

function main() {
    var path = ["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0xdac17f958d2ee523a2206206994597c13d831ec7"]   // ETH address, USDT address
    var ret = exchange.IO("encode", "address[]", path)
    Log("encode: ", ret)
}

Prise en charge de encodePacked

Par exemple, lorsque l'on appelle la méthode DEX deUniswap V3, vous devez passer dans les paramètres, tels que le chemin d'échange, de sorte que vous devez utiliser leencodePackagedopération:

function main() {
    var fee = exchange.IO("encodePacked", "uint24", 3000)
    var tokenInAddress = "0x111111111117dC0aa78b770fA6A738034120C302"
    var tokenOutAddress = "0x6b175474e89094c44da98b954eedeac495271d0f"
    var path = tokenInAddress.slice(2).toLowerCase()
    path += fee + tokenOutAddress.slice(2).toLowerCase()
    Log("path:", path)
}

Prise en charge du décodage

Le traitement des données n'est pas seulement compatible avec le codage (encode), mais aussi de décoder (decodeUtilisez leexchange.IO("decode", types, rawData)fonction d'effectuer ledecode operation.

function main() {
    // register SwapRouter02 abi
    var walletAddress = "0x398a93ca23CBdd2642a07445bCD2b8435e0a373f"
    var routerAddress = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
    var abi = `[{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"}]`
    exchange.IO("abi", routerAddress, abi)   // abi only uses the contents of the local exactOutput method, the full abi can be searched on the Internet

    // encode path
    var fee = exchange.IO("encodePacked", "uint24", 3000)
    var tokenInAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    var tokenOutAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7"
    var path = tokenInAddress.slice(2).toLowerCase()
    path += fee + tokenOutAddress.slice(2).toLowerCase()
    Log("path:", path)

    var dataTuple = {
        "path" : path, 
        "recipient" : walletAddress, 
        "amountOut" : 1000, 
        "amountInMaximum" : 1, 
    }
    // encode SwapRouter02 exactOutput 
    var rawData = exchange.IO("encode", routerAddress, "exactOutput", dataTuple)
    Log("method hash:", rawData.slice(0, 8))   // 09b81346
    Log("params hash:", rawData.slice(8))

    // decode exactOutput params
    var decodeRaw = exchange.IO("decode", "tuple(path bytes,recipient address,amountOut uint256,amountInMaximum uint256)", rawData.slice(8))
    Log("decodeRaw:", decodeRaw)
}

L'exemple réalise leencodePackedLa première opérationpathLe traitement des paramètres,exactOutputL'appel de méthode qui doit être codé plus tard nécessite lepathEnsuite, le paramètreencodeméthode deexactOutputle contrat de routage ne comporte qu'un seul paramètre, et le type de paramètre esttupleLa méthodeexactOutputnom est codé comme0x09b81346, qui est décodé le résultatdecodeRawparexchange.IO ("decode",...)méthode, et il est cohérent avec la variabledataTuple.

Prise en charge de la commutation des clés privées

Il prend en charge la commutation de clés privées pour utiliser plusieurs adresses de portefeuille, par exemple:

function main() {
    exchange.IO("key", "Private Key")   // "Private Key" represents the private key string, which needs to be filled in specifically
}

Méthode d'appel du contrat intelligent

Le premier paramètre duexchange.IOla fonction est:"api"Le deuxième paramètre de l'appelexchange.IOLa fonction est l'adresse du contrat intelligent à appeler.

Si la méthode appelée a lepayableSi vous utilisez l'attribut transfer, vous devez ajouter une valeur transfer ETH après le nom de la méthode (le quatrième paramètre duexchange.IOfonction), qui peut être de type numérique ou transmettre une valeur sous forme de chaîne, par exemple lemulticallméthode deUniswap V3Les contenus suivants sont des exemples d'appels de méthodes de contrats intelligents:

  • décimales

    Ledecimalsla méthode est uneconstantméthode deERC20qui ne génère pasgasIl est également capable de consulter les données de précision d'untokenLedecimalsLa valeur de retour: les données de précision detoken.

    function main(){
        var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"    // The contract address of the token, in the example the token is 1INCH
        Log(exchange.IO("api", tokenAddress, "decimals"))                  // Query, print 1INCH tokens with precision index of 18
    }
    
  • indemnité

    Leallowancela méthode est uneconstantméthode deERC20qui ne génère pasgasIl est possible d'obtenir des informations sur la quantité autorisée d'un certaintokenPour une certaine adresse contractuelle.allowanceLa méthode doit passer en 2 paramètres, le premier est l'adresse du portefeuille, et le second est l'adresse autorisée.token.

    function main(){
        // The contract address of the token, in the example the token is 1INCH
        var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"            
    
        // For example, the query yields 10000000000000000000000, divided by the precision unit of the token 1e18, the current exchange object bound to the wallet to the spender address authorized 1 1INCH.
        Log(exchange.IO("api", tokenAddress, "allowance", "owner", "spender"))   
    }
    

    owner: L'adresse du portefeuille est remplacée par la chaîne owner dans l'exemple.spender: L'adresse du contrat autorisé est remplacée par la chaîne spender dans l'exemple.Uniswap V3 router v1.

  • approuver

    LeapproveLa méthode est un non-constantméthode deERC20qui génèregasLa consommation, qui est utilisée pour autoriser untokenLe montant de l'opération est fixé à une certaine adresse de contrat.approveLa méthode doit passer en 2 paramètres, le premier est l'adresse à autoriser et le second est le montant autorisé.txid.

    function main(){
        // The contract address of the token, in the example the token is 1INCH
        var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"   
    
        // The hexadecimal string of the authorization amount: 0xde0b6b3a7640000 , the corresponding decimal string: 1e18 , 1e18 divided by the precision unit of the token, i.e. 1 token amount, so this refers to the authorization of one token.
        Log(exchange.IO("api", tokenAddress, "approve", "spender", "0xde0b6b3a7640000"))  
    }
    

    spender: l'adresse du contrat autorisé, l'exemple est remplacé par la chaîne spender, l'utilisation réelle doit remplir l'adresse spécifique, par exemple, il peut êtreUniswap V3 router v1 address. 0xde0b6b3a7640000: Le nombre d'autorisations, représenté ici par une chaîne hexadécimale, correspond à une valeur décimale de1e18, divisé par letokenunité de précision dans l'exemple (c'est-à-dire 1e18), donnant 1token authorized.

    Le troisième paramètre de laexchange.IOla fonction est passée le nom de la méthodeapprove, qui peut aussi s' écrire sous la formemethodId, par exemple: 0x571ac8b0. Il est également possible d'écrire le nom complet de la méthode standard, par exemple approuver(adresse,uint256) .

  • multi-appel

    LemulticallLa méthode est une méthode non constante deUniswap V3, qui généreragasLes utilisateurs peuvent utiliser les jetons pour échanger des jetons.multicallLa méthode peut avoir plusieurs méthodes de transmission de paramètres. Vous pouvez interroger l'ABI contenant la méthode pour obtenir des détails. Vous devez enregistrer l'ABI avant d'appeler la méthode. Retourner la valeur:txid.

    Pour des exemples spécifiques demulticallappels de méthode, veuillez vous référer au public Uniswap V3 Bibliothèque de classes de négociation modèlede notre plateforme.

    Le pseudocode est utilisé ici pour décrire certains détails:

    exchange.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", value, deadline, data)
    

    ContractV3SwapRouterV2: l'adresse du routeur v2 de Uniswap V3.value: le montant de l'ETH transféré, le régler à 0 si letokenInle jeton pour l'opération d'échange n'est pas ETH.deadline: Il peut être réglé sur(new Date().getTime() / 1000) + 3600, ce qui signifie qu'il est valable une heure.data: les données de l'opération d'emballage à effectuer.

    Il est également possible de spécifier legasLimit/gasPrice/nonceEn réglant les appels de méthode, nous utilisons un pseudocode pour décrire à nouveau:

    exchange.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", value, deadline, data, {gasPrice: 123456, gasLimit: 21000})
    

    Vous pouvez définir le paramètre{gasPrice: 11, gasLimit: 111, nonce: 111}Selon vos besoins spécifiques, le paramètre est réglé sur le dernier paramètre duexchange.IOVous pouvez omettre lenonceet utiliser les paramètres du système, ou ne pas définirgasLimit/gasPrice/nonceet utiliser toutes les valeurs par défaut du système.

    Il convient de noter que dans l'exemple, l'attribut destateMutabilitydansmulticall(uint256,bytes[])la méthode estpayable, et levalueLe paramètre doit être passé.stateMutability":"payable"peut être vue depuis leABILeexchange.IOLa fonction déterminera les paramètres requis en fonction de lastateMutabilityattribut dans leABISi la personne concernée a étéstateMutabilityl'attribut estnonpayable, le paramètrevaluen'a pas besoin d'être transmis.

Appels de fonctions communs

  1. Obtient l'adresse du portefeuille configuré par l'objet d'échange.
function main() {
    Log(exchange.IO("address"))         // Print the wallet address of the private key configured on the exchange object.
}
  1. Commutez les nœuds RPC de la blockchain.
function main() {
    var chainRpc = "https://bsc-dataseed.binance.org"
    e.IO("base", chainRpc)    // Switch to BSC chain
}

Fonctions des indicateurs

Lorsque vous appelez les fonctions d'indicateur, vous devez ajouterTA.outalib.comme préfixe

Exemples d'appel des fonctions d'indicateur danstalibbibliothèque etTAbibliothèque:

function main(){
    var records = exchange.GetRecords()
    var macd = TA.MACD(records)
    var atr = TA.ATR(records, 14)

    // Print the last row of indicator values
    Log(macd[0][records.length-1], macd[1][records.length-1], macd[2][records.length-1])
    Log(atr[atr.length-1])

    // Print all indicator data, and JavaScript written strategies have integrated a talib library on FMZ Quant Trading platform 
    Log(talib.MACD(records))
    Log(talib.MACD(records, 12, 26, 9))
    Log(talib.OBV(records))

    // The talib library can also be passed in an array of numbers, which can be passed in order. For example: OBV (Records [Close], Records [Volume]) requires the parameters of the two arrays, including "Close" and "Volume"
    Log(talib.OBV([1,2,3], [7.1, 6.2, 3, 3]))

    // You can also directly pass in the "records" array containing the "Close" and "Volume" attribute
    Log(talib.OBV(records))
    Log(TA.Highest(records, 30, 'High'))
    Log(TA.Highest([1,2,3,4], 0))
}
# Python needs to install the talib library separately 
import talib
def main():
    r = exchange.GetRecords()
    macd = TA.MACD(r)
    atr = TA.ATR(r, 14)
    Log(macd[0][-1], macd[1][-1], macd[2][-1])
    Log(atr[-1])

    # For Python, the system extends the attributes of the array returned by GetRecords, and adds "Open", "High", "Low", "Close" and "Volume" to facilitate the call of the functions in the talib library
    Log(talib.MACD(r.Close))
    Log(talib.MACD(r.Close, 12, 26, 9))
    Log(talib.OBV(r.Close, r.Volume))

    Log(TA.Highest(r, 30, "High"))
    Log(TA.Highest([1, 2, 3, 4], 0))
void main() {
    auto r = exchange.GetRecords();
    auto macd = TA.MACD(r);
    auto atr = TA.ATR(r, 14);
    Log(macd[0][macd[0].size() - 1], macd[1][macd[1].size() - 1], macd[2][macd[2].size() - 1]);
    Log(atr[atr.size() - 1]);

    Log(talib.MACD(r));
    Log(talib.MACD(r, 12, 26, 9));
    Log(talib.OBV(r));

    Log(TA.Highest(r.Close(), 30));
}

Les données des paramètres suivants sont toutes les données obtenues par fonctionexchange.GetRecords(Period)Je suis désolée. Faites attention à la longueur derecords, lorsque la longueur ne satisfait pas aux exigences de calcul des paramètres de la fonction indicateur, une valeur non valide est renvoyée.

TA - Bibliothèque d'indicateurs couramment utilisés

LeTAla bibliothèque d'indicateurs de la plateforme de trading FMZ Quant a optimisé les algorithmes d'indicateurs couramment utilisés pour prendre en charge l'appel des stratégies écrites enJavaScript, Pythonetcpp code de bibliothèque TA open source.

MACD - Moyenne mobile de convergence et de divergence

TA.MACD(data, fast period, slow period, signal period), avec les paramètres de période par défaut de (12, 26, 9) renvoie les tableaux bidimensionnels, qui sont[DIF, DEA, MACD] respectively.

function main(){
    // You can fill in different k-line periods, such as PERIOD_M1, PERIOD_M30 and PERIOD_H1...
    var records = exchange.GetRecords(PERIOD_M15)
    var macd = TA.MACD(records, 12, 26, 9)
    // You can see from the log that three arrays are returned, corresponding to DIF, DEA, MACD
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2])
}
def main():
    r = exchange.GetRecords(PERIOD_M15)
    macd = TA.MACD(r, 12, 26, 9)
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2])
void main() {
    auto r = exchange.GetRecords(PERIOD_M15);
    auto macd = TA.MACD(r, 12, 26, 9);
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2]);
}

Le taux de change est le taux de change de l'indicateur stochastique.

TA.KDJ(data, period 1, period 2, period 3), avec les paramètres de période par défaut de (9, 3, 3) renvoie les tableaux bidimensionnels, qui sont(K, D, J) respectively.

function main(){
    var records = exchange.GetRecords(PERIOD_M15)
    var kdj = TA.KDJ(records, 9, 3, 3)
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2])
}
def main():
    r = exchange.GetRecords(PERIOD_M15)
    kdj = TA.KDJ(r, 9, 3, 3)
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2])
void main() {
    auto r = exchange.GetRecords();
    auto kdj = TA.KDJ(r, 9, 3, 3);
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2]);
}

RSI - Indice de résistance relative

TA.RSI(data, period), avec le paramètre de période par défaut de 14, renvoie un tableau unidimensionnel.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var rsi = TA.RSI(records, 14)
    Log(rsi)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    rsi = TA.RSI(r, 14)
    Log(rsi)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto rsi = TA.RSI(r, 14);
    Log(rsi); 
}

ATR - Volatilité réelle moyenne

TA.ATR(data, period); ATR ((data, period), avec le paramètre de période par défaut de 14, renvoie un tableau unidimensionnel.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var atr = TA.ATR(records, 14)
    Log(atr)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    atr = TA.ATR(r, 14)
    Log(atr)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto atr = TA.ATR(r, 14);
    Log(atr);
}

OBV - Sur le volume du bilan

TA.OBV(data)renvoie un tableau unidimensionnel.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var obv = TA.OBV(records)
    Log(obv)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    obv = TA.OBV(r)
    Log(obv)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto obv = TA.OBV(r);
    Log(obv);
}

MA - Moyenne mobile

TA.MA(data, period); MA ((data, period), avec le paramètre de période par défaut de 9, renvoie un tableau unidimensionnel.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var ma = TA.MA(records, 14)
    Log(ma)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    ma = TA.MA(r, 14)
    Log(ma)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto ma = TA.MA(r, 14);
    Log(ma);
}

EMA - Moyenne mobile exponentielle

TA.EMA(data, period)est un indicateur de moyenne exponentielle, avec le paramètre de période par défaut de 9, renvoie un tableau unidimensionnel.

function main(){
    var records = exchange.GetRecords()
    // Determine if the number of K-line bars meets the requirement of the indicator calculation period 
    if (records && records.length > 9) {
        var ema = TA.EMA(records, 9)          
        Log(ema)
    }
}
def main():
    r = exchange.GetRecords()
    if r and len(r) > 9:
        ema = TA.EMA(r, 9)
        Log(ema)
void main() {
    auto r = exchange.GetRecords();
    if(r.Valid && r.size() > 9) {
        auto ema = TA.EMA(r, 9);
        Log(ema);
    }
}

BOLL - Bandes de Bollinger

TA.BOLL(data, period, multiplier); BOLL ((données, période, multiplicateur) est un indicateur de bande de Bollinger, avec les paramètres par défaut de (20, 2), et renvoie un tableau bidimensionnel, à savoir[Upline, Midline, Downline].

function main() {
    var records = exchange.GetRecords()
    if(records && records.length > 20) {
        var boll = TA.BOLL(records, 20, 2)
        var upLine = boll[0]
        var midLine = boll[1]
        var downLine = boll[2]
        Log(upLine)
        Log(midLine)
        Log(downLine)
    }
}
def main():
    r = exchange.GetRecords()
    if r and len(r) > 20:
        boll = TA.BOLL(r, 20, 2)
        upLine = boll[0]
        midLine = boll[1]
        downLine = boll[2]
        Log(upLine)
        Log(midLine)
        Log(downLine)
void main() {
    auto r = exchange.GetRecords();
    if(r.Valid && r.size() > 20) {
        auto boll = TA.BOLL(r, 20, 2);
        auto upLine = boll[0];
        auto midLine = boll[1];
        auto downLine = boll[2];
        Log(upLine);
        Log(midLine);
        Log(downLine);
    }
}

Alligator - Indicateur d'alligator

TA.Alligator(data, mandible period, tooth period, upper lip period); Alligator ((données, période mandibulaire, période dentaire, période labiale supérieure) est un indicateur Alligator, avec les paramètres par défaut de (13,8,5), et renvoie un tableau bidimensionnel, à savoir[Mandible, Teeth, Upper Lip].

CMF - Flux de trésorerie de Chaikin

TA.CMF(data, period); CMF ((données, période) est l'indicateur Chaikin Flux monétaire, avec le paramètre de période par défaut de 20, renvoie un tableau unidimensionnel.

Prix le plus élevé - Prix le plus élevé de la période

TA.Highest(data, period, attribute), renvoie la valeur maximale de la période la plus récente (à l' exclusion de la barre courante), telle queTA.Highest(records, 30, 'High'). Si leperiodest 0, cela signifie que toutes les barres.attributen'est pas spécifié, les données sont considérées comme un tableau ordinaire et renvoie un prix (type de valeur).

Prix le plus bas - Période Le prix le plus bas

TA.Lowest(data, period, attribute), renvoie la valeur minimale de la période la plus récente (à l' exclusion de la barre courante), telle queTA.Highest(records, 30, 'Low'). Si leperiodSi l'attribut n'est pas spécifié, les données sont considérées comme un tableau ordinaire et un prix (type de valeur) est renvoyé.

L'utilisation deTA.Highest(...)etTA.Lowest(...)dans leC++Il convient de noter queHighestetLowestLes fonctions n'ont que 2 paramètres respectivement, et le premier paramètre n'est pas la valeur de retour deauto r = exchange.GetRecords()fonction, donc vous devez appeler la méthode derpour transmettre des données d'attributs spécifiques, par exemple:r.Close()La méthode d'appel deClose, High, Low, Open, VolumeC' est commer.Close().

C++Des exemples:

void main() { 
    Records r;
    r.Valid = true;
    for (auto i = 0; i < 10; i++) {
        Record ele;
        ele.Time = i * 100000;
        ele.High = i * 10000;
        ele.Low = i * 1000;
        ele.Close = i * 100;
        ele.Open = i * 10;
        ele.Volume = i * 1;
        r.push_back(ele);
    }

    for(int j = 0; j < r.size(); j++){
        Log(r[j]);
    }

    // Note: if the first parameter passed in is not r, you need to call "r.Close()"
    auto highest = TA.Highest(r.Close(), 8);   
    Log(highest);                     
}

Bibliothèque de tiers jointe

JavaScript

C++

Des exemples

  • JavaScriptbibliothèquehttp://mathjs.org/

    function main() {
        Log(math.round(math.e, 3))                // 2.718
        Log(math.atan2(3, -3) / math.pi)          // 0.75
        Log(math.log(10000, 10))                  // 4
        Log(math.sqrt(-4))                        // {"mathjs":"Complex","re":0,"im":2}   
    }
    

    http://mikemcl.github.io/decimal.js/

    function main() {
        var x = -1.2
        var a = Decimal.abs(x)
        var b = new Decimal(x).abs()
        Log(a.equals(b))                           // true  
    
        var y = 2.2
        var sum = Decimal.add(x, y)
        Log(sum.equals(new Decimal(x).plus(y)))

Plus de