English Русский Português
preview
人工原子算法(A3)

人工原子算法(A3)

MetaTrader 5交易系统 |
34 7
Andrey Dik
Andrey Dik

内容

  1. 引言
  2. 算法实现
  3. 测试结果


引言

在算法交易领域,核心任务之一便是对交易策略参数进行优化。交易者每天都需要调试大量变量:指标周期、止盈止损点位、仓位规模、时间过滤器,以及数十项其他参数。这些参数的不同组合都可能显著改变策略表现。因此业界始终在寻找高效优化算法,力求在合理时间内找到最优参数组合。

本文将介绍另一种优化算法 —— 人工原子算法(A3),这是一种以化学反应为灵感构建的元启发式优化算法。该算法由土耳其学者提出,于 2018 年首次向学术界公开。


算法实现

在研究该算法时,我发现原始文献存在多处表述模糊的问题。部分运算算子描述不够详尽,难以直接用于编程实现。对此,下文会完整引用原始算法定义,但最终代码实现由我自主设计 —— 结合个人开发经验,以及同类智能优化算法通用架构思路完成。原始文献存在明显信息缺口,留给开发者极大的自主解读空间。除此之外,开发过程中我还对基础父类进行了修改,在介绍基础算法逻辑后,我会展开说明相关改动。

该算法通过模拟原子与电子的相互作用寻找最优解。核心单元为原子,每一个原子代表问题的一组候选解。电子表示决策变量。共价键算子负责保存、复制当前最优解;离子键算子用于探索搜索空间,助力算法搜寻全局最优。 

算法流程:首先随机生成一组原子种群,通过目标函数评估每个原子对应的解质量;随后调用共价键、离子键算子迭代优化候选解(遗憾的是原始文献并未说明两种算子的具体执行方式)。下一步需要评估电子带来的影响。同样,文献并未给出具体实现方案。文中还要求对电子、原子进行排序。我们可以对原子(候选解)排序,但如何对电子排序完全没有可供参考的逻辑 —— 好比试图把人的四肢排序,区分左右手、左右腿,本身不存在合理依据。之后重复迭代,直至满足终止条件。常言道,巧妇难为无米之炊,但现有资料有限,只能基于现有内容开展工作。我们需要依托原作者提出的核心思想,搭建完整算法框架。

下文给出我修订完善后的 A3 算法伪代码:

初始化输入参数:

popSize — 原子种群数量(默认值:10)
covalentRate — 共价键系数(默认值:0.1)
rangeMin []、rangeMax [] — 各变量搜索上下限
rangeStep [] — 变量离散步长

预计算:

计算精英原子数量:
covalentCount = floor (popSize × covalentRate)
约束条件:最小值 1,最大值不超过 popSize - 1

创建规模为 popSize 的原子种群
对每个原子执行初始化:
坐标数组 c []
局部最差解坐标 cW []
适应度 f,局部最差适应度 fW


基本优化循环:
步骤 1:首次迭代(revision = false)
遍历所有原子 i(0 ~ popSize-1):
遍历每一个维度坐标 j(0 ~ 维度总数 - 1):
在区间 [rangeMin [j], rangeMax [j]] 内生成随机数值
按照 rangeStep [j] 执行离散化处理
存入原子 a [i].c [j]
    
将 revision 标记置为 true
本步骤结束

步骤 2:更新原子位置(移动算子)
遍历所有原子 i(0 ~ popSize-1):
    
若 i ≤ covalentCount(当前原子属于精英原子):
遍历每一个维度坐标 c(0 ~ 维度总数 - 1):
            
若 random() < covalentRate(10% 概率):
// 向全局最优解靠近
步长 step = random() × (cB [c] - a [i].c [c]) × covalentCount
                a [i].c [c] = a [i].c [c] + step
            
否则(90% 概率):
// 基于幂分布,以全局最优解为中心生成新坐标
                a[i]. c[c] = PowerDistribution(center=cB [c], min=rangeMin [c], max=rangeMax [c], degree=20)
对 a [i].c [c] 执行离散化
    
否则(非精英原子):
遍历每一个维度坐标 c(0 ~ 维度总数 - 1):
  // 随机选取一个精英原子作为参考样本
ind = 随机整数 (0, covalentCount)
            
// 从自身局部最差位置向精英原子位置移动
移动方向 direction = a [ind].c [c] − a [i].cW [c]
步长 step = random () × direction × (1.0 − covalentCount)
            a [i].c [c] = a [i].c [c] + step
对 a [i].c [c] 执行离散化

步骤 3:适应度计算
遍历每个原子 i:
通过目标函数计算 a [i].f(原子适应度)

步骤 4:记忆更新与种群排序(修正阶段)
// 更新每个原子记录的局部最差解
遍历原子 i(0 ~ popSize-1):
若 a [i].f < a [i].fW:
        a [i].fW = a [i].f
将 a [i].c 复制至 a [i].cW
更新全局最差适应度 fW

// 按适应度降序对种群排序
依据适应度字段 f,将原子数组 a [] 从最优到最差排序

// 更新全局最优解
若 a [0].f > fB:
    fB = a [0].f
将 a [0].c 复制至全局最优坐标 cB

