Teach You to Use the FMZ Extended API to Batch Modify Parameters of the Bot
Tags: parameters, robot, fmzquant, api
Published: 2024-05-28 09:13:22

How can I change the parameters of live tradings in batch on FMZ? When the number of live tradings exceeds dozens and reaches hundreds, it would be very inconvenient to configure live tradings one by one manually. At this time, we can use the FMZ extended API to complete these operations. So in this article, we will explore the group control of the bot, update some details of the parameters.

In the previous article, we solved the problem of how to use the FMZ extended API to monitor all the live tradings, group control live tradings, and send commands to the live tradings. And we still use the interface call code we encapsulated in the previous article as a basis, continue to write code to realize the batch modification of the parameters of the live trading.

Parameter settings:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7lt3mafan6l7wfrdwvil.png)

Strategy code:

```
// Global variable
var isLogMsg = true   // Controls whether logs are printed or not
var isDebug = false   // Debugging mode
var arrIndexDesc = ["all", "running", "stop"]
var descRobotStatusCode = ["Idle", "Running", "Stopping", "Exited", "Stopped", "There is an error in the strategy"]
var dicRobotStatusCode = {
    "all" : -1,
    "running" : 1,
    "stop" : 4,
}

// Extended logging functions
function LogControl(...args) {
    if (isLogMsg) {
        Log(...args)
    }
}

// FMZ extended API call functions
function callFmzExtAPI(accessKey, secretKey, funcName, ...args) {
    var params = {
        "version" : "1.0",
        "access_key" : accessKey,
        "method" : funcName,
        "args" : JSON.stringify(args),
        "nonce" : Math.floor(new Date().getTime())
    }

    var data = `${params["version"]}|${params["method"]}|${params["args"]}|${params["nonce"]}|${secretKey}`
    params["sign"] = Encode("md5", "string", "hex", data)
    
    var arrPairs = []
    for (var k in params) {
        var pair = `${k}=${params[k]}`
        arrPairs.push(pair)
    }
    var query = arrPairs.join("&")
    
    var ret = null
    try {
        LogControl("url:", baseAPI + "/api/v1?" + query)
        ret = JSON.parse(HttpQuery(baseAPI + "/api/v1?" + query))
        if (isDebug) {
            LogControl("Debug:", ret)
        }
    } catch(e) {
        LogControl("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
    }
    Sleep(100)  // Control frequency
    return ret 
}

// Get information about all running bots for the specified strategy Id.
function getAllRobotByIdAndStatus(accessKey, secretKey, strategyId, robotStatusCode, maxRetry) {
    var retryCounter = 0
    var length = 100
    var offset = 0
    var arr = []

    if (typeof(maxRetry) == "undefined") {
        maxRetry = 10
    }

    while (true) {
        if (retryCounter > maxRetry) {
            LogControl("Maximum number of retries exceeded", maxRetry)
            return null
        }
        var ret = callFmzExtAPI(accessKey, secretKey, "GetRobotList", offset, length, robotStatusCode)
        if (!ret || ret["code"] != 0) {
            Sleep(1000)
            retryCounter++
            continue
        }

        var robots = ret["data"]["result"]["robots"]
        for (var i in robots) {
            if (robots[i].strategy_id != strategyId) {
                continue
            }
            arr.push(robots[i])
        }

        if (robots.length < length) {
            break
        }
        offset += length
    }

    return arr 
}
```
### Get to Know the RestartRobot Function of the FMZ Extended API First
When we need to batch modify the parameters of the live trading and then run it, there are 2 cases for this scenario to begin with.

- 1. Bot has been created
For a live trading that has already been created, it is natural to restart it using the RestartRobot function, which is an extended API interface to FMZ.
- 2. Bot has not been created
For the live trading has not been created, there is no need to "modify" the parameters of the live trading, that's the batch creation of the live trading to run, and we use FMZ extended API interface - NewRobot function.

But no matter what kind of method, the next idea as well as the operation are similar, so we will use the RestartRobot extended API function as an example to explain.

RestartRobot function is used in two ways:

- 1. Configuration with only live trading ID passed in, not the parameters of live trading
This approach keeps the parameter configuration unchanged when the live trading stopped, and restarts the live trading only.
- 2. Configuration with live trading ID and the parameters of live trading passed in
This approach starts the live trading running with the new parameter configuration.

The first approach is not useful for our demand scenario, because our own demand is to modify a large number of parameters of the live trading in bulk. So the question is, the configuration of the parameters of the live trading is very complex, there are exchange object configuration, strategy parameter configuration, K-line period settings and so on.

Do not worry, let's explore them one by one.

### Get the Information of the Live Trading You Want to Operate
On FMZ, if you want to modify the parameter configuration of a live trading, then it must be non-running. Because only a live trading that is not running can have its parameter configuration modified. A live trading that is not in the running state may be in:

- The strategy stopped.
- Strategy has errors, stopped.

So we need to get the live tradings for the specified strategy first, and these live tradings are in a **stopped state** or **have an error to stop**.

```
function main() {
    var stopRobotList = getAllRobotByIdAndStatus(accessKey, secretKey, strategyId, 4)
    var errorRobotList = getAllRobotByIdAndStatus(accessKey, secretKey, strategyId, 5)
    var robotList = stopRobotList.concat(errorRobotList)
}
```
This gives us all the information about the live trading that we need to change the configuration of, next we will get the detailed configuration of the live trading.

