BitMEX挂单策略详解
BitMEX已经成为了虚拟货币杠杆交易的首选平台,但其API交易限制严格,让人十分困扰。本文主要分享在FMZ量化交易平台实盘中API使用的少量技巧,主要针对做市策略。
1.BitMEX的特点
最明显的优势是交易活跃,特别是比特币永续合约,每分钟交易额常常超过百万甚至千万美元;BitMEX挂单交易后有返佣,尽管不高,但任吸引了大批做市交易者,所以买一卖一深度极佳,常常在百万美元以上;因为买一卖一积累的深度,所以交易价格常常在最小变动单位0.5美元上下波动。
2.BitMEX API频率限制
REST API 的请求频率限于每5分钟300次。 相当于1秒一次,这个限制比照其它交易平台可以说非常严格。超出限制后,会提醒’Rate limit exceeded’,假如继续超出限制,IP可能被禁用一小时,在短时间内的多个禁用将导致禁用一周。对每个 API 的请求,BitMEX将返回标头数据,标头数据来查看当前的剩余的请求次数,事实上,假如API使用得当,是不会超出频率限制,一般不用检查。
3.使用websocket获取行情
BitMEX REST API 限制比较严格,官方推荐多用websocket协议,并且推送的数据类型比一般的交易所要多。具体使用要注意以下几点:
- 深度数据推送时间长了会出现误差,和真实深度对应不上,预计是深度变化太多,推送有遗漏,但一般情况下因为流动性极佳,订阅ticker或者trades就可
- 订单介绍推送遗漏很多,几乎不可用。
- 账户信息推送会有显著延时,最好使用REST API确认。
- 在行情波动大时,推送延时会达到几秒钟。
以下代码为使用websocket协议,实时获取行情和账户信息,主要针对做市策略编写。具体使用需要在main()函数里执行。
var ticker = {price:0, buy:0, sell:0, time:0} //ticker信息,分别为最新价、买一价、卖一价、升级时间//账户信息,分别有仓位,买卖价格,买卖数量,买卖状态,订单Idvar info = {position:0, buyPrice:0, sellPrice:0, buyAmount:0, sellAmount:0, buyState:0, sellState:0, buyId:0, sellId:0}var buyListId = []//全局变量,预埋买单id列表,下文有详情var sellListId = []var APIKEY = 'your api id' //这里需要填入BitMEX API ID 注意不是密钥,websocket协议验证时需要var expires = parseInt(Date.now() / 1000) + 10var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey}}")//secretkey会在底层自动替换,不需要填入。var bitmexClient = Dial("wss://www.bitmex.com/realtime", 60)var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})//认证信息,不然无法订阅账户bitmexClient.write(auth)bitmexClient.write('{"op": "subscribe", "args": ["position","execution","trade:XBTUSD"]}')//订阅了仓位、订单执行和永续合约实时成交while(true){ if(bitmexClient.read()){ bitmexData = JSON.parse(data) if('table' in bitmexData && bitmexData.table == 'trade'){ data = bitmexData.data ticker.price = parseFloat(data[data.length-1].price)//最新成交价,一次会推送多条成交,取一个就可 //可根据最新成交的trade方向得出买一卖一,不用订阅深度。 if(data[data.length-1].side == 'Buy'){ ticker.sell = parseFloat(data[data.length-1].price) ticker.buy = parseFloat(data[data.length-1].price)-0.5 }else{ ticker.buy = parseFloat(data[data.length-1].price) ticker.sell = parseFloat(data[data.length-1].price)+0.5 } ticker.time = new Date(data[data.length-1].timestamp);//升级时间,可用于判断延时 } }else if(bitmexData.table == 'position'){ var position = parseInt(bitmexData.data[0].currentQty) if(position != info.position){ Log('仓位变化: ', position, info.position, '#FF0000@')//仓位变化Log,并推送到微信,去掉@不推送 info.position = position } info.position = parseInt(bitmexData.data[0].currentQty) }}
4.下单技巧
BitMEX官方推荐使用批量下单和修改订单来实现,因为 BitMEX 实时的审计、风险检查、保证金计算、以及委托操作,批量操作可以更快地被执行。因而,批量操作的频率被计算为正常频率的十分之一。因而我们的下单操作要一律使用批量下单和修改订单的方式,尽量减少API的使用,而查询订单状态也需要消耗API次数,可以根据仓位变化或者修改订单失败辅助判断订单状态。
批量下单并没有限制订单数量(不能太多),实际上一个订单也能使用批量下单接口。因为修改订单的操作,我们可以在价格偏离很大的地方预下少量订单,它们不会成交,但我们需要下单时,只要要修改已下订单的价格和数量就可。修改订单会出现失败,这也可以作为订单成交的信号。
以下为具体的实现代码:
//撤销所有订单,并重置全局变量function cancelAll(){ exchange.IO("api","DELETE","/api/v1/order/all","symbol=XBTUSD")//调用IO扩展撤销 info = {position:0, buyPrice:0, sellPrice:0, buyAmount:0, sellAmount:0, buyState:0, sellState:0, buyId:0, sellId:0} buyListId = [] sellListId = []}//下备选订单function waitOrders(){ var orders = [] if(buyListId.length<4){ //检查数量不足时再下一批 for(var i=0;i<7;i++){ //因为BitMEX限制,价格不能偏离过多,订单量不能太小,execInst参数保证只能做市成交 orders.push({symbol:'XBTUSD', side:'Buy', orderQty:100, price:ticker.buy-400+i, execInst:'ParticipateDoNotInitiate'}) } } if(sellListId.length<4){ for(var i=0;i<7;i++){ orders.push({symbol:'XBTUSD', side:'Sell', orderQty:100, price:ticker.buy+400+i, execInst:'ParticipateDoNotInitiate'}) } } if(orders.length>0){ var param = "orders=" + JSON.stringify(orders); var ids = exchange.IO("api", "POST", "/api/v1/order/bulk", param);//批量订单在这里提交 for(var i=0;i<ids.length;i++){ if(ids.side == 'Buy'){ buyListId.push(ids.orderID) }else{ sellListId.push(ids.orderID) } } }}//修改订单函数function amendOrders(order, direction, price, amount, id){ var param = "orders=" + JSON.stringify(order); var ret = exchange.IO("api", "PUT", "/api/v1/order/bulk", param);//每次修改一个订单 //修改出现错误 if(!ret){ var err = GetLastError() //overloaded未修改策成功,需要把订单id回收 if(err.includes('The system is currently overloaded')){ if(id){ if(direction == 'buy'){ buyListId.push(id) }else{ sellListId.push(id) } } Sleep(1000) return } //非法订单状态,说明待修改的订单已完全成交 else if(err.includes('Invalid ordStatus')){ Log(order, direction) if(direction == 'buy'){ info.buyId = 0 info.buyState = 0 info.buyAmount = 0 info.buyPrice = 0 }else{ info.sellId = 0 info.sellState = 0 info.sellAmount = 0 info.sellPrice = 0 } //因为推送不及时,在这里用rest协议升级一下仓位 pos = _C(exchange.GetPosition) if(pos.length>0){ info.position = pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount }else{ info.position = 0 } } //出现未知错误无法修改,撤销所有订单,重置一次 else if(err.includes('Invalid orderID')){ cancelAll() Log('Invalid orderID,重置一次') } //超过频率限制,休眠一下可继续尝试 else if(err.includes('Rate limit exceeded')){ Sleep(2000) return } //账户被禁,撤销所有订单,休眠较长时间等待恢复 else if(err.includes('403 Forbidden')){ cancelAll() Log('403,重置一次') Sleep(5*60*1000) } }else{ //修改订单成功 if(direction == 'buy'){ info.buyState = 1 info.buyPrice = price info.buyAmount = amount }else{ info.sellState = 1 info.sellPrice = price info.sellAmount = amount } }}//0.5价格变化function fixSize(num){ if(num>=_N(num,0)+0.75){ num = _N(num,0)+1 }else if(num>=_N(num,0)+0.5){ num=_N(num,0)+0.5 }else{ num=_N(num,0) } return num}//交易函数function trade(){ waitOrders()//检查能否需要下备选单 var buyPrice = fixSize(ticker.buy-5) //仅作演示用,具体的交易要自己写 var sellPrice = fixSize(ticker.sell+5) var buyAmount = 500 var sellAmount = 500 //没有订单时,从备选订单修改 if(info.buyState == 0 && buyListId.length > 0){ info.buyId = buyListId.shift() amendOrders([{orderID:info.buyId, price:buyPrice, orderQty:buyAmount}],'buy', group, buyPrice, buyAmount, info.buyId) } if(info.sellState == 0 && sellListId.length > 0){ info.sellId = sellListId.shift() amendOrders([{orderID: info.sellId, price:sellPrice, orderQty:sellAmount}],'sell', group, sellPrice, sellAmount, info.sellId ) } //已有订单需要更改价格 if(buyPrice != info.buyPrice && info.buyState == 1){ amendOrders([{orderID:info.buyId, price:buyPrice, orderQty:buyAmount}],'buy', group, buyPrice, buyAmount) } if(sellPrice != info.sellPrice && info.sellState == 1){ amendOrders([{orderID:info.sellId, price:sellPrice, orderQty:sellAmount}],'sell', group, sellPrice, sellAmount) }}
5.其它
BitMEX的服务器在爱尔兰都柏林亚马逊机房,购买此处服务器运行策略ping低于1ms,但推送任有延时,也无法处理overload问题。另外登陆账户时代理商不可位于美国等地,时间长了会直接封帐号。
本文代码从我个人策略修改而来,不保证完全正确,供参考。具体使用要把行情代码放在main函数里执行,交易相关的代码放在main函数之前,trade()函数放在推送行情里即可以了。
转载自 : https://quant.la/Article/View/2029/BitMEX挂单策略详解.html
作者 : 小草
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » BitMEX挂单策略详解