纳什博弈论与隐马尔可夫滤模型在交易中的应用·综合运用
♟️

纳什博弈论与隐马尔可夫滤模型在交易中的应用·综合运用

(3/3)·从数学定义到EA落地,前两步铺垫后这一步才真正把理论跑成信号

含代码示例偏理论 第 3/3 篇
很多人把纳什均衡当成静态结论直接套价格,忽略了市场参与者策略会随隐状态切换。隐马尔可夫滤模型正好补上这层动态推断,本篇收尾把两套数学工具接进同一套MQL5流程。

「混合模型里的权重与均值协方差矩阵长什么样」

下面这组数值来自一个十状态混合模型的实测输出,直接看结构比看公式快。第一块是各状态在 5 个历史切片上的权重分布,每行 10 个数、加和恒为 1,例如第 1 行末位权重仅 0.0346,而第 2 行第 5 列冲到 0.1666,说明该切片下第 5 状态短暂主导。 Means Matrix 给出 10 个状态在 3 个特征维度上的均值,注意第 7 状态首维均值 -0.8546、第 9 状态第三维 -0.5879,均为明显负偏,和其余接近零的中心态形成对比;第 2、6、10 状态第二维均值都大于 1.05,指向同一类扩张形态。 Covariance Matrix 只截了前 3 个状态的三维协方差,对角项即方差:状态 1 首维方差 1.253、状态 3 首维 1.764,都比状态 2 的 1.230 略宽,意味着状态 3 的首特征波动更野。非对角项里状态 1 的(2,3)协方差 0.1586 为正,状态 2 的同位置为 -0.0811,相关方向已经反转。 把这些矩阵原样贴进 MT5 的全局数组,用 Print() 跑一遍行和,能立刻验证权重归一化是否被破坏——外汇与贵金属行情下这种模型对输入尺度极敏感,高风险环境里别裸用。

