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

纳什博弈论与隐马尔可夫滤模型在交易中的应用·进阶篇

(2/3)·从纳什均衡公式到隐马尔可夫状态滤,少有人把这两套数学工具有机接进 MQL5 实战链路

新手友好 第 2/3 篇
很多交易者把报价波动当成纯随机噪声,忽略了对手盘策略互相牵制的均衡点。隐马尔可夫滤模型能剥开可见价格,反推背后不可见的行情状态。先把这两层数学骨架搭清楚,后面写 EA 才不会空中楼阁。

◍ 用高斯隐马尔可夫集成平均状态出信号

这段 Python 训练逻辑把 10 状态高斯 HMM 跑了多轮交叉验证,每轮用 20% 样本做测试集(random_state=i 控制可复现),n_iter=10000 且 tol=1e-6 保证收敛精度,min_covar=1e-3 防止协方差矩阵退化。 每轮 fit 完把转移矩阵、均值、协方差存进三维数组,再用 model.predict 对全量特征打状态标签;状态序号为偶数给 +1 多单信号、奇数给 -1 空单信号,信号滞后一期乘收益得策略收益。 最后对所有轮次的矩阵按轴求平均,得到 average_transition_matrix 等稳定参数,并把平均状态四舍五入作为 df['average_state']。用 (1+returns).cumprod() 画出市场与策略净值曲线,存成 average_strategy_returns_XXX.png。 外汇与贵金属杠杆高,HMM 平均信号仅代表历史样本的统计倾向,实盘前务必在 MT5 用对应品种复算转移矩阵并做样本外验证。

