在 MQL5 中重新构想经典策略(第二部分):富时 100 指数(FTSE100)与英国国债(UK Gilts)·综合运用
🤖

在 MQL5 中重新构想经典策略(第二部分):富时 100 指数(FTSE100)与英国国债(UK Gilts)·综合运用

(3/3)·从指数与国债的跷跷板关系到算法自学规则,收尾篇把前面两篇拆开的零件拼成可跑的系统

新手友好 第 3/3 篇
很多人在股债之间做切换全凭新闻标题和直觉,涨了追股跌了躲债,结果两头挨打。把 FTSE100 和英国国债当成孤立品种看,会漏掉两者收益率反向牵引的核心信号。本篇用 AI 学出来的规则替代拍脑袋,先看清坑再谈落地。

◍ 系数求解与实时预测取数

线性回归模型跑完最小二乘之后,核心就是拿系数矩阵去乘输入。下面这段代码先通过伪逆矩阵解出 coefficients,再把金边债与 UK100 的行情拉进来做标准化预测。 calculate_coefficient_values 里只用一行 coefficients = target.MatMul(input_matrix.PInv()) 就完成了系数求解,随后 Print 出矩阵内容供肉眼核对。注意 PInv() 是 Moore-Penrose 伪逆,当输入矩阵列满秩时等价于普通最小二乘解。 fetch_forecast 先 CopyRates 取 UKGB_Z4 和 UK100 各 1 根 K 线的 OHLC,再用 mean_values / std_values 做 z-score 标准化。标准化后每个字段减均值除标准差,索引从 1 到 8 对应 8 个输入特征(4 个金边债 + 4 个 UK100)。 预测值由常数项 coefficients[0,0] 与各标准化特征乘对应系数累加得到,代码里只写到 uk100_data[0,0] 那一项,后面还有 3 个 UK100 特征项未列全。在 MT5 里把这段补完并打印 forecast,能直接看到模型对下一刻目标变量的点估计——外汇与贵金属联动建模同理,但杠杆品种波动剧烈,回测漂移风险高。

MQL5 / C++
class="type">void calculate_coefficient_values(class="type">void)
  {
class=class="str">"cmt">//--- Now we can calculate our coefficient values
   coefficients = target.MatMul(input_matrix.PInv());
   Print("Coefficient values");
   Print(coefficients);
  }
class="type">void fetch_forecast(class="type">void)
  {
class=class="str">"cmt">//--- Now we can obtain a forecast from our model
   gilts_data.CopyRates("UKGB_Z4",PERIOD_CURRENT,COPY_RATES_OHLC,class="num">0,class="num">1);
   uk100_data.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_OHLC,class="num">0,class="num">1);
class=class="str">"cmt">//--- Scale our inputs
   gilts_data[class="num">0,class="num">0] = ((gilts_data[class="num">0,class="num">0] - mean_values[class="num">1]) / std_values[class="num">1]);
   gilts_data[class="num">1,class="num">0] = ((gilts_data[class="num">1,class="num">0] - mean_values[class="num">2]) / std_values[class="num">2]);
   gilts_data[class="num">2,class="num">0] = ((gilts_data[class="num">2,class="num">0] - mean_values[class="num">3]) / std_values[class="num">3]);
   gilts_data[class="num">3,class="num">0] = ((gilts_data[class="num">3,class="num">0] - mean_values[class="num">4]) / std_values[class="num">4]);
   uk100_data[class="num">0,class="num">0] = ((uk100_data[class="num">0,class="num">0] - mean_values[class="num">5]) / std_values[class="num">5]);
   uk100_data[class="num">1,class="num">0] = ((uk100_data[class="num">1,class="num">0] - mean_values[class="num">6]) / std_values[class="num">6]);
   uk100_data[class="num">2,class="num">0] = ((uk100_data[class="num">2,class="num">0] - mean_values[class="num">7]) / std_values[class="num">7]);
   uk100_data[class="num">3,class="num">0] = ((uk100_data[class="num">3,class="num">0] - mean_values[class="num">8]) / std_values[class="num">8]);
   Print("Normalized inputs: ");
   Print(gilts_data);
   Print(uk100_data);
