
みなさんこんにちは。私は「Oak Quantitative」です。以前私が開発した市場動向リマインダーのおかげで[ダッシュボードの監視】は皆様に広く愛されており、同名のサービスアカウント【Oak Quantitative】からも同時にリマインダーが発信され、新旧の投資家に市場動向を判断するための新たな参考資料を提供しています。この人気を利用して、ロボット間のメッセージ通信を実現し、指定されたロボットに市場アラートを直接プッシュするために、FMZ の拡張 API に接続し始めました。この記事では、議論を刺激するための例として 2 つのアプリケーション シナリオを示します。さらに興味深いものを開発できることを願っています…
この記事では主に以下の内容を紹介します。 1. 開発者は JS 言語を通じて FMZ の拡張 API にどのように接続するのでしょうか? (この記事ではGetNodeListメソッドを例に挙げます) 2. ケース 1: 拡張 API の CommandRobot メソッドを使用して、監視ロボットと他のロボット間のメッセージ通信を実装します。 3. ケース 2: 拡張 API の GetRobotDetail メソッドを使用して、複数のロボット データの統合的な監視と表示を実現します。
AccessKeyとSecretKey(以下、AKとSK)を申請します。
FMZ公式サイトの[アカウント設定]→[APIインターフェース]→[新しいApiKeyの作成]のメニューで申請し、AKとSKのセットを取得して記録します。 (FMZ の AK と SK は、最初に作成されたときにのみ表示される取引所とは異なります。FMZ では、[API インターフェース] メニューでいつでも AK と SK の完全なデータを表示できます)

拡張APIのドキュメントに従って開発する まず、APIをリクエストする主な手順を見てみましょう。
FMZ APIインターフェース:
https://www.fmz.com/api/v1
{
'version' : '1.0', //自定义版本号
'access_key': '8a148320e0bxxxxxxxxxxxxxx19js99f', //AK
'method' : 'GetNodeList', //具体调用的方法
'args' : [], //具体method算法的参数列表
'nonce' : 1516292399361, //时间戳,单位毫秒
'sign' : '085b63456c93hfb243a757366600f9c2' //签名(需要根据上面5个参数加密获取,下面有讲)
}
以GetNodeList方法为例
https://www.fmz.com/api/v1?
access_key=8a148320e0bxxxxxxxxxxxxxx19js99f&
nonce=1516292399361&
args=%5B%5D&
sign=085b63456c93hfb243a757366600f9c2&
version=1.0&
method=GetNodeList
按照如下顺序进行参数拼接后,使用MD5加密算法加密字符串,并转换为十六进制数据字符串值,该值作为参数sign的值。
version + "|" + method + "|" + args + "|" + nonce + "|" + secretKey
var URL = "https://www.fmz.com/api/v1?";
var AK = "b3a53d3XXXXXXXXXXXXXXXXXXX866fe5";//这里替换成你自己的AccessKey
var SK = "1d9ddd7XXXXXXXXXXXXXXXXXXX85be17";//这里替换成你自己的SecretKey
function main() {
//获取5个基础参数对象
var param = getParam("1.0.0",AK,getArgs());
Log("param:",param);
//获取拼接参数md5加密后的结果
var md5Result = md5(param);
//赋值加密结果到基础参数对象中
param.sign = md5Result;
//获取请求api的URL
var finalUrl = getFinalUrl(param);
Log("finalUrl:",finalUrl);
//执行请求并打印结果
var info = HttpQuery(finalUrl);
Log("info:",info);
}
//获取基础5个参数的对象
function getParam(version,ak,args){
return {
'version': version,
'access_key': ak,
'method': 'GetNodeList',
'args': JSON.stringify(args),
'nonce': new Date().getTime()
}
}
//执行md5加密
function md5(param){
var paramUrl = param.version+"|"+param.method+"|"+param.args+"|"+param.nonce+"|"+SK
Log("paramUrl:",paramUrl);
return Hash("md5", "hex", paramUrl)
}
//获取最终请求URL
function getFinalUrl(param){
return URL+"access_key="+AK+"&nonce="+param.nonce+"&args="+param.args+"&sign="+param.sign+"&version="+param.version+"&method="+param.method;
}
//js中不支持...args的命名方式,所以改用arguments关键字获取参数数组
function getArgs(){
return [].slice.call(arguments);
}
上記のコードに基づいて、CommandRobot メソッドを使用してロボット間のメッセージ通信を実装してみましょう。
まず、CommandRobot(RobotId, Cmd) メソッドに必要な 2 つのパラメータを見てみましょう。
| パラメータ名 | タイプ | 意味 |
|---|---|---|
| RobotId | int | ロボットIDは、GetRobotList(…)またはロボットの詳細ページで取得できます。 |
| Cmd | String | ボットへのメッセージ |
パラメータの意味を理解した上で、次にこの呼び出しメソッドを実装しましょう。
ロボットの詳細ページでロボット ID を取得します。

Cmdメッセージを取得するメソッドを実装する
//获取消息头信息
function getMessageBody(toUserName,msgType,content){
return ({
"toUserName":toUserName,//发送给谁
"fromUserName":AOKE_INFO,//消息来源
"createTime": new Date().getTime(),//当前时间戳
"msgType":msgType,//消息类型
"content":content,//消息内容
"msgId":Math.random().toString(36).slice(-8)//消息ID
})
}
//获取消息体趋势信息(消息头content字段的数据)
function getCtaDate(symbol,timeCycle,direction,nowCycleTime){
return {
"symbol":symbol,//交易币种
"timeCycle":timeCycle,//趋势周期
"direction":direction,//当前进入的方向,0:看空,1:看多
"createTime":new Date().getTime(),//当前时间戳
"nowCycleTime":nowCycleTime//当前进入的周期起始时间
}
}
//发送消息前先获取消息
var sendMessage = getMessageBody("测试对象",'CTARemind',getCtaDate('BTC_USDT','120','0','2020-05-1620:00:00'));
//把机器人ID和消息体通过getArgs()方法获取,并传入基础参数。
var param = getParam("1.0.0",AK,getArgs(17777,sendMessage));
function main(){
while(true) {
var cmd = GetCommand()
if (cmd) {
Log(cmd)
}
Sleep(1000)
}
}
メッセージは正常に送信されました:
メッセージを正常に受信しました:

同様に、まず2つの方法のパラメータの説明を見てみましょう。 GetRobotList(offset, length, robotStatus, label):
| パラメータ名 | タイプ | 意味 |
|---|---|---|
| offset | int | クエリページ番号 |
| length | int | クエリページデータの長さ |
| robotStatus | int | -1を渡すとすべて取得できます |
| label | String | カスタムタグは、このタグを持つすべてのロボットをフィルタリングできます |
GetRobotDetail(RobotId):
| パラメータ名 | タイプ | 意味 |
|---|---|---|
| RobotId | int | ロボットID |
//获取机器人列表信息
var robotListJson = getAPIInfo('GetRobotList',getArgs(OFF_SET,PAGE_LENGTH,-1));
var robotList = robotListJson.data.result.robots;
//获取机器人详情信息
var robotDetailJson = getAPIInfo('GetRobotDetail',getArgs(robotId));
var robotDetail = robotDetailJson.data.result.robot;
function getLogPrient(infoArr){
return table = {
type: 'table',
title: '奥克量化的机器人展示',
cols: ['机器人ID','机器人名称','策略名称','下次扣费时间','已经消耗时间ms','已经消耗金额CNY','最近活跃时间','是否公开'],
rows: infoArr
};
}
var URL = "https://www.fmz.com/api/v1?";
var AK = "b3a53d3XXXXXXXXXXXXXXXXXXX866fe5";//这里替换成你自己的AccessKey
var SK = "1d9ddd7XXXXXXXXXXXXXXXXXXX85be17";//这里替换成你自己的SecretKey
var OFF_SET = 0;//查询的页码下标
var PAGE_LENGTH = 5;//查询页的数据长度
function main() {
LogReset();
while(true){
//获取机器人列表信息
var robotListJson = getAPIInfo('GetRobotList',getArgs(OFF_SET,PAGE_LENGTH,-1));
//取出机器人列表信息
var robotList = robotListJson.data.result.robots;
//创建展示机器人信息的数组
var infoArr = new Array();
var infoArr_index = 0;
for (index = 0; index < robotList.length; index++) {
var robot = robotList[index];
//取出当前循环到的机器人ID
var robotId = robot.id;
//获取机器人详情信息
var robotDetailJson = getAPIInfo('GetRobotDetail',getArgs(robotId));
var robotDetail = robotDetailJson.data.result.robot;
//转换详情为数组对象
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: '奥克量化的机器人展示',
cols: ['机器人ID','机器人名称','策略名称','下次扣费时间','已经消耗时间ms','已经消耗金额CNY','最近活跃时间','是否公开'],
rows: infoArr
};
}
//通过参数获取API信息
function getAPIInfo(method,dateInfo){
//获取5个基础参数对象
var param = getParam("1.0.0",AK,method,dateInfo);
//Log("param:",param);
//获取拼接参数md5加密后的结果
var md5Result = md5(param);
//赋值加密结果到基础参数对象中
param.sign = md5Result;
//获取请求api的URL
var finalUrl = getFinalUrl(param);
//Log("finalUrl:",finalUrl);
//执行请求并打印结果
var info = HttpQuery(finalUrl);
//Log("info:",info);
return JSON.parse(info);
}
//获取基础5个参数的对象
function getParam(version,ak,method,args){
return {
'version': version,
'access_key': ak,
'method': method,
'args': JSON.stringify(args),
'nonce': new Date().getTime()
}
}
//执行md5加密
function md5(param){
var paramUrl = param.version+"|"+param.method+"|"+param.args+"|"+param.nonce+"|"+SK
//Log("paramUrl:",paramUrl);
return Hash("md5", "hex", paramUrl)
}
//获取最终请求URL
function getFinalUrl(param){
return URL+"access_key="+AK+"&nonce="+param.nonce+"&args="+param.args+"&sign="+param.sign+"&version="+param.version+"&method="+param.method;
}
//js中不支持...args的命名方式,所以改用arguments关键字获取参数数组
function getArgs(){
return [].slice.call(arguments);
}
//获取展示详情对象'机器人ID','机器人名称','策略名称','下次扣费时间','已经消耗时间ms','已经消耗金额CNY','最近活跃时间','是否公开'],
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?"已公开":"未公开";
return itemArr;
}

実際の拡張では、さらに興味深い機能が実現できます。たとえば、CommandRobot メソッドを使用して、各ロボットがロボット A にハートビート チェックを送信できるようにします。ロボット A は、マシンにハートビートがないがロボットがまだ実行中であることを検出すると、FMZ サービス番号を通じてアラームを発行できます。このようにして、_C() デッド ループなど、プログラムのハングを引き起こす可能性のあるアラームを回避できます。 今回の私のインスピレーションを通じて、FMZ プラットフォームが、皆さんによって開発され、オープンソース化される興味深い機能をもっともっと多く持つようになることを願っています。 最後に、FMZプラットフォームと、サポートと支援をいただいたMeng氏、Chao氏、Z氏をはじめとするすべての素晴らしい人々に感謝したいと思います。ありがとう〜