MQL5 / C++
{class="num">0.19806868, class="num">0.11292565, class="num">0.11482367, class="num">0.08324432, class="num">0.09808519, class="num">0.06727817, class="num">0.11549253, class="num">0.10657752, class="num">0.06889919, class="num">0.03460507},
{class="num">0.12257742, class="num">0.11257625, class="num">0.11910078, class="num">0.07669820, class="num">0.16660657, class="num">0.04769350, class="num">0.09667861, class="num">0.12241177, class="num">0.04856867, class="num">0.08708823},
{class="num">0.14716725, class="num">0.12232022, class="num">0.11135735, class="num">0.08488571, class="num">0.06274817, class="num">0.07390905, class="num">0.10742571, class="num">0.12550373, class="num">0.11431005, class="num">0.05037277},
{class="num">0.11766333, class="num">0.11533807, class="num">0.15497601, class="num">0.14017237, class="num">0.11214274, class="num">0.04885795, class="num">0.08394306, class="num">0.12864406, class="num">0.06945878, class="num">0.02880364},
{class="num">0.13559147, class="num">0.07444276, class="num">0.09785968, class="num">0.13599698, class="num">0.12947508, class="num">0.06385211, class="num">0.09042617, class="num">0.16088280, class="num">0.06588065, class="num">0.04559230}
};
Means Matrix:
{
{class="num">0.06871601, class="num">0.14572210, class="num">0.05961646},
{class="num">0.06903949, class="num">1.05226034, -class="num">0.25687024},
{-class="num">0.04607112, -class="num">0.00811718, class="num">0.06488246},
{-class="num">0.01769149, class="num">0.63694700, class="num">0.26965491},
{-class="num">0.01874345, class="num">0.58917438, -class="num">0.22484670},
{-class="num">0.02026370, class="num">1.09022869, class="num">0.86790417},
{-class="num">0.85455759, class="num">0.48710677, class="num">0.08980023},
{-class="num">0.02589947, class="num">0.84881170, class="num">0.00453701},
{-class="num">0.38270747, class="num">0.86916742, -class="num">0.58792329},
{-class="num">0.16057267, class="num">1.17106076, class="num">0.18531821}
};
Covariance Matrix:
{
{{class="num">1.25299224e+00, -class="num">4.05453267e-02, class="num">7.95036804e-02},
 {-class="num">4.05453267e-02, class="num">1.63177290e-01, class="num">1.58609858e-01},
 {class="num">7.95036804e-02, class="num">1.58609858e-01, class="num">8.09678270e-01}},
{{class="num">1.23040552e+00, class="num">2.52108300e-02, class="num">1.17595322e-01},
 {class="num">2.52108300e-02, class="num">3.00175953e-01, -class="num">8.11027442e-02},
 {class="num">1.17595322e-01, -class="num">8.11027442e-02, class="num">1.42259217e+00}},
{{class="num">1.76376507e+00, -class="num">7.82189996e-02, class="num">1.89340073e-01}

高斯混合模型的协方差矩阵实值

上面这段数据是高斯混合(GMM)里各分量对应的 3×3 协方差矩阵原始数值,直接喂给 MT5 里的矩阵运算或自定义指标做概率密度估算。 注意第 5 个分量首行首列是 3.19499555e+00,而第 8 个分量同位置到了 5.47457383e+00,跨度近 1.7 倍,说明不同聚类的价格散布尺度差异极大。 外汇与贵金属杠杆高、波动突变频繁,这类协方差若直接用于实时仓位尺度推断,可能严重低估尾部风险,建议先在历史 tick 上回测再上实盘。 把数值贴进下面结构,就能在 EA 里初始化一个对称矩阵数组供后续 Mahalanobis 距离计算调用。

MQL5 / C++
{{
  {-class="num">7.82189996e-02, class="num">2.56222155e-01, -class="num">1.30202288e-01},
  {class="num">1.89340073e-01, -class="num">1.30202288e-01, class="num">6.60591043e-01}},
 { {class="num">9.08926052e-01, class="num">3.02606081e-02, class="num">1.03549625e-01},
  {class="num">3.02606081e-02, class="num">2.30324420e-01, -class="num">5.46541678e-02},
  {class="num">1.03549625e-01, -class="num">5.46541678e-02, class="num">7.40333449e-01}},
 { {class="num">8.80590495e-01, class="num">7.21102489e-02, class="num">3.40982555e-02},
  {class="num">7.21102489e-02, class="num">3.26639817e-01, -class="num">1.06663221e-01},
  {class="num">3.40982555e-02, -class="num">1.06663221e-01, class="num">9.55477387e-01}},
 { {class="num">3.19499555e+00, -class="num">8.63552078e-02, class="num">5.03260281e-01},
  {-class="num">8.63552078e-02, class="num">2.92184645e-01, class="num">1.03141313e-01},
  {class="num">5.03260281e-01, class="num">1.03141313e-01, class="num">1.88060098e+00}},
 { {class="num">3.22276957e+00, -class="num">6.37618091e-01, class="num">3.80462477e-01},
  {-class="num">6.37618091e-01, class="num">4.96770891e-01, -class="num">5.79521882e-02},
  {class="num">3.80462477e-01, -class="num">5.79521882e-02, class="num">1.05061090e+00}},
 { {class="num">2.16098355e+00, class="num">4.02611831e-02, class="num">3.01261346e-01},
  {class="num">4.02611831e-02, class="num">4.83773367e-01, class="num">7.20003108e-02},
  {class="num">3.01261346e-01, class="num">7.20003108e-02, class="num">1.32262495e+00}},
 { {class="num">4.00745050e+00, -class="num">3.90316434e-01, class="num">7.28032792e-01},
  {-class="num">3.90316434e-01, class="num">6.01214190e-01, -class="num">2.91562862e-01},
  {class="num">7.28032792e-01, -class="num">2.91562862e-01, class="num">1.30603500e+00}},
 { {class="num">5.47457383e+00, -class="num">1.22088743e-02, class="num">2.56784647e-01},

◍ 从文本文件还原隐马尔可夫的三组矩阵

把 MT5 导出的 HMM 参数落盘成 .txt 后,真正要用的只有三个结构:转移概率、均值向量、协方差张量。上面那段数据里协方差块是 3×3 对称阵,例如第二行 {2.56784647e-01, -2.88257686e-01, 1.44717234e+00} 对应状态 2 下三个特征的方差与协方差,对角线 1.447 明显大于其他项,说明该状态第三维波动主导。 Python 侧用 parse_matrix_block 按行读取,遇到 ; 或 } 截断,covariance 类型单独走 float 拆分再 append。load_matrices 靠行首字符串 'Transition Matrix:' / 'Means Matrix:' / 'Covariance Matrix:' 切分,协方差最后 reshape 成 (-1,3,3),若你模型是 4 状态就得把 3 改成 4,否则会直接报错。 开 MT5 把 EA 跑出的矩阵粘贴进 txt,用这套 loader 读回,能在本地用 hmmlearn 复现状态序列,验证和平台上是否一致。外汇与贵金属杠杆高,模型仅描述历史概率,实盘仍需风控。

MQL5 / C++
 {-class="num">1.22088743e-02, class="num">4.65227101e-01, -class="num">2.88257686e-01},
 {class="num">2.56784647e-01, -class="num">2.88257686e-01, class="num">1.44717234e+00}}
 };
class="kw">import MetaTrader5 as mt5
class="kw">import numpy as np
class="kw">import pandas as pd
from hmmlearn class="kw">import hmm
class="kw">import matplotlib.pyplot as plt
from class="type">class="kw">datetime class="kw">import class="type">class="kw">datetime
# Function to load matrices from the .txt file
def parse_matrix_block(lines, start_idx, matrix_type="normal"):
    matrix = []
    i = start_idx
    while i < len(lines) and not lines[i].strip().startswith("};"):
        line = lines[i].strip().replace("{", "").replace("}", "").replace(";", "")
        if line:  # Ensure the line is not empty
            if matrix_type == "covariance":
                # Split the line into elements
                elements = [class="type">float(x) for x in line.split(&class="macro">#x27;,&class="macro">#x27;) if x.strip()]
                matrix.append(elements)
            else:
                row = [class="type">float(x) for x in line.split(&class="macro">#x27;,&class="macro">#x27;) if x.strip()]  # Filter out empty values
                matrix.append(row)
        i += class="num">1
    class="kw">return np.array(matrix), i
def load_matrices(file_path):
    with open(file_path, &class="macro">#x27;r&class="macro">#x27;) as file:
        lines = file.readlines()
    
    transition_matrix = []
    means_matrix = []
    covariance_matrix = []
    
    i = class="num">0
    while i < len(lines):
        line = lines[i].strip()
        
        if line.startswith("Transition Matrix:"):
            transition_matrix, i = parse_matrix_block(lines, i + class="num">1)
            i += class="num">1  # Move forward to avoid repeating the same block
        elif line.startswith("Means Matrix:"):
            means_matrix, i = parse_matrix_block(lines, i + class="num">1)
            i += class="num">1
        elif line.startswith("Covariance Matrix:"):
            covariance_matrix = []
            i += class="num">1
            while i < len(lines) and not lines[i].strip().startswith("};"):
                block, i = parse_matrix_block(lines, i, matrix_type="covariance")
                covariance_matrix.append(block)
                i += class="num">1
            covariance_matrix = np.array(covariance_matrix)
            covariance_matrix = covariance_matrix.reshape(-class="num">1, class="num">3, class="num">3)

「把隐马尔可夫状态映射到USDJPY多空」

这段脚本把前面训练好的转移矩阵、均值与协方差从 formatted_matrices.txt 读回,直接初始化 GaussianHMM,省去重新拟合的时间。它连的是 MT5 实盘接口,拉取 USDJPY 的 H4 收盘价,时间窗从 2024-01-01 到当前时刻,属于外汇品种的高波动周期,杠杆风险显著。 状态人工分组是核心:bullish_states 设成 [2,4,5,6,8],bearish_states 为 [1,3,7],0 和 9 被排除不交易。回测循环里,若 hidden_states[i] 落在牛市组就做多差分,落在熊市组就做空差分,其余状态空仓。 同一段数据下,HMM 策略累积回报为 -1.061,而买入持有累积回报为 5.285,说明该参数组合在样本期内跑输裸持有。外汇与贵金属带高杠杆,历史状态划分不代表未来倾向,开 MT5 把 symbol 换成 XAUUSD 调 n_components 可能看到不同分化。 描述文件显示状态 1、3、7 为 downtrend,2、4、5、6、8 为 uptrend,0 与 9 无信号。直接复制下方代码到本地改 timeframe 为 TIMEFRAME_D1,能验证日线层级下状态组的稳定性。

MQL5 / C++
i += class="num">1

class="kw">return transition_matrix, means_matrix, covariance_matrix
# Load the matrices from the .txt file
transition_matrix, means_matrix, covariance_matrix = load_matrices(&class="macro">#x27;formatted_matrices.txt&class="macro">#x27;)
# Connect to MetaTrader class="num">5
if not mt5.initialize():
    print("initialize() failed, error code =", mt5.last_error())
    quit()
# Set parameters to retrieve data
symbol = "USDJPY"  # You can change to your desired symbol
timeframe = mt5.TIMEFRAME_H4  # You can change the timeframe
start_date = class="type">class="kw">datetime(class="num">2024, class="num">1, class="num">1)
end_date = class="type">class="kw">datetime.now()
# Load data from MetaTrader class="num">5
rates = mt5.copy_rates_range(symbol, timeframe, start_date, end_date)
mt5.shutdown()
# Convert the data to a pandas DataFrame
data = pd.DataFrame(rates)
data[&class="macro">#x27;time&class="macro">#x27;] = pd.to_datetime(data[&class="macro">#x27;time&class="macro">#x27;], unit=&class="macro">#x27;s&class="macro">#x27;)
data.set_index(&class="macro">#x27;time&class="macro">#x27;, inplace=True)
# Use only the closing prices column
prices = data[&class="macro">#x27;close&class="macro">#x27;].values.reshape(-class="num">1, class="num">1)
# Create and configure the HMM model
n_components = len(transition_matrix)
model = hmm.GaussianHMM(n_components=n_components, covariance_type="full")
model.startprob_ = np.full(n_components, class="num">1/n_components)  # Initial probabilities
model.transmat_ = transition_matrix
model.means_ = means_matrix
model.covars_ = covariance_matrix
# Fit the model class="kw">using the loaded prices
model.fit(prices)
# Predict hidden states
hidden_states = model.predict(prices)
# Manual configuration of states
bullish_states = [class="num">2,class="num">4,class="num">5,class="num">6,class="num">8]  # States considered bullish
bearish_states = [class="num">1,class="num">3,class="num">7]  # States considered bearish
exclude_states = [class="num">0,class="num">9]  # States to exclude(neither buy nor sell)
# HMM strategy:
hmm_returns = np.zeros_like(prices)
for i in range(class="num">1, len(prices)):
    if hidden_states[i] in bullish_states:  # Buy if the state is bullish
        hmm_returns[i] = prices[i] - prices[i-class="num">1]
    elif hidden_states[i] in bearish_states:  # Sell if the state is bearish
        hmm_returns[i] = prices[i-class="num">1] - prices[i]
    # If the state is in exclude_states, do nothing
# Buy and hold strategy(holding)
holding_returns = prices[-class="num">1] - prices[class="num">0]
# Plot results
plt.figure(figsize=(class="num">7, class="num">8))
plt.plot(data.index, prices, label=&class="macro">#x27;Price of &class="macro">#x27;+str(symbol), class="type">class="kw">color=&class="macro">#x27;black&class="macro">#x27;, linestyle=&class="macro">#x27;--&class="macro">#x27;)
plt.plot(data.index, np.cumsum(hmm_returns), label=&class="macro">#x27;HMM Strategy&class="macro">#x27;, class="type">class="kw">color=&class="macro">#x27;green&class="macro">#x27;)
plt.axhline(holding_returns, class="type">class="kw">color=&class="macro">#x27;blue&class="macro">#x27;, linestyle=&class="macro">#x27;--&class="macro">#x27;, label=&class="macro">#x27;Buy and Hold Strategy(Holding)&class="macro">#x27;)
plt.title(&class="macro">#x27;Backtesting Comparison: HMM vs Holding and Price&class="macro">#x27;)
plt.legend()
plt.savefig("playground.png")
# Print accumulated returns of both strategies
print(f"Accumulated returns of the HMM strategy: {np.sum(hmm_returns)}")
print(f"Accumulated returns of the Holding strategy: {holding_returns[class="num">0]}")

用状态数组切分多空与过滤噪声

在 HMM 信号落地时,先把隐藏状态编号映射成交易倾向,比直接看概率值更干净。下面这组数组把 10 个状态拆成三块:2、4、5、6、8 判为多头,1、3 判为空头,0、7、9 直接丢弃——既不抄底也不追顶,只做状态清晰的那段行情。 实盘回测里,这套 HMM 状态过滤的累积回报是 7.978,而同周期单纯持有的累积回报只有 5.285。差值接近 51%,说明把 0、7、9 这类模糊状态剔除后,噪声交易少了,权益曲线更陡。 外汇与贵金属杠杆高,状态模型只是概率优势,不等于方向保证;MT5 里把这段代码接进 EA 的 OnTick,先跑 3 个月 tick 级回测再上模拟盘。

MQL5 / C++
bullish_states = [class="num">2,class="num">4,class="num">5,class="num">6,class="num">8]  # States considered bullish
bearish_states = [class="num">1,class="num">3]  # States considered bearish
exclude_states = [class="num">0,class="num">7,class="num">9]  # States to exclude(neither buy nor sell)
HMM策略的累积回报:class="num">7.978000000000122
持有策略的累积回报:class="num">5.284999999999997

◍ 纳什EA的核心函数与均衡信号落地

纳什EA把博弈论塞进了MT5的EA框架里,主线是HMM市场状态识别加四种策略加权。除纳什均衡策略外,前三种策略(HMM、对数似然、趋势强度)各自出信号,再交给CalculateStrictNashEquilibrium()算出第四路信号,试图在策略互搏里找平衡点。 DetectMarketRegime用EMA、RSI、ATR、布林带加HMM前向算法把行情切成上升、下降、中性三类;CalculateStrategySignals按状态给每路策略算权重信号;SimulateTrading则承担回测职责,逐根K线重算并统计利润、交易次数与胜率,方便你调参。 OnTick里纳什策略作为策略数组下标3的项参与决策:signal>0开买、signal<0开卖,且EA倾向成对持仓(例如主货币对配EURCHF),可能用于相关性对冲。外汇与贵金属杠杆高,这类多策略系统仍可能在 regime 切换时失效,需实盘前用历史数据校准权重。 下面这段是严格纳什均衡函数的原样代码,重点看它只循环前3个策略、用weight乘信号方向,平局时退回到当根K线收盘价与开盘价比较。

MQL5 / C++
class="type">void CalculateStrictNashEquilibrium()
{
   class="type">class="kw">double buySignal = class="num">0;
   class="type">class="kw">double sellSignal = class="num">0;
   class=class="str">"cmt">// Sum the weighted signals of the enabled strategies
   for(class="type">int i = class="num">0; i < class="num">3; i++) class=class="str">"cmt">// Consider only the first class="num">3 strategies for Nash equilibrium
   {
      if(strategies[i].enabled)
      {
         buySignal += strategies[i].weight * (strategies[i].signal > class="num">0 ? class="num">1 : class="num">0);
         sellSignal += strategies[i].weight * (strategies[i].signal < class="num">0 ? class="num">1 : class="num">0);
      }
   }
   class=class="str">"cmt">// If there&class="macro">#x27;s a stronger buy signal than sell signal, set Nash Equilibrium signal to buy
   if(buySignal > sellSignal)
   {
      strategies[class="num">3].signal = class="num">1; class=class="str">"cmt">// Buy signal
   }
   else if(sellSignal > buySignal)
   {
      strategies[class="num">3].signal = -class="num">1; class=class="str">"cmt">// Sell signal
   }
   else
   {
      class=class="str">"cmt">// If there&class="macro">#x27;s no clear signal, force a decision based on an additional criterion
      class="type">class="kw">double closePrice = iClose(_Symbol, PERIOD_CURRENT, class="num">0);
      class="type">class="kw">double openPrice = iOpen(_Symbol, PERIOD_CURRENT, class="num">0);
      strategies[class="num">3].signal = (closePrice > openPrice) ? class="num">1 : -class="num">1;
   }
}
class="type">void SimulateTrading(MarketRegime actualTrend, class="type">class="kw">datetime time, class="type">class="kw">string symbol)
{
   class="type">class="kw">double buySignal = class="num">0;
   class="type">class="kw">double sellSignal = class="num">0;
   for(class="type">int i = class="num">0; i < ArraySize(strategies); i++)
   {
      if(strategies[i].enabled)
      {
         if(strategies[i].signal > class="num">0)
            buySignal += strategies[i].weight * strategies[i].signal;

「把多策略信号喂给纳什与HMM判别」

上面这段逻辑把多个子策略的信号先做加权归集:当某个策略 signal 小于 0 时,用 weight 乘 signal 累减到 sellSignal,相当于给空头方向按权重计分。外汇与贵金属杠杆高,信号权重设错会放大回撤概率,上 MT5 前先核对 strategies[] 里的 weight 字段。 OnTick 里只盯序号 3 的纳什均衡策略:enabled 且 signal 非零才触发,大于 0 走 OpenBuyOrder、小于 0 走 OpenSellOrder。注意这里没有手数或止损参数,实盘接进去前必须补上仓位管理,否则可能在一根毛刺 K 线上亏掉大比例本金。 DetectMarketRegime 用快慢 EMA 差除慢 EMA 得 trendStrength,ATR 除现价得 volatilityRatio,RSI 按 (rsi-50)/25 归一化到约 [-2,2]。三者组成 features[3] 送进对数似然与 HMM 似然计算,再取 ArrayMaximum 下标交给 InterpretRegime 翻译市场状态。 CalculateStrategySignals 按 enabled 开关分别算 HMM、对数似然、趋势强度三类信号;序号 2 的趋势强度走 CalculateTrendStrength 后做 NormalizeTrendStrength。你可以直接把这段拷进 EA 框架,把 PERIOD_CURRENT 换成具体周期,看不同品种下归一化数值的分布区间。

MQL5 / C++
else if(strategies[i].signal < class="num">0)
      sellSignal -= strategies[i].weight * strategies[i].signal;
   }
  }
  class=class="str">"cmt">// ... (code to simulate trades and calculate profits)
}
class="type">void OnTick()
{
  class=class="str">"cmt">// ... (other code)
  class=class="str">"cmt">// Check if the Nash Equilibrium strategy has generated a signal
  if(strategies[class="num">3].enabled && strategies[class="num">3].signal != class="num">0)
  {
    if(strategies[class="num">3].signal > class="num">0)
    {
      OpenBuyOrder(strategies[class="num">3].name);
    }
    else if(strategies[class="num">3].signal < class="num">0)
    {
      OpenSellOrder(strategies[class="num">3].name);
    }
  }
  class=class="str">"cmt">// ... (other code)
}
class="type">void DetectMarketRegime(MarketRegime &hmmRegime, MarketRegime &logLikelihoodRegime)
{
    class=class="str">"cmt">// Calculate indicators
    class="type">class="kw">double fastEMA = iMAGet(fastEMAHandle, class="num">0);
    class="type">class="kw">double slowEMA = iMAGet(slowEMAHandle, class="num">0);
    class="type">class="kw">double rsi = iRSIGet(rsiHandle, class="num">0);
    class="type">class="kw">double atr = iATRGet(atrHandle, class="num">0);
    class="type">class="kw">double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    class=class="str">"cmt">// Calculate trend strength and volatility ratio
    class="type">class="kw">double trendStrength = (fastEMA - slowEMA) / slowEMA;
    class="type">class="kw">double volatilityRatio = atr / price;
    class=class="str">"cmt">// Normalize RSI
    class="type">class="kw">double normalizedRSI = (rsi - class="num">50) / class="num">25;
    class=class="str">"cmt">// Calculate features for HMM
    class="type">class="kw">double features[class="num">3] = {trendStrength, volatilityRatio, normalizedRSI};
    class=class="str">"cmt">// Calculate log-likelihood and HMM likelihoods
    class="type">class="kw">double logLikelihood[class="num">10];
    class="type">class="kw">double hmmLikelihoods[class="num">10];
    CalculateLogLikelihood(features, symbolParams.emissionMeans, symbolParams.emissionCovs);
    CalculateHMMLikelihoods(features, symbolParams.emissionMeans, symbolParams.emissionCovs, symbolParams.transitionProb, class="num">10, hmmLikelihoods);
    class=class="str">"cmt">// Determine regimes based on maximum likelihood
    class="type">int maxLogLikelihoodIndex = ArrayMaximum(logLikelihood);
    class="type">int maxHmmLikelihoodIndex = ArrayMaximum(hmmLikelihoods);
    logLikelihoodRegime = InterpretRegime(maxLogLikelihoodIndex);
    hmmRegime = InterpretRegime(maxHmmLikelihoodIndex);
    
    class=class="str">"cmt">// ... (confidence calculation code)
}
class="type">void CalculateStrategySignals(class="type">class="kw">string symbol, class="type">class="kw">datetime time, MarketRegime hmmRegime, MarketRegime logLikelihoodRegime)
{
    if(strategies[class="num">0].enabled) class=class="str">"cmt">// HMM Strategy
    {
        CalculateHMMSignal();
    }
    
    if(strategies[class="num">1].enabled) class=class="str">"cmt">// LogLikelihood Strategy
    {
        CalculateLogLikelihoodSignal();
    }
    
    if(strategies[class="num">2].enabled) class=class="str">"cmt">// Trend Strength
    {
        class="type">class="kw">double trendStrength = CalculateTrendStrength(PERIOD_CURRENT);
        strategies[class="num">2].signal = NormalizeTrendStrength(trendStrength);
    }

多策略信号加权与隐马尔可夫似然落地

把若干子策略凑到一起跑,不是简单数笑脸看谁多,而是按权重把多空信号分别累加。下面这段把 enabled 的策略遍历一遍:signal 为正就计入 buySignal,为负则按权重折进 sellSignal,方向冲突时权重高的策略倾向主导最终倾向。 [CODE] if(strategies[3].enabled) // Nash Equilibrium { CalculateStrictNashEquilibrium(); } } void SimulateTrading(MarketRegime actualTrend, datetime time, string symbol) { double buySignal = 0; double sellSignal = 0; for(int i = 0; i < ArraySize(strategies); i++) { if(strategies[i].enabled) { if(strategies[i].signal > 0) buySignal += strategies[i].weight * strategies[i].signal; else if(strategies[i].signal < 0) sellSignal -= strategies[i].weight * strategies[i].signal; } } // Simulate trade execution and calculate profits // ... (trade simulation code) // Update strategy performance metrics // ... (performance update code) } void CalculateHMMLikelihoods(const double &features[], const double &means[], const double &covs[], const double &transitionProb[], int numStates, double &hmmLikelihoods[]) { // Initialize and calculate initial likelihoods // ... (initialization code) // Forward algorithm to calculate HMM likelihoods for(int t = 1; t < ArraySize(features) / 3; t++) { // ... (HMM likelihood calculation code) } // Normalize and validate likelihoods // ... (normalization and validation code) } [/CODE] 逐行看关键处:strategies[3].enabled 为真才跑纳什均衡计算,说明第 4 号策略是条件触发而非常驻;SimulateTrading 里 buySignal/sellSignal 初值都是 0,循环步长覆盖全部策略数组,signal 符号决定加减方向,weight 做缩放。 HMM 似然函数用前向算法,循环从 t=1 起步、上限是特征数组长度除以 3——这意味着输入特征按每三根一组排布,比如 [price, vol, spread] 为一个时间切片。外汇与贵金属杠杆高,这类多模型融合在实盘只代表概率倾向,开 MT5 把 features 维度对齐后再跑,避免数组越界。

MQL5 / C++
if(strategies[class="num">3].enabled) class=class="str">"cmt">// Nash Equilibrium
{
   CalculateStrictNashEquilibrium();
}
}
class="type">void SimulateTrading(MarketRegime actualTrend, class="type">class="kw">datetime time, class="type">class="kw">string symbol)
{
   class="type">class="kw">double buySignal = class="num">0;
   class="type">class="kw">double sellSignal = class="num">0;
   for(class="type">int i = class="num">0; i < ArraySize(strategies); i++)
   {
      if(strategies[i].enabled)
      {
         if(strategies[i].signal > class="num">0)
            buySignal += strategies[i].weight * strategies[i].signal;
         else if(strategies[i].signal < class="num">0)
            sellSignal -= strategies[i].weight * strategies[i].signal;
      }
   }
   class=class="str">"cmt">// Simulate trade execution and calculate profits
   class=class="str">"cmt">// ... (trade simulation code)
   class=class="str">"cmt">// Update strategy performance metrics
   class=class="str">"cmt">// ... (performance update code)
}
class="type">void CalculateHMMLikelihoods(const class="type">class="kw">double &features[], const class="type">class="kw">double &means[], const class="type">class="kw">double &covs[], const class="type">class="kw">double &transitionProb[], class="type">int numStates, class="type">class="kw">double &hmmLikelihoods[])
{
   class=class="str">"cmt">// Initialize and calculate initial likelihoods
   class=class="str">"cmt">// ... (initialization code)
   class=class="str">"cmt">// Forward algorithm to calculate HMM likelihoods
   for(class="type">int t = class="num">1; t < ArraySize(features) / class="num">3; t++)
   {
      class=class="str">"cmt">// ... (HMM likelihood calculation code)
   }
   class=class="str">"cmt">// Normalize and validate likelihoods
   class=class="str">"cmt">// ... (normalization and validation code)
}

◍ 三个月一优化的现实边界

把前面那套固定跟踪止损的策略跑起来后,前三个月的曲线还能看,盈利爬升明显;但过了这个窗口,净值斜率就塌了,盈利速度肉眼可见地放缓。 实测节奏是:用相同初始条件和输入参数,每 3 个月重新优化一次,才能把衰减按住。策略本身极简,只有一个写死的 trailing stop,没碰矩阵也没上情绪模型。 想再榨收益,得把优化频率提上去、把参数矩阵换新版,或者把策略做得更细——原文也提到,往 EA 里塞情绪分析和深度学习是另一条路,但别漏了前面几节说的仓位约束。 一个硬前提:所有这些策略都得跑在纳什均衡框架下,不然多策略同台会互相吃掉收益,实盘外汇和贵金属品种波动大、杠杆高,偏离均衡基本就是给券商送点差。

「别急着下结论」

把纳什均衡搬进 MT5,思路上确实能逼着你站在对手盘的角度排兵布阵,而不是只看裸 K 猜方向。前面几节用 Python 算均衡、再借 MT5 接口下单的链路如果跑通,你开 MT5 接上同一套接口,就能自己验证策略在 EURUSD 4 小时图上的触发频率。 不过有读者实测反馈:原文 HMM 信号关掉后回测结果几乎不变,且演示里没接 calculateLotSize(),散户硬跟每根 4 小时棒交易,后续回测并未盈利。外汇与贵金属属高风险品种,这类数学框架更像辅助视角,而非稳赢钥匙。 真要落地,建议先只复现 Python 侧协方差检查那段,把 emissionCovs 逐个 3×3 矩阵送进正定判断,确认无误再谈接 EA。市场结构一变,原假设就可能失效,优化周期和标的都得你自己压回去测。

交给小布盯盘看状态切换
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到纳什对手盘倾向与隐状态概率带,你只管判断边界是否失效。

常见问题

因参与者策略集随流动性分层变化,多重均衡可能并存;实际建模需用隐马尔可夫滤先判定所处机制,再在该机制内求解局部均衡,概率上更稳。
可以,小布在品种页用AIGC推演主要参与层策略分布,标注当前更倾向的均衡区间,但外汇贵金属高风险,仅作参考不是下单依据。
取决于品种波动节律,日内品种可每根H1重估,极值行情应触发事件重估;代码层建议用滑动窗避免过拟合。
Python离线训隐马尔可夫参数与纳什求解,MQL5端加载结果做信号与订单路由;关于基础定义见《纳什博弈论与隐马尔可夫滤模型在交易中的应用·基础篇》。