Oak teaches you to use JS to interface with FMZ extended API
Tags: api, fmzquant, javascript, interface
Published: 2024-05-11 07:46:51

### Introduction
Hello everyone, I'm "Oak Quant". Due to the market trend reminder I developed some time ago [monitor the market](https://www.fmz.com/robot/171548), which is popular, and there is a synchronous reminder of the service number of the same name, which gives new and old users a new reference in judging the market trend. To take advantage of this heat, we started to dock the FMZ's extended API to achieve message communication between robots, and push market alerts to designated robots directly. This article takes two application scenarios as examples, and hopes that you can develop more interesting things...

This article mainly introduces:
1. How do developers interface with FMZ extended APIs through JS language. (This article takes the GetNodeList method as an example.)
2. Case 1: Use the CommandRobot method of the extended API to realize the message communication between the monitoring robot and other robots.
3. Case 2: Use the GetRobotDetail method of the extended API to realize the unified monitoring and display of multiple robot data.

### 1. Use JS to interface with the extended API of FMZ
1). Apply for AccessKey and SecretKey (hereinafter referred to as AK and SK).
We apply in the menu of [Account] ->[ApiKey] ->[Create New ApiKey] on the FMZ official website, and then obtain and record a group of AK and SK. (AK and SK in FMZ are visible, we can view the full data of AK and SK in the [API Interface] menu at any time.)

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