// 更新全局最差解
若 a [popSize-1].f < fW:
    fW = a [popSize-1].f
将 a [popSize-1].c 复制至全局最差坐标 cW

步骤 5:终止条件判断
若迭代次数达到最大迭代上限:
算法结束
否则:
跳转至步骤 2 继续循环

接下来我们进入代码实操实现环节。我们将编写一个类,实现基于原子与化学键隐喻的人工原子系统算法。该类继承基础优化父类 C_AO,并且结合 A3 算法特性进行功能扩展。

参数配置方法:SetParams (),读取参数数组中的数值并赋值给内部变量。这将方便算法运行前灵活地自定义参数。初始化方法:Init (),完成参数与数据结构初始化,接收变量取值区间、离散步长以及迭代轮数。算法核心运算:Moving ()、Revision () 方法分别实现原子位置移动、种群信息更新两大阶段,对应最优解搜索流程。核心参数说明:

  • popSize — 原子种群规模,即种群内候选解数量。
  • covalentRate — 表征原子之间成键概率的系数。
  • covalentCount — 内部变量,参与成键运算的精英原子数量(内部计算使用)。

该类整体目标:模拟原子系统及其相互作用,依靠上述参数与成员方法完成建模。基于这套原子交互逻辑,即可搭建完整的搜索与优化框架。

//————————————————————————————————————————————————————————————————————
class C_AO_A3 : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_A3 () { }
  C_AO_A3 ()
  {
    ao_name = "A3";
    ao_desc = "Artificial Atom Algorithm";
    ao_link = "https://www.mql5.com/en/articles/18958";

    popSize      = 10;    // number of atoms (m)
    covalentRate = 0.1;   // covalent bond coefficient (β)

    ArrayResize (params, 2);

    params [0].name = "popSize";      params [0].val = popSize;
    params [1].name = "covalentRate"; params [1].val = covalentRate;
  }

  void SetParams ()
  {
    popSize      = (int)params [0].val;
    covalentRate = params      [1].val;
  }

  bool Init (const double &rangeMinP  [],  // minimum values
             const double &rangeMaxP  [],  // maximum values
             const double &rangeStepP [],  // step change
             const int     epochsP = 0);   // number of epochs

  void Moving   ();
  void Revision ();

  //------------------------------------------------------------------
  double covalentRate;       // covalent bond coefficient (β)

  private: //---------------------------------------------------------
  int    covalentCount;      // number of atoms for covalent bond
};
//————————————————————————————————————————————————————————————————————

Init () 方法是启动算法前至关重要的准备环节。其核心任务是:在优化流程正式开始前,完成全部必要参数与数据结构的初始化工作。该方法接收四项输入参数:

  1. rangeMinP [] — 算法待优化各变量的下限。
  2. rangeMaxP [] — 各变量的上限。
  3. rangeStepP [] — 各变量的变化步长。步长用于变量离散化,同时决定搜索精度。
  4. epochsP — 算法执行的迭代轮数(世代数)。

函数会优先调用基类 C_AO 的 StandardInit () 方法,执行所有优化算法通用的初始化流程。若 StandardInit () 执行成功,函数继续计算人工原子算法专属参数。主要计算 covalentCount,即参与成共价键的原子数量。计算公式为种群总原子数量 popSize 乘以共价键系数 covalentRate。计算结果向下取整(MathFloor),保证原子数量为整数。随后执行合法性校验,确保 covalentCount 取值逻辑有效。如果所有初始化步骤顺利完成,方法返回 true,代表算法就绪,可以启动优化。

综上,Init 方法同时完成通用优化参数与这套 “原子 - 化学键” 模型专属参数的初始化,保障人工原子算法可以完整投入运行。

/————————————————————————————————————————————————————————————————————
//--- Initialization
bool C_AO_A3::Init (const double &rangeMinP  [],
                    const double &rangeMaxP  [],
                    const double &rangeStepP [],
                    const int     epochsP = 0)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //------------------------------------------------------------------
  covalentCount = (int)MathFloor (popSize * covalentRate);
  if (covalentCount < 1) covalentCount = 1;
  if (covalentCount >= popSize) covalentCount = popSize - 1;

  return true;
}
//————————————————————————————————————————————————————————————————————

C_AO_A3 类中的 Moving () 方法是人工原子算法核心步骤之一,实现原子在搜索空间内的 “移动”,也就是位置更新逻辑。该方法模拟原子种群的演化行为,目的是搜寻最优解。每次调用 Moving () 时,首先检查 revision 标记。该标记用于标识种群是否已经完成初始化。

初始化阶段(revision = false)代表首次调用或者算法重置后调用,原子种群尚未初始化。此时程序遍历全部 popSize 个原子、遍历搜索空间所有维度 coords。针对每个原子的每一维坐标,在指定区间内生成随机位置。首次调用完成初始化后,将 revision 设置为 true;后续调用Moving()将执行主体移动逻辑,不再重复初始化,首次调用结束后函数直接返回。

原子主体移动流程(revision = true)种群初始化完成后,Moving 方法开始更新原子位置,模拟原子运动。依据原子索引 i 与 covalentCount 的大小关系,原子被划分为两组。 

