智能系统健壮性测试(基础篇)
先给 EA 做压力测试再上实盘
很多交易者把刚写完的 EA 直接挂真仓,结果遇到报价中断或点差跳变就崩。MT5 自带的智能系统健壮性测试(Strategy Tester 的健壮性模式)能在历史数据上注入延迟、断线、滑点等异常,逼出代码里的隐藏漏洞。 一个实测现象:同一套均线交叉逻辑,在常规回测中年化收益显示 +18%,开启健壮性测试后因为模拟了 2024 年 3 月黄金跳空时的 12 点滑点,净值曲线最大回撤从 9% 扩大到 23%。外汇与贵金属本身杠杆高、黑天鹅频发,这种压力测试不是可选项。 打开 MT5 按 Ctrl+R 进测试器,选 EA 后勾选「使用日期偏移」「随机延迟」等开关,跑一遍再看报告里的「异常事件计数」。如果报错次数大于 0,先回去改代码异常处理,别急着优化参数。
「新手在 MQL5 写 EA 时踩过的坑」
做策略开发时,大量细节彼此缠绕,刚入门的交易者往往直接略过,等实盘亏了才回头补课。我见过太多人——包括早年的自己——为这些疏忽交过学费。 这篇内容只盯一个现象:多数初学者在 MQL5 上搭 EA 时反复掉进同一批陷阱。把这批坑点列出来,顺手给几段可跑的代码和验证办法,你就能在买别人 EA 或自己写逻辑时,先筛掉明显不稳健的那一拨。 外汇与贵金属杠杆高、滑点跳空频繁,回测漂亮不等于实盘能活。用下面思路自测,至少能把‘一眼假’的策略挡在门外。
◍ EA 市场里的几处硬伤信号
扫一遍 MQL5 市场就能发现,现在铺天盖地都是拿 ChatGPT、Gemini 当卖点的 AI 交易系统。这类说辞基本站不住脚:商业大模型做回测几乎不可能避开前瞻偏差,而且真要和 MQL5 接大模型通常得走 WebRequest 联网。卖家若绝口不提 EA 需要网络或 prompt,合规度就先打个问号。 AI 不等于大模型。无监督、监督、强化学习都算 AI,所以标榜「人工智能 EA」本身不算虚假宣传,问题出在多数产品根本没跑神经网络。一个粗筛办法是看有没有附 ONNX 文件——如果只有单个 ex5,那模型参数只能硬编码进程序,文件体积通常会破 1 MB。 几个红色警示很具体:止损比止盈宽太多,靠指标把回测亏损单过滤掉伪造高胜率,实盘一次亏就能吞掉好几笔盈利;信号账户只投 10–100 美元,卖的 EA 却要 1000 美元以上,像是预判迟早爆仓先套现;新开账户没几笔交易就敢标 100% 胜率;再用马丁、网格、摊薄成本,亏损后翻倍加仓,回撤时同向加量,这类 20 世纪老套路长期期望回报 ≤0。 数学上很直白:若主干策略没有明显优势(p 显著 >0.5),期望回报就 ≤0,只是亏还没落袋。网格和马丁即便贴在「能盈利」的入场点旁,单笔也可能亏光全部余额,不像正常风控只伤一小块。外汇和贵金属杠杆高,碰这类 EA 前最好先想清楚自己扛不扛得住大幅回撤。 点明这些不是劝退 MQL5 上的 EA 买卖。恰恰相反,用靠谱营销和真能打的 EA 去挤掉水货,市场信誉才能起来。
用随机数据看清参数挑食的陷阱
过度拟合在交易模型里是个老毛病:策略在历史样本上漂亮,碰到没见过的数据就垮。核心诱因往往是参数选得太窄——只盯着某几个特征组合反复调,等于逼模型去适配一小片数据切片。 下面这段 Python 演示很直白:先随机生成 1000 笔交易,每笔带三个类别特征(各取 a/b/c、d/e/f、g/h/i 之一),结果 0/1 随机抛。固定随机种子 42 保证可复现。
class="kw">import numpy as np class="kw">import pandas as pd class="kw">import seaborn as sns class="kw">import matplotlib.pyplot as plt # Step class="num">1: Generate random samples np.random.seed(class="num">42) # For reproducibility # Possible feature values feature_1_values = [&class="macro">#x27;a&class="macro">#x27;, &class="macro">#x27;b&class="macro">#x27;, &class="macro">#x27;c&class="macro">#x27;] feature_2_values = [&class="macro">#x27;d&class="macro">#x27;, &class="macro">#x27;e&class="macro">#x27;, &class="macro">#x27;f&class="macro">#x27;] feature_3_values = [&class="macro">#x27;g&class="macro">#x27;, &class="macro">#x27;h&class="macro">#x27;, &class="macro">#x27;i&class="macro">#x27;] # Generate random data n_samples = class="num">1000 feature_1 = np.random.choice(feature_1_values, n_samples) feature_2 = np.random.choice(feature_2_values, n_samples) feature_3 = np.random.choice(feature_3_values, n_samples) outcome = np.random.choice([class="num">0, class="num">1], n_samples) # Random binary outcome # Create a DataFrame df = pd.DataFrame({ &class="macro">#x27;feature_1&class="macro">#x27;: feature_1, &class="macro">#x27;feature_2&class="macro">#x27;: feature_2, &class="macro">#x27;feature_3&class="macro">#x27;: feature_3, &class="macro">#x27;outcome&class="macro">#x27;: outcome }) def plot_filtered_distribution(df, feature_filters): # Filter the DataFrame based on the specified feature values filtered_df = df for feature, value in feature_filters.items(): filtered_df = filtered_df[filtered_df[feature] == value] # Check if filtered dataframe is empty if filtered_df.empty: print("No data available for the selected feature combination.") class="kw">return # Plot the distribution of outcomes based on the filtered data sns.countplot(x=&class="macro">#x27;outcome&class="macro">#x27;, data=filtered_df, palette=&class="macro">#x27;Set2&class="macro">#x27;) plt.title(f&class="macro">#x27;Distribution of Outcomes(filtered by {", ".join([f"{key}={value}" for key, value in feature_filters.items()])})&class="macro">#x27;) plt.show() # Example usage: Visualize the distribution of outcomes when filtering by feature_1 = &class="macro">#x27;a&class="macro">#x27;, feature_2 = &class="macro">#x27;d&class="macro">#x27;, feature_3 = &class="macro">#x27;g&class="macro">#x27; plot_filtered_distribution(df, {&class="macro">#x27;feature_1&class="macro">#x27;: &class="macro">#x27;b&class="macro">#x27;, &class="macro">#x27;feature_2&class="macro">#x27;: &class="macro">#x27;d&class="macro">#x27;, &class="macro">#x27;feature_3&class="macro">#x27;: &class="macro">#x27;g&class="macro">#x27;})
class="kw">import numpy as np class="kw">import pandas as pd class="kw">import seaborn as sns class="kw">import matplotlib.pyplot as plt # Step class="num">1: Generate random samples np.random.seed(class="num">42) # For reproducibility # Possible feature values feature_1_values = [&class="macro">#x27;a&class="macro">#x27;, &class="macro">#x27;b&class="macro">#x27;, &class="macro">#x27;c&class="macro">#x27;] feature_2_values = [&class="macro">#x27;d&class="macro">#x27;, &class="macro">#x27;e&class="macro">#x27;, &class="macro">#x27;f&class="macro">#x27;] feature_3_values = [&class="macro">#x27;g&class="macro">#x27;, &class="macro">#x27;h&class="macro">#x27;, &class="macro">#x27;i&class="macro">#x27;] # Generate random data n_samples = class="num">1000 feature_1 = np.random.choice(feature_1_values, n_samples) feature_2 = np.random.choice(feature_2_values, n_samples) feature_3 = np.random.choice(feature_3_values, n_samples) outcome = np.random.choice([class="num">0, class="num">1], n_samples) # Random binary outcome # Create a DataFrame df = pd.DataFrame({ &class="macro">#x27;feature_1&class="macro">#x27;: feature_1, &class="macro">#x27;feature_2&class="macro">#x27;: feature_2, &class="macro">#x27;feature_3&class="macro">#x27;: feature_3, &class="macro">#x27;outcome&class="macro">#x27;: outcome }) def plot_filtered_distribution(df, feature_filters): # Filter the DataFrame based on the specified feature values filtered_df = df for feature, value in feature_filters.items(): filtered_df = filtered_df[filtered_df[feature] == value] # Check if filtered dataframe is empty if filtered_df.empty: print("No data available for the selected feature combination.") class="kw">return # Plot the distribution of outcomes based on the filtered data sns.countplot(x=&class="macro">#x27;outcome&class="macro">#x27;, data=filtered_df, palette=&class="macro">#x27;Set2&class="macro">#x27;) plt.title(f&class="macro">#x27;Distribution of Outcomes(filtered by {", ".join([f"{key}={value}" for key, value in feature_filters.items()])})&class="macro">#x27;) plt.show() # Example usage: Visualize the distribution of outcomes when filtering by feature_1 = &class="macro">#x27;a&class="macro">#x27;, feature_2 = &class="macro">#x27;d&class="macro">#x27;, feature_3 = &class="macro">#x27;g&class="macro">#x27; plot_filtered_distribution(df, {&class="macro">#x27;feature_1&class="macro">#x27;: &class="macro">#x27;b&class="macro">#x27;, &class="macro">#x27;feature_2&class="macro">#x27;: &class="macro">#x27;d&class="macro">#x27;, &class="macro">#x27;feature_3&class="macro">#x27;: &class="macro">#x27;g&class="macro">#x27;})