跨期布林对冲策略研究-基于发明者量化平台
时间: 2018-11-22来源:OSCHINA
前景提要
「深度学习福利」大神带你进阶工程师,立即查看>>> (Boll)指标是股市技术分析的常用工具之一,通过计算股价的“标准差”,再求股价的“信赖区间”。该指标在图形上画出三条线,其中上下两条线可以分别看成是股价的压力线和支撑线,而在两条线之间还有一条股价平均线,布林线指标的参数最好设为20。一般来说,股价会运行在压力线和支撑线所形成的通道中。
与MACD、RSI、KDJ等指标一样,BOLL指标也是股票市场最实用的技术分析参考指标。

但是这些指标也都是对于历史数据的统计计算形成的,客观的讲是不能绝对预测未来标的物的走势行情的。根据历史的行情数据,计算出的指标,可以作为参考、辅助决策,最终会发现一切都是围绕着概率。

那么 BOLL 指标的实际意义是 标的物价格的 标准差,期货的不同合约之间都有一定的价差,通常情况下 行情平稳的时候价差是保持一定趋势缓慢变动的,遇到“不理性”的订单的时候往往会出现短暂的波动,试想如何抓住这些“不理性”的订单呢?

我们考虑构建一个 《跨期布林对冲策略》 ,从底层撸代码、造车轮 太慢了, 使用 BotVS 分分钟实现你的各种交易思路。

实现这个策略,我们选择标的物为 : OKEX 的 BTC 合约, 稍后我也会写出 标的物 为: 商品期货 合约的该策略 (为什么用BTC 合约? 因为好实现,方便快速写出来 测试!标的物只是一方面,关键是思路 、策略!)