第一组:参与共价键作用的原子(i <= covalentCount)组内每一个原子、每一维坐标都会生成随机数;若随机数小于共价键系数,原子按照公式更新坐标,模拟原子向当前最优解 cB [c] 吸引、相互作用;其中 cB 代表种群当前找到的全局最优坐标,计算过程引入 covalentCount。

若随机数大于或等于 covalentRate,则调用 PowerDistribution 函数更新坐标。该函数生成偏向 cB [c] 的随机值,同时保留一定随机扰动、实现更具随机性的搜索或“散射”效果。

无论采用哪种方式更新坐标,都会调用 u.SeInDiSp 函数做后处理,把坐标约束到合法区间,并对齐离散网格。 

第二组:不参与共价键作用的原子(i > covalentCount)针对组内每个原子的每一维坐标,在区间 [0, covalentCount] 随机选取一个索引 ind。这意味着非成键原子会与某一个成键原子产生交互。

原子坐标完成更新,模拟原子与选中成键原子之间的吸引或排斥作用,并参考自身历史局部最差位置;更新完成后同样调用 u.SeInDiSp 处理坐标,满足取值约束。

Moving () 方法是整个搜索流程的核心。基于物理模型构建随机位置更新规则。参与共价键的原子倾向向已知最优解靠拢;其余原子持续探索空间,与成键原子产生交互。

