重构MQL5中的经典策略(第三部分):富时100指数预测(基础篇)
📘

重构MQL5中的经典策略(第三部分):富时100指数预测(基础篇)

第 1/3 篇

AI策略海洋里先解决筛选成本

AI在当代交易者策略里的落地场景几乎看不到天花板,但一个人的盯盘时间和回测精力都有硬上限。 现实是:没有哪个交易者能逐条手工验证海量AI策略再决定仓位分配,光是扫一遍信号源就可能耗掉一整天。 这篇系列用MT5实盘环境把各类基于AI的策略拆开重做,帮你按自己的风险偏好和品种习惯做减法,而不是堆更多看不懂的模型。 外汇与贵金属本身杠杆高、跳空频繁,接任何AI策略前先在MT5策略测试器跑历史数据,确认最大回撤和样本外表现再上真金。

「从富时100权重结构里抠交易线索」

伦敦证券交易所成立于1801年,是欧洲最大证交所,官网披露当前所有上市公司总市值约4.4万亿英镑。这个体量决定了它的指数波动不是单一标的能撬动的。 FTSE 100 跟踪伦交所市值前100的公司,也就是俗称的蓝筹股群体。这类标的长期业绩记录被市场视作相对安全,但安全不等于无波动,指数层面仍有可捕捉的均值偏移。 一个可行的切入点是:用指数当前收盘价,叠加上榜的10只大盘股表现,反推指数后续收盘的偏移方向。逻辑上,若这10只权重股同步走强,指数收高概率倾向抬升;若分化严重,则预测置信度下降。 外汇与贵金属交易者借道这类跨市场映射时,须明确这是高风险尝试,伦交所数据与MT5外汇盘之间有时差与流动性断层,任何推断都只是概率而非确定性。

◍ 用线性回归给指数做跨周期外推

我们这套 AI 驱动的 EA 完全用 MQL5 写成,核心是一个多元线性回归模型,总共吃 12 个输入,去预测富时 100 指数往后 20 根 K 线的收盘价。模型在时间框架上不挑,切换周期无需反复改结构,预测步长也能动态调。 输入在做预测前统一走了 Z 标准化:拿每列的均值和标准差把每一个特征归一化缩放,目标变量就是 20 步后的收盘价本身。这一处理让不同量纲的因子能直接进同一套权重运算。 树模型在这里天然吃亏——它靠把数据切成组、预测时返回最匹配组的均值,本质不会外推。五个时刻的输入只要够相似,树模型可能给出完全一样的收盘价。线性回归则能沿权重方向推出样本外数值,对证券未来收盘价给出有梯度差异的估计,这种能力在价格行为突破临界时尤其关键。 外汇与贵金属市场高波动、高杠杆,此类外推仅提供概率性参考,实盘前务必在 MT5 用历史数据回测验证。

从脚本起步搭线性回归骨架

