首页 / 交易学院 / 会自己换策略的 EA:Trademinator 3 遗传算法自优化架构
会自己换策略的 EA:Trademinator 3 遗传算法自优化架构
🤖

会自己换策略的 EA:Trademinator 3 遗传算法自优化架构

EA 开发实战 难度 · 高级 2011 15 分钟阅读
自优化 EA遗传算法适应度函数策略选择回撤触发自适应

手动把 EA 参数调到“刚好适合某段历史”是件苦差事,而且市场一变就失效。Trademinator 3 的思路更激进:让 EA 自己在历史数据里选出“最佳策略 + 最佳品种 + 最佳存款占比 + 最佳指标参数”的组合,实盘里一旦回撤超阈值就重新优化。它把遗传算法从“调一个策略的参数”升级成“在所有策略里选最好的那一个”。本文拆解它的架构与关键代码。

一、自优化 EA 要回答的四个问题

作者先定义了自优化 EA 的硬性要求:在历史数据上,它要能(1)从候选策略里选最好的;(2)选最佳交易品种;(3)选带杠杆校正的存款占比;(4)选该策略指标的最佳参数。在实盘上,它还要能(5)开平仓、选仓位大小、(6)判断是否需要新一轮优化。这六个能力把“策略选择”和“参数优化”合并成一个搜索问题——这正是遗传算法擅长的事。

二、设计约束:只在新的 K 线做决定

为了避免过度交易和重绘,作者给 EA 加了明确约束:交易决定只在“选定时间周期出现新柱”时做;平仓只依据指标信号(不用止盈/止损/追踪止损,纯信号驱动);触发新优化的条件是“余额回撤超过初始化时预设的最大值”。适应度函数则要求:在历史中最大化模拟余额,同时约束相对回撤低于某预设水平。这些约束既控制风险,又给优化器划定了清晰的搜索边界。

三、OnTick 主循环:策略分派与回撤监控

EA 的核心在 OnTick:先 isNewBars() 判断有无新柱,有则按当前 strat 用 switch 分派到对应的 NeedCloseX 函数(MA/SAR/Stoch…)。NeedCloseX 返回 true 表示应平仓。平仓后检查 GetRelDD()(相对回撤)是否超过 maxDD——超了就调用 GA() 重新遗传优化,再 GetTrainResults() 取回新参数,并把回撤基准从历史最高余额切到当前余额。这样“信号平仓”和“回撤触发再优化”被串成一条自动闭环。

// OnTick 主循环骨架(节选)
void OnTick()
  {
   if(isNewBars()==true)
     {
      trig=false;
      switch(strat)            // 当前选定的策略
        {
         case 0: trig=NeedCloseMA();   break;
         case 1: trig=NeedCloseSAR();  break;
         case 2: trig=NeedCloseStoch();break;
         default: trig=NeedCloseMA();  break;
        }
      if(trig==true)
        {
         if(GetRelDD()>maxDD)   // 回撤超限 -> 重新优化
           {
            GA();                // 调用遗传优化
            GetTrainResults();   // 取回最优参数
            maxBalance=AccountInfoDouble(ACCOUNT_BALANCE); // 基准切到当前余额
           }
        }
     }
  }

四、平仓信号函数:以 SAR 为例

每个策略对应一个布尔型 NeedCloseX 函数,平仓时返回 true,OnTick 才能据此决定是否进入再优化流程。以 SAR 策略为例:读 SAR 缓冲与前一根开盘价,当 SAR[0]>Open[0] 且 SAR[1]<Open[1](或反向)时,若有持仓就 ClosePosition() 并返回 true。函数必须是布尔型且平仓时返回 true,这是整套机制能跑通的契约。

// NeedCloseSAR:SAR 翻转即平仓(节选)
bool NeedCloseSAR()
  {
   CopyBuffer(SAR,0,0,count,SARBuffer);
   CopyOpen(s,tf,0,count,o);
   if((SARBuffer[0]>o[0] && SARBuffer[1]<o[1]) ||
      (SARBuffer[0]<o[0] && SARBuffer[1]>o[1]))
     {
      if(PositionsTotal()>0) { ClosePosition(); return(true); }
     }
   return(false);
  }

五、遗传优化与适应度函数

GA() 调用 GAModule.mqh 里的适应度函数 FitnessFunction(int chromos)。染色体(chromos)编码了策略、品种、存款占比和指标参数;适应度函数按这组基因在历史中模拟交易,目标是最大化余额、同时把相对回撤压在预设水平下。GetTrainResults() 再从最优染色体里解出 strat(最佳策略)和 s(最佳品种),切换 EA 的当前配置。这样 EA 不是“一个写死策略”,而是“一个会挑策略的机器”。

风险提示:自优化能适配历史,但不保证适配未来。回撤触发的再优化若发生在实盘连续亏损后,可能正好在不利段重估参数。务必在策略测试器里做样本外与多段历史验证,并给 maxDD 留足缓冲,否则“自动换策略”会变成“自动追涨杀跌”。

六、小结

Trademinator 3 把遗传算法从“调参”升级为“选策略 + 调参 + 选品种”的一揽子搜索:OnTick 按当前策略评估信号、按回撤触发再优化、适应度函数在历史中最大化余额并约束回撤、GetTrainResults 把最优染色体解码回运行配置。它是“自适应 EA”的范本,但代价是需要严谨的样本外验证与回撤护栏——否则自动化反而放大了过拟合。把它当架构参考,而不是“装上去就躺赚”的黑盒。

常见问题

传统优化只在“一个固定策略”里找最佳参数;Trademinator 3 用遗传算法同时搜“最佳策略 + 最佳品种 + 最佳存款占比 + 指标参数”,EA 会在运行时按回撤触发切换配置。它是“会挑策略的机器”,而非写死单一策略。
当账户相对回撤 GetRelDD() 超过预设的 maxDD(最大允许回撤)时,OnTick 会调用 GA() 重新遗传优化,再用 GetTrainResults() 取回新参数,并把回撤基准从历史最高余额切到当前余额。这是作者设定的再优化条件。
OnTick 用 NeedCloseX 的返回值决定是否平仓、以及平仓后是否进入“回撤检查→再优化”流程。函数平仓时必须返回 true,这样主循环才能串起“信号平仓→回撤监控→GA()”的自动闭环。这是整套机制的契约。
FitnessFunction 把染色体(编码策略/品种/存款占比/指标参数)在历史中模拟交易,目标是最大化模拟余额,同时约束相对回撤低于预设水平。GetTrainResults 再从最优染色体解出最佳策略与品种,切换 EA 运行配置。
历史自适配 ≠ 未来有效。回撤触发的再优化若发生在实盘连续亏损后,可能刚好在不利段重估参数,变成“自动追涨杀跌”。必须有样本外/多段历史验证和充足的 maxDD 缓冲,否则自动化会放大过拟合。