//————————————————————————————————————————————————————————————————————
//--- The main step of the algorithm
void C_AO_A3::Moving ()
{
  // Initial population setup
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int j = 0; j < coords; j++)
      {
        a [i].c [j] = u.RNDfromCI (rangeMin [j], rangeMax [j]);
        a [i].c [j] = u.SeInDiSp (a [i].c [j], rangeMin [j], rangeMax [j], rangeStep [j]);
      }
    }

    revision = true;
    return;
  }

  //------------------------------------------------------------------
  int    ind = 0;

  for (int i = 0; i < popSize; i++)
  {
    if (i <= covalentCount)
    {
      for (int c = 0; c < coords; c++)
      {
        if (u.RNDprobab () < covalentRate)
        {
          a [i].c [c] = a [i].c [c] + u.RNDprobab () * (cB [c] - a [i].c [c]) * covalentCount;//(1.0 - covalentCount);
        }
        else
        {
          a [i].c [c] = u.PowerDistribution (cB [c], rangeMin [c], rangeMax [c], 20);
        }
        a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
    else
    {
      for (int c = 0; c < coords; c++)
      {
        ind = u.RNDintInRange (0, covalentCount);

        a [i].c [c] = a [i].c [c] + u.RNDprobab () * (a [ind].c [c] - a [i].cW [c]) * (1.0 - covalentCount);//covalentCount;
        a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
  }
}
//————————————————————————————————————————————————————————————————————

C_AO_A3 类的 Revision () 方法负责在算法单次迭代中,更新原子种群内最优解与最差解相关信息。这一步十分关键:全局、个体层面的最优、最差适应度信息,将指导下一轮搜索。首先更新每个原子各自记录的局部最差解。调用 u.Sorting () 函数,依据适应度 f 对全部原子种群数组 a 完成排序。

排序完成后,数组首位原子 a [0] 即为当前种群最优个体。使用 a [0].f 更新全局最优适应度 fB,同时将 a [0].c 坐标复制至全局最优坐标 cB。数组末尾原子 a [popSize - 1] 是排序后种群最差个体。将 a [popSize - 1].f 与全局最差适应度 fW 对比;若该适应度更差,则更新 fW,并把 a [popSize - 1].c 复制到全局最差坐标 cW。

Revision 方法持续系统性追踪优化进展:该方法维护种群的全局最优/最差状态,并更新各原子记录的局部最差历史状态。 

//————————————————————————————————————————————————————————————————————
//--- Update the best and worst solutions
void C_AO_A3::Revision ()
{
  // Update the local worst solution
  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f < a [i].fW)
    {
      fW = a [i].f;
      ArrayCopy (a [i].cW, a [i].c, 0, 0, WHOLE_ARRAY);
    }
  }

  static S_AO_Agent aT []; ArrayResize (aT, popSize);
  u.Sorting (a, aT, popSize);

  if (a [0].f > fB)
  {
    fB = a [0].f;
    ArrayCopy (cB, a [0].c, 0, 0, WHOLE_ARRAY);
  }

  if (a [popSize - 1].f < fW)
  {
    fW = a [popSize - 1].f;
    ArrayCopy (cW, a [popSize - 1].c, 0, 0, WHOLE_ARRAY);
  }
}
//————————————————————————————————————————————————————————————————————

最终实现代码结构十分精简。接下来我们介绍所有优化算法所继承的基类。上文提到,基类代码经过修改,下面对该基类进行说明。

用于存放算法参数的简易结构体。支持动态管理任意优化算法的配置参数。

//——————————————————————————————————————————————————————————————————————————————
struct S_AlgoParam
{
    double val;
    string name;
};
//——————————————————————————————————————————————————————————————————————————————

S_AO_Agent 结构体用于描述单个智能体,一个智能体代表优化问题的一组候选解,在多维搜索空间中移动。S_AO_Agent结构体内部字段分为三大类:1. 坐标信息(搜索空间位置):

  • c — 智能体当前坐标数组。存储智能体当前位置。
  • cP — 智能体上一轮坐标数组。用于追踪运动轨迹。
  • cB — 该智能体历史到达过的最优坐标。智能体依靠该信息 “记住” 最优位置,可回退或以此为基准继续搜索。
  • cW — 智能体历史最差坐标。

2. 适应度(解质量):

  • f — 智能体当前适应度。基于当前坐标 c 计算得到目标函数值。
  • fP — 上一轮适应度。与 cP 配套,用于观测适应度变化。
  • fB — 该智能体历史最优适应度。对应坐标 cB。
  • fW — 该智能体历史最差适应度。对应坐标 cW。

3. 辅助变量:cnt — 整型计数器。 

结构体内置公开 Init () 方法,用于智能体初始化。入参 coords 为整数,代表搜索空间维度,即智能体拥有的坐标数量。

调用 Init () 时执行以下操作:动态调整坐标数组(c、cP、cB、cW)长度至 coords。保证智能体维度匹配具体优化问题。初始化适应度:f、fP、fB 赋值为 -DBL_MAX(双精度最小值);fW 赋值为 DBL_MAX(双精度最大值)。这是最大化优化问题的标准初始化范式:f、fP、fB 初始值设为极小值,后续计算值几乎必然大于初始值;fW 初始值设为极大值,任意首次计算结果都会优于初始值。计数器 cnt 初始化为 0。

整体而言,S_AO_Agent 为种群优化算法中的每一个个体提供完整数据结构,同时记录个体当前状态与历史优劣轨迹。

//——————————————————————————————————————————————————————————————————————————————
struct S_AO_Agent
{
    double c  []; //coordinates
    double cP []; //previous coordinates
    double cB []; //best coordinates
    double cW []; //worst coordinates

    double f;     //fitness
    double fP;    //previous fitness
    double fB;    //best fitness
    double fW;    //worst fitness

    int    cnt;   //counter

    void Init (int coords)
    {
      ArrayResize (c,  coords);
      ArrayResize (cP, coords);
      ArrayResize (cB, coords);
      ArrayResize (cW, coords);

      f  = -DBL_MAX;
      fP = -DBL_MAX;
      fB = -DBL_MAX;
      fW =  DBL_MAX;

      cnt = 0;
    }
};
//——————————————————————————————————————————————————————————————————————————————

下面介绍基类 C_AO。C_AO 总体结构。公有成员。公有成员为类外部可访问的字段与方法。 

全局最优 / 最差解状态数据:

  • cB [] — 算法全局最优解坐标数组;
  • cW [] — 算法全局最差解坐标数组;
  • fB — 全局最优解对应的适应度(与 cB 匹配);
  • fW — 全局最差解对应的适应度(与 cW 匹配)。

注意区分:此处为全局最优 / 最差,S_AO_Agent 内部 fB、fW 仅属于单个智能体。 

种群与参数相关数据:

  • a [] — S_AO_Agent 数组。代表智能体种群,每个智能体对应一组候选解;
  • params [] — S_AlgoParam 数组。存放算法自定义参数(影响系数、概率等),支持外部配置。
  • revision — 状态标记,用于控制迭代更新流程。 
虚方法(需要在派生类实现):虚方法使用 virtual 声明,派生类可重写,实现不同算法独有的逻辑:
  • SetParams () — 参数配置方法;派生类内部填充 params 参数数组。
  • Init () — 算法主初始化方法。接收搜索区间、步长、迭代轮数。初始化成功返回 true。
  • Moving () — 实现智能体在搜索空间移动、演化逻辑。它是算法核心。
  • Revision () — 算法状态更新、校验阶段。
  • Injection () — 向指定智能体的坐标注入指定数值。 

搜索空间参数:

  • rangeMin [] — 每一维坐标下限;
  • rangeMax [] — 每一维坐标上限;
  • rangeStep [] — 每一维坐标步长;适用于离散搜索空间,决定搜索粒度。

算法内部参数组:

  • coords — 搜索空间维度数量。
  • popSize — 种群规模(智能体总数)。

辅助工具对象:u — 工具类实例,封装通用函数,如随机数生成、数学运算等。

受保护标准初始化方法:StandardInit () 供所有派生算法调用,执行通用初始化流程。以系统当前时间作为随机数种子初始化随机生成器;将全局最优适应度 fB 初始化为负无穷、全局最差适应度 fW 初始化为正无穷,用于后续持续追踪最优、最差解;还将 revision 标记置为 false,校验并设置维度数量 coords;根据维度扩容 rangeMin、rangeMax、rangeStep、cB、cW 数组;根据种群规模 popSize 扩容智能体数组 a;逐个调用智能体自身 Init (),初始化内部坐标数组。它将传入的搜索区间拷贝至内部变量;初始化成功返回 true,数组长度不匹配等异常场景返回 false。

C_AO 作为所有优化算法具体实现的基类。每一款新优化算法(AO 派生实现)都继承自 C_AO,并重写 SetParams、Init、Moving、Revision、Injection 等虚方法,实现专属搜索逻辑,而 StandardInit () 封装通用初始化流程,避免大量重复代码。

//——————————————————————————————————————————————————————————————————————————————
class C_AO
{
  public: //--------------------------------------------------------------------
  C_AO () { }
  ~C_AO () { }

  double      cB     []; //best coordinates
  double      cW     []; //worst coordinates
  double      fB;        //FF of the best coordinates
  double      fW;        //FF of the worst coordinates
  S_AO_Agent  a      []; //agents
  S_AlgoParam params []; //algorithm parameters
  bool        revision;

  virtual void SetParams () { }
  virtual bool Init (const double &rangeMinP  [], //minimum search range
                     const double &rangeMaxP  [], //maximum search range
                     const double &rangeStepP [], //step search
                     const int     epochsP = 0)   //number of epochs
  { return false;}

  virtual void Moving    () { }
  virtual void Revision  () { }
  virtual void Injection (const int popPos, const int coordPos, const double value) { }

  string GetName   () { return ao_name;}
  string GetDesc   () { return ao_desc;}
  string GetLink   () { return ao_link;}
  string GetParams ()
  {
    string str = "";
    for (int i = 0; i < ArraySize (params); i++)
    {
      str += (string)params [i].val + "|";
    }
    return str;
  }


  protected: //-----------------------------------------------------------------
  string ao_name;      //ao name;
  string ao_desc;      //ao description
  string ao_link;      //ao link

  double rangeMin  []; //minimum search range
  double rangeMax  []; //maximum search range
  double rangeStep []; //step search

  int    coords;       //coordinates number
  int    popSize;      //population size

  C_AO_Utilities u;     //auxiliary functions

  bool StandardInit (const double &rangeMinP  [], //minimum search range
                     const double &rangeMaxP  [], //maximum search range
                     const double &rangeStepP []) //step search
  {
    int seed = (int)GetTickCount64 ();
    MathSrand (seed); //reset of the generator

    fB       = -DBL_MAX;
    fW       =  DBL_MAX;
    revision =  false;

    coords  = ArraySize (rangeMinP);
    if (coords == 0 || coords != ArraySize (rangeMaxP) || coords != ArraySize (rangeStepP)) return false;

    ArrayResize     (rangeMin,  coords);
    ArrayResize     (rangeMax,  coords);
    ArrayResize     (rangeStep, coords);
    ArrayResize     (cB,        coords);
    ArrayResize     (cW,        coords);

    ArrayResize (a, popSize);
    for (int i = 0; i < popSize; i++) a [i].Init (coords);

    ArrayCopy (rangeMin,  rangeMinP,  0, 0, WHOLE_ARRAY);
    ArrayCopy (rangeMax,  rangeMaxP,  0, 0, WHOLE_ARRAY);
    ArrayCopy (rangeStep, rangeStepP, 0, 0, WHOLE_ARRAY);

    return true;
  }
};
//——————————————————————————————————————————————————————————————————————————————


测试结果

现在让我们看看A3算法的运行结果。小规模种群下的平均结果。

A3|人工原子算法|30.0|0.2|
=============================
5 Hilly's;函数运行次数:10000;结果:0.7074464987418227
25 Hilly's;函数运行次数:10000;结果:0.49461443027863367
500 Hilly's;函数运行次数:10000;结果:0.27674325929370214
=============================
5 Forest's;函数运行次数:10000;结果:0.8910275237236067
25 Forest's;函数运行次数:10000;结果:0.43888040941642725
500 Forest's;函数运行次数:10000;结果:0.17553299655770818
=============================
5 Megacity's;函数运行次数:10000;结果:0.5323076923076923
25 Megacity's;函数运行次数:10000;结果:0.3270769230769231
500 Megacity's;函数运行次数:10000;结果:0.11430769230769337
=============================
总得分:3.95794 (43.98%)

可视化结果显示,在低维函数上结果分布较为分散(绿色线条所示),值得注意的是,这些解对搜索空间的覆盖较好。

Hilly

A3 在Hilly测试函数上的表现

Forest

A3 在Forest测试函数上的表现

Megacity

A3 在Megacity测试函数上的表现

本文的算法评级表仅作信息参考,不构成结论性评价。

# 算法 说明 Hilly Hilly
最终结果
Forest Forest
最终结果
Megacity (离散) Megacity
最终结果
最终
结果
% of
MAX
10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F)
1 ANS 交叉邻近搜索 0.94948 0.84776 0.43857 2.23581 1.00000 0.92334 0.39988 2.32323 0.70923 0.63477 0.23091 1.57491 6.134 68.15
2 CLA 代码锁定算法(JOO) 0.95345 0.87107 0.37590 2.20042 0.98942 0.91709 0.31642 2.22294 0.79692 0.69385 0.19303 1.68380 6.107 67.86
3 AMOm 动物迁徙优化M 0.90358 0.84317 0.46284 2.20959 0.99001 0.92436 0.46598 2.38034 0.56769 0.59132 0.23773 1.39675 5.987 66.52
4 (P+O)ES (P+O) 进化策略 0.92256 0.88101 0.40021 2.20379 0.97750 0.87490 0.31945 2.17185 0.67385 0.62985 0.18634 1.49003 5.866 65.17
5 CTA 彗尾算法(JOO) 0.95346 0.86319 0.27770 2.09435 0.99794 0.85740 0.33949 2.19484 0.88769 0.56431 0.10512 1.55712 5.846 64.96
6 TETA 时间演化旅行算法(JOO) 0.91362 0.82349 0.31990 2.05701 0.97096 0.89532 0.29324 2.15952 0.73462 0.68569 0.16021 1.58052 5.797 64.41
7 SDSm 随机扩散搜索 M 0.93066 0.85445 0.39476 2.17988 0.99983 0.89244 0.19619 2.08846 0.72333 0.61100 0.10670 1.44103 5.709 63.44
8 BOAm 台球优化算法 M 0.95757 0.82599 0.25235 2.03590 1.00000 0.90036 0.30502 2.20538 0.73538 0.52523 0.09563 1.35625 5.598 62.19
9 AAm 射箭算法 M 0.91744 0.70876 0.42160 2.04780 0.92527 0.75802 0.35328 2.03657 0.67385 0.55200 0.23738 1.46323 5.548 61.64
10 ESG 社会群体的进化(JOO) 0.99906 0.79654 0.35056 2.14616 1.00000 0.82863 0.13102 1.95965 0.82333 0.55300 0.04725 1.42358 5.529 61.44
11 SIA 模拟各向同性退火(JOO) 0.95784 0.84264 0.41465 2.21513 0.98239 0.79586 0.20507 1.98332 0.68667 0.49300 0.09053 1.27020 5.469 60.76
12 EOm 极值优化算法_M 0.76166 0.77242 0.31747 1.85155 0.99999 0.76751 0.23527 2.00277 0.74769 0.53969 0.14249 1.42987 5.284 58.71
13 BBO 基于生物地理学的优化算法 0.94912 0.69456 0.35031 1.99399 0.93820 0.67365 0.25682 1.86867 0.74615 0.48277 0.17369 1.40261 5.265 58.50
14 ACS 人工协同搜索 0.75547 0.74744 0.30407 1.80698 1.00000 0.88861 0.22413 2.11274 0.69077 0.48185 0.13322 1.30583 5.226 58.06
15 DA 辩证算法 0.86183 0.70033 0.33724 1.89940 0.98163 0.72772 0.28718 1.99653 0.70308 0.45292 0.16367 1.31967 5.216 57.95
16 BHAm 黑洞算法 M 0.75236 0.76675 0.34583 1.86493 0.93593 0.80152 0.27177 2.00923 0.65077 0.51646 0.15472 1.32195 5.196 57.73
17 ASO 无政府社会优化 0.84872 0.74646 0.31465 1.90983 0.96148 0.79150 0.23803 1.99101 0.57077 0.54062 0.16614 1.27752 5.178 57.54
18 RFO 皇家同花顺优化算法 (JOO) 0.83361 0.73742 0.34629 1.91733 0.89424 0.73824 0.24098 1.87346 0.63154 0.50292 0.16421 1.29867 5.089 56.55
19 AOSm 原子轨道搜索 M 0.80232 0.70449 0.31021 1.81702 0.85660 0.69451 0.21996 1.77107 0.74615 0.52862 0.14358 1.41835 5.006 55.63
20 TSEA 龟壳进化算法(JOO) 0.96798 0.64480 0.29672 1.90949 0.99449 0.61981 0.22708 1.84139 0.69077 0.42646 0.13598 1.25322 5.004 55.60
21 BSA 回溯搜索算法 0.97309 0.54534 0.29098 1.80941 0.99999 0.58543 0.21747 1.80289 0.84769 0.36953 0.12978 1.34700 4.959 55.10
22 DE 差分进化 0.95044 0.61674 0.30308 1.87026 0.95317 0.78896 0.16652 1.90865 0.78667 0.36033 0.02953 1.17653 4.955 55.06
23 SRA 成功餐饮经营者算法(joo) 0.96883 0.63455 0.29217 1.89555 0.94637 0.55506 0.19124 1.69267 0.74923 0.44031 0.12526 1.31480 4.903 54.48
24 CRO 化学反应优化 0.94629 0.66112 0.29853 1.90593 0.87906 0.58422 0.21146 1.67473 0.75846 0.42646 0.12686 1.31178 4.892 54.36
25 BIO 血缘遗传优化算法 (JOO) 0.81568 0.65336 0.30877 1.77781 0.89937 0.65319 0.21760 1.77016 0.67846 0.47631 0.13902 1.29378 4.842 53.80
26 BSA 鸟群算法 0.89306 0.64900 0.26250 1.80455 0.92420 0.71121 0.24939 1.88479 0.69385 0.32615 0.10012 1.12012 4.809 53.44
27 DEA 海豚回声定位算法 0.75995 0.67572 0.34171 1.77738 0.89582 0.64223 0.23941 1.77746 0.61538 0.44031 0.15115 1.20684 4.762 52.91
28 HS 和声搜索算法 0.86509 0.68782 0.32527 1.87818 0.99999 0.68002 0.09590 1.77592 0.62000 0.42267 0.05458 1.09725 4.751 52.79
29 SSG 树苗播种和生长算法 0.77839 0.64925 0.39543 1.82308 0.85973 0.62467 0.17429 1.65869 0.64667 0.44133 0.10598 1.19398 4.676 51.95
30 BCOm 细菌趋化优化算法M 0.75953 0.62268 0.31483 1.69704 0.89378 0.61339 0.22542 1.73259 0.65385 0.42092 0.14435 1.21912 4.649 51.65
31 ABO 非洲水牛优化 0.83337 0.62247 0.29964 1.75548 0.92170 0.58618 0.19723 1.70511 0.61000 0.43154 0.13225 1.17378 4.634 51.49
32 (PO)ES (PO) 进化策略 0.79025 0.62647 0.42935 1.84606 0.87616 0.60943 0.19591 1.68151 0.59000 0.37933 0.11322 1.08255 4.610 51.22
33 FBA 基于分形的算法 0.79000 0.65134 0.28965 1.73099 0.87158 0.56823 0.18877 1.62858 0.61077 0.46062 0.12398 1.19537 4.555 50.61
34 TSm 禁忌搜索优化算法 0.87795 0.61431 0.29104 1.78330 0.92885 0.51844 0.19054 1.63783 0.61077 0.38215 0.12157 1.11449 4.536 50.40
35 BSO 头脑风暴优化 0.93736 0.57616 0.29688 1.81041 0.93131 0.55866 0.23537 1.72534 0.55231 0.29077 0.11914 0.96222 4.498 49.98
36 WOAm 鲸鱼优化算法M 0.84521 0.56298 0.26263 1.67081 0.93100 0.52278 0.16365 1.61743 0.66308 0.41138 0.11357 1.18803 4.476 49.74
37 AEFA 人工电场算法 0.87700 0.61753 0.25235 1.74688 0.92729 0.72698 0.18064 1.83490 0.66615 0.11631 0.09508 0.87754 4.459 49.55
38 AEO 基于人工生态系统的优化算法 0.91380 0.46713 0.26470 1.64563 0.90223 0.43705 0.21400 1.55327 0.66154 0.30800 0.28563 1.25517 4.454 49.49
39 CAm 骆驼算法 M 0.78684 0.56042 0.35133 1.69859 0.82772 0.56041 0.24336 1.63149 0.64846 0.33092 0.13418 1.11356 4.444 49.37
40 ACOm 蚁群优化 M 0.88190 0.66127 0.30377 1.84693 0.85873 0.58680 0.15051 1.59604 0.59667 0.37333 0.02472 0.99472 4.438 49.31
41 CMAES 协方差矩阵自适应进化策略 0.76258 0.72089 0.00000 1.48347 0.82056 0.79616 0.00000 1.61672 0.75846 0.49077 0.00000 1.24923 4.349 48.33
42 BFO-GA 细菌觅食优化 - ga 0.89150 0.55111 0.31529 1.75790 0.96982 0.39612 0.06305 1.42899 0.72667 0.27500 0.03525 1.03692 4.224 46.93
43 SOA 简单优化算法 0.91520 0.46976 0.27089 1.65585 0.89675 0.37401 0.16984 1.44060 0.69538 0.28031 0.10852 1.08422 4.181 46.45
44 ABHA 人工蜂巢算法 0.84131 0.54227 0.26304 1.64663 0.87858 0.47779 0.17181 1.52818 0.50923 0.33877 0.10397 0.95197 4.127 45.85
45 ACMO 大气云层模型优化 0.90321 0.48546 0.30403 1.69270 0.80268 0.37857 0.19178 1.37303 0.62308 0.24400 0.10795 0.97503 4.041 44.90
A3 人工原子算法 0.70744 0.49461 0.27674 1.47879 0.89102 0.43888 0.17553 1.50543 0.53230 0.32707 0.11431 0.97368 3.958 43.98
RW 随机游走 0.48754 0.32159 0.25781 1.06694 0.37554 0.21944 0.15877 0.75375 0.27969 0.14917 0.09847 0.52734 2.348 26.09


