海龟策略深入研究-策略回测系列-14 上一笔盈利过滤检验

本文探讨了上一笔盈利过滤在不同频率CTA策略中的应用效果。研究发现,对于日线级别的中低频策略,此过滤器能显著提高年化收益和夏普比率,有效降低无效交易造成的损失。但在日内中高频策略中,该过滤器可能因市场噪声而失去效用。

上一笔盈利过滤的意思是,若上一次交易为盈利的,则当前的交易信号无效,即当前不进行交易。

 

基于20日唐奇安通道,费思认为若上一次突破是盈利的,那么新突破点可能离当前价格,因为有可能跑到55日突破点上面去;若上一次突破点亏损,那么新突破点将更加接近当前价格。
 
若基于传统日内中高频CTA策略的视角,这是非常主观的解释:费思认为这几乎不可能连续2次出现大行情,但是事实是分钟级别的CTA策略有可能出现2次大行情,故首次盈利过滤的作用仅仅是节省手续费和滑点,但是错过了潜在的巨大收益。
 
但是呢,基于日线级别中低频CTA策略,其首次盈利过滤是否有效还需要进行验证。
 
本次测试的基准是剔除长周期版本的“新”海龟策略,海龟组合是在上面的章节中挑选的投资组合(回望周期为3年;筛选标准是回归夏普比率>0.6),然后把海龟策略分为含义上一笔盈利过滤和不含上一笔盈利过滤这两个版本,测试效果如图所示。
 
enter image description here
 

从上一笔盈利对比图中可以看出:

  • 不含上一笔盈利过滤版本:总成交笔数1325,年化收益41.23%,百分比最大回撤-22.32%,夏普比率达1.4。
  • 含上一笔盈利过滤版本:总成交笔数为1090,年化收益44.34%,百分比最大回撤-25.61%,夏普比率达1.5。

 

增加过滤器后,总成交笔数降低了,年化收益和夏普比率都提高了,因此可以推断海龟策略独有的上一笔盈利过滤是对于日线级别的趋势跟踪策略是非常有效的,其作用在于降低无效交易(即假突破)所造成的亏损,在整体上提高的策略的胜率。

 

(该结论在统计学来看,就是在日线级别中,连续出现2次大行情的概率极其低,应对方案就是剔除低概率事件,从而提高整体的胜率。)

 

  • 在日内中高频CTA策略中,该过滤器无效或许是Tick或者分别级别K线所包含的噪声更多,故提高连续出现2次大行情的概率;
  • 但是日线级别数据所包含的噪声更少,更能够有助于判断趋势,而趋势本身就非常难以出现连续2次的大行情。
你提到“很容易爆仓,盈利不理想”,这是很多量化交易者在使用海龟交易策略或其他趋势跟踪策略时常见的问题,尤其是在没有合理资金管理和风险控制的情况下。 为了优化策略并避免爆仓,我们可以从以下几个方面进行改进: --- ## ✅ 优化方向 ### 1. **引入 ATR 动态止损** 使用平均真实波幅(ATR)来设置止损,可以避免固定止损在波动大的行情中频繁止损。 ### 2. **动态仓位管理** 根据账户余额、风险比例和止损点数动态计算下单手数。 ### 3. **过滤震荡行情** 加入布林带或 ADX 指标,避免在震荡行情中频繁开仓。 ### 4. **优化入场信号** 使用更精确的通道突破方式,如结合 20 周期和 55 周期通道突破。 --- ## ✅ 优化后的 MQL5 EA 示例代码(部分优化) ```mql5 //+------------------------------------------------------------------+ //| TurtleEA.mq5 | //| 优化后的海龟策略EA | //+------------------------------------------------------------------+ #property strict extern int FastPeriod = 20; // 入场通道周期 extern int SlowPeriod = 55; // 出场通道周期 extern double RiskPercent = 1.0; // 风险百分比 extern int ATRPeriod = 14; // ATR周期 extern double ATRMultiplier = 2.0;// ATR乘数作为止损 extern int MagicNumber = 123456; // 订单魔术号 //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if (IsNewBar()) { // 开仓逻辑 TradeLogic(); } } // 判断是否新K线 bool isNewBar() { static datetime lastTime = 0; datetime curTime = iTime(_Symbol, 0, 0); if (curTime != lastTime) { lastTime = curTime; return true; } return false; } // 交易逻辑 void TradeLogic() { double fastHigh = iHigh(NULL, 0, FastPeriod); double fastLow = iLow(NULL, 0, FastPeriod); double slowHigh = iHigh(NULL, 0, SlowPeriod); double slowLow = iLow(NULL, 0, SlowPeriod); double currentClose = SymbolInfoDouble(_Symbol, SYMBOL_BID); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double lot = CalculateLotSize(ATRPeriod, ATRMultiplier); int total = PositionsTotal(); // 做多信号 if (currentClose > fastHigh && total == 0) { TradeOpen(ORDER_TYPE_BUY, lot); } // 做空信号 else if (currentClose < fastLow && total == 0) { TradeOpen(ORDER_TYPE_SELL, lot); } // 动态止损止盈 for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == _Symbol) { double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double stopLoss = PositionGetDouble(POSITION_SL); double atrValue = iATR(NULL, 0, ATRPeriod, 1); double newSl = 0; ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE); if (type == ORDER_TYPE_BUY) newSl = openPrice - ATRMultiplier * atrValue; else if (type == ORDER_TYPE_SELL) newSl = openPrice + ATRMultiplier * atrValue; if (newSl != stopLoss) { TradeModify(ticket, newSl, 0); // 修改止损 } } } } // 计算手数(根据风险) double CalculateLotSize(int atrPeriod, double atrMultiplier) { double atr = iATR(NULL, 0, atrPeriod, 1); double stopLossPoints = atr * atrMultiplier / Point(); double riskAmount = AccountInfoDouble(ACCOUNT_EQUITY) * RiskPercent / 100; double lot = riskAmount / (stopLossPoints * MarketInfo(_Symbol, MODE_TICKVALUE)); return NormalizeDouble(lot, 2); } // 开仓函数 void TradeOpen(int orderType, double volume) { MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); double price = SymbolInfoDouble(_Symbol, orderType == ORDER_TYPE_BUY ? SYMBOL_ASK : SYMBOL_BID); double sl = 0, tp = 0; double atr = iATR(NULL, 0, ATRPeriod, 1); if (orderType == ORDER_TYPE_BUY) sl = price - ATRMultiplier * atr; else sl = price + ATRMultiplier * atr; request.action = TRADE_ACTION_DEAL; request.symbol = _Symbol; request.volume = volume; request.type = orderType; request.price = price; request.sl = sl; request.tp = 0; // 不设固定止盈 request.deviation = 3; request.magic = MagicNumber; request.type_filling = ORDER_FILLING_IOC; OrderSend(request, result); } // 修改止损止盈 void TradeModify(ulong ticket, double sl, double tp) { MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); if (!PositionSelectByTicket(ticket)) return; request.action = TRADE_ACTION_SLTP; request.position = ticket; request.symbol = _Symbol; request.sl = sl; request.tp = tp; OrderSend(request, result); } ``` --- ## ✅ 优化建议总结 | 优化点 | 说明 | |--------|------| | ATR止损 | 根据市场波动动态调整止损,避免死板止损 | | 动态手数 | 根据账户资金和风险比例计算下单手数 | | 新K线入场 | 避免重复开仓,只在新K线开始时交易 | | 止损移动 | 持仓后根据ATR动态上移止损,保护利润 | | 过滤震荡 | 可加入 ADX 或布林带判断趋势强弱,过滤震荡行情 | --- ## ✅
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值