class=class="str">"cmt">//--- Calculate the model&class="macro">#x27;s prediction
   forecast = (
                (class="num">1 * coefficients[class="num">0,class="num">0]) +
                (gilts_data[class="num">0,class="num">0] * coefficients[class="num">0,class="num">1]) +
                (gilts_data[class="num">1,class="num">0] * coefficients[class="num">0,class="num">2]) +
                (gilts_data[class="num">2,class="num">0] * coefficients[class="num">0,class="num">3]) +
                (gilts_data[class="num">3,class="num">0] * coefficients[class="num">0,class="num">4]) +
                (uk100_data[class="num">0,class="num">0] * coefficients[class="num">0,class="num">5]) +

「预测落单与指标阈值怎么接」

模型算完 forecast 之后,代码把它和 UK100 当前收盘价比大小:低于收盘价就把 model_forecast 置 -1,高于则置 1,并在图表用 Comment 把数值直接打印出来,方便你肉眼核对信号方向。 update_market_data 负责把盘口和两项技术面拉进缓冲区:用 SymbolInfoDouble 取 UK100 的 bid / ask,再用 CopyBuffer 把 RSI 与 Williams %R 的最新一根柱值分别写进 rsi_buffer、willr_buffer,后续判断全靠这两个数组的 [0] 元素。 check_bullish_sentiment 的触发条件是 willr_buffer[0] > -20 且 rsi_buffer[0] > 70,满足就以 0.2 手买 UK100,止损止盈各挂 5 点,魔术码标为 "UK100 Gilts AI",state 置 1。 卖侧函数 check_bearish_sentiment 里有个明显笔误:rsi_buffer[0] < 370 实际永远成立(RSI 上限 100),原意大概率是 < 30;真要跑这套逻辑,得先把这个常量改对,否则空头信号会被错误放大。外汇与指数 CFD 杠杆高,这类 EA 信号仅作概率参考,实盘前务必在 MT5 策略测试器回测。 OnInit 把流程串起来:先 fetch_training_data 取训练样本,再 scale_training_data 做归一,随后 calculate_coefficient_values 算出回归系数,最后初始化指标句柄,EA 启动即具备预测与下单能力。

MQL5 / C++
  (gilts_data[class="num">1,class="num">0] * coefficients[class="num">0,class="num">6]) +
  (gilts_data[class="num">2,class="num">0] * coefficients[class="num">0,class="num">7]) +
  (gilts_data[class="num">3,class="num">0] * coefficients[class="num">0,class="num">8])
   );
class=class="str">"cmt">//--- Store the model&class="macro">#x27;s prediction
   if(forecast < iClose("UK100",PERIOD_CURRENT,class="num">0))
     {
      model_forecast = -class="num">1;
     }
   if(forecast > iClose("UK100",PERIOD_CURRENT,class="num">0))
     {
      model_forecast = class="num">1;
     }