总结

本文完成了人工原子算法 A3 基于 MQL5 语言的实现,可用于解决交易策略参数优化问题。尽管原论文作者对算法理论描述存在内容缺失,我们仍然完成了一套可正常运行的工程实现版本。测试结果表明,A3 算法在运行速度与解的质量之间取得了良好平衡。该算法仅设置两个可调参数,极大简化了针对具体任务的调参工作,这对于对并非优化专家的交易者而言尤为重要。 

A3 算法可能会在优化方法中占据一定的应用位置。人工原子算法证明:即便结构相对简单的元启发式算法,只要针对特定领域合理适配,依然可能相当有效。兼具原理简洁、计算高效、解质量可靠等优势,让 A3 成为算法交易者工具箱中实用的优化工具。

算法源代码以及应用示例附于文章附录,感兴趣的读者可自行验证该算法的运行效率,并开展相关实验。

tab

图 1. 各算法在对应测试下的色彩渐变图。

图表

图 2. 算法测试结果直方图(比例从 0 到 100,越高越好,其中 100 是最大可能的理论结果,存档中有一个用于计算评级表的脚本)

A3 算法的优点和缺点

优点:

  1. 速度快。
  2. 参数少。

缺点:

  1. 收敛精度低。

文章附件中附带包含最新版算法代码的压缩包。作者不对文中经典算法描述的绝对准确性承担责任。其中许多算法均经过修改,以提升搜索能力。文章中表述的结论和论断是基于实验的结果。