MQL5 / C++
model = hmm.GaussianHMM(n_components=class="num">10, covariance_type="full", n_iter=class="num">10000, tol=class="num">1e-6, min_covar=class="num">1e-3)
X_train, X_test = train_test_split(scaled_features, test_size=class="num">0.2, random_state=i)
model.fit(X_train)
# Save the transition matrix, emission means, and covariances
transition_matrices[:, :, i] = model.transmat_
means_matrices[i, :, :] = model.means_
covariance_matrices[i, :, :, :] = model.covars_
# State prediction
states = model.predict(scaled_features)
state_predictions[:, i] = states
# Generate signals and calculate strategy returns for this model
df[&class="macro">#x27;state&class="macro">#x27;] = states
df[&class="macro">#x27;signal&class="macro">#x27;] = class="num">0
for j in range(class="num">10):
    df.loc[df[&class="macro">#x27;state&class="macro">#x27;] == j, &class="macro">#x27;signal&class="macro">#x27;] = class="num">1 if j % class="num">2 == class="num">0 else -class="num">1
df[&class="macro">#x27;strategy_returns&class="macro">#x27;] = df[&class="macro">#x27;returns&class="macro">#x27;] * df[&class="macro">#x27;signal&class="macro">#x27;].shift(class="num">1)
strategy_returns[:, i] = df[&class="macro">#x27;strategy_returns&class="macro">#x27;].values
# Average of matrices
average_transition_matrix = transition_matrices.mean(axis=class="num">2)
average_means_matrix = means_matrices.mean(axis=class="num">0)
average_covariance_matrix = covariance_matrices.mean(axis=class="num">0)
# Save the average matrices in the output file in appropriate format
print("Average Transition Matrix:")
for i, row in enumerate(average_transition_matrix):
    for j, val in enumerate(row):
        print(f"average_transition_matrix[{i}][{j}] = {val:.8f};")
print("\nAverage Means Matrix:")
for i, row in enumerate(average_means_matrix):
    for j, val in enumerate(row):
        print(f"average_means_matrix[{i}][{j}] = {val:.8f};")
print("\nAverage Covariance Matrix:")
for i in range(class="num">10):  # For each state
    for j in range(class="num">3):  # For each row of the covariance matrix
        for k in range(class="num">3):  # For each column of the covariance matrix
            print(f"average_covariance_matrix[{i}][{j}][{k}] = {average_covariance_matrix[i, j, k]:.8e};")
# Average of state predictions and strategy returns
average_states = np.round(state_predictions.mean(axis=class="num">1)).astype(class="type">int)
average_strategy_returns = strategy_returns.mean(axis=class="num">1)
# Store the average results in the original dataframe
df[&class="macro">#x27;average_state&class="macro">#x27;] = average_states
df[&class="macro">#x27;average_strategy_returns&class="macro">#x27;] = average_strategy_returns
# Calculate cumulative returns class="kw">using the average strategy
df[&class="macro">#x27;cumulative_market_returns&class="macro">#x27;] = (class="num">1 + df[&class="macro">#x27;returns&class="macro">#x27;]).cumprod()
df[&class="macro">#x27;cumulative_strategy_returns&class="macro">#x27;] = (class="num">1 + df[&class="macro">#x27;average_strategy_returns&class="macro">#x27;]).cumprod()
# Plot cumulative returns(training)
plt.figure(figsize=(class="num">7, class="num">6))
plt.plot(df.index, df[&class="macro">#x27;cumulative_market_returns&class="macro">#x27;], label=&class="macro">#x27;Market Returns&class="macro">#x27;)
plt.plot(df.index, df[&class="macro">#x27;cumulative_strategy_returns&class="macro">#x27;], label=&class="macro">#x27;Strategy Returns(Average)&class="macro">#x27;)
plt.title(&class="macro">#x27;Cumulative Returns with Average Strategy&class="macro">#x27;)
plt.xlabel(&class="macro">#x27;Date&class="macro">#x27;)
plt.ylabel(&class="macro">#x27;Cumulative Returns&class="macro">#x27;)
plt.legend()
plt.grid(True)
plt.savefig(f&class="macro">#x27;average_strategy_returns_{symbol}.png&class="macro">#x27;)
plt.close()
# Additional plots for averages
fig, (ax1, ax2, ax3) = plt.subplots(class="num">3, class="num">1, figsize=(class="num">12, class="num">15), sharex=True)
# Plot closing price and average HMM states

「把隐马尔可夫状态映射成收益图」

这段脚本把训练好的 HMM 平均状态直接画到价格序列上:用 viridis 色阶给收盘价散点上色,颜色越亮代表模型判定的平均状态编号越高,左轴图同时叠了收盘线与状态散点,肉眼能扫出哪些价位区间对应哪种隐状态。 下方三幅子图分别给出每日收益(蓝为市场、红为策略平均,透明度 0.5)、累计收益曲线,以及各平均状态在历史样本里的收益求和——代码里写死 range(10),也就是默认拆 10 个隐状态,state_returns 把每个状态的 returns 加总,正负一眼可辨。 图存成 average_returns_{symbol}.png 与 average_bars_{symbol}.png,柱图还逐根标了 f'{height:.4f}' 的四位小数,并画了 y=0 红线做盈亏分界参考。 近期数据走同一套 scaler 再预测:df_recent 用训练集的 scaler.transform 而非 fit,避免未来函数;循环里每个 i 用不同 random_state 做 train_test_split 重训 GaussianHMM(n_components=10, tol=1e-4),把 recent_states 填回 df_recent['state'],后续按 10 个状态编号生成 signal。外汇与贵金属行情受杠杆与跳空影响,这类状态映射仅作概率参考,实盘前务必在 MT5 用历史品种复跑核对。

MQL5 / C++
ax1.plot(df.index, df[&class="macro">#x27;close&class="macro">#x27;], label=&class="macro">#x27;Closing Price&class="macro">#x27;)
scatter = ax1.scatter(df.index, df[&class="macro">#x27;close&class="macro">#x27;], c=df[&class="macro">#x27;average_state&class="macro">#x27;], cmap=&class="macro">#x27;viridis&class="macro">#x27;, s=class="num">30, label=&class="macro">#x27;Average HMM States&class="macro">#x27;)
ax1.set_ylabel(&class="macro">#x27;Price&class="macro">#x27;)
ax1.set_title(&class="macro">#x27;Closing Price and Average HMM States&class="macro">#x27;)
ax1.legend(loc=&class="macro">#x27;upper left&class="macro">#x27;)
# Add class="type">class="kw">color bar for states
cbar = plt.colorbar(scatter, ax=ax1)
cbar.set_label(&class="macro">#x27;Average HMM State&class="macro">#x27;)
# Plot returns
ax2.bar(df.index, df[&class="macro">#x27;returns&class="macro">#x27;], label=&class="macro">#x27;Market Returns&class="macro">#x27;, alpha=class="num">0.5, class="type">class="kw">color=&class="macro">#x27;blue&class="macro">#x27;)
ax2.bar(df.index, df[&class="macro">#x27;average_strategy_returns&class="macro">#x27;], label=&class="macro">#x27;Average Strategy Returns&class="macro">#x27;, alpha=class="num">0.5, class="type">class="kw">color=&class="macro">#x27;red&class="macro">#x27;)
ax2.set_ylabel(&class="macro">#x27;Return&class="macro">#x27;)
ax2.set_title(&class="macro">#x27;Daily Returns&class="macro">#x27;)
ax2.legend(loc=&class="macro">#x27;upper left&class="macro">#x27;)
# Plot cumulative returns
ax3.plot(df.index, df[&class="macro">#x27;cumulative_market_returns&class="macro">#x27;], label=&class="macro">#x27;Cumulative Market Returns&class="macro">#x27;)
ax3.plot(df.index, df[&class="macro">#x27;cumulative_strategy_returns&class="macro">#x27;], label=&class="macro">#x27;Cumulative Average Strategy Returns&class="macro">#x27;)
ax3.set_ylabel(&class="macro">#x27;Cumulative Return&class="macro">#x27;)
ax3.set_title(&class="macro">#x27;Cumulative Returns&class="macro">#x27;)
ax3.legend(loc=&class="macro">#x27;upper left&class="macro">#x27;)
# Adjust layout
plt.tight_layout()
plt.xlabel(&class="macro">#x27;Date&class="macro">#x27;)
# Save figure
plt.savefig(f&class="macro">#x27;average_returns_{symbol}.png&class="macro">#x27;)
plt.close()
# Calculate cumulative returns for each average state
state_returns = {}
for state in range(class="num">10):  # Assuming class="num">10 states
    state_returns[state] = df[df[&class="macro">#x27;average_state&class="macro">#x27;] == state][&class="macro">#x27;returns&class="macro">#x27;].sum()
# Create lists for states and their cumulative returns
states = list(state_returns.keys())
returns = list(state_returns.values())
# Create bar chart
plt.figure(figsize=(class="num">7, class="num">6))
bars = plt.bar(states, returns)
# Customize chart
plt.title(&class="macro">#x27;Cumulative Returns by Average HMM State&class="macro">#x27;, fontsize=class="num">7)
plt.xlabel(&class="macro">#x27;State&class="macro">#x27;, fontsize=class="num">7)
plt.ylabel(&class="macro">#x27;Cumulative Return&class="macro">#x27;, fontsize=class="num">7)
plt.xticks(states)
# Add value labels above each bar
for bar in bars:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/class="num">2., height,
             f&class="macro">#x27;{height:.4f}&class="macro">#x27;,
             ha=&class="macro">#x27;center&class="macro">#x27;, va=&class="macro">#x27;bottom&class="macro">#x27;)
# Add horizontal line at y=class="num">0 for reference
plt.axhline(y=class="num">0, class="type">class="kw">color=&class="macro">#x27;r&class="macro">#x27;, linestyle=&class="macro">#x27;-&class="macro">#x27;, linewidth=class="num">0.5)
# Adjust layout and save chart
plt.tight_layout()
plt.savefig(f&class="macro">#x27;average_bars_{symbol}.png&class="macro">#x27;)
plt.close()
# Get recent data to test the model
df_recent = get_mt5_data(symbol, timeframe, end_date, current_date)
df_recent = calculate_features(df_recent)
# Apply the same scaler to recent data
scaled_recent_features = scaler.transform(df_recent[[&class="macro">#x27;returns&class="macro">#x27;, &class="macro">#x27;volatility&class="macro">#x27;, &class="macro">#x27;trend&class="macro">#x27;]].values)
# Lists to store the results of each model for recent data
recent_state_predictions = np.zeros((scaled_recent_features.shape[class="num">0], n_models))
recent_strategy_returns = np.zeros((scaled_recent_features.shape[class="num">0], n_models))
# Apply the trained model to recent data
for i in range(n_models):
    model = hmm.GaussianHMM(n_components=class="num">10, covariance_type="full", n_iter=class="num">10000, tol=class="num">1e-4, min_covar=class="num">1e-3)
    X_train, X_test = train_test_split(scaled_features, test_size=class="num">0.2, random_state=i)
    model.fit(X_train)
    
    recent_states = model.predict(scaled_recent_features)
    recent_state_predictions[:, i] = recent_states
    df_recent[&class="macro">#x27;state&class="macro">#x27;] = recent_states
    df_recent[&class="macro">#x27;signal&class="macro">#x27;] = class="num">0
    for j in range(class="num">10):

隐状态标签与平均转移矩阵的实际落地

把隐藏马尔可夫跑出来的 10 个状态映射到可读标签,是回测之后最该补的一步。代码里用 state_returns[state] 是否大于 0 来判定该状态倾向「Uptrend」还是「Downtrend」,没出现的状态直接标成 Not present,这样你打开终端不会对着 State 7 发懵。 近期样本的平均策略收益是这样攒出来的:recent_strategy_returns 按列(不同模型或不同 seed)取 mean,得到 average_recent_strategy_returns,再用 (1 + average_strategy_returns).cumprod() 画累计曲线。图存成 average_recent_strategy_returns_{symbol}.png,市场收益和策略收益叠在同一张 7×6 的图上,肉眼能比出斜率差。 转移矩阵给的是 10×10 的平均结果,例如状态 0 留在自身的概率仅 0.1574,跳去状态 2 的概率 0.1679 反而最高;状态 9 跳去状态 3 为 0.1360、去状态 4 为 0.1295。外汇与贵金属属高风险品种,这些概率只描述历史样本内的状态游走倾向,换周期可能漂移。 取 H4 级别、2020-01-01 到 2023-12-31 的行情做上述统计,跑完记得 mt5.shutdown() 释放终端连接,否则下一个脚本容易卡在登录态。

MQL5 / C++
df_recent.loc[df_recent[&class="macro">#x27;state&class="macro">#x27;] == j, &class="macro">#x27;signal&class="macro">#x27;] = class="num">1 if j % class="num">2 == class="num">0 else -class="num">1
df_recent[&class="macro">#x27;strategy_returns&class="macro">#x27;] = df_recent[&class="macro">#x27;returns&class="macro">#x27;] * df_recent[&class="macro">#x27;signal&class="macro">#x27;].shift(class="num">1)
recent_strategy_returns[:, i] = df_recent[&class="macro">#x27;strategy_returns&class="macro">#x27;].values
# Average of state predictions and strategy returns for recent data
average_recent_states = np.round(recent_state_predictions.mean(axis=class="num">1)).astype(class="type">int)
average_recent_strategy_returns = recent_strategy_returns.mean(axis=class="num">1)
# Store the average results in the recent dataframe
df_recent[&class="macro">#x27;average_state&class="macro">#x27;] = average_recent_states
df_recent[&class="macro">#x27;average_strategy_returns&class="macro">#x27;] = average_recent_strategy_returns
# Calculate cumulative returns class="kw">using the average strategy on recent data
df_recent[&class="macro">#x27;cumulative_market_returns&class="macro">#x27;] = (class="num">1 + df_recent[&class="macro">#x27;returns&class="macro">#x27;]).cumprod()
df_recent[&class="macro">#x27;cumulative_strategy_returns&class="macro">#x27;] = (class="num">1 + df_recent[&class="macro">#x27;average_strategy_returns&class="macro">#x27;]).cumprod()
# Plot cumulative returns(recent test)
plt.figure(figsize=(class="num">7, class="num">6))
plt.plot(df_recent.index, df_recent[&class="macro">#x27;cumulative_market_returns&class="macro">#x27;], label=&class="macro">#x27;Market Returns&class="macro">#x27;)
plt.plot(df_recent.index, df_recent[&class="macro">#x27;cumulative_strategy_returns&class="macro">#x27;], label=&class="macro">#x27;Strategy Returns(Average)&class="macro">#x27;)
plt.title(&class="macro">#x27;Cumulative Returns with Average Strategy(Recent Data)&class="macro">#x27;)
plt.xlabel(&class="macro">#x27;Date&class="macro">#x27;)
plt.ylabel(&class="macro">#x27;Cumulative Returns&class="macro">#x27;)
plt.legend()
plt.grid(True)
plt.savefig(f&class="macro">#x27;average_recent_strategy_returns_{symbol}.png&class="macro">#x27;)
plt.close()
# Close MetaTrader class="num">5
mt5.shutdown()
# Assign descriptive names to the hidden states
state_labels = {}
for state in range(class="num">10):  # Assuming class="num">10 states
    if state in df[&class="macro">#x27;average_state&class="macro">#x27;].unique():
        label = f"State {state}: "  # You can customize this description based on your observations
        if state_returns[state] > class="num">0:
            label += "Uptrend"
        else:
            label += "Downtrend"
        state_labels[state] = label
    else:
        state_labels[state] = f"State {state}: Not present"
# Print the states and their descriptive labels
print("\nDescription of Hidden States:")
for state, label in state_labels.items():
    print(f"{label} (State ID: {state})")
# Close MetaTrader class="num">5 connection
mt5.shutdown()
# Finally, close the output file
sys.stdout.close()
sys.stdout = sys.__stdout__
timeframe = mt5.TIMEFRAME_H4
start_date = "class="num">2020-class="num">01-class="num">01"
end_date = "class="num">2023-class="num">12-class="num">31"
average_transition_matrix[class="num">0][class="num">0] = class="num">0.15741321;
average_transition_matrix[class="num">0][class="num">1] = class="num">0.07086962;
average_transition_matrix[class="num">0][class="num">2] = class="num">0.16785905;
average_transition_matrix[class="num">0][class="num">3] = class="num">0.08792403;
average_transition_matrix[class="num">0][class="num">4] = class="num">0.11101073;
average_transition_matrix[class="num">0][class="num">5] = class="num">0.05415263;
average_transition_matrix[class="num">0][class="num">6] = class="num">0.08019415;
average_transition_matrix[class="num">9][class="num">3] = class="num">0.13599698;
average_transition_matrix[class="num">9][class="num">4] = class="num">0.12947508;
average_transition_matrix[class="num">9][class="num">5] = class="num">0.06385211;
average_transition_matrix[class="num">9][class="num">6] = class="num">0.09042617;

◍ 隐状态参数矩阵的实际读数

模型跑完之后落地的不是图表,而是三组冷冰冰的数组:转移概率、均值、协方差。以第 9 号隐状态为例,转移到自身的概率是 0.04559230,转到第 7 状态为 0.16088280,转到第 8 状态为 0.06588065——说明该状态具备一定持续性,但向外跳转的倾向更散。 均值矩阵里,第 9 状态对三个特征维度的中心读数分别是 -0.16057267、1.17106076、0.18531821;对比第 8 状态的 -0.38270747、0.86916742、-0.58792329,能看出两者虽同属极端波动区,但方向权重并不一致。外汇与贵金属杠杆高,这类读数只描述历史分布,不预示下一根 K 线。 协方差矩阵第 9 状态对角项给出 5.47457383、0.46522710、1.44717234,非对角项里 [0][2] 与 [2][0] 都是 0.25678465,[1][2] 为 -0.28825769。正负交叉说明特征间既有同向放大也有互斥,直接拿来当开仓信号会过拟合。 状态 0 被标为 Not present(不存在态),状态 1 是 Downtrend(下跌趋势态)。在 MT5 里把这两类 ID 打印出来,对照 EURUSD 的 H1 分段,能验证标签和实际波段是否对得上。

MQL5 / C++
average_transition_matrix[class="num">9][class="num">7] = class="num">0.16088280;
average_transition_matrix[class="num">9][class="num">8] = class="num">0.06588065;
average_transition_matrix[class="num">9][class="num">9] = class="num">0.04559230;
average_means_matrix[class="num">9][class="num">0] = -class="num">0.16057267;
average_means_matrix[class="num">9][class="num">1] = class="num">1.17106076;
average_means_matrix[class="num">9][class="num">2] = class="num">0.18531821;
average_covariance_matrix[class="num">9][class="num">0][class="num">0] = class="num">5.47457383;
average_covariance_matrix[class="num">9][class="num">1][class="num">2] = -class="num">0.28825769;

「状态机里的趋势片段与矩阵离线解析」

这套隐藏马尔可夫式的状态切分里,ID 2~8 构成了主行情脉络:2、4、5、6、8 被标为 Uptrend,3 与 7 是 Downtrend,9 则直接 Not present。也就是说在已观测样本里,上行状态占了 5/7,下行仅 2 段,状态 9 从未触发——拿去跑 EURUSD 这类高杠杆品种时,要清楚这种不对称本身就可能让反转概率被低估,外汇和贵金属杠杆风险极高。 上面的 Python 片段不是 MT5 终端里跑的,而是把专家顾问导出的矩阵文件离线扒出来重排格式用的。read_file 先判存在性再 try 读盘,避免路径写错直接崩;parse_matrix 用正则抓 名称[i][j]=数值 的二维赋值,parse_covariance_matrix 则多抓一层 k 变成三维协方差块。 format_matrix 的入口先判空返回 { };,否则按 key 排序拼换行。is_3d 为 True 时才走三层嵌套:先写 { ,再对 j 循环把每个 k 序列用 8 位科学计数法 :.8e 串成子数组。你可以在本地用这段把 EA 日志里的 average_covariance_matrix 重排,再贴回 MT5 做可视化验证。

MQL5 / C++
class="kw">import re
class="kw">import os
def read_file(filename):
    if not os.path.exists(filename):
        print(f"Error: The file {filename} does not exist.")
        class="kw">return None
    try:
        with open(filename, "r") as file:
            class="kw">return file.read()
    except Exception as e:
        print(f"Error reading the file: {str(e)}")
        class="kw">return None
def parse_matrix(file_content, matrix_name):
    pattern = rf"{matrix_name}\[(\d+)\]\[(\d+)\]\s*=\s*([-+]?(?:\d*\.\d+|\d+)(?:e[-+]?\d+)?)"
    matches = re.findall(pattern, file_content)
    matrix = {}
    for match in matches:
        i, j, value = class="type">int(match[class="num">0]), class="type">int(match[class="num">1]), class="type">float(match[class="num">2])
        if i not in matrix:
            matrix[i] = {}
        matrix[i][j] = value
    class="kw">return matrix
def parse_covariance_matrix(file_content):
    pattern = r"average_covariance_matrix\[(\d+)\]\[(\d+)\]\[(\d+)\]\s*=\s*([-+]?(?:\d*\.\d+|\d+)(?:e[-+]?\d+)?)"
    matches = re.findall(pattern, file_content)
    matrix = {}
    for match in matches:
        i, j, k, value = class="type">int(match[class="num">0]), class="type">int(match[class="num">1]), class="type">int(match[class="num">2]), class="type">float(match[class="num">3])
        if i not in matrix:
            matrix[i] = {}
        if j not in matrix[i]:
            matrix[i][j] = {}
        matrix[i][j][k] = value
    class="kw">return matrix
def format_matrix(matrix, is_3d=False):
    if not matrix:
        class="kw">return "{  };"
    
    formatted = "{\n"
    for i in sorted(matrix.keys()):
        if is_3d:
            formatted += "      {  "
            for j in sorted(matrix[i].keys()):
                formatted += "{" + ", ".join(f"{matrix[i][j][k]:.8e}" for k in sorted(matrix[i][j].keys())) + "}"
                if j < max(matrix[i].keys()):
                    formatted += ",\n        "
            formatted += "}"
        else:

把隐藏马尔可夫矩阵落盘成可读文本

上面这段 Python 脚本干的事很直接:读取 USDJPY_output.txt 里由 MT5 导出的平均转移矩阵、均值矩阵和协方差矩阵,重新排版后写进 formatted_matrices.txt。它先打印输入文件字节数和前 200 字符,方便你确认没读错文件。 parse_matrix 与 parse_covariance_matrix 分别抽取三类矩阵,随后 format_matrix 按 8 位小数格式化,协方差矩阵因是三维结构多传一个 is_3d=True 参数。脚本跑完会在控制台输出各矩阵元素数量,并把输出文件前 20 行回显出来供肉眼校验。 从实际落盘结果看,转移矩阵首行十个状态概率分别为 0.15741321、0.07086962、0.16785905、0.08792403、0.11101073、0.05415263、0.08019415、0.12333382、0.09794255、0.04930020,总和逼近 1。外汇与贵金属属高风险品种,这类概率分布只反映历史样本特征,后续状态切换倾向需结合实时行情验证。 在 MT5 里跑完 HMM 测算后,用这套脚本转格式比手动抄表稳得多;改 input_filename 就能批次处理其他货币对输出。

MQL5 / C++
formatted += "          {" + ", ".join(f"{matrix[i][j]:.8f}" for j in sorted(matrix[i].keys())) + "}"
    if i < max(matrix.keys()):
        formatted += ","
    formatted += "\n"
formatted += "  };"
class="kw">return formatted
def main():
    input_filename = "USDJPY_output.txt"
    output_filename = "formatted_matrices.txt"
    content = read_file(input_filename)
    
    if content is None:
        class="kw">return
    print(f"Input file size: {len(content)} bytes")
    print("First class="num">200 characters of the file:")
    print(content[:class="num">200])
    transition_matrix = parse_matrix(content, "average_transition_matrix")
    means_matrix = parse_matrix(content, "average_means_matrix")
    covariance_matrix = parse_covariance_matrix(content)
    print(f"\nElements found in the transition matrix: {len(transition_matrix)}")
    print(f"Elements found in the means matrix: {len(means_matrix)}")
    print(f"Elements found in the covariance matrix: {len(covariance_matrix)}")
    output = "Transition Matrix:\n"
    output += format_matrix(transition_matrix)
    output += "\n\nMeans Matrix:\n"
    output += format_matrix(means_matrix)
    output += "\n\nCovariance Matrix:\n"
    output += format_matrix(covariance_matrix, is_3d=True)
    try:
        with open(output_filename, "w") as outfile:
            outfile.write(output)
        print(f"\nFormatted matrices saved in &class="macro">#x27;{output_filename}&class="macro">#x27;")
    except Exception as e:
        print(f"Error writing the output file: {str(e)}")
    print(f"\nFirst lines of the output file &class="macro">#x27;{output_filename}&class="macro">#x27;:")
    output_content = read_file(output_filename)
    if output_content:
        print("\n".join(output_content.split("\n")[:class="num">20]))  # Display the first class="num">20 lines
if __name__ == "__main__":
    main()
把均衡计算交给小布
小布盯盘的 AIGC 模块已内置纳什均衡与隐状态概率的预计算视图,打开对应品种页就能直接看到当前盘口所处的推断状态,你只管做决策。

常见问题

通常可抽象为散户动量盘、机构对冲盘与流动性提供方,三方在给定对方策略下无意单方面变招时即近均衡;外汇贵金属属高风险,该状态仅代表概率倾向非确定性。
实盘建议至少覆盖一个完整波段周期的样本,参数过拟合会令隐状态跳变失真,MQL5 中可用 CV 切分验证。
借助 MetaTrader 5 的 Python API 异步取数、本地算完回写全局变量,可以避免主线程阻塞影响 tick 响应。
可以,小布的品种页会把博弈参与方效用差画成带宽,落入阈值内即提示均衡倾向,但仍需你结合隐马尔可夫滤出的状态一起看。
前者定「谁在牌桌怎么出牌」的静态结构,后者管「牌局背后藏哪几种局」的动态推断,两者串起来才是一套可落地的识别链路。