季节性过滤与ONNX周期选择基础:用Python给EA模型挑对时间窗口(基础篇)
(1/3)·从下载全量tick到识别货币对季节规律,这篇把数据地基和概念门槛一次铺平
不少交易者把深度学习EA直接丢进任意周期跑,却从没问过这段行情本身有没有季节性偏向。等回测漂亮、实盘漂移,才回头怀疑模型,而不是怀疑自己喂给模型的时间窗口。先把数据过滤和季节结构搞清楚,比盲目调参更省命。
◍ 用季节性过滤给 ONNX 模型挑周期
在 MT5 里跑深度学习 EA,周期选错比模型结构更致命。把 Python 拉进来对历史报价做季节性分解,能先把被季节节律绑架的噪声剥掉,再决定 ONNX 模型该吃哪个 timeframe 的料。 做法不复杂:从 MT5 导出的 OHLC 序列进 Python,用 statsmodels 的 seasonal_decompose 按周或月周期拆出 trend / seasonal / resid 三块。resid 里还残存可被模型学的结构,seasonal 占比过高的品种(比如某些贵金属在美盘时段的规律摆动),直接喂原序列只会让 ONNX 过拟合周期而非预测价格。 实证上,2024-11-04 发布的这套思路在 702 次社区浏览里被标记 2 条讨论,核心结论倾向是:EURUSD 在 H1 上 seasonal 成分弱、resid 信息密度高,比 M15 更适合做 ONNX 输入;而 XAUUSD 在 M15 的时段性尖峰会让模型误把开盘节律当信号。外汇与贵金属杠杆交易高风险,过滤只是降噪,不承诺胜率。 让小布替你跑这套:在 Python 里先 print 各周期的 seasonal 方差占比,占比超 35% 的周期直接从 EA 的 timeframe 枚举里剔除,再让 MT5 用剩下周期训 ONNX。
「为什么拿 EA 验季节性」
读完《利用外汇市场季节性因素获利》后,我打算换个角度:直接把「带季节性过滤」和「不带过滤」的 EA 摆到一起跑,看季节因子到底有没有边际优势。 市场受季节扰动并不是新鲜事。一个直观例子是:有投资者在少年礼拿到一笔钱后押注石油股,理由是加勒比海飓风季会推高油价——他甚至对照了天气预报里的恶劣气候窗口。这类事件让我更确信,价格行为和自然周期之间存在可建模的关联。 本篇的做法是先做对照实验:同一套 EA,一组加数据过滤、一组不加,观察过滤是否改变结果。随后用 2024 年 2 月这段真实行情,把加与不加季节因子的表现画出来比对。 数据准备阶段,我会用下载脚本把某交易品种的全部 tick 拉到本地。脚本挂上图表后,通常不到一小时就能在品种「文件」目录生成历史变动 CSV。本实验截取的是 2015 年 1 月至 2023 年 2 月这段样本,外汇与贵金属品种波动受季节与事件影响明显,属高风险验证环境,结论仅具概率意义。
用低通滤波给季节信号去噪
季节性在交易里指资产价格随年内的重复节奏起伏,比如零售股在节日季倾向走强、能源需求在冬夏两季分化。但原始价格序列里混着大量高频杂波,直接拿来跟季节规律对齐,容易被短期噪音带偏。 算法层面更务实的做法是上低通滤波器:它只放行低于截止频率的成分,把高频波动衰减掉。相比高通滤波,低通更契合中长线季节策略——平滑噪声、减少无效交易、压低手续费,也让风控更稳。作者实测用 butterworth 低通对 EURUSD 小时级收盘做处理,再喂给 LSTM-ONNX 模型。 滤波参数不是越狠越好。原文三组对照里,cutoff=0.01/order=4 的 R2 约 0.8799,cutoff=0.01/order=4(西语注释同参)R2 提升到 0.8922;而 cutoff=0.1/order=2 时 R2 掉到 0.8776。可见仅当参数匹配数据节奏,滤波才带来更好拟合,乱调反而劣化。 下面这段 Python 是滤波核心,建议在本地用相同 EURUSD 一小时数据复跑,重点看 normal_cutoff 怎么由 Nyquist 折算: cutoff_frequency = 0.01 设定截止频率为 Nyquist 频率的 1% order = 4 指定 butterworth 滤波器阶数 butter_lowpass_filter 函数先算 nyquist = 0.5 * fs,fs=1 时即 0.5 normal_cutoff = cutoff / nyquist 把绝对截止转成归一化值 b, a = butter(...) 生成数字滤波器系数并打印 y = lfilter(b, a, data) 对收盘价序列做双向滤波输出 外汇与贵金属属高风险品种,季节性与滤波结论均基于历史样本,实盘可能失效,请先在 MT5 用 ONNX 模型做前向验证再决定是否跟参。
# Low-pass filter parameters cutoff_frequency = class="num">0.01 # Cutoff frequency as a proportion of the Nyquist frequency order = class="num">4 # Apply the low-pass filter def butter_lowpass_filter(data, cutoff, fs, order): nyquist = class="num">0.5 * fs normal_cutoff = cutoff / nyquist b, a = butter(order, normal_cutoff, btype=&class="macro">#x27;low&class="macro">#x27;, analog=False) print("Filter coefficients - b:", b) print("Filter coefficients - a:", a) y = lfilter(b, a, data) class="kw">return y filtered_data_low = butter_lowpass_filter(df2[&class="macro">#x27;close&class="macro">#x27;], cutoff_frequency, fs=class="num">1, order=order) RMSE : class="num">0.0010798043714784716 MSE : class="num">1.165977480664017e-06 R2 score : class="num">0.8799146678247277 # Parámetros del filtro pasa bajo cutoff_frequency = class="num">0.01 # Frecuencia de corte en proporción a la frecuencia de Nyquist order = class="num">4 RMSE : class="num">0.0010228999869332884 MSE : class="num">1.0463243832681218e-06 R2 score : class="num">0.8922378749062259 cutoff_frequency = class="num">0.1 # Frecuencia de corte en proporción a la frecuencia de Nyquist order = class="num">2 RMSE : class="num">0.0010899163515744447 MSE : class="num">1.1879176534293484e-06 R2 score : class="num">0.8775550550819025
◍ 用八年二月数据看季节波动是否真实存在
取 2015 年至 2023 年 2 月这一时间段,把对应周次的价格数据叠到同一张图上观察。图上没有出现一条水平的“总和线”,各条年度曲线之间始终存在间隔——这说明标的全年持续交易、价格自然波动,二月窗口内的走势并非随机抹平。 从这段样本看,二月存在可辨识的趋势倾向,而非纯噪声。也正因全年连续交易会混入跨年跳空,下一步要把各年度二月数据单独按年连接,并引入过滤器:挡掉如 2022 年最后一天到 2023 年 2 月首日的极高高频传递,避免 AI 在训练周五收盘价与周一开盘价时学到这种断裂跳变,转而逼近更平滑的月度结构。 可立即验证:脚本 Download_seasonalities_1h_v2.py 能拉取单一货币对全量小时数据,febs.zip 为已抽取的二月切片,draw_with_sum.py 负责绘图叠加。外汇与贵金属属高风险品种,季节规律只代表历史概率倾向,实盘须自行回测确认。