输入/搜索内容
入门
欢迎使用发明者量化交易平台
快速开始
密钥安全性
平台基础
账号与计费
实盘计费与充值
子账号
交易所
通用协议
本地凭据文件
交易所特殊说明
证券与期货
加密货币
托管者
策略库
实盘
编写策略
开发工具
回测系统
进阶专题
数据与研究
对外接口

从AI助手或外部程序操作平台:AI接入(MCP服务)、扩展API接口、交易终端插件。

把发明者量化接入Claude Code、Codex、Cursor等AI编程助手(AI agent)后,可以直接用对话完成写策略、回测、创建和管理实盘、查看日志与收益。AI助手通过平台提供的MCP(Model Context Protocol)服务调用这些功能,用的是一把专门为它创建的API KEY,权限由你在授权时决定,随时可以修改或吊销。

一句话接入

在AI助手里输入:

读 https://www.fmz.com/agent/setup.zh-CN.md 然后接入发明者量化

AI助手会按这份说明完成以下步骤,你只需要在浏览器里点一次同意:

  1. AI助手向平台申请授权,然后给出一个授权链接(形如https://www.fmz.com/agent/authorize?code=XXXX-XXXX),链接10分钟内有效。
  2. 在已登录发明者量化的浏览器中打开链接,确认申请者名称和权限后点击同意。可以在页面上取消勾选不想给的权限。
  3. AI助手取得API KEY,写入自己的MCP配置并连接。之后就可以直接对它说「列出我的实盘」「给这个策略跑一次回测」。

申请时AI助手会用「名字 @ 机器名」(例如Claude Code @ MacBook)作为这把API KEY的名称。同一个名称再次申请并同意时,旧的API KEY会被吊销、换成新的,重复接入不会累积多余的API KEY。

权限

权限允许的操作默认
read查看策略、实盘、托管者、交易所账户列表与详情,读取日志、消息、账户概览(不含任何密钥)是
backtest发起、查询、停止回测是
write保存策略与版本、分组、告警开关,修改已停止实盘的配置是
trade创建、启动、停止实盘,给实盘发送交互命令(会扣费并真实下单)是
danger删除策略、实盘、托管者,公开策略否

danger权限默认不授予,只有AI助手明确申请、并在授权页面勾选时才会获得。AI助手调用[trade]或[danger]类工具前,应当先向你确认。

手动配置

不能执行命令的客户端(例如Cherry Studio)可以手动配置:

  1. 在「账号设置 → API KEY」(https://www.fmz.com/m/account#apikey)创建API KEY,记下Access Key和Secret Key。
  2. 在客户端添加一个MCP服务,类型选Streamable HTTP:
    • URL:https://www.fmz.com/api/mcp/<Access Key>
    • 请求头:Authorization: Bearer <Secret Key>

Secret Key只能放在请求头里,不能写进URL。各客户端的配置示例:

bash
# Claude Code claude mcp add --transport http fmz "https://www.fmz.com/api/mcp/<Access Key>" --header "Authorization: Bearer <Secret Key>"
json
{"mcpServers": {"fmz": {"url": "https://www.fmz.com/api/mcp/<Access Key>", "headers": {"Authorization": "Bearer <Secret Key>"}}}}

上面的JSON用于Cursor(~/.cursor/mcp.json)等支持Streamable HTTP的客户端;Claude Desktop需要通过npx mcp-remote转接,见接入说明原文。

安装skills(推荐)

skills是给AI助手阅读的平台知识包:平台操作流程、完整的API文档、各编程语言的策略写法、回测和指标。装上之后AI助手写出的策略更准确。在终端执行:

bash
npx skills add fmzquant/skills --global --yes -a claude-code

-a后面填你使用的AI助手名称(claude-code、codex、cursor、gemini-cli等)。也可以直接在GitHub阅读:https://github.com/fmzquant/skills。

可用的工具

连接后AI助手可以使用以下工具,完整说明以AI助手看到的工具列表为准:

权限工具
readping、get_account_summary、list_exchanges、list_platforms、list_nodes、list_strategies、get_strategy、list_strategy_versions、get_strategy_version、list_robots、get_robot、get_robot_logs、get_robot_profit、get_robot_output、list_messages、list_groups、revoke_my_key
backtestrun_backtest、get_backtest、list_backtests、stop_backtest
writecheck_strategy、save_strategy、save_strategy_version、delete_strategy_version、update_robot、save_group、move_to_group、delete_group、set_robot_alert、set_node_alert、delete_messages
tradecreate_robot、start_robot、stop_robot、restart_robot、send_robot_command,以及交易终端插件工具plugin_*(查询行情、下单等)
dangerdelete_strategy、delete_robot、delete_node、publish_strategy

一个典型的流程:list_platforms和list_nodes了解账户里有哪些交易所账户和托管者;save_strategy保存策略并用check_strategy检查语法;run_backtest和get_backtest回测;确认后create_robot创建实盘,再用get_robot、get_robot_logs观察运行情况。

安全与管理

  • 交易所的API KEY不经过AI助手:在网页的「交易所」页面添加,AI助手按编号选择。所有工具的返回结果里都不包含任何密钥。
  • 在https://www.fmz.com/m/account#apikey可以查看AI助手使用的API KEY,修改权限或锁定。权限除了填写上表的权限名,还可以填工具名,用!工具名排除某个工具。
  • 不再使用时,让AI助手调用revoke_my_key吊销它自己的API KEY,或在上面的页面中删除。
  • stop_robot只停止实盘,不会平仓。
  • 第一次让AI助手创建实盘时,建议先回测,再用模拟盘或小额资金运行。

常见问题

  • 提示没有在线托管者:创建实盘需要至少一个在线的托管者,见「平台基础 → 托管者」。
  • 提示回测任务过多:同时运行的回测数量有上限,让AI助手先用stop_backtest停止不再需要的回测。
  • AI助手说没有某个工具,或者调用被拒绝:这把API KEY没有对应的权限,在API KEY页面修改权限后重新连接。

同一把API KEY也可以用于扩展API接口,供脚本和定时任务调用;能用MCP的场景优先使用MCP。

扩展API接口是平台的HTTP接口(https://www.fmz.com/api/v1),供脚本、定时任务等程序调用平台功能:查询账号、托管者、策略和实盘,创建、重启、停止实盘,向实盘发送交互命令等。

在AI助手(Claude Code、Cursor等)中交互式地操作平台时,优先使用AI接入(MCP服务):工具更全,参数按名称传递,权限可以按类别授予。两者可以使用同一把API KEY。

使用步骤:创建ApiKey,按验证方式发送请求,方法与参数见扩展API接口详解。

在账号设置 → API KEY页面(/m/account#apikey)点击「创建新的ApiKey」,得到一对AccessKey和SecretKey。SecretKey代表这把API KEY的全部权限,不要泄露。在该页面也可以修改已有API KEY的权限,或者禁用、删除API KEY。

权限

创建或修改时,在「API权限」输入框中填写逗号分隔的列表:

  • *:允许全部扩展API接口。
  • 方法名:只允许列出的方法,例如GetRobotList,GetRobotDetail,CommandRobot。
  • !方法名:排除某个方法,通常与*搭配,例如*,!DeleteRobot,!DeleteNode。

同一把API KEY也可以用于AI接入(MCP服务)。MCP工具除了按工具名授权,还可以按权限类别授权:read、backtest、write、trade、danger(含义见AI接入页面),同样支持用!名称排除。权限类别只对MCP工具生效;扩展API接口只认方法名和*。

权限留空时,扩展API接口不限制方法(MCP开放danger以外的全部工具)。建议按用途只授予需要的方法,例如只用于TradingView警报的API KEY只授予CommandRobot。

调用扩展API接口时有两种验证方式:

  • 签名验证:用SecretKey对请求参数签名,SecretKey本身不在网络上传输。程序调用应使用这种方式。
  • 直接验证:把SecretKey直接放进请求URL,主要用于TradingView等只能填写一个URL的Webhook场景。

请求格式

向https://www.fmz.com/api/v1发送POST请求,参数以表单(application/x-www-form-urlencoded)提交。服务端也接受把同样的参数放在URL查询串中的GET请求,但参数会留在各处的访问日志里,推荐使用POST。

参数说明
version版本号,固定为1.0。
access_keyAPI KEY的AccessKey。
method调用的方法名,例如GetNodeList。
args方法参数组成的JSON字符串:按顺序排列的数组(如[]、[123, "ok"]),或按参数名传值的对象(如{"robotId": 123}),见扩展API接口详解。不传时按[]处理。
nonce毫秒时间戳。与服务器时间相差不能超过1小时,并且必须大于这把API KEY上一次请求使用的nonce。
sign签名,计算方法见下文。

请求中不包含SecretKey。

签名方式

按下面的格式拼接字符串,其中args是实际提交的JSON字符串原文:

plaintext
version + "|" + method + "|" + args + "|" + nonce + "|" + secretKey

对拼接结果计算MD5,转换为32位小写十六进制字符串,作为sign的值。

Python示例

python
import hashlib import json import time import urllib.parse import urllib.request ACCESS_KEY = '' # API KEY 的 AccessKey SECRET_KEY = '' # API KEY 的 SecretKey def api(method, *args, **kwargs): d = { 'version': '1.0', 'access_key': ACCESS_KEY, 'method': method, # 位置参数传数组,关键字参数传对象(按参数名传值) 'args': json.dumps(kwargs if kwargs else list(args)), 'nonce': int(time.time() * 1000), } s = '%s|%s|%s|%d|%s' % (d['version'], d['method'], d['args'], d['nonce'], SECRET_KEY) d['sign'] = hashlib.md5(s.encode('utf-8')).hexdigest() body = urllib.parse.urlencode(d).encode('utf-8') with urllib.request.urlopen('https://www.fmz.com/api/v1', body, timeout=10) as resp: return json.loads(resp.read().decode('utf-8')) print(api('GetNodeList')) # 托管者列表 print(api('GetRobotList', appId='member2')) # 按参数名传值:标签为 member2 的实盘 print(api('CommandRobot', 123, 'ok')) # 向实盘 123 发送交互命令 print(api('GetRobotDetail', 123)) # 实盘 123 的详细信息

Go示例

mylang
package main import ( "crypto/md5" "encoding/hex" "encoding/json" "fmt" "io" "net/http" "net/url" "strconv" "time" ) const ( accessKey = "" // API KEY 的 AccessKey secretKey = "" // API KEY 的 SecretKey baseAPI = "https://www.fmz.com/api/v1" ) var client = &http.Client{Timeout: 10 * time.Second} func api(method string, args ...interface{}) (string, error) { if args == nil { args = []interface{}{} } b, err := json.Marshal(args) if err != nil { return "", err } nonce := strconv.FormatInt(time.Now().UnixMilli(), 10) sum := md5.Sum([]byte("1.0|" + method + "|" + string(b) + "|" + nonce + "|" + secretKey)) form := url.Values{ "version": {"1.0"}, "access_key": {accessKey}, "method": {method}, "args": {string(b)}, "nonce": {nonce}, "sign": {hex.EncodeToString(sum[:])}, } resp, err := client.PostForm(baseAPI, form) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) return string(body), err } func main() { ret, err := api("GetNodeList") fmt.Println(ret, err) // 用新的配置重启实盘 123,settings 字段见「扩展API接口详解」中的实盘配置说明 settings := map[string]interface{}{ "name": "hedge test", "strategy": 456, "period": 60, "node": 789, "exchanges": []interface{}{ map[string]interface{}{"pid": 1001, "pair": "BTC_USDT"}, }, } ret, err = api("RestartRobot", 123, settings) fmt.Println(ret, err) }

直接验证不计算签名,而是把secret_key直接放在请求参数中,因此可以生成一个固定的URL,填到TradingView等只能设置一个URL的Webhook回调里。

**安全提示**:secret_key写在URL中,会留在浏览器历史、代理和服务器的访问日志、Webhook服务方的配置里,任何拿到这个URL的人都能以这把API KEY的权限调用接口。建议只在CommandRobot的Webhook中使用直接验证,并为它单独创建一把只授权CommandRobot的API KEY(见创建ApiKey);一旦泄露,立即删除这把API KEY。

请求参数为access_key、secret_key、method、args(JSON数组,需要URL编码),不需要version、nonce、sign。CommandRobot不做nonce校验;其他方法仍会校验:不传nonce时服务器以当前时间(精确到秒)代替,同一秒内的第二次调用会返回Nonce错误(code为3)。

例如API KEY的AccessKey为xxx、SecretKey为yyy,访问下面的URL即可向Id为186515的实盘发送交互命令ok12345:

plaintext
https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyy&method=CommandRobot&args=%5B186515%2C%22ok12345%22%5D

接收Webhook请求体

CommandRobot的命令参数为空字符串、请求为POST时,服务器把请求体(Body)作为交互命令发给实盘。例如在TradingView的Webhook URL中设置:

plaintext
https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyy&method=CommandRobot&args=%5B186515%2C+%22%22%5D

其中args的值%5B186515%2C+%22%22%5D解码后为[186515, ""](+是URL编码中的空格),186515是实盘Id,命令为空字符串。

模拟TradingView发送Webhook警报:

javascript
function main() { var options = { method: "POST", body: `{"test": 123}`, headers: {"Content-Type": "application/json"} } // Webhook 警报会自动发送 POST 请求,并带上需要的 headers return HttpQuery("https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyy&method=CommandRobot&args=%5B186515%2C+%22%22%5D", options) }

TradingView警报消息框中的内容就是请求体:

  • JSON格式:

    plaintext
    {"close": {{close}}, "name": "aaa"}

    Id为186515的实盘收到交互命令:{"close": 39773.75, "name": "aaa"}。

  • 文本格式:

    plaintext
    BTCUSDTPERP 穿过(Crossing) 39700.00 close: {{close}}

    Id为186515的实盘收到交互命令:BTCUSDTPERP 穿过(Crossing) 39700.00 close: 39739.4。

Python、Go示例

python
import json import urllib.parse import urllib.request ACCESS_KEY = '' # 只授权了 CommandRobot 的 API KEY 的 AccessKey SECRET_KEY = '' # SecretKey def api(method, *args): query = urllib.parse.urlencode({ 'access_key': ACCESS_KEY, 'secret_key': SECRET_KEY, 'method': method, 'args': json.dumps(list(args)), }) with urllib.request.urlopen('https://www.fmz.com/api/v1?' + query, timeout=10) as resp: return json.loads(resp.read().decode('utf-8')) # API KEY 没有该方法的权限时返回 {'code': 4, 'data': None} print(api('CommandRobot', 186515, 'ok12345'))
mylang
package main import ( "encoding/json" "fmt" "io" "net/http" "net/url" "time" ) const ( accessKey = "" // 只授权了 CommandRobot 的 API KEY 的 AccessKey secretKey = "" // SecretKey baseAPI = "https://www.fmz.com/api/v1" ) var client = &http.Client{Timeout: 10 * time.Second} func api(method string, args ...interface{}) (string, error) { if args == nil { args = []interface{}{} } b, err := json.Marshal(args) if err != nil { return "", err } q := url.Values{ "access_key": {accessKey}, "secret_key": {secretKey}, "method": {method}, "args": {string(b)}, } resp, err := client.Get(baseAPI + "?" + q.Encode()) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) return string(body), err } func main() { ret, err := api("CommandRobot", 186515, "ok12345") fmt.Println(ret, err) }

参考:

所有方法都通过https://www.fmz.com/api/v1调用,请求格式与签名见签名验证,返回结构与错误码见扩展API接口返回码。各方法页面示例中的api()即签名验证页面Python示例中的函数。

方法一览

对象方法参数(按顺序,方括号内可省略)说明注意
账号GetAccount无账号信息只读
托管者GetNodeList[offset, limit]托管者列表只读
托管者DeleteNodenid删除托管者删除,不可恢复
交易所GetExchangeListisSummary平台支持的交易所及配置项只读
交易所GetPlatformList[offset, limit]已添加的交易所账户只读
策略GetStrategyListoffset, length, strategyType, category, language, kw[, groupId, orderBy]策略列表只读
实盘GetRobotGroupList无实盘分组只读
实盘GetRobotList[offset, length, customStatus, appId, kw, groupId, orderBy, strategyId]实盘列表只读
实盘GetRobotDetailrobotId实盘详细信息只读
实盘GetRobotLogsrobotId, logMinId, …, summaryLimit[, logExchange, logKeyword, logTypes]日志、收益、图表与状态栏数据只读
实盘NewRobotsettings创建并启动实盘扣费;实盘会真实交易
实盘RestartRobotrobotId[, settings]启动(重启)实盘扣费;实盘会真实交易
实盘StopRobotrobotId停止实盘不会平仓
实盘CommandRobotrobotId, cmd向实盘发送交互命令策略可能据此下单
实盘DeleteRobotrobotId[, removeLog]删除实盘删除,不可恢复
调试PluginRunsettings在托管者上执行一段代码代码可以真实下单

API KEY需要有对应方法的权限,见创建ApiKey。

参数传法

args有两种写法:

  • 数组:按上表的顺序传位置参数,例如[123, "ok"]。
  • 对象:按参数名传值,例如{"robotId": 123, "cmd": "ok"}。参数名不区分大小写、忽略下划线,没有传的参数取默认值。可选参数多的方法(GetRobotList、GetRobotLogs、GetStrategyList)建议用这种写法。

实盘配置(settings)

NewRobot、RestartRobot、PluginRun的settings参数是一个JSON对象,常用字段如下:

字段说明
name实盘名称。
strategy策略Id,可用GetStrategyList查询。RestartRobot不能更换实盘的策略。
args策略参数,每个元素为["参数名", 值],例如[["Interval", 500]];策略没有参数时为[]。
exchanges交易所对象配置数组,每个元素对应一个交易所对象,写法见下文。
period默认K线周期,单位为秒,例如60、3600。
node运行实盘的托管者Id,可用GetNodeList查询;不写或为-1时自动分配。
group实盘分组Id,可用GetRobotGroupList查询。
appid自定义标签,GetRobotList可以按标签筛选。

exchanges的元素有两种写法,同一个数组中不能混用(以第一个元素的写法为准):

  • 引用平台上已添加的交易所账户:{"pid": 123, "pair": "BTC_USDT"}。pid可用GetPlatformList查询(返回数据中的id)。
  • 直接传入交易所配置:{"eid": "Binance", "label": "test", "pair": "BTC_USDT", "meta": {"AccessKey": "...", "SecretKey": "..."}}。eid为交易所Id;meta的字段名见GetExchangeList返回的meta;label是交易所对象的标签,策略中用exchange.GetLabel()获取。平台不保存meta中的密钥,而是直接转发给托管者,所以用这种写法创建的实盘,每次重启时都必须重新传入settings。

通用协议交易所的写法:{"eid": "Exchange", "label": "test", "pair": "BTC_USDT", "meta": {"AccessKey": "...", "SecretKey": "...", "Front": "http://127.0.0.1:6666/test"}},Front为通用协议服务的地址。

GetAccount方法用于获取请求中的API KEY对应的发明者量化交易平台账号的账户信息。

返回值

json
{ "code":0, "data":{ "result":{ "balance":22944702436, "concurrent":0, "consumed":211092719653, "email":"[email protected]", "openai":false, "settings":null, "sns":{"wechat":true}, "uid":"105ea6e51bcc177926a10fdbb7e2a1d6", "username":"abc" }, "error":null } }
  • balance: 账户余额,单位为USD。为了控制精度使用整数表示,除以1e8(10的8次方)得到实际数值,示例中为229.44702436。
  • consumed: 累计消费金额,单位与换算方式同balance。

参数

无参数

GetNodeList方法用于获取请求中的API KEY对应的平台账号可以使用的托管者列表,包括自己的托管者和平台的公共托管者。

返回值

json
{ "code": 0, "data": { "result": { "all": 1, "nodes": [{ "build": "3.7", "city": "...", "created": "2024-11-08 09:21:08", "date": "2024-11-08 16:37:16", "forward": "...", "guid": "...", "host": "node.fmz.com:9902", "id": 123, "ip": "...", "is_owner": true, "loaded": 0, "name": "MacBook-Pro-2.local", "online": true, "os": "darwin/amd64", "peer": "...", "public": 0, "region": "...", "tunnel": false, "version": "...", "wd": 0 }] }, "error": null } }

返回值字段说明(字面意思较明显的不再赘述):

  • all: 托管者总数(包括公共托管者)。
  • nodes: 记录托管者节点详细信息。
    • build: 版本号。
    • city: 所在城市。
    • is_owner: true表示是私有托管者,false表示是公共托管者。
    • loaded: 负载,搭载策略实例的个数。
    • public: 0表示私有托管者,1表示公共托管者。
    • region: 地理位置。
    • version: 托管者详细版本信息。
    • wd: 是否开启离线报警,0表示未开启。

一键部署的托管者包含一些额外信息,字段以ecs_、unit_前缀开头,记录了一键部署托管者服务器的相关信息(运营商名称、配置、状态等),计费周期、价格等信息,不再赘述。

参数

名称类型必填描述

offset

number

否

分页偏移,默认为0。

limit

number

否

每页数量;不传或小于等于0时返回全部。

DeleteNode方法用于删除请求中API KEY对应的发明者量化交易平台账号下的托管者节点,删除的托管者节点ID为nid参数指定的托管者ID。

返回值

json
{ "code":0, "data":{ "result":true, "error":null } }
  • result: 是否成功删除关联的托管者程序。

参数

名称类型必填描述

nid

number

是

nid参数用于指定要删除的托管者ID,可通过GetNodeList方法获取账号下托管者的信息。

GetExchangeList方法用于获取FMZ量化交易平台支持的交易所列表及其配置信息。

返回值

isSummary参数为false时,返回的数据:

json
{ "code": 0, "data": { "result": { "exchanges": [{ "category": "加密货币||Crypto", "eid": "Futures_Binance", "id": 74, "logo": "/upload/asset/d8d84b23e573e9326b99.svg", "meta": "[{\"desc\": \"Access Key\", \"qr\":\"apiKey\",\"required\": true, \"type\": \"string\", \"name\": \"AccessKey\", \"label\": \"Access Key\"}, {\"encrypt\": true, \"qr\":\"secretKey\",\"name\": \"SecretKey\", \"required\": true, \"label\": \"Secret Key\", \"type\": \"password\", \"desc\": \"Secret Key\"}]", "name": "币安期货|Futures_Binance", "priority": 200, "stocks": "BTC_USDT,ETH_USDT,ETH_USD", "website": "https://accounts.binance.com/zh-TC/register?ref=45110270" }] }, "error": null } }

isSummary参数为true时,返回的数据:

json
{ "code": 0, "data": { "result": { "exchanges": [{ "category": "加密货币||Crypto", "eid": "Futures_Binance", "id": 74, "logo": "/upload/asset/d8d84b23e573e9326b99.svg", "name": "币安期货|Futures_Binance", "priority": 200, "website": "https://accounts.binance.com/zh-TC/register?ref=45110270" }] }, "error": null } }
  • meta: 交易所配置元数据。

参数

名称类型必填描述

isSummary

bool

是

isSummary参数用于指定返回的数据是否为摘要信息。

GetPlatformList方法用于获取请求中的API KEY对应的发明者量化交易平台账号下的已添加的交易所列表。

返回值

json
{ "code": 0, "data": { "result": { "all": 2, "platforms": [{ "category": "加密货币||Crypto", "date": "2023-12-07 13:44:52", "eid": "Binance", "id": 123, "label": "币安", "logo": "...", "name": "币安现货|Binance", "stocks": ["BTC_USDT", "LTC_USDT", "ETH_USDT", "ETC_USDT", "BTC_TUSD", "ETH_TUSD", "BNB_TUSD"], "website": "..." }, { "category": "通用协议|Custom Protocol", "date": "2020-11-09 11:23:48", "eid": "Exchange", "id": 123, "label": "XX交易所REST协议", "logo": "...", "name": "通用协议|Custom Protocol", "stocks": ["BTC_USDT", "ETH_USDT"], "website": "" }] }, "error": null } }
  • all: 已添加/配置的交易所对象个数。
  • platforms: 交易所相关信息。
    • eid: 在发明者量化交易平台上交易所的Id,一些配置、参数中会使用到eid。

参数

名称类型必填描述

offset

number

否

分页偏移,默认为0。

limit

number

否

每页数量;不传或小于等于0时返回全部。

GetStrategyList方法用于获取平台策略信息。

返回值

json
{ "code": 0, "data": { "result": { "all": 123, "strategies": [{ "category": 9, "date": "2024-11-10 20:40:04", "description": "", "forked": 0, "hits": 0, "id": 123, "is_buy": false, "is_owner": false, "language": 0, "last_modified": "2024-11-11 17:23:52", "name": "HedgeGridStrategy", "profile": { "avatar": "...", "nickname": "abc", "uid": "4ed225440db1eda23fe05ed10184113e" }, "public": 0, "tags": "", "uid": "4ed225440db1eda23fe05ed10184113e", "username": "abc" }] }, "error": null } }
  • all: 筛选查询出的策略总数。
  • strategies: 查询出的具体策略信息,其中category、language的取值同上面的参数说明。

参数

名称类型必填描述

offset

number

是

分页偏移。

length

number

是

每页数量;小于等于0时返回全部。

strategyType

number

是

查询范围:

  • -1:自己的策略和租用的策略(含官方策略)。
  • 0:自己的策略和租用的策略(不含官方策略)。
  • -3:只查自己的策略。
  • -6:只查租用的策略(含已过期的)。
  • -4:官方策略。
  • -2:策略广场中公开的策略和付费策略。
  • 1:已公开的策略。
  • 2:待审核的策略。

category

number

是

策略类型:

  • -1:全部。
  • 0:普通策略。
  • 20:模板类库。
  • 21:交易插件。

language

number

是

策略的编程语言:

  • -1:全部语言。
  • 0:JavaScript(TypeScript策略也按JavaScript保存,源码中带//@ts-check)。
  • 1:Python。
  • 3:Blockly可视化。
  • 4:My语言。
  • 5:PINE语言。
  • 6:Workflow工作流。
  • 7:Rust。

kw

string

是

按策略名称模糊匹配的关键字,多个词用空格分隔;空字符串表示不筛选。以id:开头时按策略Id查询,例如id:123,456。

groupId

number

否

策略分组:-1全部(默认),0未分组,大于0为指定分组。只对自己的策略生效。

orderBy

string

否

排序字段:name、last_modified、date,可在后面加 asc表示升序(默认降序);空字符串为默认排序。

备注

参数中没有needArgs。按旧版文档在category之后多传一个参数,会使后面的参数错位,请按上面的顺序传参,或按参数名传值:

plaintext
api('GetStrategyList', 0, 10, -3, -1, -1, '') # 自己的前10个策略 api('GetStrategyList', strategyType=-3, language=7) # 自己的全部Rust策略

GetRobotGroupList方法用于获取请求中的API KEY对应的发明者量化交易平台账号下的实盘分组列表。

返回值

json
{ "code": 0, "data": { "result": { "items": [{ "id": 3417, "name": "测试" }, { "id": 3608, "name": "实盘演示" }] }, "error": null } }
  • items: 实盘分组信息。
    • id: 实盘分组Id。
    • name: 实盘分组名称。

items字段只记录创建的新分组,「默认」分组不在items中。

参数

无参数

GetRobotList方法用于获取请求中的API KEY对应的平台账号下的实盘列表。参数都可以省略。

返回值

json
{ "code": 0, "data": { "result": { "all": 1, "concurrent": 0, "robots": [{ "charge_time": 1731654846, "date": "2024-11-12 14:05:29", "end_time": "2024-11-15 14:56:32", "fixed_id": 4509153, "id": 591026, "is_sandbox": 0, "name": "测试", "node_guid": "45891bcf3d57f99b08a43dff76ee1ea1", "node_id": 4519153, "node_public": 0, "profit": 0, "public": 0, "refresh": 1731651257000, "start_time": "2024-11-15 14:56:30", "status": 3, "strategy_id": 411670, "strategy_isowner": true, "strategy_language": 0, "strategy_name": "测试", "strategy_public": 0, "uid": "105ed6e511cc977921610fdbb7e2a1d6", "wd": 0 }] }, "error": null } }
  • all: 符合条件的实盘总数。
  • robots: 实盘信息,status为实盘状态码。
    • group_id: 实盘分组Id;如果策略实盘在默认分组中则没有group_id字段。

参数

名称类型必填描述

offset

number

否

分页偏移,默认为0。

length

number

否

每页数量;小于等于0时返回全部(默认)。

customStatus

number

否

按实盘状态码筛选,见实盘状态码;-1为全部实盘(默认),-2为全部实盘并按启动时间排序。

appId

string

否

按实盘的自定义标签(创建时settings中的appid)筛选,空字符串表示不筛选。

kw

string

否

按实盘名称模糊匹配的关键字,空字符串表示不筛选。

groupId

number

否

实盘分组:-1全部(默认),0未分组,大于0为指定分组。

orderBy

string

否

排序字段:name、status、node、profit、date、refresh、start_time、strategy_name,可在后面加 asc表示升序(默认降序);空字符串为默认排序。

strategyId

number

否

大于0时只返回该策略的实盘,默认为0(不筛选)。

备注

以签名验证页面Python示例中的api()为例:

  • api('GetRobotList'):获取全部实盘。
  • api('GetRobotList', 'member2'):只传一个字符串时视为标签,获取标签为member2的全部实盘。
  • api('GetRobotList', 0, 100, -1, 'member2', ''):按位置传参,从第0条开始最多获取100个标签为member2的实盘。
  • api('GetRobotList', appId='member2', length=100):按参数名传值,效果同上。

GetRobotDetail方法用于获取请求中的API KEY对应的发明者量化交易平台账号下的实盘详细信息,所要被获取详细信息的实盘Id为robotId参数指定的实盘Id。

返回值

json
{ "code": 0, "data": { "result": { "robot": { "charge_time": 1732246539, "charged": 5850000, "consumed": 5375000000, "date": "2018-12-28 14:34:51", "favorite": { "added": false, "type": "R" }, "fixed_id": 123, "hits": 1, "id": 123, "is_deleted": 0, "is_manager": true, "is_sandbox": 0, "name": "测试", "node_id": 123, "pexchanges": { "123": "Futures_OKX" }, "phash": { "123": "ca1aca74b9cf7d8624f2af2dac01e36d" }, "plabels": { "123": "OKX期货" }, "priority": 0, "profit": 0, "public": 0, "refresh": 1732244453000, "robot_args": "[]", "start_time": "2024-11-22 11:00:48", "status": 1, "strategy_args": "[]", "strategy_exchange_pairs": "[60,[123],[\"ETH_USDT\"]]", "strategy_id": 123, "strategy_last_modified": "2024-11-21 16:49:25", "strategy_name": "测试", "strategy_public": "0", "uid": "105ed6e51bcc17792a610fdbb7e2a1d6", "username": "abc", "wd": 0 } }, "error": null } }
  • charge_time: 下次扣费时间(Unix时间戳,秒),即当前已付费时段的截止时间。
  • charged: 累计计费时长,单位为秒。
  • consumed: 累计扣费金额,单位为USD,按1e8放大为整数,示例中5375000000即53.75 USD。
  • date: 创建日期。
  • fixed_id: 实盘运行时指派的托管者ID,如果是自动,该值为-1。
  • is_manager: 是否有权限管理该实盘。
  • is_sandbox: 是否是模拟盘。
  • name: 实盘名称。
  • node_id: 托管者ID。
  • pexchanges: 实盘配置的交易所对象,123为pid,"Futures_OKX"为交易所Id(eid)。
  • plabels: 实盘配置的交易所对象的标签信息。
  • profit: 实盘收益数据。
  • public: 实盘是否公开。
  • refresh: 最近活跃时间。
  • strategy_exchange_pairs: 配置的交易所对象,设置的交易对信息。
  • wd: 是否开启离线报警。

参数

名称类型必填描述

robotId

number

是

robotId参数用于指定所要获取详细信息的实盘Id,可以用GetRobotList方法获取账号下实盘的信息,其中包含实盘Id。

备注

strategy_exchange_pairs属性说明,用以下数据为例:

plaintext
"[60,[44314,42960,15445,14703],[\"BTC_USDT\",\"BTC_USDT\",\"ETH_USDT\",\"ETH_USDT\"]]"

其中第一个数据60,代表实盘设置的默认K线周期为1分钟,即60秒。

[44314,42960,15445,14703]为实盘配置的交易所对象的pid(按添加顺序)。

[\"BTC_USDT\",\"BTC_USDT\",\"ETH_USDT\",\"ETH_USDT\"]为实盘配置的交易所对象设置的交易对(按添加顺序与pid一一对应)。

GetRobotLogs方法用于获取请求中的API KEY对应的发明者量化交易平台账号下的实盘日志信息,所要被获取日志信息的实盘Id为robotId参数指定的实盘Id。

返回值

json
{ "code": 0, "data": { "result": { "chart": "", "chartTime": 0, "logs": [{ "Total": 20, "Max": 20, "Min": 1, "Arr": [] }, { "Total": 0, "Max": 0, "Min": 0, "Arr": [] }, { "Total": 0, "Max": 0, "Min": 0, "Arr": [] }], "node_id": 123, "online": true, "refresh": 1732201544000, "status": 4, "summary": "...", "updateTime": 1732201532636, "wd": 0 }, "error": null } }
  • logs: 日志信息;查询出的若干条日志数据在Arr字段中。
    logs中第一个数据结构为实盘数据库中策略日志表中的日志记录。
    logs中第二个数据结构为实盘数据库中收益日志表中的日志记录。
    logs中第三个数据结构为实盘数据库中图表日志表中的日志记录。
  • summary: 实盘状态栏数据。

参数

名称类型必填描述

robotId

number

是

robotId参数用于指定所要获取日志信息的实盘Id,可以用GetRobotList方法获取账号下实盘的信息,其中包含实盘Id。

logMinId

number

是

logMinId参数用于指定Log日志的最小Id。

logMaxId

number

是

logMaxId参数用于指定Log日志的最大Id。

logOffset

number

是

logOffset参数用于设置偏移,由logMinId和logMaxId确定范围后,根据logOffset偏移(跳过多少条记录),开始作为获取数据的起始位置。

logLimit

number

是

logLimit参数用于设置确定起始位置后,选取的数据记录条数。

profitMinId

number

是

profitMinId参数用于设置收益日志的最小Id。

profitMaxId

number

是

profitMaxId参数用于设置收益日志的最大Id。

profitOffset

number

是

profitOffset参数用于设置偏移(跳过多少条记录),作为起始位置。

profitLimit

number

是

profitLimit参数用于设置确定起始位置后,选取的数据记录条数。

chartMinId

number

是

chartMinId参数用于设置图表数据记录的最小Id。

chartMaxId

number

是

chartMaxId参数用于设置图表数据记录的最大Id。

chartOffset

number

是

chartOffset参数用于设置偏移。

chartLimit

number

是

chartLimit参数用于设置获取的记录条数。

chartUpdateBaseId

number

是

chartUpdateBaseId参数用于设置查询更新后的基础Id。

chartUpdateDate

number

是

chartUpdateDate参数用于设置数据记录更新时间戳,会筛选出比这个时间戳大的记录。

summaryLimit

number

是

summaryLimit参数用于设置查询的状态栏数据字节数。查询实盘的状态栏数据,该参数类型为整型。
设置0表示不需要查询状态栏信息,设置为非0表示需要查询的状态栏信息字节数(该接口不限制数据量,可以指定一个较大的summaryLimit参数来获取所有状态栏信息),状态栏数据储存在返回的数据的summary字段中。

logExchange

string

否

只返回该交易所对象(按标签)的日志,空字符串表示不筛选。

logKeyword

string

否

只返回日志内容包含该关键字的日志,空字符串表示不筛选。

logTypes

string

否

只返回这些类型的日志,日志类型号用逗号分隔,例如"0,1,2"只看买单、卖单、撤单日志;空字符串表示全部类型。

备注

  • 数据库中的策略日志表
    返回数据中logs的属性值(数组结构)的第一个元素中(日志数据)Arr属性值描述如下:

    plaintext
    "Arr": [ [3977, 3, "Futures_OKX", "", 0, 0, "Sell(688.9, 2): 20016", 1526954372591, "", ""], [3976, 5, "", "", 0, 0, "this_week 仓位过多, 多: 2", 1526954372410, "", ""] ],
    idlogTypeeidorderIdpriceamountextradatecontractTypedirection
    39773"Futures_OKX"""00"Sell(688.9, 2): 20016"1526954372591""""
    39765""""00"this_week 仓位过多, 多: 2"1526954372410""""

    extra为打印的日志的附加消息。

    logType值具体代表的日志类型描述如下:

    logType:0123456
    logType意义:BUYSALERETRACTERRORPROFITMESSAGERESTART
    中文意义买单类型日志卖单类型日志撤销错误收益日志重启
  • 数据库中的收益图表日志表
    该图表日志表数据与策略日志表中的收益日志一致。

    plaintext
    "Arr": [ [202, 2515.44, 1575896700315], [201, 1415.44, 1575896341568] ]

    以其中一条日志数据为例:

    plaintext
    [202, 2515.44, 1575896700315]

    202为日志Id,2515.44为收益数值,1575896700315为时间戳。

  • 数据库中的图表日志表

    plaintext
    "Arr": [ [23637, 0, "{\"close\":648,\"high\":650.5,\"low\":647,\"open\":650,\"x\":1575960300000}"], [23636, 5, "{\"x\":1575960300000,\"y\":3.0735}"] ]

    以其中一条日志数据为例:

    plaintext
    [23637, 0, "{\"close\":648,\"high\":650.5,\"low\":647,\"open\":650,\"x\":1575960300000}"],

    23637为日志Id,0为图表数据系列索引,最后的数据"{\"close\":648,\"high\":650.5,\"low\":647,\"open\":650,\"x\":1575960300000}"为日志数据,这条数据为图表上的K线数据。

NewRobot方法用于在请求中的API KEY对应的平台账号下创建一个实盘并启动运行,与在网页上创建实盘一样会扣费。

返回值

json
{ "code":0, "data":{ "result":591988, "error":null } }
  • result: 创建成功时为新实盘的Id;失败时为负数,含义同实盘状态码中的异常代码(例如-2没有找到托管者,-5余额不足)。

参数

名称类型必填描述

settings

JSON对象

是

实盘配置,字段见扩展API接口详解中的「实盘配置(settings)」。例如:

json
{ "name": "test", "strategy": 123, "args": [], "exchanges": [ {"pid": 123, "pair": "SOL_USDT"} ], "period": 60, "node": 123, "group": 123, "appid": "test" }

备注

用eid方式直接传入交易所配置时,平台不保存meta中的密钥,之后每次用RestartRobot重启这个实盘都必须传入settings。

RestartRobot方法用于启动(重启)请求中的API KEY对应的平台账号下的实盘,实盘Id由robotId参数指定。启动会扣费。

返回值

json
{ "code":0, "data":{ "result":1, "error":null } }
  • result: 实盘状态码,1即运行中。

参数

名称类型必填描述

robotId

number

是

实盘Id,可以用GetRobotList方法查询。

settings

JSON对象

否

实盘配置,字段见扩展API接口详解中的「实盘配置(settings)」。传入时先用它更新实盘的配置(名称、参数、交易所、K线周期、托管者、分组),再启动;不能更换策略。

备注

在平台页面创建、使用已添加交易所账户(pid)的实盘,可以只传robotId,按实盘当前的配置启动。用eid方式直接传入交易所配置的实盘(通常由扩展API接口创建),平台没有保存密钥,每次重启都必须传入settings。

StopRobot方法用于停止请求中API KEY对应的发明者量化交易平台账号下的实盘。停止运行的实盘Id由robotId参数指定。

返回值

json
{ "code":0, "data":{ "result":2, "error":null } }
  • result: 实盘状态码,2表示停止中。

参数

名称类型必填描述

robotId

number

是

robotId参数用于指定要停止的实盘Id。可以通过GetRobotList方法获取账号下的实盘信息,其中包含实盘Id。

CommandRobot方法用于向请求中的API KEY对应的发明者量化交易平台账号下的实盘发送交互命令,接收交互命令的实盘Id为robotId参数指定的实盘Id,交互命令由策略中调用的GetCommand()函数捕获返回。

返回值

json
{ "code":0, "data":{ "result":true, "error":null } }
  • result: 交互指令是否发送成功;向一个没有运行的实盘发送指令,返回的数据中result为false。

参数

名称类型必填描述

robotId

number

是

robotId参数用于指定接收交互指令的实盘Id,可以用GetRobotList方法获取账号下实盘的信息,其中包含实盘Id。

cmd

string

是

发送给实盘的交互命令,策略中用GetCommand()函数获取,见GetCommand。

备注

实盘策略,假设这个策略实盘处于运行中,实盘Id为123:

javascript
function main() { while (true) { var cmd = GetCommand() if (cmd) { Log(cmd) } Sleep(2000) } }

用签名验证页面Python示例中的api()调用api("CommandRobot", 123, "test command"),Id为123的实盘会收到交互指令:test command,然后通过Log函数输出打印出来。

DeleteRobot方法用于删除请求中的API KEY对应的平台账号下的实盘,实盘Id由robotId参数指定。运行中的实盘需要先停止才能删除。删除后不可恢复。

返回值

json
{ "code":0, "data":{ "result":0, "error":null } }
  • result: 删除操作的结果。
    • 0:删除成功。
    • -1:没有删除:实盘不存在,或者仍在运行、启动中、停止中。
    • -2:实盘已删除,但无法与实盘所在的托管者联系,日志数据没有删除;需要到托管者目录logs/storage/<实盘Id>/下手动删除(例如123.db3)。

参数

名称类型必填描述

robotId

number

是

要删除的实盘Id,可以用GetRobotList方法查询。

removeLog

bool

否

是否同时删除托管者上的实盘日志数据,默认为true。

PluginRun方法在托管者上执行一段JavaScript代码并返回结果,与开发工具中的「调试工具」、交易终端插件使用同一种执行机制(见插件原理与编写)。执行时不创建实盘、不计费,单次执行最长5分钟。

返回值

json
{ "code": 0, "data": { "result": "{\"logs\":[{\"PlatformId\":\"\",\"OrderId\":\"0\",\"LogType\":5,\"Price\":0,\"Amount\":0,\"Extra\":\"Hello FMZ\",\"Currency\":\"\",\"Instrument\":\"\",\"Direction\":\"\",\"Time\":1732267473108}],\"result\":\"\"}", "error": null } }
  • result: 执行结果,是一个JSON字符串:logs为代码中Log()输出的日志,result为main()返回值的JSON文本。

参数

名称类型必填描述

settings

JSON对象

是

执行配置,例如:

json
{ "source": "function main() {Log(\"Hello FMZ\")}", "node": 123, "period": 60, "exchanges": [{"pid": 123, "pair": "SOL_USDT"}] }
  • source:要执行的代码。入口为main(),其返回值就是执行结果。
  • strategy:不传source时,执行账号中这个Id的策略(例如交易插件)。
  • node:执行代码的托管者Id;不写或为-1时自动选择。
  • exchanges:交易所对象配置,写法同扩展API接口详解中的「实盘配置(settings)」。

备注

exchanges也可以不引用平台上的交易所账户,直接传入交易所配置,例如:

plaintext
{"eid": "Binance", "pair": "ETH_BTC", "meta": {"AccessKey": "...", "SecretKey": "..."}}

meta的字段名见GetExchangeList返回的meta。exchanges中通常只设置一个交易所对象(调试工具页面也只支持一个);设置两个不会报错,但代码中访问第二个交易所对象时会报错。

扩展API接口返回的结构如下:

json
{ "code": 0, "data": { "result": null, "error": null } }

code是请求本身的状态码:

描述代码
执行成功0
错误的API KEY:AccessKey不存在或已禁用;直接验证时secret_key不正确1
错误的签名2
Nonce错误:nonce不大于上次请求的值,或与服务器时间相差超过1小时3
方法不正确:方法不存在、不对外开放,或这把API KEY没有该方法的权限4
参数不正确:args不是合法的JSON,或调用失败5
内部未知错误6
请求来源IP不在这把API KEY的IP白名单内7

code为0只表示请求被受理。方法的结果在data.result中;方法执行出错时,data.error为错误信息(成功时为null)。例如参数个数不对:

json
{ "code": 0, "data": { "result": null, "error": "Params number mismatch for StopRobot: expected 1, got 0" } }

GetRobotList接口、GetRobotDetail接口、GetRobotLogs接口返回的数据中status字段为:实盘状态码。

  • 正常启动
    状态代码
    空闲中0
    运行中1
    停止中2
    已退出3
    被停止4
    策略有错误5
  • 异常
    状态代码
    策略已过期,请联系作者重新购买-1
    未找到托管者-2
    策略编译错误-3
    实盘已处于运行状态-4
    余额不足-5
    策略并发数超限-6

平台提供模块化、可定制的交易终端页面:可以自由添加行情、交易等各种模块,模块可以拖动、缩放,可以修改模块绑定的交易所、交易对,同一类模块可以添加多个,方便手动交易和半程序化交易。

交易终端还支持交易插件:自己编写一段代码作为模块,在选定的托管者上执行,辅助手动交易。

原理

交易插件是一段在托管者上执行的短代码:在交易终端页面点击「执行」时,平台把插件代码和模块选定的交易所账户发送到选定的托管者执行,执行结束后把返回值显示在模块中。下面几个入口使用同一种执行机制:

入口执行的代码说明
交易终端插件策略库中类型为「交易插件」的策略在交易终端页面添加、执行
调试工具(开发工具)页面中临时编写的JavaScript代码用于测试API调用
扩展API接口PluginRun请求中的source,或账号中已有的策略供程序调用
MCP的plugin_*工具平台内置的查询行情、下单等函数供AI助手调用,按trade权限授权,见AI接入

这种执行方式不创建实盘、不计费,单次执行最长5分钟,超时中断。适合辅助手动交易的简单任务,例如冰山委托、批量挂单撤单、计算;需要长期运行的逻辑应创建实盘。

编写

在新建策略页面把策略类型设置为「交易插件」即可创建交易插件。交易插件、调试工具和PluginRun都只支持JavaScript。

插件的入口是main(),返回值就是执行结果:返回表格对象、图表对象时,在模块中显示为表格、图表(示例见插件示例)。插件中Log()输出的日志不会在模块中显示。

使用

  • 添加:在交易终端页面打开模块添加菜单,账号策略库中的交易插件会出现在列表中,选择需要的插件添加。
  • 执行:点击插件模块中的「执行」运行插件。

数据目录

插件和调试工具在托管者上执行时,以托管者运行目录下的logs/storage/p<数字>/为工作目录(每个平台账号一个以p开头的目录,第一次执行后创建)。如果交易终端使用的交易所账户以密钥文件路径(file:///xxx.txt)的方式配置密钥,需要把密钥文件放在这个目录中。

插件可以在一段时间内执行代码,完成一些简单的操作,例如冰山委托、挂单、撤单、计算等。插件用return返回结果,返回表格、图表对象时直接显示为表格、图表。下面是两个例子,更多范例可以在策略广场中查找,例如逐笔小量买入/卖出。

返回深度快照

以表格显示当前盘口前15档:

javascript
// 返回深度快照 function main() { var tbl = { type: 'table', title: '深度快照 @ ' + _D(), cols: ['#', 'Amount', 'Ask', 'Bid', 'Amount'], rows: [] } var d = exchange.GetDepth() var n = Math.min(d.Asks.length, d.Bids.length, 15) for (var i = 0; i < n; i++) { tbl.rows.push([i, d.Asks[i].Amount, d.Asks[i].Price + '#ff0000', d.Bids[i].Price + '#0000ff', d.Bids[i].Amount]) } return tbl }

画跨期差价

期货交易所对象上,取季度合约与当周合约的5分钟K线,画出收盘价差:

javascript
// 画跨期差价 var chart = { __isStock: true, title: {text: '差价分析图'}, xAxis: {type: 'datetime'}, yAxis: { title: {text: '差价'}, opposite: false }, series: [ {name: "diff", data: []} ] } function main() { exchange.SetContractType('quarter') var recordsA = exchange.GetRecords(PERIOD_M5) exchange.SetContractType('this_week') var recordsB = exchange.GetRecords(PERIOD_M5) var n = Math.min(recordsA.length, recordsB.length) for (var i = 0; i < n; i++) { var a = recordsA[recordsA.length - n + i] var b = recordsB[recordsB.length - n + i] chart.series[0].data.push([a.Time, a.Close - b.Close]) } return chart }