我们继续上篇文章:基于FMZ量化的订单同步管理系统设计(1)的讨论,开始设计同步跟单的策略。
考虑这样几个设计问题:
1、如果暂时不想同步跟单,是不是可以暂停。一旦暂停便禁止从扩展API启动,使用密码验证。 实现该功能,增加2个全局变量:
var isStopFollow = false // 用于标记当前是否跟单
var reStartPwd = null // 用于记录重启密码
然后在策略编辑页面增加交互控件,用于策略的暂停/重启(并不是停止这个实盘,只是逻辑暂停,不跟单了,什么都不做而已)。暂停时可以设置一个暂停口令,这样即使有你的扩展API KEY的订单同步管理系统类库(Single Server)
端实盘也无法唤醒你的策略了。重启跟单时,输入预设的口令唤醒跟单功能。
相关功能的实现代码:
...
// 判断交互指令
if (arr.length == 2) {
// 带控件的按钮
if (arr[0] == "stop/restart") {
// 暂停/重启跟单
if (!isStopFollow) {
isStopFollow = true
reStartPwd = arr[1]
Log("已经停止跟单,", "设置的重启密码为:", reStartPwd, "#FF0000")
} else if (isStopFollow && arr[1] == reStartPwd) {
isStopFollow = false
reStartPwd = null
Log("已经重启跟单,", "清空重启密码。", "#FF0000")
} else if (isStopFollow && arr[1] != reStartPwd) {
Log("重启密码错误!")
}
}
continue
}
2、可以指定跟单的下单量或者可以倍数缩放 给策略增加参数:
specifiedAmount :指定跟单的数量,默认为-1,即不指定。
zoomAmountRatio :根据发送来的信号中的下单量缩放,例如发送来的信号是:ETH_USDT,swap,buy,1
,就把其中下单量的值乘以zoomAmountRatio。默认为-1,即不缩放。
var amount = specifiedAmount == -1 ? action.amount : specifiedAmount
amount = zoomAmountRatio == -1 ? amount : amount * zoomAmountRatio
这里实现了给收到的信号中的需要跟单的下单量缩放或者指定具体值。
3、代码尽量精简,下单处理使用其它模板类库。
现货下单使用类库:https://www.fmz.com/strategy/10989 期货下单使用类库:https://www.fmz.com/strategy/203258
function trade(action) {
// 切换交易对,设置合约
exchange.SetCurrency(action.symbol)
if (action.ct != "spot") {
exchange.SetContractType(action.ct)
}
var retTrade = null
var amount = specifiedAmount == -1 ? action.amount : specifiedAmount
amount = zoomAmountRatio == -1 ? amount : amount * zoomAmountRatio
if (action.direction == "buy") {
retTrade = action.ct == "spot" ? $.Buy(amount) : $.OpenLong(exchange, action.ct, amount)
} else if (action.direction == "sell") {
retTrade = action.ct == "spot" ? $.Sell(amount) : $.OpenShort(exchange, action.ct, amount)
} else if (action.direction == "closebuy") {
retTrade = action.ct == "spot" ? $.Sell(amount) : $.CoverLong(exchange, action.ct, amount)
} else if (action.direction == "closesell") {
retTrade = action.ct == "spot" ? $.Buy(amount) : $.CoverShort(exchange, action.ct, amount)
}
return retTrade
}
所以看到,下单就只需一句:$.Sell(amount)
、$.Buy(amount)
、 $.OpenLong(exchange, action.ct, amount)
… 等。
之前的订单同步管理系统(Synchronous Server)
临时代码是这样的:
现在开始重新设计订单同步管理系统(Synchronous Server)
:
// 全局变量
var isStopFollow = false
var reStartPwd = null
function trade(action) {
// 切换交易对,设置合约
exchange.SetCurrency(action.symbol)
if (action.ct != "spot") {
exchange.SetContractType(action.ct)
}
var retTrade = null
var amount = specifiedAmount == -1 ? action.amount : specifiedAmount
amount = zoomAmountRatio == -1 ? amount : amount * zoomAmountRatio
if (action.direction == "buy") {
retTrade = action.ct == "spot" ? $.Buy(amount) : $.OpenLong(exchange, action.ct, amount)
} else if (action.direction == "sell") {
retTrade = action.ct == "spot" ? $.Sell(amount) : $.OpenShort(exchange, action.ct, amount)
} else if (action.direction == "closebuy") {
retTrade = action.ct == "spot" ? $.Sell(amount) : $.CoverLong(exchange, action.ct, amount)
} else if (action.direction == "closesell") {
retTrade = action.ct == "spot" ? $.Buy(amount) : $.CoverShort(exchange, action.ct, amount)
}
return retTrade
}
function parseCmd(cmd) {
var objAction = {}
// 解析cmd ,例如:ETH_USDT,swap,buy,1
var arr = cmd.split(",")
if (arr.length != 4) {
return null
}
objAction.symbol = arr[0]
objAction.ct = arr[1]
objAction.direction = arr[2]
objAction.amount = arr[3]
return objAction
}
function main() {
// 清除所有日志
LogReset(1)
if (isSimulateOKEX) {
exchange.IO("simulate", true)
Log("切换到OKEX模拟盘!")
}
// 设置精度
exchange.SetPrecision(pricePrecision, amountPrecision)
// 检查缩放、指定不能同时设置
if (specifiedAmount != -1 && zoomAmountRatio != -1) {
throw "不能同时指定同步量和缩放量"
}
while (true) {
var cmd = GetCommand()
if (cmd) {
Log("cmd: ", cmd)
var arr = cmd.split(":")
// 判断交互指令
if (arr.length == 2) {
// 带控件的按钮
if (arr[0] == "stop/restart") {
// 暂停/重启跟单
if (!isStopFollow) {
isStopFollow = true
reStartPwd = arr[1]
Log("已经停止跟单,", "设置的重启密码为:", reStartPwd, "#FF0000")
} else if (isStopFollow && arr[1] == reStartPwd) {
isStopFollow = false
reStartPwd = null
Log("已经重启跟单,", "清空重启密码。", "#FF0000")
} else if (isStopFollow && arr[1] != reStartPwd) {
Log("重启密码错误!")
}
}
continue
}
// 允许跟单
if (!isStopFollow) {
// 解析跟单信号交互指令
var objAction = parseCmd(cmd)
if (objAction) {
// 解析正确
var ret = trade(objAction)
} else {
Log("错误的信号指令 cmd:", cmd)
}
}
}
// 显示跟单情况
LogStatus(_D(), isStopFollow ? "停止同步" : "保持同步", "\n")
Sleep(1000)
}
}
这次带单账户使用Binance实盘测试,跟单的实盘使用OKEX账号。带单我们依然使用上篇文章中使用的测试函数(订单同步管理系统类库(Single Server)
模板中的main
函数)。
只不过我们把交易方向改为做空,交易的量改为0.003(币安USDT本位合约可以小数张数下单)。但是OKEX账户跟单必须是整数(OKEX交易所下单必须是整张数),所以参数我就指定策略参数specifiedAmount
为1。
订单同步管理系统类库(Single Server)
的测试函数实盘触发了交易。
跟单的实盘策略收到了信号,执行跟单动作:
交易所开出了对应订单。
接下来测试一下平仓,把测试main函数中的下单方向改成平掉空头仓位0.003张。
然后再次运行起来负责带单的这个实盘(订单同步管理系统类库(Single Server)
)。
跟单实盘也触发了同样操作:
策略地址: 订单同步管理系统类库(Single Server) 订单同步管理系统(Synchronous Server)
策略设计仅为交流学习、实际生产需要请自行修改调整、优化。