获取市场优势的秘诀(第二部分):预测技术指标(基础篇)
📘

获取市场优势的秘诀(第二部分):预测技术指标(基础篇)

第 1/2 篇

「用指标预测给交易抢跑」

很多交易者把技术指标当成滞后确认工具,但在 MT5 里指标本身可以拿来做前向推演。做法是把已计算的历史缓冲区往未来索引延伸,用线性回归或简单外推填出接下来几根 K 的可能位置。 以 iMA 为例,取一段已收盘的均线值序列,用最小二乘拟合斜率,就能估算第 N 根之后的均线落点。下面这段代码在脚本里直接算出未来 5 根的均线预测值并打印。 外汇与贵金属杠杆高,预测值只是概率参考,实际价格可能快速脱离推演区间,实盘前务必在策略测试器里跑历史校验。

MQL5 / C++
class="type">int ma_handle = iMA(_Symbol, PERIOD_H1, class="num">14, class="num">0, MODE_SMA, PRICE_CLOSE);
class="type">class="kw">double ma_buf[class="num">100];
CopyBuffer(ma_handle, class="num">0, class="num">0, class="num">100, ma_buf);
class=class="str">"cmt">// 用最后30点做线性拟合
class="type">class="kw">double sum_x=class="num">0, sum_y=class="num">0, sum_xy=class="num">0, sum_x2=class="num">0;
for(class="type">int i=class="num">0;i<class="num">30;i++){
   sum_x+=i; sum_y+=ma_buf[i]; sum_xy+=i*ma_buf[i]; sum_x2+=i*i;
}
class="type">class="kw">double slope=(class="num">30*sum_xy - sum_x*sum_y)/(class="num">30*sum_x2 - sum_x*sum_x);
class="type">class="kw">double intercept=(sum_y - slope*sum_x)/class="num">30;
for(class="type">int k=class="num">1;k<=class="num">5;k++){
   class="type">class="kw">double pred = slope*(class="num">30+k-class="num">1) + intercept;
   Print("未来第", k, "根预测均线=", pred);
}

◍ 为什么预测价格胜率卡在50%

做算法交易的人常有个错觉:模型越复杂,回报就该越好。实际在 MT5 环境里跑机器学习,很多人的价格方向预测准确率长期压在 50% 附近,和抛硬币没本质区别。 问题出在直接拿收盘价当标签。金融价格序列噪声占比高、非平稳,监督学习很难从里面榨出稳定边缘。 换个思路,不去猜下一根 K 线的价格,而是猜技术指标的后值。实测中这类目标的预测准确率能抬到 70% 左右,模型可用性立刻不同。 后面会按时间序列分析的实操顺序,一步步拆怎么在 MQL5 里落地这套做法,让你比只用 Python 的人更早抓到指标拐点的领先信号。外汇与贵金属杠杆高,任何模型信号都只是概率倾向,实盘前务必在策略测试器里验证。

预测指标值比预测价格更靠谱

从 MT5 导出历史数据后,用 Python 把同一套模型分别去猜「未来 60 根 K 线的收盘价方向」和「未来 60 根 K 线的移动平均线方向」,结果差距很直观:直接预测收盘价的神经网络准确率只有 49.9%,基本和抛硬币无异;而预测 MA 变化的同结构模型准确率到了 68.8%。 之所以出现这种分化,核心在于价格受无数难以建模的隐性因素驱动,而技术指标的值完全由已观测的 OHLC 推算,输入空间是「可完全观察」的。把问题从价格预测换成指标预测,等于把目标变量关进了可解释的黑盒里。 实操上,MT5 菜单里点交易对象列表 → 选品种与周期 → 选 bars 拉满历史 → 导出 csv(实际是制表符分隔)。读进 pandas 后重命名列、算 SMA_60,再按 60 根偏移编码涨跌目标,一组盯 close、一组盯 SMA_60。 数据需按首行归一化以消除量纲,PCA 降维去掉输入间相关性,最后用 TimeSeriesSplit 切训练集验证误差。外汇与贵金属杠杆高、滑点跳空频繁,这类回测准确率仅代表历史样本倾向,实盘可能显著衰减。