跨期布林对冲策略 var P_isSetOneKLine = true; var isShowChart = true; var retrySlidePrice = 2; // 全局变量 var KPeriod = [PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_D1][P_KPeriod]; var DiffData = { // 差价K线数据 plusKLine : [], // 差价K线数组 minusKLine : [], KPeriod : KPeriod, // 差价K线周期 }; var distance = 0; // 距离 var IDLE = 0; var PLUS = 1; var MINUS = 2; var State = IDLE; // 策略 运行状态状态 var perState = IDLE; var OPEN = 3; // 用于区分 是那种操作 在 BuyA_SellB 、 SellA_BuyB 函数中 var COVER = 4; var isTradeOnThisBar = false; // 是否在当前Bar 交易了 废弃 var isCoverOnthisBar = false; // 废弃 var upRatio = 0; var downRatio = 0; var P = null; // 交易控制对象 var ManagerData = { // 控制对象 initAccount : null, // 初始账户 信息 Account : null, // 当前账户 信息 perAccount : null, MaxUsedRatio : MaxUsedRatio, // 最大 保证金使用率 MaxUsedMargin : 0, // 每次 平仓后 重新计算的 最大保证金使用量 APosition : null, // 多头 仓位信息 BPosition : null, // 空头 仓位信息 floatProfit : 0, // 浮动盈亏 CoverProfit : 0, // 平仓盈亏 MarginLevel : MarginLevel, // 杠杆数 Margin : 0, // 当前保证金使用 // 行情数据 DepthA : null, // A 合约的 深度数据 DepthB : null, // B 合约的 深度数据 // 错误信息 ErrorStr : "", // 错误信息字符串 ErrorTimeStamp : 0, // 错误信息 时间戳 } var DiffDataOneKLine = { // K线结构 KLine : [], // K线数组 ,整理后的差价 KPeriod : KPeriod, // K线周期 } var test = { // 测试 模式 使用的结构 amount : 4, ProfitDiff : 0, ID : 0, OpenDiff : 0, }; var perRecordsTime = 0; // 合成的 K线 上一个bar 的时间戳 var PeriodBeginTime = 0; // 周期起始时间 function UpdateDiffData(DepthA, DepthB, RecordsA, RecordsB){ // 处理差价K线数据的更新 var plusDiff = DepthA.Bids[0].Price - DepthB.Asks[0].Price; var minusDiff = DepthA.Asks[0].Price - DepthB.Bids[0].Price; if(P_isSetOneKLine){ var Diff = _N((plusDiff + minusDiff) / 2 , 4); } if(RecordsA[RecordsA.length - 1].Time == RecordsB[RecordsB.length - 1].Time && RecordsB[RecordsB.length - 1].Time !== PeriodBeginTime){ if(!P_isSetOneKLine){ // 新K线周期出现 var plusBar = { Open : plusDiff, Close : plusDiff, High : plusDiff, Low : plusDiff, Time : 0, }; var minusBar = { Open : minusDiff, Close : minusDiff, High : minusDiff, Low : minusDiff, Time : 0, }; PeriodBeginTime = RecordsB[RecordsB.length - 1].Time; plusBar.Time = PeriodBeginTime; minusBar.Time = PeriodBeginTime; DiffData.plusKLine.push(plusBar); DiffData.minusKLine.push(minusBar); }else{ var Bar = { Open : Diff, Close : Diff, High : Diff, Low : Diff, Time : 0, }; PeriodBeginTime = RecordsB[RecordsB.length - 1].Time; Bar.Time = PeriodBeginTime; DiffDataOneKLine.KLine.push(Bar); } }else{ if(!P_isSetOneKLine){ if(plusDiff > DiffData.plusKLine[DiffData.plusKLine.length - 1].High){ DiffData.plusKLine[DiffData.plusKLine.length - 1].High = plusDiff; }else if(plusDiff < DiffData.plusKLine[DiffData.plusKLine.length - 1].Low){ DiffData.plusKLine[DiffData.plusKLine.length - 1].Low = plusDiff; } DiffData.plusKLine[DiffData.plusKLine.length - 1].Close = plusDiff; if(minusDiff > DiffData.minusKLine[DiffData.minusKLine.length - 1].High){ DiffData.minusKLine[DiffData.minusKLine.length - 1].High = minusDiff; }else if(minusDiff < DiffData.minusKLine[DiffData.minusKLine.length - 1].Low){ DiffData.minusKLine[DiffData.minusKLine.length - 1].Low = minusDiff; } DiffData.minusKLine[DiffData.minusKLine.length - 1].Close = minusDiff; }else{ if(Diff > DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].High){ DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].High = Diff; }else if(Diff < DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Low){ DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Low = Diff; } DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close = Diff; } } if(!P_isSetOneKLine){ if(DiffData.plusKLine.length > 100){ DiffData.plusKLine.shift(); } if(DiffData.minusKLine.length > 100){ DiffData.minusKLine.shift(); } }else{ if(DiffDataOneKLine.KLine.length > 100){ DiffDataOneKLine.KLine.shift(); } } } function UseAPI(fun, symbol, param){ exchange.SetContractType(symbol); if(typeof(param) == "undefined"){ return fun(); }else{ return fun(param); } } function GetPositions(){ var positions = _C(exchange.GetPosition); for(var i = 0; i < positions.length; i++){ if(positions[i].ContractType == P_SymbolA){ ManagerData.APosition = positions[i]; }else if(positions[i].ContractType == P_SymbolB){ ManagerData.BPosition = positions[i]; }else if(i == 2){ throw "error:" + JSON.stringify(positions); } } if(positions.length == 0){ ManagerData.APosition = null; ManagerData.BPosition = null; } return positions; } function SellA_BuyB(DiffPrice, Action){ // GetBestAmount var Piece = P_piece; if(Action == OPEN){ // 检查 是否超出 保证金 var MarginAndAmount_A = CalcPieceEqualAmount(ManagerData.DepthA.Bids[0].Price, Piece); var MarginAndAmount_B = CalcPieceEqualAmount(ManagerData.DepthB.Asks[0].Price, Piece); if(MarginAndAmount_A.NeedMargin + MarginAndAmount_B.NeedMargin + ManagerData.Margin > ManagerData.MaxUsedMargin){ ManagerData.ErrorStr = "超过最大可用保证金:" + ManagerData.MaxUsedMargin; ManagerData.ErrorTimeStamp = new Date().getTime(); return false; } // 交易 _C(exchange.SetContractType, P_SymbolA); var infoA = P.OpenShort(P_SymbolA, Piece, ManagerData.DepthA.Bids[0].Price); if(infoA.amount == 0){ return false; } _C(exchange.SetContractType, P_SymbolB); var dealAmount = infoA.amount; var infoB = P.OpenLong(P_SymbolB, dealAmount, ManagerData.DepthB.Asks[0].Price); var slidePrice = retrySlidePrice; while((dealAmount -= infoB.amount) > 0){ infoB = P.OpenLong(P_SymbolB, dealAmount, ManagerData.DepthB.Asks[0].Price + slidePrice); slidePrice += retrySlidePrice; LogStatus("while(), P_SymbolB:", P_SymbolB, infoB, dealAmount, slidePrice); } // 更新数据 ManagerData.perAccount = ManagerData.Account; ManagerData.Account = _C(exchange.GetAccount); ManagerData.Margin += (ManagerData.perAccount.Stocks - ManagerData.Account.Stocks); Log("持仓信息:", GetPositions(), "本次使用保证金:", (ManagerData.perAccount.Stocks - ManagerData.Account.Stocks)); perState = State; State = PLUS; }else if(Action == COVER){ // 全平 _C(exchange.SetContractType, P_SymbolA); var infoA = P.Cover(P_SymbolA, ManagerData.DepthA.Bids[0].Price, Math.min(ManagerData.APosition.Amount, Math.max(_N(ManagerData.APosition.Amount * CoverRatio, 0), minCoverAmount)), PD_LONG); if(infoA == 0){ return false; } _C(exchange.SetContractType, P_SymbolB); var dealAmount = infoA; var infoB = P.Cover(P_SymbolB, ManagerData.DepthB.Asks[0].Price, dealAmount, PD_SHORT); var slidePrice = retrySlidePrice; while((dealAmount -= infoB) > 0){ infoB = P.Cover(P_SymbolB, ManagerData.DepthB.Asks[0].Price + slidePrice, dealAmount, PD_SHORT); slidePrice += retrySlidePrice; LogStatus("while(), P_SymbolB:", P_SymbolB, infoB, dealAmount, slidePrice); } Log("持仓信息:", GetPositions()); if(ManagerData.APosition == null && ManagerData.BPosition == null){ perState = State; State = IDLE; upRatio = 0; downRatio = 0; Log("完全平仓!#FF0000"); Log("更新最大保证金使用量:", DealManagerData()); LogProfit(ManagerData.Account.Stocks - ManagerData.initAccount.Stocks); // ceshi }else{ ManagerData.perAccount = ManagerData.Account; ManagerData.Account = _C(exchange.GetAccount); Log("部分平仓:", infoA); } } return true; } function BuyA_SellB(DiffPrice, Action){ // GetBestAmount var Piece = P_piece; if(Action == OPEN){ // 检查 是否超出 保证金 var MarginAndAmount_A = CalcPieceEqualAmount(ManagerData.DepthA.Asks[0].Price, Piece); var MarginAndAmount_B = CalcPieceEqualAmount(ManagerData.DepthB.Bids[0].Price, Piece); if(MarginAndAmount_A.NeedMargin + MarginAndAmount_B.NeedMargin + ManagerData.Margin > ManagerData.MaxUsedMargin){ ManagerData.ErrorStr = "超过最大可用保证金:" + ManagerData.MaxUsedMargin; ManagerData.ErrorTimeStamp = new Date().getTime(); return false; } // 交易 _C(exchange.SetContractType, P_SymbolA); var infoA = P.OpenLong(P_SymbolA, Piece, ManagerData.DepthA.Asks[0].Price); if(infoA.amount == 0){ return false; } _C(exchange.SetContractType, P_SymbolB); var dealAmount = infoA.amount; var infoB = P.OpenShort(P_SymbolB, dealAmount, ManagerData.DepthB.Bids[0].Price); var slidePrice = retrySlidePrice; while((dealAmount -= infoB.amount) > 0){ infoB = P.OpenShort(P_SymbolB, dealAmount, ManagerData.DepthB.Bids[0].Price - slidePrice); slidePrice += retrySlidePrice; LogStatus("while(), P_SymbolB:", P_SymbolB, infoB, dealAmount, slidePrice); } // 更新数据 ManagerData.perAccount = ManagerData.Account; ManagerData.Account = _C(exchange.GetAccount); ManagerData.Margin += (ManagerData.perAccount.Stocks - ManagerData.Account.Stocks); Log("持仓信息:", GetPositions(), "本次使用保证金:", (ManagerData.perAccount.Stocks - ManagerData.Account.Stocks)); perState = State; State = MINUS; }else if(Action == COVER){ // 全平 _C(exchange.SetContractType, P_SymbolA); var infoA = P.Cover(P_SymbolA, ManagerData.DepthA.Asks[0].Price, Math.min(ManagerData.APosition.Amount, Math.max(_N(ManagerData.APosition.Amount * CoverRatio, 0), minCoverAmount)), PD_SHORT); if(infoA == 0){ return false; } _C(exchange.SetContractType, P_SymbolB); var dealAmount = infoA; var infoB = P.Cover(P_SymbolB, ManagerData.DepthB.Bids[0].Price, dealAmount, PD_LONG); var slidePrice = retrySlidePrice; while((dealAmount -= infoB) > 0){ infoB = P.Cover(P_SymbolB, ManagerData.DepthB.Bids[0].Price - slidePrice, dealAmount, PD_LONG); slidePrice += retrySlidePrice; LogStatus("while(), P_SymbolB:", P_SymbolB, infoB, dealAmount, slidePrice); } Log("持仓信息:", GetPositions()); if(ManagerData.APosition == null && ManagerData.BPosition == null){ perState = State; State = IDLE; upRatio = 0; // 重置 downRatio = 0; // 重置 Log("完全平仓!#FF0000"); Log("更新最大保证金使用量:", DealManagerData()); LogProfit(ManagerData.Account.Stocks - ManagerData.initAccount.Stocks); // ceshi }else{ ManagerData.perAccount = ManagerData.Account; ManagerData.Account = _C(exchange.GetAccount); Log("部分平仓:", infoA); } } return true; } function DealManagerData(){ // 处理 ManagerData ManagerData.perAccount = ManagerData.Account; ManagerData.Account = _C(exchange.GetAccount); // 获取 平仓后的 账户信息 var Position = _C(exchange.GetPosition); // 获取 平仓后的持仓信息 if(Position.length == 0){ // 如果 平仓完成 ,没有持仓了 重置 ManagerData 的 持仓信息属性 ManagerData.APosition = null; ManagerData.BPosition = null; ManagerData.Margin = 0; // 重置 当前使用的保证金 为 0 }else{ // 如果有持仓 报错,打印持仓 Log("平仓后还有持仓!", Position, "#FF0000"); throw "error!"; } ManagerData.MaxUsedMargin = _N(ManagerData.Account.Stocks * ManagerData.MaxUsedRatio, 2); // 计算下一轮 最大的 保证金使用量 return ManagerData.MaxUsedMargin; } function CalcPieceEqualAmount(Price, Piece){ return { EqualAmount : (100 / Price * Piece), NeedMargin : (100 / Price * Piece) / ManagerData.MarginLevel, } } function Loop(nowTime){ // 主循环 var DepthA = UseAPI(exchange.GetDepth, P_SymbolA); var DepthB = UseAPI(exchange.GetDepth, P_SymbolB); var RecordsA = UseAPI(exchange.GetRecords, P_SymbolA, KPeriod); var RecordsB = UseAPI(exchange.GetRecords, P_SymbolB, KPeriod); // 过滤数据 if(!RecordsA || !RecordsB || !DepthA || !DepthB || DepthA.Bids.length == 0 || DepthA.Asks.length == 0 || DepthB.Bids.length == 0 || DepthB.Asks.length == 0 || RecordsA.length == 0 || RecordsB.length == 0){ return; } ManagerData.DepthA = DepthA; ManagerData.DepthB = DepthB; // 更新 差价K线数据 UpdateDiffData(DepthA, DepthB, RecordsA, RecordsB); if(isShowChart == true){ if(!P_isSetOneKLine){ $.PlotRecords(DiffData.plusKLine, 'plus'); }else{ $.PlotRecords(DiffDataOneKLine.KLine, 'KLine'); } } // BOLL if(P_isSetOneKLine && DiffDataOneKLine.KLine.length > 20){ var boll = TA.BOLL(DiffDataOneKLine.KLine); var up = boll[0]; var mid = boll[1]; var down = boll[2]; if(perRecordsTime !== DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time){ if(isShowChart == true){ $.PlotLine("up", up[up.length - 2], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 2].Time); $.PlotLine("mid", mid[mid.length - 2], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 2].Time); $.PlotLine("down", down[down.length - 2], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 2].Time); $.PlotLine("up", up[up.length - 1], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time); $.PlotLine("mid", mid[mid.length - 1], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time); $.PlotLine("down", down[down.length - 1], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time); // $.PlotHLine(up[up.length - 1], 'UpTrack', "red"); // $.PlotHLine(down[down.length - 1], 'DownTrack', "green"); } perRecordsTime = DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time; isTradeOnThisBar = false; // 重置 是否当前Bar 交易的标记为 false isCoverOnthisBar = false; }else{ if(isShowChart == true){ $.PlotLine("up", up[up.length - 1], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time); $.PlotLine("mid", mid[mid.length - 1], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time); $.PlotLine("down", down[down.length - 1], DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time); // $.PlotHLine(up[up.length - 1], 'UpTrack', "red"); // $.PlotHLine(down[down.length - 1], 'DownTrack', "green"); } } // 突破判断 // 计算加仓距离 distance = _N((up[up.length - 1] - down[down.length - 1]) * 0.5, 0); if(distance * 2 < 20 && (upRatio == 0 && downRatio == 0)){ // 计算安全间距 return; } if(DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close > up[up.length - 1]){ if((State == IDLE || State == PLUS) && (DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close > (up[up.length - 1] + upRatio * distance)) /*&& isTradeOnThisBar == false*/){ // Open PLUS if(P_isSetTest){ // 模拟 $.PlotFlag(nowTime, 'plus', 'P', 'flag', 'red'); State = PLUS; exchange.Log(LOG_TYPE_SELL, test.ID++, DepthA.Bids[0].Price, test.amount, "Open:" + P_SymbolA); exchange.Log(LOG_TYPE_BUY, test.ID++, DepthB.Asks[0].Price, test.amount, "Open:" + P_SymbolB); test.OpenDiff = DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close; }else{ var info = SellA_BuyB(DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close, OPEN); if(info == false){ return; } $.PlotFlag(nowTime, 'plus', 'P', 'flag', 'red'); isTradeOnThisBar = true; upRatio += Add_lv; } }else if(State == MINUS /*&& isCoverOnthisBar == false*/){ // Cover MINUS if(P_isSetTest){ // 模拟 $.PlotFlag(nowTime, 'Cover_Minus', 'CM', 'circlepin', 'blue'); State = IDLE; exchange.Log(LOG_TYPE_SELL, test.ID++, DepthA.Bids[0].Price, test.amount, "Cover:" + P_SymbolA); exchange.Log(LOG_TYPE_BUY, test.ID++, DepthB.Asks[0].Price, test.amount, "Cover:" + P_SymbolB); test.ProfitDiff += DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close - test.OpenDiff; Log("本次盈亏:" + (DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close - test.OpenDiff)); LogProfit(test.ProfitDiff); }else{ // SellA_BuyB var info = SellA_BuyB(DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close, COVER); if(info == false){ Log("MINUS 平仓失败!"); return; } $.PlotFlag(nowTime, 'Cover_Minus', 'CM', 'circlepin', 'blue'); isCoverOnthisBar = true; } } }else if(DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close < down[down.length - 1]){ if((State == IDLE || State == MINUS) && (DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close < (down[down.length - 1] - downRatio * distance)) /*&& isTradeOnThisBar == false*/){ if(P_isSetTest){ // 模拟 $.PlotFlag(nowTime, 'minus', 'M', 'circlepin', 'green'); // DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Time State = MINUS; exchange.Log(LOG_TYPE_BUY, test.ID++, DepthA.Asks[0].Price, test.amount, "Open:" + P_SymbolA); exchange.Log(LOG_TYPE_SELL, test.ID++, DepthB.Bids[0].Price, test.amount, "Open:" + P_SymbolB); test.OpenDiff = DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close; }else{ // BuyA_SellB var info = BuyA_SellB(DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close, OPEN); if(info == false){ return; } $.PlotFlag(nowTime, 'minus', 'M', 'circlepin', 'green'); isTradeOnThisBar = true; downRatio += Add_lv; } }else if(State == PLUS /*&& isCoverOnthisBar == false*/){ if(P_isSetTest){ // 模拟 $.PlotFlag(nowTime, 'Cover_Plus', 'CP', 'flag', 'blue'); State = IDLE; exchange.Log(LOG_TYPE_BUY, test.ID++, DepthA.Asks[0].Price, test.amount, "Cover:" + P_SymbolA); exchange.Log(LOG_TYPE_SELL, test.ID++, DepthB.Bids[0].Price, test.amount, "Cover:" + P_SymbolB); test.ProfitDiff += test.OpenDiff - DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close; Log("本次盈亏:" + (test.OpenDiff - DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close)); LogProfit(test.ProfitDiff); }else{ // BuyA_SellB var info = BuyA_SellB(DiffDataOneKLine.KLine[DiffDataOneKLine.KLine.length - 1].Close, COVER); if(info == false){ Log("PLUS 平仓失败!"); return; } $.PlotFlag(nowTime, 'Cover_Plus', 'CP', 'flag', 'blue'); isCoverOnthisBar = true; } } } } } function main(){ // 初始化工作 if(isLogReset){ LogReset(1); } Log("最大保证金使用量:", DealManagerData()); ManagerData.initAccount = ManagerData.Account; ManagerData.perAccount = ManagerData.Account; exchange.SetMarginLevel(ManagerData.MarginLevel); // 初始设置杠杆 // 设置禁用汇率 exchange.SetRate(1); Log("已禁用汇率,显示价格为美元价格!"); // 创建交易控制对象 P = $.NewPositionManager(exchange); //主要循环 while(true){ var nowTime = new Date().getTime(); Loop(nowTime); LogStatus("时间:", _D(nowTime), '\n', P_isSetTest ? JSON.stringify(test) : "Margin: " + ManagerData.Margin, '\n', ManagerData.ErrorStr, _D(ManagerData.ErrorTimeStamp), '\n', ManagerData.initAccount, '\n', ManagerData.Account, '\n', ManagerData.APosition, '\n', ManagerData.BPosition, '\n', "upRatio:" + upRatio, '\n', "downRatio:" + downRatio, "distance:" + distance); Sleep(P_Interval); } }

编程语言使用的是 JavaScript , 引用了 “ 模板-画线类库” 和 “ OKCoin期货跨期对冲策略(模板测试使用)” 两个模板, 策略公开地址: https://www.botvs.com/strategy/43049** 声明:

该策略为平台用户 小小梦 分享,主要用于发明者量化平台策略编写学习, 实盘虽可用,风险自担! 欢迎大家讨论,多交流,多学习,多提升! 作者本人其实不喜欢闭门造车,进步就要互相学习!

上个回测:

因为频率挺高的,回测滑点等因素影响较小,所以回测仅供参考,策略应该可以进一步优化,小心参数撞车!原创文章, 发明者量化 版权所有。

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

热门排行