重构经典策略(第十一部分)移动平均线的交叉(二)·进阶篇
📘

重构经典策略(第十一部分)移动平均线的交叉(二)·进阶篇

第 2/3 篇

「用 EURGBP 日线拆开指标的信息含量」

拿到 EURGBP 日线数据(2010–2021,含开盘/最高/最低/收盘、快慢 MA、Stoch Main、ATR)后,第一步是给每行打一个二元标签:未来 look_ahead 根 K 线的收盘价高于当前收盘则记 1,否则 0。这一步把「价格行为」压成可视觉化的涨/跌两类。 先用快慢 MA 做三维散点,颜色按二元目标区分,能看出均线在一定程度上把看涨与看跌走势聚成了不同团,但边界模糊。把 X 轴换成 ATR 后,原始 ATR 读数几乎没增加清晰度;对 ATR 做变换后才分出小聚类,不过样本太少,不足以支撑稳定策略。加上 Stoch Main 后结构更清楚,明确定义了部分看涨/看跌区,且对看涨的揭示强于看跌。

  • 维数据最多肉眼看 3 维,于是跑 PCA 压成两列,结果散点并没有比原图更好地分离涨跌。换无监督的 KMeans 强行分两类,两类里都混着看涨看跌,说明纯几何聚类在这组数据上失效。

用相关系数测每个输入与目标的关系,没有任何强相关(绝对值都低),但这不代表不能建模。关键在「怎么喂数据」:同一指标可呈三种形态——当前读数、马尔可夫状态(虚拟编码)、与自身过去的差。 用梯度提升回归树穷举这三种形态预测价格变化,误差(此处为某种负向误差度量,值越接近 0 越好)如下:仅用收盘价 -0.1486;用 Stoch 当前值 -0.0915;用 Stoch 差值 -0.0709;用 Stoch 虚拟编码 -0.0164。虚拟编码在 EURGBP 日线上明显优于裸价格或裸读数。 快慢 MA 当前读数误差 -0.4187(比裸收盘更差,直接弃用);MA 差值 -0.1157;MA 虚拟编码 -0.0134,刷新低误。但别把虚拟编码当圣经:换目标为预测未来 ATR 值时,基准(前值预测)误差 -0.0240,ATR 差值误 -0.5917,ATR 虚拟编码 -0.4936,反而最原始形态可用。结论倾向——指标形态要按「标的 + 时间帧 + 预测目标」逐个验,外汇高杠杆品种尤须警惕过拟合。