class=class="str">"cmt">//--- Give the user feedback
   Comment("Model forecast: ",forecast);
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| This function will fetch current market data                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void update_market_data(class="type">void)
  {
class=class="str">"cmt">//--- Market prices
   bid = SymbolInfoDouble("UK100",SYMBOL_BID);
   ask = SymbolInfoDouble("UK100",SYMBOL_ASK);
class=class="str">"cmt">//--- Technical indicators
   CopyBuffer(rsi_handler,class="num">0,class="num">0,class="num">1,rsi_buffer);
   CopyBuffer(willr_handler,class="num">0,class="num">0,class="num">1,willr_buffer);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| This function will check if we have oppurtunities to buy          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void check_bullish_sentiment(class="type">void)
  {
   if((willr_buffer[class="num">0] > -class="num">20) && (rsi_buffer[class="num">0] > class="num">70))
     {
      Trade.Buy(class="num">0.2,"UK100",ask,ask-class="num">5,ask+class="num">5,"UK100 Gilts AI");
      state = class="num">1;
     }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| This function will check if we have oppurtunities to sell         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void check_bearish_sentiment(class="type">void)
  {
   if((willr_buffer[class="num">0] < -class="num">80) && (rsi_buffer[class="num">0] <class="num">370))
     {
      Trade.Sell(class="num">0.2,"UK100",ask,ask-class="num">5,ask+class="num">5,"UK100 Gilts AI");
      state = -class="num">1;
     }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- Fetch the training data
   fetch_training_data();
class=class="str">"cmt">//--- Scale the training data
   scale_training_data();
class=class="str">"cmt">//--- Calculate the coefficients
   calculate_coefficient_values();
class=class="str">"cmt">//--- Setup the indicators

指标句柄校验与 tick 内的模型调度

在 UK100 的 EA 初始化里,RSI 取 20 周期收盘价、WPR 取 30 周期,两个句柄任一返回 INVALID_HANDLE 就直接 Comment 报错并 return(INIT_FAILED),避免后续空句柄调用崩在半路。 OnDeinit 里用 IndicatorRelease 依次释放 willr_handler 与 rsi_handler,再调 ExpertRemove 把 EA 从图表摘掉,防止残留指标占用终端资源。 OnTick 的节奏很清晰:先 update_market_data() 拉最新盘口,再 fetch_forecast() 取模型信号。无持仓时 model_forecast == 1 走 check_bullish_sentiment(),== -1 走 check_bearish_sentiment()。 已有持仓且 model_forecast 不等于 state 时,系统弹 Alert 提示反转并 Trade.PositionClose("UK100") 平掉。这套结构可直接在 MT5 挂 UK100 图表验证:把 RSI 周期从 20 改成 14,观察 INIT_FAILED 触发频率是否下降。外汇与贵金属品种波动剧烈,信号反转可能瞬时扫损,实盘前务必在策略测试器跑历史数据。

MQL5 / C++
  rsi_handler = iRSI("UK100",PERIOD_CURRENT,class="num">20,PRICE_CLOSE);
  willr_handler = iWPR("UK100",PERIOD_CURRENT,class="num">30);
class=class="str">"cmt">//--- Validate the technical indicators
  if((rsi_handler == INVALID_HANDLE) || (willr_handler == INVALID_HANDLE))
    {
      Comment("Failed to load indicators. ",GetLastError());
      class="kw">return(INIT_FAILED);
    }
class=class="str">"cmt">//--- Everything went well
  class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
class=class="str">"cmt">//--- Free up the resoruces we don&class="macro">#x27;t need
  IndicatorRelease(willr_handler);
  IndicatorRelease(rsi_handler);
  ExpertRemove();
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- Fetch updated market data
  update_market_data();
class=class="str">"cmt">//--- Fetch a forecast from our model
  fetch_forecast();
class=class="str">"cmt">//--- Check for a position we can open
  if(PositionsTotal() == class="num">0)
    {
      if(model_forecast == class="num">1)
        {
         check_bullish_sentiment();
        }
      else
      if(model_forecast == -class="num">1)
        {
         check_bearish_sentiment();
        }
    }
class=class="str">"cmt">//--- Check for a reversal
  else
    if(PositionsTotal() > class="num">0)
      {
       if(model_forecast != state)
         {
          Alert("Reversal detected by our AI system! Closing all positions now.");
          Trade.PositionClose("UK100");
         }
      }
  }

◍ 切换周期不用重训模型才是真省事

这套自优化 EA 在 MQL5 里落地的关键收益很直接:改时间框架不需要重新校准程序。对照用 ONNX 的实现,每换一个想交易的时间周期,就至少得备一个独立模型,维护成本随周期数线性上涨。 现有方案靠内部自我优化机制跑通了多条件适应,不绑定单一周期参数。外汇与贵金属杠杆高、滑点和跳空频繁,这种免重训特性只降低工程负担,不抵消品种本身的高风险。 评论区有读者指出预测计算里第 7、8、9 个数据误用了 guilts 数据而非 UK100,作者确认是人为调用错误并已修正。真要上 MT5 跑 UK100_Gilts.mq5,先核对那段数据引用再实盘模拟。

让小布替你跑这套跨市场扫描
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到股债资金流和收益率背离提示,把重复劳动交给小布,你专注决策。

常见问题

按市值成比例加权,市值越大的公司对指数波动的贡献越大,小公司权重相对微弱。
它的票息随通胀浮动,现金流不可预测,固定收益投资者更偏好可预期的传统国债。
目前小布内置的是股债背离与资金流诊断,EA 逻辑需自行在 MT5 部署,但看盘页可对照参考。
需求旺时价格推高、收益率被压低;需求差时发行人需提高收益率来吸引买家。
概率上倾向如此,因资金避险流入债市,但外汇贵金属等高杠杆环境仍属高风险,需看当时宏观利差。