2). Develop according to the extended API document
First, let's look at the key steps of the request API.
1. FMZ API interface:
```
https://www.fmz.com/api/v1
```
2. Basic parameters of the request
```
{
    'version'   : '1.0',                                //Custom version number
    'access_key': '8a148320e0bxxxxxxxxxxxxxx19js99f',   //AK
    'method'    : 'GetNodeList',                        //The specific method to call
    'args'      : [],                                   //List of parameters for the specific method algorithm
    'nonce'     : 1516292399361,                        //Timestamp, in milliseconds
    'sign'      : '085b63456c93hfb243a757366600f9c2'    //Signature (need to be encrypted according to the above 5 parameters to obtain, as discussed below)
}
```
3. Complete request URLs are spliced in the form of question mark and parameter passing
```
Take the GetNodeList method as an example:
https://www.fmz.com/api/v1?
access_key=8a148320e0bxxxxxxxxxxxxxx19js99f&
nonce=1516292399361&
args=%5B%5D&
sign=085b63456c93hfb243a757366600f9c2&
version=1.0&
method=GetNodeList
```
4. Signature method
```
After the parameters are spliced in the following order, the MD5 encryption algorithm is used to encrypt the string and convert it to a hexadecimal data string value, which is used as the value of the parameter sign.
version + "|" + method + "|" + args + "|" + nonce + "|" + secretKey
```
5. In summary, the following code is available
Source code address: [[Oak Quant] - JS docking FMZ extended API Demo](https://www.fmz.com/strategy/208065)
```
var URL = "https://www.fmz.com/api/v1?";
var AK = "b3a53d3XXXXXXXXXXXXXXXXXXX866fe5";//Replace here with your own AccessKey
var SK = "1d9ddd7XXXXXXXXXXXXXXXXXXX85be17";//Replace here with your own SecretKey

function main() {
    //Get 5 basic parameter objects
    var param = getParam("1.0.0",AK,getArgs());
    Log("param:",param);
    //Get the result after md5 encryption of splicing parameters
    var md5Result = md5(param);
    //Assign the encryption result to the basic parameter object
    param.sign = md5Result;
    //Get the URL of the request api
    var finalUrl = getFinalUrl(param);
    Log("finalUrl:",finalUrl);
    //Execute the request and print the results
    var info = HttpQuery(finalUrl);
    Log("info:",info);
}

//Get 5 basic parameter objects
function getParam(version,ak,args){
    return {
        'version': version,
        'access_key': ak,
        'method': 'GetNodeList',
        'args': JSON.stringify(args),
        'nonce': new Date().getTime()
    }
}

//Execute md5 encryption
function md5(param){
    var paramUrl = param.version+"|"+param.method+"|"+param.args+"|"+param.nonce+"|"+SK
    Log("paramUrl:",paramUrl);
    return Hash("md5", "hex", paramUrl)
}

//Get the final request URL
function getFinalUrl(param){
    return URL+"access_key="+AK+"&nonce="+param.nonce+"&args="+param.args+"&sign="+param.sign+"&version="+param.version+"&method="+param.method;
}

//The naming method of... args is not supported in js, so the arguments keyword is used instead to obtain the parameter array
function getArgs(){
    return [].slice.call(arguments);
}
```
### Case 2: Using the CommandRobot method of the extended API to achieve message communication between robots
On the basis of the above code, we will use the CommandRobot method to achieve message communication between robots.

First, let's take a look at the two parameters required by the CommandRobot (RobotId, Cmd) method:

|Parameter Name | Type | Meaning|
| ----------- | ----------- | ----------- |
|RobotId | int | Robot ID, which can be obtained with GetRobotList (...) or on the robot details page|
|Cmd | String | Message sent to robot|
Now that we know the meaning of the parameter, let's implement the calling method.

1. Get the robot ID on the robot details page

2. Implement the method of obtaining Cmd message
```
//Get message header information
function getMessageBody(toUserName,msgType,content){
    return ({
        "toUserName":toUserName,//Who to send to
        "fromUserName":AOKE_INFO,//Source
        "createTime": new Date().getTime(),//Current timestamp
        "msgType":msgType,//Message Type
        "content":content,//Message content
        "msgId":Math.random().toString(36).slice(-8)//Message ID
    })
}

//Get message body trend information (data of message header content field)
function getCtaDate(symbol,timeCycle,direction,nowCycleTime){
    return {
        "symbol":symbol,//Trading currency
        "timeCycle":timeCycle,//Trend cycle
        "direction":direction,//Current entry direction, 0: berish, 1: bullish
        "createTime":new Date().getTime(),//Current timestamp
        "nowCycleTime":nowCycleTime//Start time of current cycle
    }
}
```
3. Modify sending message code
```
//Get messages before sending them
var sendMessage = getMessageBody("Test object",'CTARemind',getCtaDate('BTC_USDT','120','0','2020-05-1620:00:00'));

//Get the robot ID and message body through the getArgs() method, and pass in the basic parameters.
var param = getParam("1.0.0",AK,getArgs(17777,sendMessage));
```
4. Execute the main method. After sending the message, use the GetCommand() method to get the message
```
function main(){
    while(true) { 
        var cmd = GetCommand()
        if (cmd) { 
            Log(cmd)
        }
        Sleep(1000) 
    }
}
```
Message sent successfully:

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

Message received successfully:

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

### Case 3: Use the GetRobotList and GetRobotDetail methods of the extended API to realize the data monitoring and display of robots.
Similarly, let's first look at the parameter descriptions of the next two methods
GetRobotList(offset, length, robotStatus, label):

|Parameter Name|Type|Meaning|
| ----------- | ----------- | ----------- |
|offset|int|Page number of query|
|length|int|Data length of query page|
|robotStatus|int|Pass in - 1 to get all|
|label|	String|Customized tags can filter out all robots with this tag|

GetRobotDetail(RobotId):

|Parameter Name|Type|Meaning|
| ----------- | ----------- | ----------- |
|RobotId|int|Robot ID|

1. Get the list of Robots via the GetRobotList method
```
//Get robot list information
var robotListJson = getAPIInfo('GetRobotList',getArgs(OFF_SET,PAGE_LENGTH,-1));
var robotList = robotListJson.data.result.robots;
```
2. Get robot detail information
```
//Get robot detail information
var robotDetailJson = getAPIInfo('GetRobotDetail',getArgs(robotId));
var robotDetail = robotDetailJson.data.result.robot;
```
3. Console output table data
```
function getLogPrient(infoArr){
    return table = {
            type: 'table',
            title: 'Oak Quant robot display',
            cols: [''Robot ID', 'Robot name', 'Strategy name', 'Next deduction time', 'Consumed time ms', 'Consumed amount CNY', 'Latest active time', 'Publish or not'],
            rows: infoArr
        };
}
```
4. In summary, the following code is available
Source code address: [[Oak Quant] - Use the extended API to get information about the robot and display it](https://www.fmz.com/strategy/208526)
```
var URL = "https://www.fmz.com/api/v1?";
var AK = "b3a53d3XXXXXXXXXXXXXXXXXXX866fe5";//Replace here with your own AccessKey
var SK = "1d9ddd7XXXXXXXXXXXXXXXXXXX85be17";//Replace here with your own SecretKey
var OFF_SET = 0;//Page number subscript of query
var PAGE_LENGTH = 5;//Data length of the query page

function main() {
    LogReset();
    while(true){
        //Get robot list information
        var robotListJson = getAPIInfo('GetRobotList',getArgs(OFF_SET,PAGE_LENGTH,-1));
        //Get the robot list information
        var robotList = robotListJson.data.result.robots;
        //Create an array to display robot information
        var infoArr = new Array();
        var infoArr_index = 0;
        for (index = 0; index < robotList.length; index++) {
            var robot = robotList[index];
            //Get the robot ID of the current loop
            var robotId = robot.id;
            //Get robot detail information
            var robotDetailJson = getAPIInfo('GetRobotDetail',getArgs(robotId));
            var robotDetail = robotDetailJson.data.result.robot;
            //Convert details to array objects
            var arr = getLogPrientItem(robotDetail);
            infoArr[infoArr_index] = arr;
            infoArr_index++;
        }
        Log("infoArr:",infoArr);
        LogStatus('`' + JSON.stringify(getLogPrient(infoArr)) + '`');
        Sleep(30000);
    }
}

function getLogPrient(infoArr){
    return table = {
            type: 'table',
            title: 'Oak Quant robot display',
            cols: [''Robot ID', 'Robot name', 'Strategy name', 'Next deduction time', 'Consumed time ms', 'Consumed amount CNY', 'Latest active time', 'Publish or not'],
            rows: infoArr
        };
}

//Get API information by parameters
function getAPIInfo(method,dateInfo){
    //Get 5 basic parameter objects
    var param = getParam("1.0.0",AK,method,dateInfo);
    //Log("param:",param);
    //Get the result after md5 encryption of splicing parameters
    var md5Result = md5(param);
    //Assign the encryption result to the basic parameter object
    param.sign = md5Result;
    //Get the URL of the request api
    var finalUrl = getFinalUrl(param);
    //Log("finalUrl:",finalUrl);
    //Execute the request and print the results
    var info = HttpQuery(finalUrl);
    //Log("info:",info);
    return JSON.parse(info);
}

//Get the object of the basic 5 parameters
function getParam(version,ak,method,args){
    return {
        'version': version,
        'access_key': ak,
        'method': method,
        'args': JSON.stringify(args),
        'nonce': new Date().getTime()
    }
}

//Execute md5 encryption
function md5(param){
    var paramUrl = param.version+"|"+param.method+"|"+param.args+"|"+param.nonce+"|"+SK
    //Log("paramUrl:",paramUrl);
    return Hash("md5", "hex", paramUrl)
}

//Get the final request URL
function getFinalUrl(param){
    return URL+"access_key="+AK+"&nonce="+param.nonce+"&args="+param.args+"&sign="+param.sign+"&version="+param.version+"&method="+param.method;
}

//The naming method of... args is not supported in js, so the arguments keyword is used instead to obtain the parameter array
function getArgs(){
    return [].slice.call(arguments);
}

//Get the display details object: ['Robot ID', 'Robot Name', 'Strategy Name', 'Next Deduction Time', 'Time Consumed ms', 'Amount Consumed CNY', 'Latest Active Time', 'Whether to Publish'],
function getLogPrientItem(robotDetail){
    var itemArr = new Array();
    var iteArr_index = 0;
    itemArr[iteArr_index++] = robotDetail.id;
    itemArr[iteArr_index++] = robotDetail.name;
    itemArr[iteArr_index++] = robotDetail.strategy_name;
    itemArr[iteArr_index++] = robotDetail.charge_time;
    itemArr[iteArr_index++] = robotDetail.charged;
    itemArr[iteArr_index++] = robotDetail.consumed/1e8;
    itemArr[iteArr_index++] = robotDetail.refresh;
    itemArr[iteArr_index++] = robotDetail.public == 0?"Published":"Unpublished";
    return itemArr;
}
```

### Conclusion
In the actual extension, more and more interesting functions can be realized. For example, using the CommandRobot method, each robot sends heartbeat detection to robot A. If robot A finds that a machine has no heartbeat, but the robot is still running, it can give an alarm through the FMZ service. In this way, alarms such as _C() dead loops that lead to program fake death scenarios can be avoided.
I hope that through my introduction this time, the FMZ platform can have more and more interesting functions to be developed and opened.
Finally, I would like to thank the FMZ platform and all the great men such as Xiaoxiaomeng, Mr. Zhang and Mr. Z for their support and help. Thanks~

From: https://blog.mathquant.com/2022/12/20/oak-teaches-you-to-use-js-to-interface-with-fmz-extended-api.html