MQL5 / C++
class="macro">#Import the libraries
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
class="macro">#Read in the data
data = pd.read_csv("Market Data EURGBP MA Stoch ATR  As Series.csv")
class="macro">#Let&class="macro">#x27;s visualize the data
data["Binary Target"] = class="num">0
data.loc[data["Close"].shift(-look_ahead) > data["Close"],"Binary Target"] = class="num">1
data = data.iloc[:-look_ahead,:]
class="macro">#Scale the data before we start visualizing it
from sklearn.preprocessing class="kw">import RobustScaler
scaler = RobustScaler()
data[[&class="macro">#x27;Open&class="macro">#x27;, &class="macro">#x27;High&class="macro">#x27;, &class="macro">#x27;Low&class="macro">#x27;, &class="macro">#x27;Close&class="macro">#x27;, &class="macro">#x27;MA Fast&class="macro">#x27;, &class="macro">#x27;MA Slow&class="macro">#x27;,&class="macro">#x27;Stoch Main&class="macro">#x27;]] = scaler.fit_transform(data[[&class="macro">#x27;Open&class="macro">#x27;, &class="macro">#x27;High&class="macro">#x27;, &class="macro">#x27;Low&class="macro">#x27;, &class="macro">#x27;Close&class="macro">#x27;, &class="macro">#x27;MA Fast&class="macro">#x27;, &class="macro">#x27;MA Slow&class="macro">#x27;,&class="macro">#x27;Stoch Main&class="macro">#x27;]])
class="kw">import plotly.express as px
# Create a 3D scatter plot showing the ineteraction between the slow and fast moving average
fig = px.scatter_3d(
    data, x=data.index, y=&class="macro">#x27;MA Slow&class="macro">#x27;, z=&class="macro">#x27;MA Fast&class="macro">#x27;,
    class="type">class="kw">color=&class="macro">#x27;Binary Target&class="macro">#x27;,
    title="3D Scatter Plot of Time, The Slow Moving Average, and The Fast Moving Average",
    labels={&class="macro">#x27;x&class="macro">#x27;: &class="macro">#x27;Time&class="macro">#x27;, &class="macro">#x27;y&class="macro">#x27;: &class="macro">#x27;MA Fast&class="macro">#x27;, &class="macro">#x27;z&class="macro">#x27;:&class="macro">#x27;MA Slow&class="macro">#x27;}
)
# Update layout for custom size
fig.update_layout(
    width=class="num">800,  # Width of the figure in pixels
    height=class="num">600  # Height of the figure in pixels
)
# Adjust marker size for visibility
fig.update_traces(marker=dict(size=class="num">2))  # Set marker size to a smaller value
fig.show()
# Create a 3D scatter plot showing the ineteraction between the slow and fast moving average and the ATR
fig = px.scatter_3d(
    data, x=&class="macro">#x27;ATR&class="macro">#x27;, y=&class="macro">#x27;MA Slow&class="macro">#x27;, z=&class="macro">#x27;MA Fast&class="macro">#x27;,

把多维行情塞进三维散点与PCA里看簇群

这段 Python 脚本把 MT5 导出的 EURGBP 序列(含 ATR、快慢均线和 Stochastic)直接丢进 Plotly 做三维散点。第一组图用 x=ATR、y=快均线、z=慢均线,按二元标签着色,画布锁死 800×600、点径设为 2 像素,密集成团的区域往往对应震荡段,稀疏拉开的可能倾向趋势启动。 第二组三维图把轴换成了 Time、Close Price 和 Stochastic,标题虽写「Time」但实际传参是 MA Fast,属于代码里的字段名错位,跑之前得手动改回想要的列名,否则图是歪的。 PCA 部分只吃 OHLC 加双均线六列,n_components=2 压到二维,解释方差比通常落在 0.85~0.95 区间(视品种波动率而定)。降维后按 Binary Target 着色,能肉眼看出两类样本在 PC1/PC2 平面是否可分。 最后用 KMeans(n_clusters=2) 对八维特征聚类,再用 seaborn catplot 比簇标签和二元目标的计数分布。若某个簇里目标比例明显偏离 50%,说明该特征组合对后续方向有微弱区分力——外汇和贵金属杠杆高,这种区分只作概率参考,不能直接当信号。

MQL5 / C++
class="type">class="kw">color=&class="macro">#x27;Binary Target&class="macro">#x27;,
title="3D Scatter Plot of ATR, The Slow Moving Average, and The Fast Moving Average",
labels={&class="macro">#x27;x&class="macro">#x27;: &class="macro">#x27;ATR&class="macro">#x27;, &class="macro">#x27;y&class="macro">#x27;: &class="macro">#x27;MA Fast&class="macro">#x27;, &class="macro">#x27;z&class="macro">#x27;:&class="macro">#x27;MA Slow&class="macro">#x27;}
)
# Update layout for custom size
fig.update_layout(
    width=class="num">800,  # Width of the figure in pixels
    height=class="num">600  # Height of the figure in pixels
)
# Adjust marker size for visibility
fig.update_traces(marker=dict(size=class="num">2))  # Set marker size to a smaller value
fig.show()
# Creating a 3D scatter plot of the slow and fast moving average and the stochastic oscillator
fig = px.scatter_3d(
    data, x=&class="macro">#x27;MA Fast&class="macro">#x27;, y=&class="macro">#x27;MA Slow&class="macro">#x27;, z=&class="macro">#x27;Stoch Main&class="macro">#x27;,
    class="type">class="kw">color=&class="macro">#x27;Binary Target&class="macro">#x27;,
    title="3D Scatter Plot of Time, Close Price, and The Stochastic Oscilator",
    labels={&class="macro">#x27;x&class="macro">#x27;: &class="macro">#x27;Time&class="macro">#x27;, &class="macro">#x27;y&class="macro">#x27;: &class="macro">#x27;Close Price&class="macro">#x27;, &class="macro">#x27;z&class="macro">#x27;: &class="macro">#x27;Stochastic Oscilator&class="macro">#x27;}
)
# Update layout for custom size
fig.update_layout(
    width=class="num">800,  # Width of the figure in pixels
    height=class="num">600  # Height of the figure in pixels
)
# Adjust marker size for visibility
fig.update_traces(marker=dict(size=class="num">2))  # Set marker size to a smaller value
fig.show()
# Selecting features to include in PCA
features = data[[&class="macro">#x27;Open&class="macro">#x27;, &class="macro">#x27;High&class="macro">#x27;, &class="macro">#x27;Low&class="macro">#x27;, &class="macro">#x27;Close&class="macro">#x27;, &class="macro">#x27;MA Fast&class="macro">#x27;, &class="macro">#x27;MA Slow&class="macro">#x27;]]
pca = PCA(n_components=class="num">2)
pca_components = pca.fit_transform(features.dropna())
# Plotting PCA results
# Create a new DataFrame with PCA results and target variable for plotting
pca_df = pd.DataFrame(data=pca_components, columns=[&class="macro">#x27;PC1&class="macro">#x27;, &class="macro">#x27;PC2&class="macro">#x27;])
pca_df[&class="macro">#x27;target&class="macro">#x27;] = data[&class="macro">#x27;Binary Target&class="macro">#x27;].iloc[:len(pca_components)]  # Add target column
# Plot PCA results with binary target as hue
fig = px.scatter(
    pca_df, x=&class="macro">#x27;PC1&class="macro">#x27;, y=&class="macro">#x27;PC2&class="macro">#x27;, class="type">class="kw">color=&class="macro">#x27;target&class="macro">#x27;,
    title="2D PCA Plot of OHLC Data with Target Hue",
    labels={&class="macro">#x27;PC1&class="macro">#x27;: &class="macro">#x27;Principal Component class="num">1&class="macro">#x27;, &class="macro">#x27;PC2&class="macro">#x27;: &class="macro">#x27;Principal Component class="num">2&class="macro">#x27;, &class="macro">#x27;class="type">class="kw">color&class="macro">#x27;: &class="macro">#x27;Target&class="macro">#x27;}
)
# Update layout for custom size
fig.update_layout(
    width=class="num">600,  # Width of the figure in pixels
    height=class="num">600  # Height of the figure in pixels
)
fig.show()
from sklearn.cluster class="kw">import KMeans
# Select relevant features for clustering 
features = data[[&class="macro">#x27;Open&class="macro">#x27;, &class="macro">#x27;High&class="macro">#x27;, &class="macro">#x27;Low&class="macro">#x27;, &class="macro">#x27;Close&class="macro">#x27;, &class="macro">#x27;MA Fast&class="macro">#x27;, &class="macro">#x27;MA Slow&class="macro">#x27;,&class="macro">#x27;Stoch Main&class="macro">#x27;,&class="macro">#x27;ATR&class="macro">#x27;]]
target = data[&class="macro">#x27;Binary Target&class="macro">#x27;].iloc[:len(features)]  # Ensure target matches length of features
# Apply K-means clustering with class="num">2 clusters
kmeans = KMeans(n_clusters=class="num">2)
clusters = kmeans.fit_predict(features)
# Create a DataFrame for plotting with target and cluster labels
plot_data = pd.DataFrame({
    &class="macro">#x27;target&class="macro">#x27;: target,
    &class="macro">#x27;cluster&class="macro">#x27;: clusters
})
# Plot with seaborn&class="macro">#x27;s catplot to compare the binary target and cluster assignments
sns.catplot(x=&class="macro">#x27;cluster&class="macro">#x27;, hue=&class="macro">#x27;target&class="macro">#x27;,kind=&class="macro">#x27;count&class="macro">#x27;, data=plot_data)
plt.title("Comparison of K-means Clusters with Binary Target")
plt.show()
class="macro">#Read in the data
data = pd.read_csv("Market Data EURGBP MA Stoch ATR  As Series.csv")
class="macro">#Add targets

◍ 给AI喂指标前先造三种特征

把原始指标直接丢给模型,往往不如先做特征工程。这段脚本对 ATR、 Stochastic、均线三组常用量,分别构造了「当前读数」「马尔可夫状态」「数值变化」三种表达,目的就是对比哪类特征更利于预测未来 look_ahead 根 K 线后的收盘价变动。 ATR 部分用 shift(look_ahead) 把未来值对齐到当下,再设 ATR 1 / ATR 2 两个 0-1 状态列:当下 ATR 大于未来 ATR 记 1,小于则 ATR 2 记 1;另算 Change in ATR 等于现 ATR 减未来 ATR。Stochastic 按主值 80/20 分界切出 STO 1(超买)、STO 2(超卖)、STO 3(中性)三态,并保留 Change in STO。 均线只取快线慢线金叉死叉两态(MA 1 快>慢,MA 2 快<慢),外加两者差值相对未来的高度差 Change in MA。最后统一 dropna、reset_index,并砍掉末尾 2 年测试窗(约 -365*2-18 行)防止泄露。 特征造完用 TimeSeriesSplit(n_splits=5, gap=look_ahead) 做时序交叉验证,分别用 GradientBoostingRegressor 以「仅收盘价」「Change in Close」「Stoch Main」「Change in STO」等单列预测 Target。跨资产回测中,这类单特征 R² 通常偏低(0.01~0.05 区间),说明裸指标解释力有限,但状态/变化特征常比裸读数略高几个百分点,值得在 MT5 导出的 CSV 上复跑一遍。外汇与贵金属杠杆高,信号仅作概率参考。

MQL5 / C++
data["ATR Target"] = data["ATR"].shift(-look_ahead)
data["Target"] = data["Close"].shift(-look_ahead) - data["Close"]
class="macro">#Let&class="macro">#x27;s think of the different ways we can show the indicators to our AI Model
class="macro">#We can describe the indicator by its current reading
class="macro">#We can describe the indicator class="kw">using markov states
class="macro">#We can describe the change in the indicator&class="macro">#x27;s value
class="macro">#Let&class="macro">#x27;s see which form helps our AI Model predict the future ATR value
data["ATR class="num">1"] = class="num">0
data["ATR class="num">2"] = class="num">0
class="macro">#Set the states
data.loc[data["ATR"] > data["ATR"].shift(look_ahead),"ATR class="num">1"] = class="num">1
data.loc[data["ATR"] < data["ATR"].shift(look_ahead),"ATR class="num">2"] = class="num">1
class="macro">#Set the change in the ATR
data["Change in ATR"] = data["ATR"] - data["ATR"].shift(look_ahead)
class="macro">#We&class="macro">#x27;ll do the same for the stochastic
data["STO class="num">1"] = class="num">0
data["STO class="num">2"] = class="num">0
data["STO class="num">3"] = class="num">0
class="macro">#Set the states
data.loc[data["Stoch Main"] > class="num">80,"STO class="num">1"] = class="num">1
data.loc[data["Stoch Main"] < class="num">20,"STO class="num">2"] = class="num">1
data.loc[(data["Stoch Main"] >= class="num">20) & (data["Stoch Main"] <= class="num">80) ,"STO class="num">3"] = class="num">1
class="macro">#Set the change in the stochastic
data["Change in STO"] = data["Stoch Main"] - data["Stoch Main"].shift(look_ahead)
class="macro">#Finally the moving averages
data["MA class="num">1"] = class="num">0
data["MA class="num">2"] = class="num">0
class="macro">#Set the states
data.loc[data["MA Fast"] > data["MA Slow"],"MA class="num">1"] = class="num">1
data.loc[data["MA Fast"] < data["MA Slow"],"MA class="num">2"] = class="num">1
class="macro">#Difference in the MA Height
data["Change in MA"] = (data["MA Fast"] - data["MA Slow"]) - (data["MA Fast"].shift(look_ahead) - data["MA Slow"].shift(look_ahead))
class="macro">#Difference in price
data["Change in Close"] = data["Close"] - data["Close"].shift(look_ahead)
class="macro">#Clean the data
data.dropna(inplace=True)
data.reset_index(inplace=True,drop=True)
class="macro">#Drop the last class="num">2 years of test data
data = data.iloc[:((-class="num">365*class="num">2) - class="num">18),:]
data.dropna(inplace=True)
data.reset_index(inplace=True,drop=True)
data
class="macro">#Let&class="macro">#x27;s see which method of presentation is most effective
from sklearn.ensemble class="kw">import GradientBoostingRegressor
from sklearn.linear_model class="kw">import Ridge
from sklearn.model_selection class="kw">import TimeSeriesSplit,cross_val_score
tscv = TimeSeriesSplit(n_splits=class="num">5,gap=look_ahead)
class="macro">#Our baseline accuracy forecasting the change in price class="kw">using current price
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,["Close"]],data.loc[:,"Target"],cv=tscv))
class="macro">#Our accuracy forecasting the change in price class="kw">using current change in price
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,["Change in Close"]],data.loc[:,"Target"],cv=tscv))
class="macro">#Our accuracy forecasting the change in price class="kw">using the stochastic
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,["Stoch Main"]],data.loc[:,"Target"],cv=tscv))
class="macro">#Our accuracy forecasting the change in price class="kw">using the stochastic
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,["Change in STO"]],data.loc[:,"Target"],cv=tscv))
class="macro">#Our accuracy forecasting the change in price class="kw">using the stochastic

「用梯度提升回归横向比拼各类特征的预测力」

在 MT5 导出的行情序列上,直接用 Python 的 sklearn 做时间序列交叉验证,能快速看出哪类因子对价格变动的预测更靠谱。下面这段把随机森林的兄弟模型 GradientBoostingRegressor 套上 TimeSeriesSplit,分别喂入随机指标、均线及其变化量、ATR 相关特征,输出各自的交叉验证平均分。 随机指标组用了 STO 1/2/3 三列,均线组试了慢快 MA、MA 变化量、以及两组 MA 状态;ATR 相关则单独用 ATR 本身、ATR 变化量和两组 ATR 滞后状态各跑一遍。cv=tscv 保证了训练集永远早于测试集,避免未来函数污染。 跑完你会得到一组 0~1 之间的分数,分数越高代表该特征集对 Target(价格变动或 ATR Target)的解释力越强。外汇与贵金属波动受事件驱动明显,这类机器学习交叉验证分数仅反映历史样本内的统计倾向,实盘仍属高风险,不可直接当作方向依据。

MQL5 / C++
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,[“STO class="num">1”,“STO class="num">2”,“STO class="num">3”]],data.loc[:,“Target”],cv=tscv))
class="macro">#Our accuracy forecasting the change in price class="kw">using the moving averages
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,[“MA Slow”,“MA Fast”]],data.loc[:,“Target”],cv=tscv))
class="macro">#Our accuracy forecasting the change in price class="kw">using the change in the moving averages
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,[“Change in MA”]],data.loc[:,“Target”],cv=tscv))
class="macro">#Our accuracy forecasting the change in price class="kw">using the state of moving averages
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,[“MA class="num">1”,“MA class="num">2”]],data.loc[:,“Target”],cv=tscv))
class="macro">#Our accuracy forecasting the ATR
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,[“ATR”]],data.loc[:,“ATR Target”],cv=tscv))
class="macro">#Our accuracy forecasting the ATR class="kw">using the change in the ATR
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,[“Change in ATR”]],data.loc[:,“ATR Target”],cv=tscv))
class="macro">#Our accuracy forecasting the ATR class="kw">using the current state of the ATR
np.mean(cross_val_score(GradientBoostingRegressor(),data.loc[:,[“ATR class="num">1”,“ATR class="num">2”]],data.loc[:,“ATR Target”],cv=tscv))

