初学数字货币量化交易策略设计时,经常有各种各样的策略需求,不论用那种语言,那种平台,都会遇到各种不同情况的策略设计需求。例如有时候需要多品种轮动,有时候需要多平台对冲,有时候又需要不同品种行情并发等等。下面我们就一起分享下策略需求实现时的一些设计经验。 学习平台依然使用发明者量化交易平台(https://www.fmz.com),市场选择为数字货币市场。
此类需求情况多为需要编写一个多品种趋势策略,多品种网格策略等,需要针对策略逻辑,用不同的交易对行情迭代执行。 通常这样设计:
function Process (symbol) {
exchange.IO("currency", symbol)
var ticker = _C(exchange.GetTicker)
Log("已经切换交易对,按照策略逻辑处理交易对 :", symbol, "行情:", ticker)
// ...
// ..
// .
}
function main(){
var symbols = ["BTC_USDT", "LTC_USDT", "ETH_USDT"]
while (true) {
for (var i = 0 ; i < symbols.length; i++) {
Process(symbols[i])
Sleep(500)
}
}
}
我们给机器人配置:
可以看到,这样就实现了在机器人上配置一个交易所对象,切换交易对,获取不同交易对的行情,进行多品种行情,在一种策略逻辑下执行。 可以看到,三种我们定义的交易对:BTC_USDT,LTC_USDT,ETH_USDT ,在循环中依次迭代获取行情,获取行情后,就可以具体对于行情检测,触发策略设计好的交易逻辑。
有的同学可能会提出:“我不喜欢切换交易对,感觉有点麻烦,策略这样设计也不清晰”。 确实也有其它的设计办法,就是下面我们介绍的另一种方式。
通过多个交易所对象来获取不同交易对的行情数据,迭代策略逻辑中执行。 例如这样配置机器人:给机器人配置三个交易所对象,交易对分别设置为 BTC_USDT , LTC_USDT , ETH_USDT 。
名字是 「OKEX现货V3测试」的交易所对象,在控制中心,交易所配置页面: 已经配置好了。
代码修改一下,因为这次我们给机器人添加了多个交易所对象,分别是交易对为 BTC_USDT 、LTC_USDT、ETH_USDT 的交易所对象。
function Process (e) {
var ticker = _C(e.GetTicker)
Log("交易所", e.GetName(), "按照策略逻辑处理交易对 :", e.GetCurrency(), "行情:", ticker)
// ...
// ..
// .
}
function main(){
while (true) {
for (var i = 0 ; i < exchanges.length; i++) {
Process(exchanges[i])
Sleep(500)
}
}
}
运行机器人:
以上讲述的例子,无论是切换交易对,还是添加一个配置账户的多个不同交易对的交易所对象。 都只是使用一个交易所账号配置(使用一个配置好的交易所)。那么如何在一个策略中使用多个交易所账号呢?
某些策略例如,多交易所跨市对冲,单交易所内多账户策略等。
多个交易所配置,但是是不同的交易所。 例如,我在控制中心->交易所->添加交易所 页面,配置了2个交易所。 我在策略中就可以访问这两个交易所配置的账户的资产信息。
function main(){
Log(exchanges[0].GetAccount()) // 打印第一个 交易所对象的账户资产信息,即火币期货 这个交易所的资产信息。
Log(exchanges[1].GetAccount()) // ... 打印Bit-Z这个交易所的资产信息
}
当然我也可以,给一个交易所添加第二个、第三个账户的交易所配置。
多个交易所配置,是相同的交易所。
例如我们再添加一个火币期货的账号。
可以看到,这样就配置了两个「火币期货」交易所的账号。
在创建策略时,机器人的 「修改配置」 选项中就又出现了一个火币期货交易所对象以供选择。
比如这样可以让两个账户一个做先卖后买网格策略(向上),一个做先买后卖网格策略(向下)。
这里讲下机器人上配置多个交易所对象 和 「同一个交易所账户给机器人配置多个交易所对象」的区别:
这个猛地一看和上面讲解的「同一个交易所账户给机器人配置多个交易所对象」例子有些类似,但是是有区别的。 区别在于上面讲的例子是一个交易所配置,即:
在机器人配置交易所对象时,始终用的都是: 这个配置。
只不过是添加交易所对象时,交易对设置不同而已。 如果调用 GetAccount 函数,始终访问的都是同一个账户的资产信息。
然而: 这样配置的两个火币期货交易所对象,虽然都是火币期货,代表的却是不同的交易所账户。
有时候在做数字货币合约对冲的策略时,为了抓住转瞬即逝的交易机会,很多场景需要并发下单。但是因为合约不同,需要在获取行情,下单操作时切换到对应的合约。在使用 exchange.Go 函数并发执行下单函数或者获取行情时,由于有同步的问题,并不是很快。并且这样切换合约的设计也让逻辑显得不是那么简洁。那有没有更好的办法呢?
当然有办法!我们可以按照上文中讲的「同一个交易所账户给机器人配置多个交易所对象」给机器人添加两个交易所对象。 然后还是使用 这个交易所配置,再添加一个交易所对象。 这时会弹出一个提示框! 一个交易所账户配置,不能添加相同币种、交易对的交易所对象。
这样怎么办?看来是不能让策略机器人用两个交易所对象,并且让交易所对象上绑定的是一个交易所账号了码? 还是有办法的!
我们在「控制中心」->「交易所」,再添加一个 OKEX 期货交易所配置。
配置好以后点击保存。
这样带来的好处是什么呢? 当然是编写策略时,设计就很简单啦!
function main(){
exchanges[0].SetContractType("quarter") // 设置第一个添加的交易所对象 当前的合约为季度合约
exchanges[1].SetContractType("this_week") // 设置第二个添加的交易所对象,当前的合约为当周合约
while (true) {
var beginTime = new Date().getTime() // 记录这次获取行情时起始的时间戳。
var rA = exchanges[0].Go("GetTicker") // 创建并发 线程去获取 第一个交易所对象,也就是季度合约的行情数据。
var rB = exchanges[1].Go("GetTicker") // 创建并发 线程去获取 第二个交易所对象,也就是当周合约的行情数据。
var tickerA = rA.wait() // 并发的两个线程各自执行自己的任务,这里等待获取数据,A 等待时,B任务也在执行。
var tickerB = rB.wait() // 所以这里看似是顺序执行,实际在底层是并发的。只不过获取的时候是顺序先获取A,在获取B。
var endTime = new Date().getTime() // 记录并发获取两个合约行情结束时的时间戳。
if (tickerA && tickerB) { // 如果获取的数据没有问题,执行以下逻辑。
var diff = tickerA.Last - tickerB.Last // 计算差价
$.PlotLine("diff", diff) // 使用画线类库把差价画在图表上。
if (diff > 500) { // 如果差价大于500, 对冲套利(当然设置500 的差价是比较大的,很少见。)
// 对冲
rA = exchanges[0].Go("Sell", tickerA.Buy, 1) // 并发线程创建 季度合约下卖单
rB = exchanges[1].Go("Buy", tickerB.Sell, 1) // 并发线程创建 当周合约下买单
var idA = rA.wait() // 等待 返回下单结果,返回的是订单ID
var idB = rB.wait() // ...
}
// ...
}
LogStatus(_D(), "并发获取两个合约行情耗时:", endTime - beginTime, "毫秒。") // 显示在状态栏上时间,以便知道程序在执行。
Sleep(500)
}
}
这样设计策略是不是感觉简单了许多,思路清晰了许多。
实盘运行:
可以看到,每次并发获取两个合约的行情,只耗时50毫秒左右。
韬奋量化 最后一个方法真不错
bwxiaok 棒,这个很有帮助!