MQL5 中的定量分析:实现有前途的算法·综合运用
📘

MQL5 中的定量分析:实现有前途的算法·综合运用

第 3/3 篇

按当前K线开仓与加仓的EA骨架

下面这段逻辑是剥离开指标信号后,纯按时间栅栏和 ATR 距离管控仓位的下单核心。它先在每根新 K 线到来时清空旧单,再判断方向标志 buy / sell 与持仓数是否小于 1,决定首单入场。 首单用 Bid/Ask 加减 atr*StopLoss 个 Point 算止损、atr*TakeProfit 个 Point 算止盈,NormalizeDouble 对齐 _Digits 小数位,trade.Buy / trade.Sell 带空注释下单。若已有持仓,则检查多空类型:多头时若 (FindLastBuyPrice-Ask)/pp >= atr*30 才追多,空头时若 (Bid-FindLastSellPrice)/pp >= atr*30 才追空,相当于要求回撤或反向空间达到 30 倍 ATR 才加仓。 注意 atr*30 这个阈值极宽,在 EURUSD 这类平均日波幅 80~120 点、ATR(14) 约 0.0008~0.0012 的品种上,30 倍即 240~360 点,实盘极少触发,更像防极端跳空的保险而非常规加仓。外汇与贵金属杠杆高,这类追单逻辑若放宽阈值可能瞬间放大风险,建议先上 MT5 策略测试器用 2023 年 XAUUSD 数据跑一遍验证触发频率。

MQL5 / C++
  CloseAll();
  if(t!=iTime(symb,PERIOD_CURRENT,class="num">0))
   {
    if(buy && CountTrades(symb)<class="num">1)
     {
      if(StopLoss>class="num">0)
       sl=NormalizeDouble(Bid-(atr*StopLoss)*Point(),_Digits);
      if(TakeProfit>class="num">0)
       tp=NormalizeDouble(Bid+(atr*TakeProfit)*Point(),_Digits);
      pr=NormalizeDouble(Bid,dg);
      trade.Buy(Lot(),symb,pr,sl,tp,"");
      last=pr;
     }
    if(sell && CountTrades(symb)<class="num">1)
     {
      if(StopLoss>class="num">0)
       sl=NormalizeDouble(Ask+(atr*StopLoss)*Point(),_Digits);
      if(TakeProfit>class="num">0)
       tp=NormalizeDouble(Ask-(atr*TakeProfit)*Point(),_Digits);
      pr=NormalizeDouble(Ask,dg);
      trade.Sell(Lot(),symb,Ask,sl,tp,"");
      last=pr;
     }
    if(CountTrades(symb)>class="num">0)
     {
      if(PositionType(symb)==class="num">0 && (FindLastBuyPrice(symb)-Ask)/pp>=atr*class="num">30)
       {
       if(StopLoss>class="num">0)
        sl=NormalizeDouble(Bid-(atr*StopLoss)*Point(),_Digits);
       if(TakeProfit>class="num">0)
        tp=NormalizeDouble(Bid+(atr*TakeProfit)*Point(),_Digits);
       trade.Buy(Lot(),symb,Ask,sl,tp);
       }
      if(PositionType(symb)==class="num">1 && (Bid-FindLastSellPrice(symb))/pp>=atr*class="num">30)
       {
       if(StopLoss>class="num">0)
        sl=NormalizeDouble(Ask+(atr*StopLoss)*Point(),_Digits);
       if(TakeProfit>class="num">0)
        tp=NormalizeDouble(Ask-(atr*TakeProfit)*Point(),_Digits);
       trade.Sell(Lot(),symb,Bid,sl,tp);
       }
     }
    t=iTime(symb,class="num">0,class="num">0);
   }

◍ EURUSD H1 开盘价回测的残酷真相

把循环类模型直接丢进真实行情跑,最省算力的办法是只吃开盘价。我们取 EURUSD 的 H1 开盘价,区间 2020-01-01 到 2023-12-06,在 MT5 里做了一轮单测:账面上盈利,但回撤大得离谱,这种额外风险没人愿意扛。 先试了「盈利 >0 就平」的逻辑,账户类型切到对冲,结果均摊法把 EA 变成了高危炸弹;换净额结算再跑,回撤依旧夸张,盈利完全盖不住风险。接着改代码,加信号反手平仓——看涨转看跌就清掉原仓。 实测下来更沮丧:无论净额还是对冲,回撤都巨大,按信号平仓甚至稳定亏损。外汇与贵金属属高风险品种,这类回测结果只说明原模型在 H1 开盘价下暂时不成立,别拿去实盘硬怼。 下面这段就是按信号平仓的插入代码,逻辑很直白:CloseSig 开关打开后,有多头仓就 CloseAll(1),有空头仓就 CloseAll(0),输入项 CloseSig 默认置 1。

MQL5 / C++
if (CloseSig)
  {
    if (buy)
      CloseAll(class="num">1);
    if (sell)
      CloseAll(class="num">0);
  }
class="kw">input class="type">bool CloseSig    = class="num">1;        class=class="str">"cmt">// close by signal

「画得少,看得清」

这套波浪计数加均值比较的初版逻辑跑下来是亏的,思路底子不差,只是样本太薄、过滤条件几乎没有。作者在文末附的 QuantAnalsysSample.zip 只有 3.07 KB,说明示例刻意压到最小可运行,没堆任何花哨指标。 后续文章会接着拆量化分析,这一节就停在这里:先把能跑通的基础框架搭起来,比立刻追求正收益更有用。

常见问题

开盘价回测默认无滑点,实盘市价单会被点差和延迟吃掉利润;验证时务必在策略测试器开真实tick并加佣金。
开盘价模型忽略了K线内波动,加仓易被扫损;改用逐笔tick回测并把加仓间距拉大到覆盖平均波动率。
可以,小布盯盘的AIGC已内置品种诊断,打开EURUSD页就能看开盘跳空与加仓胜率分布,不用自己写脚本。
够,H1级别用收盘突破前高加一根20期均线过滤,比堆四五层指标更易执行且回测更稳。
用静态变量记录本根K线时间戳,仅当Time[0]变化时下单一次,并在加仓后标记已操作避免追单。