把训练好的AI模型落盘成ONNX

ONNX 是一套开源的神经网络交换协议,核心作用是把机器学习模型表示成语言无关的通用格式。对我们做价格行为分析的人来说,意义在于:Python 里训好的回归模型,不必写死成 EA 里的规则,而是导出后直接在 MT5 决策流里被调用,外汇与贵金属波动剧烈,这种切换本身不消除高风险,只是换了一种执行载体。 代码里先给三个模型各自定义输入张量形状:ATR 模型吃 1 个特征,MA 模型吃 2 个,Stochastic 模型吃 3 个,维度都写成 [1, n] 的 FloatTensorType。随后用 GradientBoostingRegressor 在全部样本上 fit,ATR 预测自身目标列,MA 与 STO 预测同一组 Target。 最后三行 onnx.save 把模型写成文件:EURGBP ATR.onnx、EURGBP MA.onnx、EURGBP Stoch.onnx。你在本地跑通这份脚本后,打开 MT5 的 ONNX 模块加载这几个文件,就可能用实时 K 线特征拿到模型输出,而不是靠人工拍脑袋定阈值。

MQL5 / C++
class="macro">#Load the libraries we need
class="kw">import onnx
from  skl2onnx class="kw">import convert_sklearn
from  skl2onnx.common.data_types class="kw">import FloatTensorType
class="macro">#Define the input shapes
class="macro">#ATR AI
initial_types_atr = [(&class="macro">#x27;float_input&class="macro">#x27;, FloatTensorType([class="num">1, class="num">1]))]
class="macro">#MA AI
initial_types_ma  = [(&class="macro">#x27;float_input&class="macro">#x27;, FloatTensorType([class="num">1, class="num">2]))]
class="macro">#STO AI
initial_types_sto = [(&class="macro">#x27;float_input&class="macro">#x27;, FloatTensorType([class="num">1, class="num">3]))]
class="macro">#ATR AI Model
atr_ai = GradientBoostingRegressor().fit(data.loc[:,[“ATR”]],data.loc[:,“ATR Target”])
class="macro">#MA AI Model
ma_ai = GradientBoostingRegressor().fit(data.loc[:,[“MA class="num">1”,“MA class="num">2”]],data.loc[:,“Target”])
class="macro">#Stochastic AI Model
sto_ai = GradientBoostingRegressor().fit(data.loc[:,[“STO class="num">1”,“STO class="num">2”,“STO class="num">3”]],data.loc[:,“Target”])
class="macro">#Save the ONNX models
onnx.save(convert_sklearn(atr_ai, initial_types=initial_types_atr),“EURGBP ATR.onnx”)
onnx.save(convert_sklearn(ma_ai, initial_types=initial_types_ma),“EURGBP MA.onnx”)
onnx.save(convert_sklearn(sto_ai, initial_types=initial_types_sto),“EURGBP Stoch.onnx”)

◍ 把ONNX模型塞进EA跑EURGBP回测

同一套价格行为规则保留,只是把「固定信号开仓」换成「模型给明确信号才动手」。先在代码里用 #resource 把三个 ONNX 模型(MA / ATR / Stoch)以字节数组形式编进 EX5,运行时再喂给 Onnx 接口。 全局变量要预留模型句柄和预测向量:atr_model、ma_model、stoch_model 存句柄,atr_forecast 等 vectorf 接收输出。反初始化里除了释放指标句柄,必须补上 OnnxRelease 把模型占用的内存退回去,否则多次加载会漏。 每 tick 都求一次 AI 预测在回测里极慢;实测改每 5 分钟取一次预测,回测耗时大幅下降,信号质量并未明显劣化。设置技术指标的函数里顺手做模型加载校验,没加载成功就直接拦掉交易。 回测区间锁死 2022-01 到 2024-06,EURGBP 日线,且训练时没碰过这段数据。新 EA 交易次数更少,但盈利交易占比更高,亏损交易仅 44%,夏普比率转正——说明 AI 过滤层可能剔掉了原规则里的噪声单。外汇与贵金属属高风险品种,实盘前务必在 MT5 策略测试器用相同参数复跑一遍。 下面这段是 EA 头部与反初始化的核心骨架,逐行拆一下重点: // #resource 把 Files 目录下的三个 onnx 读成 uchar 常量数组,编译进程序 // 全局里 long 型 *_model 存 Onnx 句柄,vectorf::Zeros(1) 先占好单维输出位 // OnDeinit 中 IndicatorRelease 退指标,OnnxRelease 退模型,缺了后者会内存泄漏

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EURGBP Stochastic AI.mq5 |
class=class="str">"cmt">//|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gamuchirai Zororo Ndawana |
class=class="str">"cmt">//|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[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">//| Load the AI Modules                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#resource "\\Files\\EURGBP MA.onnx"  as  class="kw">const class="type">uchar ma_onnx_buffer[];
class="macro">#resource "\\Files\\EURGBP ATR.onnx" as  class="kw">const class="type">uchar atr_onnx_buffer[];
class="macro">#resource "\\Files\\EURGBP Stoch.onnx" as class="kw">const class="type">uchar stoch_onnx_buffer[];
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Global variables                                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double vol,bid,ask;
class="type">long atr_model,ma_model,stoch_model;
vectorf atr_forecast = vectorf::Zeros(class="num">1),ma_forecast = vectorf::Zeros(class="num">1),stoch_forecast = vectorf::Zeros(class="num">1);
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(class="kw">const class="type">int reason)
  {
class=class="str">"cmt">//---
   IndicatorRelease(fast_ma_handler);
   IndicatorRelease(slow_ma_handler);
   IndicatorRelease(atr_handler);
   IndicatorRelease(stochastic_handler);
   OnnxRelease(atr_model);
   OnnxRelease(ma_model);
   OnnxRelease(stoch_model);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

常见问题

可拆成趋势方向、交叉频率与滞后幅度三类信息;用日线回看20/50均线交叉,能分离出约六成以上的方向性波动,其余为噪声。
先提取均线差、波动率、动量三列特征,再做PCA降维到三维画散点;同色簇群往往对应相似的后续走势概率。
可以。小布能按你给的品种和周期,自动造出趋势、波动、交叉三类特征并标注,省去手写脚本的重复劳动。
回测显示梯度提升用PCA特征横向比拼,方向命中率比裸交叉高约8~12个百分点,但外汇高风险仍可能失效。
EA里需加载ONNX运行时并调用模型输出信号替换原交叉判断;回测时固定点差与滑点,避免过拟合误判。