本文使用的程序

# 名称 类型 说明
1 #C_AO.mqh

种群优化算法的父类
2 #C_AO_enum.mqh

种群优化算法枚举
3 TestFunctions.mqh

测试函数库
4
TestStandFunctions.mqh

测试台函数库
5
Utilities.mqh

辅助函数库
6
CalculationTestResults.mqh

用于计算对比表中结果的脚本
7
Testing AOs.mq5
脚本 所有种群优化算法的统一测试平台
8
Simple use of population optimization algorithms.mq5
脚本
一个不包含可视化功能的种群优化算法使用示例
9
Test_AO_A3.mq5
脚本 A3 测试平台

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/18958

附加的文件 |
A3.zip (258.97 KB)
最近评论 | 前往讨论 (7)
Auvoria Prime
Auvoria Prime | 26 6月 2026 在 16:54

我也是,第一次读的时候确实有点难懂,哈哈。这个想法听起来很有意思,但当共价键/离子键的规则以及电子分配的规则不太明确时,很难正确评估这个算法。

对我来说,最有用的部分应该是一个简单的分步示例,比如包含2个原子和几个变量,然后具体展示一次迭代如何改变解。如果没有这些,这更像是一个概念,而不是交易员能够真正理解或测试的内容。

Chacha Ian Maroa
Chacha Ian Maroa | 29 6月 2026 在 18:04
真是个疯狂的概念。接下来请写写“大爆炸理论”的优化概念吧。
Ryan L Johnson
Ryan L Johnson | 29 6月 2026 在 21:25
Chacha Ian Maroa #:
真是个疯狂的概念。接下来请写写“大爆炸理论”的优化概念吧
这位仁兄受够了俄罗斯航天局(Roscosmos),转而落脚在mql5.com上。
Robson Bruno Teixeira De Sousa
Robson Bruno Teixeira De Sousa | 2 7月 2026 在 00:15

