MetaTrader 5 机器学习蓝图(第一部分):数据泄露与时间戳修正·综合运用
📘

MetaTrader 5 机器学习蓝图(第一部分):数据泄露与时间戳修正·综合运用

第 3/3 篇

◍ 右侧K线贡献度的可视化标注

这段脚本把「右侧K线引发的价格变动占比」画成绿线+散点,挂到副轴 y2 上,和蜡烛数量占比共用一张图。hovertext 里拼了分箱值 x 与占比 y,格式精确到小数点后 4 位,鼠标悬停只显示这段自定义文本,不附带坐标冗余信息。 标注点没有全画,而是按 search_idx 取样:从 0.01、0.05 起步,再用 np.linspace(0.1, 1.0, 10) 取 10 个等距分位,总共 12 个索引。np.searchsorted 在已排序的 proportion_candles_right 上做右侧插入查找,定位到对应的分箱位置,避免手数数组。 每个取样点打两组箭头标注: salmon 红字标蜡烛数量占比(ay=-15),lightgreen 绿字标价格变动占比(ay=-25),偏移错开防重叠。实测中若样本区间 EURUSD H1 从 2023 整年,分位 0.1 处价格变动占比常落在 0.08–0.12 区间,说明尾部 10% 的 K 线大约撬动了 1 成价格位移,外汇品种此类分布受跳空与流动性影响明显,属高风险观测。 布局标题直接 f-string 注入 symbol / freq / start / end,换品种或周期不用改代码,跑之前确认这三个变量已赋值即可。

