大气云模型优化(ACMO):理论·进阶篇
📘

大气云模型优化(ACMO):理论·进阶篇

第 2/2 篇

「云滴优化器的参数骨架」

用雨滴云模型做 EA 参数寻优时,先得把种群与云结构的基础常量钉死。下面这组初值来自一套实盘前回测用的默认配置:种群规模 50、云数量 5、每维区域数 10,初始熵 1.0、超熵 0.5,阈值因子 λ=0.7、衰减率 γ=0.2。 这些量不是拍脑袋,dMin=0.2 表示最稀疏云内雨滴数不低于平均值的 20%,λ 控制“暴雨区”入选门槛,γ 决定每次迭代后云势的削弱速度。外汇与贵金属波动高、滑点随机,直接套用可能偏离你的品种特性,建议先在 MT5 策略测试器里跑一轮 EURUSD M15 观察收敛曲线。 代码里用 ArrayResize(params,8) 开出 8 个槽位,把上面 8 个变量名和值成对塞进 params 数组,SetParams() 再反向读回——这样外部面板改一个数,优化器内部常量就跟着变,不用动核心逻辑。

MQL5 / C++
popSize       = class="num">50;     class=class="str">"cmt">//population size
cloudsNumber  = class="num">5;      class=class="str">"cmt">// Number of clouds
regionsNumber = class="num">10;     class=class="str">"cmt">// Number of regions per dimension(M)
dMin          = class="num">0.2;    class=class="str">"cmt">// Minimum number of drops relative to the average number of drops in the clouds(dN)
EnM0          = class="num">1.0;    class=class="str">"cmt">// Initial value of entropy
HeM0          = class="num">0.5;    class=class="str">"cmt">// Initial value of hyperentropy
λ             = class="num">0.7;    class=class="str">"cmt">// Threshold factor(threshold of the rainiest regions)
γ             = class="num">0.2;    class=class="str">"cmt">// Weaken rate
ArrayResize(params, class="num">8);
params [class="num">0].name = "popSize";       params [class="num">0].val = popSize;
params [class="num">1].name = "cloudsNumber";  params [class="num">1].val = cloudsNumber;
params [class="num">2].name = "regionsNumber"; params [class="num">2].val = regionsNumber;
params [class="num">3].name = "dMin";          params [class="num">3].val = dMin;
params [class="num">4].name = "EnM0";          params [class="num">4].val = EnM0;
params [class="num">5].name = "HeM0";          params [class="num">5].val = HeM0;
params [class="num">6].name = "λ";             params [class="num">6].val = λ;
params [class="num">7].name = "γ";             params [class="num">7].val = γ;
}
class="type">void SetParams()
{
  popSize       = (class="type">int)params [class="num">0].val;
  cloudsNumber  = (class="type">int)params [class="num">1].val;
  regionsNumber = (class="type">int)params [class="num">2].val;
  dMin          = params      [class="num">3].val;
  EnM0          = params      [class="num">4].val;
  HeM0          = params      [class="num">5].val;
  λ             = params      [class="num">6].val;
  γ             = params      [class="num">7].val;
}
class="type">bool Init(class="kw">const class="type">class="kw">double &rangeMinP  [], class=class="str">"cmt">//minimum search range
                    class="kw">const class="type">class="kw">double &rangeMaxP  [], class=class="str">"cmt">//maximum search range
                    class="kw">const class="type">class="kw">double &rangeStepP [], class=class="str">"cmt">//step search

◍ ACMO 云滴结构体的字段与初始化落点

这段 C_AO_ACMO 类的成员变量定义了云优化(ACMO)的核心参数:cloudsNumber 控制云的数量,regionsNumber 即每个维度的区域数 M,dMin 是相对平均云滴数的最小雨滴比例,λ 与 γ 分别充当阈值因子和衰减率。私有段里的 dTotal 对应最大总雨滴数 N,entropy[] 与 minGp 用于跟踪演化过程中的熵和压力。 Init 函数接收区间上下限与步长数组,并带一个默认 0 的 epochsP 参数。进去先跑 StandardInit 做基础校验,失败直接返 false;随后把 epochs 设为传入值、epochNow 归零,dTotal 绑定 popSize,并把 dMin 按云数比例缩放:dMin = dMin * (popSize / (double)cloudsNumber)。 最后两行 ArrayResize 把 entropy 和 areas 都拉到 coords 长度,意味着维度坐标数直接决定熵数组与区域数组的规模。在 MT5 里改 coords 或 popSize 后,这两处 resize 会直接影响内存占用和后续降雨分布的分辨率,外汇与贵金属行情下此类算法对参数敏感,实盘验证前务必用历史数据回测。

MQL5 / C++
class="kw">const class="type">int      epochsP = class="num">0);  class=class="str">"cmt">//number of epochs
class="type">void Moving(); 
class="type">void Revision(); 
class=class="str">"cmt">//----------------------------------------------------------------------------
class="type">int    cloudsNumber;   class=class="str">"cmt">// Number of clouds
class="type">int    regionsNumber; class=class="str">"cmt">// Number of regions per dimension(M)
class="type">class="kw">double dMin;           class=class="str">"cmt">// Minimum number of drops relative to the average number of drops in the clouds(dN)
class="type">class="kw">double EnM0;           class=class="str">"cmt">// Initial value of entropy
class="type">class="kw">double HeM0;           class=class="str">"cmt">// Initial value of hyperentropy
class="type">class="kw">double λ;              class=class="str">"cmt">// Threshold factor
class="type">class="kw">double γ;              class=class="str">"cmt">// Weaken rate
S_ACMO_Area   areas  [];
S_ACMO_Cloud  clouds [];
class="kw">private: class=class="str">"cmt">//-------------------------------------------------------------------
class="type">int    epochs;
class="type">int    epochNow;
class="type">int    dTotal;          class=class="str">"cmt">// Maximum total number of droplets(N)
class="type">class="kw">double entropy [];      class=class="str">"cmt">// Entropy
class="type">class="kw">double minGp;           class=class="str">"cmt">// Minimum global pressure
class="type">void   MoveClouds(class="type">bool &rev);
class="type">int    GetRegionIndex(class="type">class="kw">double point, class="type">int ind);
class="type">void   RainProcess(class="type">bool &rev);
class="type">void   DropletsDistribution(class="type">class="kw">double &clouds [], class="type">int &droplets []);
class="type">void   UpdateRegionProperties();
class="type">void   GenerateClouds();
class="type">class="kw">double CalculateHumidityThreshold();
class="type">void   CalculateNewEntropy(S_ACMO_Cloud &cl, class="type">int t);
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">bool C_AO_ACMO::Init(class="kw">const class="type">class="kw">double &rangeMinP  [],
                      class="kw">const class="type">class="kw">double &rangeMaxP  [],
                      class="kw">const class="type">class="kw">double &rangeStepP [],
                      class="kw">const class="type">int     epochsP = class="num">0)
{
  if (!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) class="kw">return class="kw">false;
  class=class="str">"cmt">//----------------------------------------------------------------------------
  epochs   = epochsP;
  epochNow = class="num">0;
  class=class="str">"cmt">//----------------------------------------------------------------------------
  dTotal       = popSize;
  dMin         = dMin * (popSize / (class="type">class="kw">double)cloudsNumber);
  ArrayResize(entropy, coords);
  ArrayResize(areas,   coords);

网格区域的熵宽与云点初始化

这段逻辑干的事,是把每个坐标维度的取值范围切成等宽区间,并为后续聚类准备空云。熵宽 entropy[c] 直接由 (rangeMax[c] - rangeMin[c]) / regionsNumber 算出,区间数量 regionsNumber 决定粒度,设太大在 MT5 里会拖慢实时计算。 内层循环给每个 region 算中心价:先取区间中值,再用 u.SeInDiSp 按最小/最大/步长吸附到合法报价网格上,最后把 x 也指向该中心。注意 centre 被函数二次处理,意味着你给的 rangeStep 会真实影响聚类重心位置。 clouds 数组按 cloudsNumber 扩容,每个云调用 Init(coords) 清成空壳;minGp 置为 DBL_MAX 是为了后面找最小组间距离时有干净初值。外汇与贵金属波动大,这种网格法对参数敏感,回测时建议先固定 regionsNumber 做敏感性排查。

MQL5 / C++
  for (class="type">int c = class="num">0; c < coords; c++)
  {
    entropy [c] = (rangeMax [c] - rangeMin [c]) / regionsNumber;
    ArrayResize(areas [c].regions, regionsNumber);
    for (class="type">int r = class="num">0; r < regionsNumber; r++)
    {
      areas [c].regions [r].Init();
      areas [c].regions [r].centre = rangeMin [c] + entropy [c] * (r + class="num">0.5);
      areas [c].regions [r].centre = u.SeInDiSp(areas [c].regions [r].centre, rangeMin [c], rangeMax [c], rangeStep [c]);
      areas [c].regions [r].x       = areas [c].regions [r].centre;
    }
  }
  ArrayResize(clouds, cloudsNumber);
  for (class="type">int i = class="num">0; i < cloudsNumber; i++) clouds [i].Init(coords);
  minGp = DBL_MAX;
  class="kw">return true;
}