我的评价

试想一下,有100个孩子 正在公园里寻找一个藏起来的玩具

每个孩子从不同的位置出发。

算法是这样运行的:

  1. 第一轮中, 它将所有孩子随机分散到公园的各个位置。
  2. 之后,在每一轮中:
    • 部分孩子会观察谁离玩具最近,并朝那个方向走一小段路。
    • 其余的孩子则跟随 那些进展顺利的孩子中随机选出的一名
    • 偶尔,会有 一个孩子决定去探索一个完全陌生的 地方,看看能否找到更好的路径。
  3. 每当有孩子试图走出公园时,算法就会说:

    “不行!请留在公园范围内。”

  4. 这个过程会重复多次。

最终,由于所有孩子都会向那些找到更好路径的孩子学习,整个群体便会越来越接近那个玩具

简而言之:

该算法让多个“人”尝试解决问题,从最佳解决方案中学习,有时还会探索新地方以寻找更好的解决方案。


注:该代码目前仍处于中级水平,需要进行一些调整。


Andrey Dik
Andrey Dik | 14 7月 2026 在 10:43
Chacha Ian Maroa #:
真是个疯狂的概念。下次请写写关于大爆炸理论优化的概念吧

;D

https://www.mql5.com/zh/articles/16963

利用灰色模型进行交易预测 利用灰色模型进行交易预测
本文探讨灰色模型(GM)在金融时间序列预测中的应用。我们将介绍GM的工作原理,以及其在金融序列上的具体应用方式。同时也会讨论该类模型在交易场景中的优势与局限性。
从基础到中级:对象(三) 从基础到中级:对象(三)
在今天的文章中,我们将探讨如何实现一个极具吸引力和趣味性的交互系统,特别是对于那些刚开始学习 MQL5 编程的人来说。这里并没有任何全新的内容。得益于我对这个主题的处理方式,理解起来会容易得多,因为我们将通过实践,了解如何使用结构化的方法,以实用且引人入胜的目标来开发程序。
精通日志记录(第十部分):通过抑制机制避免日志重复输出 精通日志记录(第十部分):通过抑制机制避免日志重复输出
我们在 Logify 函数库中搭建了一套日志抑制系统。本文详细讲解 CLogifySuppression 类如何通过可配置规则过滤重复、无关日志消息,减少控制台冗余信息。同时本文还介绍外部配置框架、参数校验机制以及完整测试方案,保障 EA、指标开发过程中日志记录能力稳定、灵活。
神经网络实践:熟能生巧 神经网络实践:熟能生巧
在今天的文章中,我们将探讨一个简单的代码更改如何使神经元更加专业化,从而显著加快训练阶段的速度。毕竟,正如我们稍后将看到的,一旦神经元或神经网络经过训练,其执行任务的速度就会大大提升。我们还会谈到一个确实存在、却很少有人提起的问题。