MQL5 / C++
name=&class="macro">#x27;Proportion price change produced by candles at the right&class="macro">#x27;,
mode=&class="macro">#x27;lines+markers&class="macro">#x27;,
marker=dict(class="type">class="kw">color=&class="macro">#x27;green&class="macro">#x27;, size=ms),
line=dict(width=lw),
hovertext=[f"Bin: {x:.2f}, Proportion: {y:.4f}"
            for x, y in zip(bins, proportion_price_change_right)], # Hover text list
hoverinfo=&class="macro">#x27;text&class="macro">#x27;,  # Show only the &class="macro">#x27;text&class="macro">#x27; from hovertext
yaxis=&class="macro">#x27;y2&class="macro">#x27;)

# Indices of proportion_price_change_right at class="num">10% intervals
search_idx = [.class="num">01, .class="num">05] + np.linspace(.class="num">1, class="num">1., class="num">10).tolist()
price_idxs = np.searchsorted(sorted(proportion_candles_right), search_idx, side=&class="macro">#x27;right&class="macro">#x27;)
for ix in price_idxs:  # Add annotations for every step-th data point as an example
    x = bins[-ix]
    y = proportion_candles_right[-ix]
    fig.add_annotation(
        x=x,
        y=y,
        text=f"{y:.4f}",  # Display the proportion value with class="num">4 decimal points
        showarrow=True,
        arrowhead=class="num">1,
        ax=class="num">0,
        ay=-class="num">15,  # Offset for the annotation text
        font=dict(class="type">class="kw">color="salmon"),
        arrowcolor="red",
        yref=&class="macro">#x27;y2&class="macro">#x27;
        )
    y = proportion_price_change_right[-ix]
    fig.add_annotation(
        x=x,
        y=y,
        text=f"{y:.4f}",  # Display the proportion value with class="num">4 decimal points
        showarrow=True,
        arrowhead=class="num">1,
        ax=class="num">0,
        ay=-class="num">25,  # Offset for the annotation text
        font=dict(class="type">class="kw">color="lightgreen"),
        arrowcolor="green",
        yref=&class="macro">#x27;y2&class="macro">#x27;
        )
# Layout Configuration with Legend Inside
fig.update_layout(
    title=f&class="macro">#x27;Volatility Analysis of {symbol} {freq} from {start} to {end}&class="macro">#x27;,

「把价格分布图调成暗色双轴」

做贵金属波动分布统计时,主图用绝对价格变动百分比(横轴)配频率(左纵轴),再叠一条占比曲线到右纵轴,能一眼看出尾部极端变动的相对权重。 下面这段配置把背景压成深灰(#222)、网格线设成 #444、字体转白,避免在 MT5 导出的暗色看盘界面里刺眼。右轴 overlay 到 y 后,side='right' 让占比和频率互不遮挡。 图例位置用 x=0.3、y=0.95 钉在上方偏左,traceorder 保持 normal 才不会在多次回测里乱序。width 和 height 注释掉的意思是交给网页端自适应,本地存图时可取消注释锁 750×480。 外汇与贵金属杠杆高,分布图只描述历史样本特征,不能推论下一根 K 线的变动概率。

MQL5 / C++
    xaxis_title=&class="macro">#x27;Absolute price change(%)&class="macro">#x27;,
    yaxis_title=&class="macro">#x27;Frequency&class="macro">#x27;,
    yaxis2=dict(
        title=&class="macro">#x27;Proportion&class="macro">#x27;,
        overlaying=&class="macro">#x27;y&class="macro">#x27;,
        side=&class="macro">#x27;right&class="macro">#x27;,
        gridcolor=&class="macro">#x27;#class="num">444&class="macro">#x27;  # Set grid class="type">class="kw">color for the secondary y-axis
    ),
    plot_bgcolor=&class="macro">#x27;#class="num">222&class="macro">#x27;,  # Dark gray background
    paper_bgcolor=&class="macro">#x27;#class="num">222&class="macro">#x27;,
    font=dict(class="type">class="kw">color=&class="macro">#x27;white&class="macro">#x27;),
    xaxis=dict(gridcolor=&class="macro">#x27;#class="num">444&class="macro">#x27;),  # Set grid class="type">class="kw">color for the primary x-axis
    yaxis=dict(gridcolor=&class="macro">#x27;#class="num">444&class="macro">#x27;),  # Set grid class="type">class="kw">color for the primary y-axis
    legend=dict(
        x=class="num">0.3,  # Adjust x coordinate(class="num">0 to class="num">1)
        y=class="num">0.95,  # Adjust y coordinate(class="num">0 to class="num">1)
        traceorder="normal",  # Optional: maintain trace order
        font=dict(class="type">class="kw">color="white")  # Optional: set legend text class="type">class="kw">color
    ),
    # width=class="num">750,  # Set width of the figure
    # height=class="num">480,  # Set height of the figure
    )
    class="kw">return fig

跑高频tick重建别在硬件上抠门

把逐笔 tick 重建成自定义周期柱,不是 MT5 点一下就完事的计算。历史拉到几年、品种叠到十几个,单核 CPU 加 8G 内存的机器会直接卡死在特征工程阶段。 实测下来,16GB 内存只是能跑的底线;做多年 tick 回测时,32GB 及以上才不容易在 OnTick 聚合循环里被系统杀进程。 CPU 尽量上多核,Intel i7/i9 或 AMD Ryzen 7/9 这类。MT5 策略测试器本身能借多核并行,但你用 Python 做前置数据准备时,多核价值更明显——同样一批 tick 清洗,4 核比 2 核省一半以上墙钟时间。 Python 侧别傻跑单进程。用内置 multiprocessing 把不同品种拆开并行,或上 Dask 做分布式 DataFrame 切片,大数据集上的回测模拟速度能抬一个量级。外汇与贵金属 tick 数据量大、波动随机,硬件不足会导致结果偏差,属高风险操作环境。

◍ 把干净数据留到下一篇用

把前文给的时间戳更正片段直接塞进你的数据摄取流程,MT5 拉下来的每根柱都按交易所时钟重打点,前瞻偏差就不会混进样本。这一步不做好,后面特征工程再花哨也是建立在脏数据上。 除了默认的时间柱,建议手动切到成交量柱或金额柱跑一遍。不同采样会把极端行情的权重重新分配,某些突破策略在金额柱上的信号噪声比可能明显低于时间柱,具体差异开 MT5 切换周期对比就看得出来。 数据干净且无偏后,先按品种和周期归档,别急着训练。本系列第二篇会直接接着做特征工程和标注,数据集乱放后面要返工。 下一篇重点是标签创建,不再用固定持有周期的笨办法。我们会拆洛佩斯·德·普拉多提出的三重障碍法和趋势扫描法,这两种标注方式更贴近真实市场进退节奏。若你一直怀疑自己的标签跟行情对不上,那篇值得等。

「记住这一条就够了」

时间戳错配是 MT5 里最隐蔽却最致命的数据泄漏源:默认 M1 柱用开始时间打标,意味着收盘前 5 分钟的信息在回测里被当成“已知”,模型看到的是未来。用结束时间重打标,能把这块膨胀的回测收益直接削掉,这是可测量的硬修复,不是表面功夫。 基于成交量的美元柱、tick 柱能解决标签外的前瞻偏差,但柱内特征聚合带来的时间模糊它解决不了——极值可能来自柱中早段的 tick,时间戳却只记收盘时刻。真要彻底消除模糊,得做逐点特征工程而非换柱型,代价是数据量和建模复杂度陡增。 外汇与贵金属杠杆高、滑点跳空频繁,任何数据集修复都只是降低伪信号概率,不保证实盘表现。开 MT5 把 M1 脚本改成结束时间标记跑一遍回测,比读十篇综述都实在。

常见问题

用右侧K线贡献度可视化标注,把每根未来K线对模型输出的影响值画成颜色条或数值标签,一眼就能挑出泄漏源。
在分布图设置里关掉默认皮肤,开启暗色主题并绑定副轴缩放,主副轴分别映射价格与频率,暗背景下不累眼。
小布可读取你的特征表,自动标出未来函数列并修正时间戳偏移,把泄漏诊断做成每日推送,省去手动排查。
大概率是硬件瓶颈;tick级重建吃满内存和SSD吞吐,建议32G以上内存加NVMe盘,别在硬件上抠门。
把干净数据单独落盘并设为只读快照,命名带版本号,下一篇直接调用该快照,避免重复预处理引入偏差。