「画得少,看得清」

ACMO 把大气气象映射成三组实体:云层管解的空间多样性,区域框定搜索边界,水滴负责在解之间迁移。三者各自独立运行,耦合后形成一套不依赖多群体框架的连续优化机制,实数编码下既能跑离散决策也能跑浮点调参。 第二部分的落点很直接——把这套模型丢进标准测试函数,看收敛曲线和稳定性,再判断能不能挪到实盘参数寻优里。俄文原帖附的 ACMO.zip 只有 37.22 KB,本地解压后用 MT5 的 MetaEditor 直接编译,先跑几个低维函数验证水滴迁移逻辑有没有按文档走。 外汇和贵金属策略寻优天然高波动、高杠杆,任何算法给出的参数组合都只是概率倾向更优,不是免死金牌。跑通代码后,建议拿 EUR/USD 的 H1 历史数据做一轮样本外回测,再决定要不要进实盘。

常见问题

重点看云滴数量、熵宽和迭代次数;云滴数决定搜索密度,熵宽控制初始落点分散度,先从小样本回测再放大。
检查网格区域的熵宽设置是否过小,适当拉宽熵宽可让云点在边界更分散,避免局部重叠导致早熟。
可以,小布盯盘的 AIGC 已内置云滴分布与熵宽诊断,打开对应品种页即可看到当前参数下的收敛倾向。
熵宽过大会稀释有效信号,概率上外盘噪音增多;建议按品种波动分级设宽,贵金属高风险需更保守。
冗余云滴线会掩盖主干收敛路径;只留熵宽边界与核心云滴,更利于识别价格行为真实走向。