先把交易想法落成一个 MQL5 脚本,比直接写 EA 更利于看清各模块怎么咬合。第一步是抓数据并做规范化,输入塞进一个矩阵,目标值单独放另一个矩阵,这样后面算参数时不会搅在一起。 模型参数用多元线性回归的闭式解直接算,不用迭代。系数矩阵里第一项其实是偏置:当所有输入为 0 时目标的平均值;在 FTSE 100 这个场景里,若成分股价格全为 0 英镑,指数未来均值也数学上趋近 0,实战里没什么直观含义。第二个系数代表其他股价不变时,某只股票每变动一单位带来的指数边际变化,比如阿迪尔(ADM.LSE)价格涨一个单位,模型给出的指数未来收盘价倾向轻微下移。 预测本身不复杂:把每只股票现价比上各自系数相乘,全部乘积相加即得。脚本里先定全局变量,fetch 取 2000 根 K 线、look_ahead 设 20 根作为前瞻,list_of_companies 存了 10 只 LSE 股票加 UK100 本身,input_matrix 是 12 行 fetch 列的零矩阵——多出来的那行留给截距向量。 跑通这套脚本后,你就知道数据怎么流、系数怎么出,下一步包成 EA 不过是加信号与下单逻辑。外汇与贵金属以外指数也属高波动标的,回测结论仅代表历史样本,实盘概率会漂移。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                 UK100.mq5 |
class=class="str">"cmt">//|                                                     Gamuchirai Zororo Ndawana |
class=class="str">"cmt">//|                                        [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Gamuchirai Zororo Ndawana"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Script program start function                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//class="num">1) ADM.LSE   - Admiral
class=class="str">"cmt">//class="num">2) AAL.LSE   - Anglo American
class=class="str">"cmt">//class="num">3) ANTO.LSE - Antofagasta
class=class="str">"cmt">//class="num">4) AHT.LSE   - Ashtead
class=class="str">"cmt">//class="num">5) AZN.LSE   - AstraZeneca
class=class="str">"cmt">//class="num">6) ABF.LSE   - Associated British Foods
class=class="str">"cmt">//class="num">7) AV.LSE    - Aviva
class=class="str">"cmt">//class="num">8) BARC.LSE - Barclays
class=class="str">"cmt">//class="num">9) BP.LSE    - BP
class=class="str">"cmt">//class="num">10) BKG.LSE - Berkeley Group 
class=class="str">"cmt">//class="num">11) UK100    - FTSE class="num">100 Index
class=class="str">"cmt">//+-------------------------------------------------------------------+
class=class="str">"cmt">//| Global variables                                                  |
class=class="str">"cmt">//+-------------------------------------------------------------------+
class="type">int fetch = class="num">2000;
class="type">int look_ahead = class="num">20;
class="type">class="kw">double mean_values[class="num">11],std_values[class="num">11];
class="type">class="kw">string list_of_companies[class="num">11] = {"ADM.LSE","AAL.LSE","ANTO.LSE","AHT.LSE","AZN.LSE","ABF.LSE","AV.LSE","BARC.LSE","BP.LSE","BKG.LSE","UK100"};
vector intercept = vector::Ones(fetch);
matrix target = matrix::Zeros(class="num">1,fetch);
matrix coefficients;
matrix input_matrix = matrix::Zeros(class="num">12,fetch);
class="type">void OnStart()
  {
class=class="str">"cmt">//--- Fetch the target
   target.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">1,fetch);
class=class="str">"cmt">//--- Fill in the class="kw">input matrix
   for(class="type">int i = class="num">0; i < class="num">11; i++)
     {
      class=class="str">"cmt">//--- Add the symbol to market watch
      SymbolSelect(list_of_companies[i],true);
      class=class="str">"cmt">//--- Fetch historical data
      vector temp = vector::Zeros(fetch);

「把多品种收盘序列灌进回归矩阵」

上面这段把前面准备好的品种列表逐个拉取收盘价,做标准化后塞进同一张输入矩阵。CopyRates 取的是 PERIOD_CURRENT 下 1+look_ahead 根 K 线的收盘价,look_ahead 若设为 5,实际就抓 6 个样本点,样本极少,外汇与贵金属品种上跑这套极易过拟合,高风险。 均值和标准差先按各自序列算,再用 (x-mean)/std 把量纲拉开,避免某个指数波动绝对值大就 dominate 了回归。Row(temp,i) 把第 i 个品种的标准化行写进矩阵第 i 行,循环结束后再用 Row(intercept,11) 补一行截距项,矩阵变成 12 行。 矩阵拼好后 Print 出来肉眼核对,再用 target.MatMul(input_matrix.PInv()) 求系数——PInv 是伪逆,普通最小二乘闭式解。最后把系数转置打印,UK100 那行就是各品种对它的线性权重。打开 MT5 接上前面几节的数据,直接复制这段就能看到你自选列表的回归系数。

MQL5 / C++
   temp.CopyRates(list_of_companies[i],PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">1+look_ahead,fetch);
   class=class="str">"cmt">//--- Store the mean value and standard deviation, also scale the data
   mean_values[i] = temp.Mean();
   std_values[i] = temp.Std();
   temp = ((temp - mean_values[i]) / std_values[i]);
   class=class="str">"cmt">//--- Add the data to the matrix
   input_matrix.Row(temp,i);
   }
class=class="str">"cmt">//--- Add the intercept
input_matrix.Row(intercept,class="num">11);
class=class="str">"cmt">//--- Show the class="kw">input data
Print("Input data:");
Print(input_matrix);
class=class="str">"cmt">//--- Calculating coefficient values
coefficients = target.MatMul(input_matrix.PInv());
class=class="str">"cmt">//--- Display the coefficient values
Print("UK100 Coefficients:");
Print(coefficients.Transpose());

常见问题

先按品种波动特性和自身风险偏好做初筛,只保留逻辑透明、可回测的策略,别一上来就全仓跟。
权重股占比高,单日异动常带动指数跳空;盯前十大成分股收盘强弱,可提前感知指数倾向。
小布盯盘的AIGC已内置跨周期回归诊断,打开对应品种页就能看到外推结果与预警,不用自己写脚本。
周期错配会让外推线严重滞后或虚高,建议先用日线校准再切4小时验证,外汇贵金属高风险需谨慎。
先写单品种收盘序列灌入回归,跑通后再扩到多品种矩阵,避免一上来就处理维度爆炸。