首页 / 交易学院 / 小布知识库 / 自训练 EA:用遗传算法让 EA 自己决定何时再优化、换策略
自训练 EA:用遗传算法让 EA 自己决定何时再优化、换策略
🤖

自训练 EA:用遗传算法让 EA 自己决定何时再优化、换策略

EA 开发实战 难度 · 高阶 2011 15 分钟阅读
自训练 EA遗传算法再优化适应度函数MQL5

EA 上线后最尴尬的事,是市场一变参数就失效,而你还在手动跑优化。本文的核心思路:把“是否再优化、换成哪个策略、参数取什么”变成 EA 自己的运行逻辑,用遗传算法在变化的市场里持续搜索更好的配置,尽量不中断交易。

一、自训练 EA 要解决什么问题

传统流程是:跑回测→选参数→上线→行情变了→停 EA→再优化→再上线。这个循环靠人盯,反应慢、还打断交易。自训练 EA 把“再优化决策”和“再优化执行”本身变成 EA 的一部分:它一边交易,一边在后台判断是否需要重算参数,需要时调用 GA 找新解。

适应度函数里模拟的测试模式,文章用的是“Open Prices Only(仅开盘价)”。但这只是示例,不是唯一选项。想正确模拟止损止盈,必须支持“Every Tick(每一价格变动)”模式——文中提醒可直接复用 MetaQuotes 已有的价格生成算法,别重复造轮子。

二、EA 的三大职责:交易 / 决策 / 再优化

一个自训练 EA 要明确做三件事:用选定策略正常交易;决定“现在该不该再优化”;用遗传算法执行再优化。最简单的再优化是单一策略换参数;进阶的是让 GA 在变化后的市场里直接挑选另一套策略(比如从均线交叉切到神经网络)。

三、适应度函数怎么写

每一个交易策略有自己专属的适应度函数(FF),每次再优化都会重新创建。对均线策略的 FF 和神经网络策略的 FF 完全不同。文章示例里,FF 的结果是“最大余额”,前提是相对回撤没超过外部变量设的临界值(示例 0.5);如果某次 GA 跑出余额 100000 但相对回撤 -0.6,FF 直接判 0。

// 检测新 K 线开盘(节选)
bool isNewBars() {
  CopyTime(s,tf,0,1,curBT);
  TimeToStruct(curBT[0],curT);
  if(tf==PERIOD_M1||...||PERIOD_M30)
    if(curT.min!=prevT.min){ prevBT[0]=curBT[0]; ...; return(true);}
  // H1/D1/MN1 类似按 hour/day/mon 判断
  return(false);
}
// 根据可用保证金算手数
double GetPossibleLots() {
  request.volume=1.0;
  OrderCheck(request,check);
  return(NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)/check.margin,2));
}

四、遗传算法做再优化

GA 每次运行会产出一组“性能结果”:对均线策略是均线周期,对神经网络是突触权重,共同的部分是“下次再优化前交易哪个品种”和“用多少保证金比例 optF”。你还可以往 FF 里加更多优化维度,比如时间框架。EA 初始化时先跑一次 GA 拿到初解,之后在触发条件下反复重跑。

// OnInit 里调用遗传优化并取结果
int OnInit() {
  tf = Period();
  depth = 10000; count = 2;     // 历史深度与每次复制根数
  ArrayResize(LongBuffer,count); ArrayResize(ShortBuffer,count);
  GA();                         // 遗传优化
  GetTrainResults();            // 取优化后的参数
  InitRelDD();                  // 记录最大余额(再优化起点)
  return(0);
}

五、再优化触发条件:相对回撤

什么时候该再优化?文章用“相对回撤(RelDD)”作触发器:一旦相对余额回撤达到外部变量设的临界值(示例 0.2),就跑 GA 再优化。为避免在临界值上每根 K 线都触发,触发后把“最大余额”更新为当前值,作为新一轮起点。你的 EA 完全可以用别的标准(比如收益曲线斜率、波动率突变)。

// 记录最大余额 / 计算相对回撤
void InitRelDD() {
  curBalance = AccountInfoDouble(ACCOUNT_BALANCE);
  maxBalance = curBalance;
  HistorySelect(D'2000.01.01',TimeCurrent());
  for(int i=HistoryDealsTotal();i>0;i--){
    DealTicket=HistoryDealGetTicket(i);
    curBalance+=HistoryDealGetDouble(DealTicket,DEAL_PROFIT);
    if(curBalance>maxBalance) maxBalance=curBalance;
  }
}
double GetRelDD() {
  if(AccountInfoDouble(ACCOUNT_BALANCE)>maxBalance) maxBalance=AccountInfoDouble(ACCOUNT_BALANCE);
  return((maxBalance-AccountInfoDouble(ACCOUNT_BALANCE))/maxBalance);
}

六、两种策略示例:均线交叉 vs 神经网络

文章给了两套可运行的策略源码。其一是双均线交叉(金叉买入、死叉卖出),其二是简单神经网络,输入是最近五个交易时段的价格变动(归一化到 [0,1])。两者都通过同一个 GA 框架驱动:GA 负责选品种、选 optF、选各自参数;交易逻辑在 OnTick 里根据新 K 线触发。

七、实战注意与风险

自训练 EA 很诱人,但坑也不少。第一,再优化用的是历史,历史不代表未来,GA 仍可能过拟合某段行情;第二,回测模式要和实盘一致,只用“仅开盘价”会低估止损止盈的影响,关键策略请用“每一价格变动”;第三,GA 跑在 OnInit/触发时,别让它阻塞 OnTick 的主交易逻辑。把这些想清楚,自训练才是加分项而不是定时炸弹。

再优化的标准由你定,文章的 RelDD/最大余额只是示例。务必把“再优化触发”和“适应度函数”解耦设计,方便你日后换成夏普比率、卡玛比率或回撤恢复速度等更贴合你风险偏好的指标。

八、小结

自训练 EA 把“参数维护”从人工循环变成 EA 的内置能力:用相对回撤触发、用遗传算法搜索、用专属适应度函数评估。它适合“行情多变、需要 EA 自己微调”的场景,但本质仍是历史外推,过拟合和回测一致性是两条必须守住的底线。把它当“会自我微调的助手”,而不是“印钞永动机”。

常见问题

普通 EA 参数靠人事先回测定好、静态运行;自训练 EA 把“是否再优化、换哪个策略、参数取什么”变成自身逻辑,能在运行中用遗传算法持续搜索更优配置,尽量不中断交易地适应变化的市场。
每个策略有专属 FF,每次再优化重建。文章示例用“最大余额”作结果,但要求相对回撤不超过外部临界值(否则 FF=0)。你也可以换成夏普、卡玛或回撤恢复速度。重点是 FF 必须同时编码“收益”和“风险约束”,否则 GA 会只追收益。
文章用相对回撤(RelDD)作触发器:回撤达到外部变量设定的临界值(示例 0.2)就跑 GA。触发后把最大余额更新为当前值,避免每根 K 线重复触发。你也可以用收益曲线斜率、波动率突变等其它标准。
对只基于开盘价的简单逻辑够,但对带止损止盈的策略不够——只用开盘价会低估止损止盈的影响。关键策略应该用 Every Tick(每一价格变动)模式,文中建议直接复用 MetaQuotes 已有的价格生成算法,保证回测与实盘一致。
会。GA 优化的仍是历史,历史不代表未来。缓解办法:控制优化维度、用样本外验证、让再优化标准包含风险约束、避免触发过频繁。把它当“会自我微调的助手”而非“永动机”,守住回测一致性这条底线。