MQL5 / C++
class="macro">#Load libraries
class="kw">import pandas as pd
class="kw">import numpy as np
class="kw">import matplotlib.pyplot as plt
class="macro">#Read the data
csv = pd.read_csv("/content/Volatility class="num">75 Index_M1_20190101_20240131.csv",sep="\t")
csv
class="macro">#Format the data
csv.rename(columns={"<DATE>":"date","<TIME>":"time","<TICKVOL>":"tickvol","<VOL>":"vol","<SPREAD>":"spread","<OPEN>":"open","<HIGH>":"high","<LOW>":"low","<CLOSE>":"close"},inplace=True)
csv.ta.sma(length= class="num">60,append=True)
csv.dropna(inplace=True)
csv
class="macro">#Define the inputs
predictors = ["open","high","low","close","SMA_60"]
class="macro">#Scale the data
csv["open"] = csv["open"] /csv.loc[class="num">0,"open"]
csv["high"] = csv["high"] /csv.loc[class="num">0,"high"]
csv["low"] = csv["low"] /csv.loc[class="num">0,"low"]
csv["close"] = csv["close"] /csv.loc[class="num">0,"close"]
csv["SMA_60"] = csv["SMA_60"] /csv.loc[class="num">0,"SMA_60"]
class="macro">#Define the close
csv["Target Close"] = class="num">0
csv["Target MA"] = class="num">0
class="macro">#Define the forecast horizon
look_ahead = class="num">60
class="macro">#Set the targets
csv.loc[csv["close"] > csv["close"].shift(-look_ahead) ,"Target Close"] = class="num">0
csv.loc[csv["close"] < csv["close"].shift(-look_ahead) ,"Target Close"] = class="num">1
csv.loc[csv["SMA_60"] > csv["SMA_60"].shift(-look_ahead) ,"Target MA"] = class="num">0
csv.loc[csv["SMA_60"] < csv["SMA_60"].shift(-look_ahead) ,"Target MA"] = class="num">1
csv = csv[:-look_ahead]
class="macro">#Get ready
from sklearn.discriminant_analysis class="kw">import LinearDiscriminantAnalysis
from sklearn.linear_model class="kw">import LogisticRegression
from xgboost class="kw">import XGBClassifier
from sklearn.neural_network class="kw">import MLPClassifier
from sklearn.metrics class="kw">import accuracy_score
from sklearn.decomposition class="kw">import PCA
from sklearn.model_selection class="kw">import TimeSeriesSplit
class="macro">#Time series split
splits = class="num">10
gap = look_ahead
models_close = ["Logistic Regression","LDA","XGB","Nerual Net Simple","Nerual Net Large"]
models_ma = ["Logistic Regression","LDA","XGB","Nerual Net Simple","Nerual Net Large"]
class="macro">#Prepare the data
pca = PCA()
csv_reduced = pd.DataFrame(pca.fit_transform(csv.loc[:,predictors]))
class="macro">#Fit the neural network predicting close price
model_close = MLPClassifier(solver=&class="macro">#x27;lbfgs&class="macro">#x27;,alpha=class="num">1e-5,hidden_layer_sizes=(class="num">5, class="num">2), random_state=class="num">1)
model_close.fit(csv_reduced.loc[class="num">0:class="num">300000,:],csv.loc[class="num">0:class="num">300000,"Target Close"])
print("Close accuracy: ",accuracy_score(csv.loc[class="num">300070:,"Target Close"], model_close.predict(csv_reduced.loc[class="num">300070:,:])))
class="macro">#Fit the model predicting the moving average
model_ma = MLPClassifier(solver=&class="macro">#x27;lbfgs&class="macro">#x27;,alpha=class="num">1e-5,hidden_layer_sizes=(class="num">5, class="num">2), random_state=class="num">1)
model_ma.fit(csv_reduced.loc[class="num">0:class="num">300000,:],csv.loc[class="num">0:class="num">300000,"Target MA"])
print("MA accuracy: ",accuracy_score(csv.loc[class="num">300070:,"Target MA"], model_ma.predict(csv_reduced.loc[class="num">300070:,:])))
class="macro">#Error metrics

「用时间序列交叉验证压一下过拟合」

把历史行情当成一条不可打乱的时间轴来切分,才能看出模型在未知未来片段上的真实表现。下面这段做法用了带间隔的时间序列交叉验证(TimeSeriesSplit),gap 参数让训练集和测试集之间留出空白,避免相邻样本泄漏导致准确率虚高。 具体实现里,n_splits 决定回测折数,gap 是折间隔离的 K 线根数;每一折都用 MLPClassifier(隐藏层 20、10,alpha=1e-5,lbfgs 求解器)去拟合收盘价变动方向,再把预测结果和测试集真实标签算 accuracy_score,逐折填进 error_close_df 的第 5 列(索引 4)。 你在 MT5 导出 csv 后跑这套,重点看各折准确率是否陡降:若训练集内 0.9 以上、测试集掉到 0.55 附近,说明模型大概率只是记住了样本噪声。外汇与贵金属波动受事件驱动,此类方向预测仅作概率参考,实盘仍属高风险。

MQL5 / C++
tscv = TimeSeriesSplit(n_splits=splits,gap=gap)
error_close_df = pd.DataFrame(index=np.arange(class="num">0,splits),columns=models_close)
error_ma_df = pd.DataFrame(index=np.arange(class="num">0,splits),columns=models_ma)
class="macro">#Training each model to predict changes in the close price
for i,(train,test) in enumerate(tscv.split(csv)):
    model= MLPClassifier(solver=&class="macro">#x27;lbfgs&class="macro">#x27;,alpha=class="num">1e-5,hidden_layer_sizes=(class="num">20, class="num">10), random_state=class="num">1)
    model.fit(csv_reduced.loc[train[class="num">0]:train[-class="num">1],:],csv.loc[train[class="num">0]:train[-class="num">1],"Target Close"])
    error_close_df.iloc[i,class="num">4] = accuracy_score(csv.loc[test[class="num">0]:test[-class="num">1],"Target Close"],model.predict(csv_reduced.loc[test[class="num">0]:test[-class="num">1],:]))

常见问题

指标预测本质是给当前信号加一层前瞻,多数情况下能提前1~3根K线提示拐点,但外汇贵金属高风险,仅作辅助不宜单独开仓。
价格本身近似随机游走,直接预测价格天然胜率约50%;改预测指标值而非价格,再交叉验证可略微抬升概率。
小布可自动跑指标预测并标出疑似抢跑信号,你打开对应品种页就能直接看AIGC诊断,省去手算。
按时间顺序切训练集与测试集,禁止随机洗牌;用滚动窗口回测,样本外误差不飙升才算过关。
是,震荡市指标易来回假突破;建议叠加波动率过滤,且外汇贵金属杠杆高,误报期减仓或空仓。