### Modification of Live Trading Configuration Parameters
For example, the live trading strategy for which we need to modify the parameters is as follows (i.e., the strategy whose strategy ID is the strategyId variable):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ry53rxd2i7e1fmnldw7n.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9kcviikt7gct54tv3q3m.png)

The strategy has 3 parameters as a test.

Modify the strategy parameters for the live trading, but maybe we don't want to modify the strategy's exchange configuration, but for the Extended API interface RestartRobot function, either no parameters are specified (as is just start the live trading) or all parameter configurations must be specified.

That is to say, before we use the RestartRobot function to start the live trading, we must use the extended API interface GetRobotDetail function to get the current configuration of the live trading first, and then we replace the part of the parameters that need to be modified, to re-construct the configuration parameters for the start of the live trading (i.e., the parameters that will be used to call RestartRobot), and then restart the live trading.

So, next we traverse robotList, and get the current parameter configuration one by one, the /**/ commented part of the following code is the live trading details, we need to deal with these data.

```
function main() {
    var stopRobotList = getAllRobotByIdAndStatus(accessKey, secretKey, strategyId, 4)
    var errorRobotList = getAllRobotByIdAndStatus(accessKey, secretKey, strategyId, 5)

    var robotList = stopRobotList.concat(errorRobotList)
    _.each(robotList, function(robotInfo) {
        var robotDetail = callFmzExtAPI(accessKey, secretKey, "GetRobotDetail", robotInfo.id)
        
        /*
        {
            "code": 0,
            "data": {
                "result": {
                    "robot": {
                        ...
                        "id": 130350,
                        ...
                        "name": "Test 1B",
                        "node_id": 3022561,
                        ...
                        "robot_args": "[[\"pairs\",\"BTC_USDT,ETH_USDT,EOS_USDT,LTC_USDT\"],[\"col\",3],[\"htight\",300]]",
                        "start_time": "2023-11-19 21:16:12",
                        "status": 5,
                        "strategy_args": "[[\"pairs\",\"Currency list\",\"English comma spacing\",\"BTC_USDT,ETH_USDT,EOS_USDT,LTC_USDT\"],[\"col\",\"breadth\",\"Total width of the page is 12\",6],[\"htight\",\"height\",\"unit px\",600],[\"$$$__cmd__$$$coverSymbol\",\"close the position\",\"close out trading pairs\",\"\"]]",
                        "strategy_exchange_pairs": "[3600,[186193],[\"BTC_USD\"]]",
                        "strategy_id": 131242,
                        "strategy_last_modified": "2023-12-09 23:14:33",
                        "strategy_name": "Test 1",
                        ...
                    }
                },
                "error": null
            }
        }
        */

        // Parse the exchange configuration data
        var exchangePairs = JSON.parse(robotDetail.data.result.robot.strategy_exchange_pairs)

        // Get the exchange object index, trading pairs, these settings are not going to be changed
        var arrExId = exchangePairs[1]
        var arrSymbol = exchangePairs[2]

        // Parse parameter configuration data
        var params = JSON.parse(robotDetail.data.result.robot.robot_args)

        // Update parameters
        var dicParams = {
            "pairs" : "AAA_BBB,CCC_DDD",
            "col" : "999",
            "htight" : "666"
        }
        
        var newParams = []
        _.each(params, function(param) {
            for (var k in dicParams) {
                if (param[0] == k) {
                    newParams.push([k, dicParams[k]])  // Construct the strategy parameters and update the new parameter values
                }
            }
        })
        
        // Note that if there are spaces in the data you need to transcode it, otherwise the request will report an error
        settings = {
            "name": robotDetail.data.result.robot.name,
            // Strategy parameter
            "args": newParams,         
            // The strategy ID can be obtained by the GetStrategyList method.
            "strategy": robotDetail.data.result.robot.strategy_id,
            // K-period parameter, 60 means 60 seconds
            "period": exchangePairs[0],
            // Specifies which docker to run on; not writing this attribute means automatically assigning the run
            "node" : robotDetail.data.result.robot.node_id,
            "exchanges": []
        }
                                
        for (var i = 0 ; i < arrExId.length ; i++) {
            settings["exchanges"].push({"pid": arrExId[i], "pair": arrSymbol[i]})
        }
        Log(settings) // Test
        var retRestart = callFmzExtAPI(accessKey, secretKey, "RestartRobot", robotInfo.id, settings)
        Log("retRestart:", retRestart)
    })
}
```
After running the batch parameter modification strategy, my live trading:

- Test 1A
- Test 1B

Batch modification of parameters was done with the configured exchange objects, trading pairs and K-line periods unchanged:

It was changed on the live trading page automatically:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6el5qr6zdrxxlcnqyba.png)

And start running. Because we specified the modified parameters in the code above:

```
        // Update parameters
        var dicParams = {
            "pairs" : "AAA_BBB,CCC_DDD",
            "col" : "999",
            "htight" : "666"
        }
```
### END
For dozens, hundreds of live trading batch modify parameters, this method is more convenient. In the example, the parameters are modified to a uniform, of course you can customize your own modification rules in the code to specify different parameter configurations for each live trading. Or specify different exchange objects, trading pairs and so on.

For the FMZ platform, these requirements are flexible and customizable to achieve. Feel free to leave a comment if you have any requirement ideas, we can discuss, research and learn from each other , and find the solution to the problem.

From: https://blog.mathquant.com/2023/12/11/teach-you-to-use-the-fmz-extended-api-to-batch-modify-parameters-of-the-bot.html