索罗斯在1987年撰写的《金融炼金术》 一书中,曾经提出过一个重要的命题:I believe the market prices are always wrong in the sense that they present a biased view of the future. 算法
市场有效假说只是理论上的假设,实际上市场参与者并不老是理性的,而且在每个时间点上,参与者不可能彻底获取和客观解读全部的信息,再者就算是一样的信息,每一个人的反馈都不尽相同。数组
也就是说,价格自己就已经包含了市场参与者的错误预期,因此本质上市场价格总错误的。这或许是套利者的利润来源。框架
根据上述原理,咱们也就知道,在一个非有效的期货市场中,不一样时期交割合约之间受到市场影响也并不老是同步,其订价也并不是彻底有效的缘由。函数
那么,根据同一种交易标的的不一样时期交割合约价格为基础,若是两个价格出现了较大的价差幅度,就能够同时买卖不一样时期的期货合约,进行跨期套利。区块链
与商品期货同样,数字货币也有与之相关的跨期套利合约组合。如在 OkEX 交易所中就有:ETC 当周、ETC 次周、ETC 季度。
举个例子,假设 ETC 当周和 ETC 季度的价差长期维持在 5 左右。若是某一天价差达到 7,咱们预计价差会在将来某段时间回归到 5。那么就能够卖出 ETC 当周,同时买入 ETC 季度,来作空这个价差。反之亦然。this
尽管这种价差是存在的,可是人工操做耗时、准确性差以及价格变化的影响,人工套利每每存在诸多不肯定性。
经过量化模型捕捉套利机会并制定套利交易策略,以及程序化算法自动向交易所下达交易订单,快速准确捕捉机会,高效稳定赚取收益,这就是量化套利的魅力所在。 spa
本篇将会教你们如何在数字货币交易中,利用发明者量化交易平台和 OkEX 交易所中 ETC 期货合约,以一个简单的套利策略,来演示若是捕捉瞬时的套利机会,把握住每一次能够看获得的利润,同时对冲有可能遇到的风险。prototype
建立一个数字货币跨期套利策略3d
难易度:普通级 code
策略环境
策略逻辑
上面是一个简单的数字货币跨期套利策略逻辑描述,那么如何在程序中实现本身的想法呢?咱们试着在发明者量化交易平台先把框架搭建起来。
策略框架:
/* 全局变量 */ // 基础数据 function Data(tradeTypeA, tradeTypeB) {} // 获取持仓 Data.prototype.mp = function (tradeType, type) {} // 合成新K线数据和boll指标数据 Data.prototype.boll = function (num, timeCycle) {} // 下单 Data.prototype.trade = function (tradeType, type) {} // 取消订单 Data.prototype.cancelOrders = function () {} // 处理持有单个合约 Data.prototype.isEven = function () {} // 画图 Data.prototype.drawingChart = function (boll) {} // 交易条件 function onTick() { var data; // 获取基础数据对象 data.accountData.Stocks; // 获取帐户余额 data.boll; // 获取boll指标数据 data.mp; // 获取持仓状态 data.cancelOrders(); // 撤单 data.drawingChart(boll); // 画图 data.isEven(); // 处理持有单个合约 } //入口函数 function main() { /* 交易策略预处理 */ while (true) { // 进入轮询模式 onTick(); // 执行onTick函数 Sleep(500); // 休眠0.5秒 } }
对照着策略思路以及交易流程,能够很轻松把策略框架搭建起来。整个策略能够简化为三个步骤:
接下来,咱们就须要根据实际交易流程和交易细节,在策略框架里面填充必要的细节代码。
第1步:在全局环境中,声明必要的全局变量。
第2步:配置策略的外部参数。
第3步:定义数据处理函数
基础数据函数:Data ( )
建立一个构造函数 Data,并定义它的内部属性。包括:帐户数据、持仓数据、K线数据时间戳、套利A/B合约的买/卖一价、正/反套价差。
// 基础数据 function Data(tradeTypeA, tradeTypeB) { // 传入套利A合约和套利B合约 this.accountData = _C(exchange.GetAccount); // 获取帐户信息 this.positionData = _C(exchange.GetPosition); // 获取持仓信息 var recordsData = _C(exchange.GetRecords); //获取K线数据 exchange.SetContractType(tradeTypeA); // 订阅套利A合约 var depthDataA = _C(exchange.GetDepth); // 套利A合约深度数据 exchange.SetContractType(tradeTypeB); // 订阅套利B合约 var depthDataB = _C(exchange.GetDepth); // 套利B合约深度数据 this.time = recordsData[recordsData.length - 1].Time; // 获取最新数据时间 this.askA = depthDataA.Asks[0].Price; // 套利A合约卖一价 this.bidA = depthDataA.Bids[0].Price; // 套利A合约买一价 this.askB = depthDataB.Asks[0].Price; // 套利B合约卖一价 this.bidB = depthDataB.Bids[0].Price; // 套利B合约买一价 // 正套价差(合约A卖一价 - 合约B买一价) this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price; // 反套价差(合约A买一价 - 合约B卖一价) this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price; }
获取持仓函数:mp ( )
遍历整个持仓数组,返回指定合约、指定方向的持仓数量,若是没有就返回 false
// 获取持仓 Data.prototype.mp = function (tradeType, type) { var positionData = this.positionData; // 获取持仓信息 for (var i = 0; i < positionData.length; i++) { if (positionData[i].ContractType == tradeType) { if (positionData[i].Type == type) { if (positionData[i].Amount > 0) { return positionData[i].Amount; } } } } return false; }
K线和指标函数:boll ( )
根据正/反套价差数据,合成新的K线序列。并返回由boll指标计算的上轨、中轨、下轨数据。
// 合成新K线数据和boll指标数据 Data.prototype.boll = function (num, timeCycle) { var self = {}; // 临时对象 // 正套价差和反套价差中间值 self.Close = (this.basb + this.sabb) / 2; if (this.timeA == this.timeB) { self.Time = this.time; } // 对比两个深度数据时间戳 if (this.time - oldTime > timeCycle * 60000) { bars.push(self); oldTime = this.time; } // 根据指定时间周期,在K线数组里面传入价差数据对象 if (bars.length > num * 2) { bars.shift(); // 控制K线数组长度 } else { return; } var boll = TA.BOLL(bars, num, 2); // 调用talib库中的boll指标 return { up: boll[0][boll[0].length - 1], // boll指标上轨 middle: boll[1][boll[1].length - 1], // boll指标中轨 down: boll[2][boll[2].length - 1] // boll指标下轨 } // 返回一个处理好的boll指标数据 }
下单函数:trade ( )
传入下单合约名称和下单类型,而后以对价下单,并返回下单后的结果。因为须要同时下两个不一样方向的单子,因此在函数内部根据下单合约名称对买/卖一价作了转换。
// 下单 Data.prototype.trade = function (tradeType, type) { exchange.SetContractType(tradeType); // 下单前先从新订阅合约 var askPrice, bidPrice; if (tradeType == tradeTypeA) { // 若是是A合约下单 askPrice = this.askA; // 设置askPrice bidPrice = this.bidA; // 设置bidPrice } else if (tradeType == tradeTypeB) { // 若是是B合约下单 askPrice = this.askB; // 设置askPrice bidPrice = this.bidB; // 设置bidPrice } switch (type) { // 匹配下单模式 case "buy": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); case "sell": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closebuy": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closesell": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); default: return false; } }
取消订单函数:cancelOrders ( )
获取全部未成交订单数组,并逐个取消。而且若是有未成交的订单就返回false,若是没有未成交的订单就返回true。
// 取消订单 Data.prototype.cancelOrders = function () { Sleep(500); // 撤单前先延时,由于有些交易所你懂的 var orders = _C(exchange.GetOrders); // 获取未成交订单数组 if (orders.length > 0) { // 若是有未成交的订单 for (var i = 0; i < orders.length; i++) { //遍历未成交订单数组 exchange.CancelOrder(orders[i].Id); //逐个取消未成交的订单 Sleep(500); //延时0.5秒 } return false; // 若是取消了未成交的单子就返回false } return true; //若是没有未成交的订单就返回true }
处理持有单个合约:isEven ( )
在处理套利交易中出现单腿状况,这里直接用简单的平掉全部仓位处理。固然,也能够改成追单方式。
// 处理持有单个合约 Data.prototype.isEven = function () { var positionData = this.positionData; // 获取持仓信息 var type = null; // 转换持仓方向 // 若是持仓数组长度余2不等于0或者持仓数组长度不等于2 if (positionData.length % 2 != 0 || positionData.length != 2) { for (var i = 0; i < positionData.length; i++) { // 遍历持仓数组 if (positionData[i].Type == 0) { // 若是是多单 type = 10; // 设置下单参数 } else if (positionData[i].Type == 1) { // 若是是空单 type = -10; // 设置下单参数 } // 平掉全部仓位 this.trade(positionData[i].ContractType, type, positionData[i].Amount); } } }
画图函数:drawingChart ( )
调用 ObjChart.add ( ) 方法,在图表中画出必要的行情数据和指标数据:上轨、中轨、下轨、正/反套价差。
// 画图 Data.prototype.drawingChart = function (boll) { var nowTime = new Date().getTime(); ObjChart.add([0, [nowTime, boll.up]]); ObjChart.add([1, [nowTime, boll.middle]]); ObjChart.add([2, [nowTime, boll.down]]); ObjChart.add([3, [nowTime, this.basb]]); ObjChart.add([4, [nowTime, this.sabb]]); ObjChart.update(chart); }
第4步:在入口函数 main ( ) 里面,执行交易前预处理代码,这些代码在程序启动后,只运行一次。包括:
//入口函数 function main() { // 过滤控制台中不是很重要的信息 SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP"); exchange.IO("currency", name + '_USDT'); //设置要交易的数字货币币种 ObjChart.reset(); //程序启动前清空以前绘制的图表 LogProfitReset(); //程序启动前清空以前的状态栏信息 }
定义完上述的交易前预处理,紧接着就要进入下一个步骤,进入轮询模式,重复执行 onTick ( ) 函数。
并设置 Sleep ( ) 轮询时的休眠时间,由于部分数字货币交易所的 API 对必定时间内内置了访问次数限制。
//入口函数 function main() { // 过滤控制台中不是很重要的信息 SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP"); exchange.IO("currency", name + '_USDT'); //设置要交易的数字货币币种 ObjChart.reset(); //程序启动前清空以前绘制的图表 LogProfitReset(); //程序启动前清空以前的状态栏信息 while (true) { // 进入轮询模式 onTick(); // 执行onTick函数 Sleep(500); // 休眠0.5秒 } }
第1步:获取基础数据对象、帐户余额、boll 指标数据,以供交易逻辑使用。
// 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 建立一个基础数据对象 var accountStocks = data.accountData.Stocks; // 帐户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 若是没有boll数据就返回 }
第1步:根据上述的策略逻辑,执行买卖操做。首先会判断价格和指标条件是否成立,而后再判断持仓条件是否成立,最后执行 trade ( ) 下单函数
// 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 建立一个基础数据对象 var accountStocks = data.accountData.Stocks; // 帐户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 若是没有boll数据就返回 // 价差说明 // basb = (合约A卖一价 - 合约B买一价) // sabb = (合约A买一价 - 合约B卖一价) if (data.sabb > boll.middle && data.sabb < boll.up) { // 若是sabb高于中轨 if (data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "closebuy"); // 合约A平多 } if (data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "closesell"); // 合约B平空 } } else if (data.basb < boll.middle && data.basb > boll.down) { // 若是basb低于中轨 if (data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "closesell"); // 合约A平空 } if (data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "closebuy"); // 合约B平多 } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 若是帐户有余额 if (data.basb < boll.down) { // 若是basb价差低于下轨 if (!data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "buy"); // 合约A开多 } if (!data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "sell"); // 合约B开空 } } else if (data.sabb > boll.up) { // 若是sabb价差高于上轨 if (!data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "sell"); // 合约A开空 } if (!data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "buy"); // 合约B开多 } } } }
第2步:下单完成后,须要对未成交的订单、持有单个合约等非正常状况作处理。以及绘制图表。
// 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 建立一个基础数据对象 var accountStocks = data.accountData.Stocks; // 帐户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 若是没有boll数据就返回 // 价差说明 // basb = (合约A卖一价 - 合约B买一价) // sabb = (合约A买一价 - 合约B卖一价) if (data.sabb > boll.middle && data.sabb < boll.up) { // 若是sabb高于中轨 if (data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "closebuy"); // 合约A平多 } if (data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "closesell"); // 合约B平空 } } else if (data.basb < boll.middle && data.basb > boll.down) { // 若是basb低于中轨 if (data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "closesell"); // 合约A平空 } if (data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "closebuy"); // 合约B平多 } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 若是帐户有余额 if (data.basb < boll.down) { // 若是basb价差低于下轨 if (!data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "buy"); // 合约A开多 } if (!data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "sell"); // 合约B开空 } } else if (data.sabb > boll.up) { // 若是sabb价差高于上轨 if (!data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "sell"); // 合约A开空 } if (!data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "buy"); // 合约B开多 } } } data.cancelOrders(); // 撤单 data.drawingChart(boll); // 画图 data.isEven(); // 处理持有单个合约 }
以上,咱们经过 200 多行,就把一个简单的数字货币跨期套利策略完完整整的建立出来。完整的代码以下:
// 全局变量 // 声明一个配置图表的 chart 对象 var chart = { __isStock: true, tooltip: { xDateFormat: '%Y-%m-%d %H:%M:%S, %A' }, title: { text: '交易盈亏曲线图(详细)' }, rangeSelector: { buttons: [{ type: 'hour', count: 1, text: '1h' }, { type: 'hour', count: 2, text: '3h' }, { type: 'hour', count: 8, text: '8h' }, { type: 'all', text: 'All' }], selected: 0, inputEnabled: false }, xAxis: { type: 'datetime' }, yAxis: { title: { text: '价差' }, opposite: false, }, series: [{ name: "上轨", id: "线1,up", data: [] }, { name: "中轨", id: "线2,middle", data: [] }, { name: "下轨", id: "线3,down", data: [] }, { name: "basb", id: "线4,basb", data: [] }, { name: "sabb", id: "线5,sabb", data: [] }] }; var ObjChart = Chart(chart); // 画图对象 var bars = []; // 存储价差序列 var oldTime = 0; // 记录历史数据时间戳 // 参数 var tradeTypeA = "this_week"; // 套利A合约 var tradeTypeB = "quarter"; // 套利B合约 var dataLength = 10; //指标周期长度 var timeCycle = 1; // K线周期 var name = "ETC"; // 币种 var unit = 1; // 下单量 // 基础数据 function Data(tradeTypeA, tradeTypeB) { // 传入套利A合约和套利B合约 this.accountData = _C(exchange.GetAccount); // 获取帐户信息 this.positionData = _C(exchange.GetPosition); // 获取持仓信息 var recordsData = _C(exchange.GetRecords); //获取K线数据 exchange.SetContractType(tradeTypeA); // 订阅套利A合约 var depthDataA = _C(exchange.GetDepth); // 套利A合约深度数据 exchange.SetContractType(tradeTypeB); // 订阅套利B合约 var depthDataB = _C(exchange.GetDepth); // 套利B合约深度数据 this.time = recordsData[recordsData.length - 1].Time; // 获取最新数据时间 this.askA = depthDataA.Asks[0].Price; // 套利A合约卖一价 this.bidA = depthDataA.Bids[0].Price; // 套利A合约买一价 this.askB = depthDataB.Asks[0].Price; // 套利B合约卖一价 this.bidB = depthDataB.Bids[0].Price; // 套利B合约买一价 // 正套价差(合约A卖一价 - 合约B买一价) this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price; // 反套价差(合约A买一价 - 合约B卖一价) this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price; } // 获取持仓 Data.prototype.mp = function (tradeType, type) { var positionData = this.positionData; // 获取持仓信息 for (var i = 0; i < positionData.length; i++) { if (positionData[i].ContractType == tradeType) { if (positionData[i].Type == type) { if (positionData[i].Amount > 0) { return positionData[i].Amount; } } } } return false; } // 合成新K线数据和boll指标数据 Data.prototype.boll = function (num, timeCycle) { var self = {}; // 临时对象 // 正套价差和反套价差中间值 self.Close = (this.basb + this.sabb) / 2; if (this.timeA == this.timeB) { self.Time = this.time; } // 对比两个深度数据时间戳 if (this.time - oldTime > timeCycle * 60000) { bars.push(self); oldTime = this.time; } // 根据指定时间周期,在K线数组里面传入价差数据对象 if (bars.length > num * 2) { bars.shift(); // 控制K线数组长度 } else { return; } var boll = TA.BOLL(bars, num, 2); // 调用talib库中的boll指标 return { up: boll[0][boll[0].length - 1], // boll指标上轨 middle: boll[1][boll[1].length - 1], // boll指标中轨 down: boll[2][boll[2].length - 1] // boll指标下轨 } // 返回一个处理好的boll指标数据 } // 下单 Data.prototype.trade = function (tradeType, type) { exchange.SetContractType(tradeType); // 下单前先从新订阅合约 var askPrice, bidPrice; if (tradeType == tradeTypeA) { // 若是是A合约下单 askPrice = this.askA; // 设置askPrice bidPrice = this.bidA; // 设置bidPrice } else if (tradeType == tradeTypeB) { // 若是是B合约下单 askPrice = this.askB; // 设置askPrice bidPrice = this.bidB; // 设置bidPrice } switch (type) { // 匹配下单模式 case "buy": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); case "sell": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closebuy": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closesell": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); default: return false; } } // 取消订单 Data.prototype.cancelOrders = function () { Sleep(500); // 撤单前先延时,由于有些交易所你懂的 var orders = _C(exchange.GetOrders); // 获取未成交订单数组 if (orders.length > 0) { // 若是有未成交的订单 for (var i = 0; i < orders.length; i++) { //遍历未成交订单数组 exchange.CancelOrder(orders[i].Id); //逐个取消未成交的订单 Sleep(500); //延时0.5秒 } return false; // 若是取消了未成交的单子就返回false } return true; //若是没有未成交的订单就返回true } // 处理持有单个合约 Data.prototype.isEven = function () { var positionData = this.positionData; // 获取持仓信息 var type = null; // 转换持仓方向 // 若是持仓数组长度余2不等于0或者持仓数组长度不等于2 if (positionData.length % 2 != 0 || positionData.length != 2) { for (var i = 0; i < positionData.length; i++) { // 遍历持仓数组 if (positionData[i].Type == 0) { // 若是是多单 type = 10; // 设置下单参数 } else if (positionData[i].Type == 1) { // 若是是空单 type = -10; // 设置下单参数 } // 平掉全部仓位 this.trade(positionData[i].ContractType, type, positionData[i].Amount); } } } // 画图 Data.prototype.drawingChart = function (boll) { var nowTime = new Date().getTime(); ObjChart.add([0, [nowTime, boll.up]]); ObjChart.add([1, [nowTime, boll.middle]]); ObjChart.add([2, [nowTime, boll.down]]); ObjChart.add([3, [nowTime, this.basb]]); ObjChart.add([4, [nowTime, this.sabb]]); ObjChart.update(chart); } // 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 建立一个基础数据对象 var accountStocks = data.accountData.Stocks; // 帐户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 若是没有boll数据就返回 // 价差说明 // basb = (合约A卖一价 - 合约B买一价) // sabb = (合约A买一价 - 合约B卖一价) if (data.sabb > boll.middle && data.sabb < boll.up) { // 若是sabb高于中轨 if (data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "closebuy"); // 合约A平多 } if (data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "closesell"); // 合约B平空 } } else if (data.basb < boll.middle && data.basb > boll.down) { // 若是basb低于中轨 if (data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "closesell"); // 合约A平空 } if (data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "closebuy"); // 合约B平多 } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 若是帐户有余额 if (data.basb < boll.down) { // 若是basb价差低于下轨 if (!data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "buy"); // 合约A开多 } if (!data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "sell"); // 合约B开空 } } else if (data.sabb > boll.up) { // 若是sabb价差高于上轨 if (!data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "sell"); // 合约A开空 } if (!data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "buy"); // 合约B开多 } } } data.cancelOrders(); // 撤单 data.drawingChart(boll); // 画图 data.isEven(); // 处理持有单个合约 } //入口函数 function main() { // 过滤控制台中不是很重要的信息 SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP"); exchange.IO("currency", name + '_USDT'); //设置要交易的数字货币币种 ObjChart.reset(); //程序启动前清空以前绘制的图表 LogProfitReset(); //程序启动前清空以前的状态栏信息 while (true) { // 进入轮询模式 onTick(); // 执行onTick函数 Sleep(500); // 休眠0.5秒 } }
本篇策略只是一个抛砖引玉,真实的实盘可不是这么简单,不过你能够照着例子发挥本身天马行空的想象。
须要提醒你们的是,以我有限的经验来看,目前的数字货币市场情况,纯粹的期期套利策略基本上所有不值得跑,不管是无风险的三角套利仍是跨市场套利。
缘由就在于,不管哪一个数字货币交易所的期货市场,其保证金不是法币。现现在几乎全部的数字货币从今年初至今已经下跌了70%左右。也就是说策略始终都是在赚币,可是币价是下跌的。
放眼望去,数字货币市场俨然已经脱离了区块链,就像当年的郁金香同样,价格始终来自于人们的预期和信心,信心又来源于价格…