数据科学与机器学习(第四十部分):斐波那契回调位在机器学习中的应用·进阶篇
(2/3)· 跳过玄学画线,直接看斐波那契水平怎么变成可训练的样本标签
用回看窗口算斐波那契基准线
把收盘价序列丢进回看窗口,就能得到一条随行情滑动的斐波那契基准线。下面这段代码用 10 根 K 线的滚动高低点,按 0.618 比例反推阻力参考位:窗口内最高价减去(最高价-最低价)×0.618。 high = price.rolling(lookback_window).max() low = price.rolling(lookback_window).min() return high - (high - low) * fib_level 这三行是核心:rolling(10) 取每根 bar 前 10 根的最高/最低,再套 0.618 黄金比。实盘里黄金 XAUUSD 的 15 分钟图,用 10 根回看常能在趋势中段给出贴近价格的假突破防线。 调用时 lookback_window=10、fib_level=0.618 直接挂到 Close 上,生成的新列叫 Fibonacci Level。记得 dropna(),因为滚动计算前 9 根没有完整窗口会出 NaN。外汇和贵金属杠杆高,这条线只是概率参考,破位不代表必反转。
df["Fib signals"] = create_fib_clftargetvar(price=df["Close"], lookback_window=class="num">10, lookahead_window=class="num">5, fib_level=class="num">0.618) df.dropna(inplace=True) # drop nan(s) caused by the shifting operation df def create_fib_regtargetvar(price: pd.Series, lookback_window: class="type">int=class="num">10, fib_level: class="type">float=class="num">0.618): """ This function helps us in calculating the target variable based on fibonacci breakthroughs given a price price: Can be close, open, high, low """ high = price.rolling(lookback_window).max() low = price.rolling(lookback_window).min() class="kw">return high - (high - low) * fib_level df["Fibonacci Level"] = create_fib_regtargetvar(price=df["Close"], lookback_window=class="num">10, fib_level=class="num">0.618) df.dropna(inplace=True) df.head(class="num">5)
「用随机森林啃斐波那契信号」
先把目标变量定为「Fib signals」分类标签,用随机森林直接喂 OHLC 数据训练。决策树系模型本不需要特征缩放,但开盘高低收都是连续量且随行情漂移、容易出异常值,所以管线里塞了个 RobustScaler 压住离群点。 切数据按 test_size=0.3、random_state=42、shuffle=False 来分,避免未来信息泄漏;类别权重走 balanced 计算,塞进 RandomForestClassifier(n_estimators=100,max_depth=10)。训练集分类报告里 accuracy 0.61、宏平均 f1 0.60,看着还行。 测试集表现明显塌了,说明模型没学到训练分布外的规律。根子可能在两点:只拿 OHLC 做特征太单薄,以及目标变量只用下一根 K 线判趋势,忽略了中间 K 线就捅穿斐波那契位的情况。外汇和贵金属这种高波动品种,过拟合信号在实盘大概率翻车,先留着模型别急着弃。 下一步把管线导成 ONNX,MT5 里就能外部调用做突破了。下面这段是训练加评估的原样代码,逐行看比读说明快。
from sklearn.ensemble class="kw">import RandomForestClassifier from sklearn.model_selection class="kw">import train_test_split from sklearn.metrics class="kw">import classification_report from sklearn.utils.class_weight class="kw">import compute_class_weight from sklearn.pipeline class="kw">import Pipeline from sklearn.preprocessing class="kw">import RobustScaler X = df.drop(columns=[ "Fib signals" ]) y = df["Fib signals"] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=class="num">0.3, random_state=class="num">42, shuffle=False) class_weights = compute_class_weight(&class="macro">#x27;balanced&class="macro">#x27;, classes=np.unique(y_train), y=y_train) weight_dict = dict(zip(np.unique(y_train), class_weights)) model = RandomForestClassifier(n_estimators=class="num">100, min_samples_split=class="num">2, max_depth=class="num">10, class_weight=weight_dict, random_state=class="num">42 ) clf_pipeline = Pipeline(steps=[ ("scaler", RobustScaler()), ("rfc", model) ]) clf_pipeline.fit(X_train, y_train) y_train_pred = clf_pipeline.predict(X_train) print("Train Classification report\n",classification_report(y_train, y_train_pred)) y_test_pred = clf_pipeline.predict(X_test) print("Test Classification report\n",classification_report(y_test, y_test_pred))
◍ 分类报告暴露的泛化短板
上面这段输出是某随机森林管道在 8495 个样本上的分类评估报告。三类标签(-1.0 / 0.0 / 1.0)对应的精确率分别是 0.22、0.38、0.42,宏平均 F1 仅 0.32,加权 F1 为 0.33,整体 accuracy 落在 0.35。
单看 1.0 类(倾向多头)召回有 0.27、样本量 3504,而 0.0 类(震荡)精确率冲到 0.60 但召回仅 0.46,说明模型对无趋势段的判定偏保守,容易把震荡误判为方向。外汇与贵金属杠杆高、滑点随机,这种三成出头的命中率在实盘直接跟单大概率会磨损本金。
把训练好的管道落地到 MT5 前,需要先转成 ONNX 以便推理引擎调用。下面这段 Python 负责把 sklearn 管道序列化,注意 target_opset=13 是多数 MT5 插件能解析的最低兼容版本之一。
转换完的文件名按 {symbol}.{timeframe}.Fibonnacitarg-RFC.onnx 规则生成,你打开对应品种周期目录就能看到。建议先在 EURUSD M5 上跑通再换 XAUUSD,贵金属跳空会让输入特征分布偏移、推理置信度下降。
class="kw">import skl2onnx from skl2onnx class="kw">import convert_sklearn from skl2onnx.common.data_types class="kw">import FloatTensorType # Define the initial type of the model’s input initial_type = [(&class="macro">#x27;input&class="macro">#x27;, FloatTensorType([None, X_train.shape[class="num">1]]))] # Convert the pipeline to ONNX onnx_model = convert_sklearn(clf_pipeline, initial_types=initial_type, target_opset=class="num">13) # Save the ONNX model to a file with open(f"{symbol}.{timeframe}.Fibonnacitarg-RFC.onnx", "wb") as f: f.write(onnx_model.SerializeToString())
用随机森林回归预测斐波那契目标位
把分类换成回归,思路完全一样,只是把目标变量从方向改成具体的斐波那契层级数值。数据照旧切分,但注意这里 shuffle=False,保留时间序列顺序,避免未来信息泄漏。 随机森林回归用 100 棵树、最大深度 10、最小切分样本 2,套一层 RobustScaler 做鲁棒缩放。训练集 R² 冲到 0.999,测试集 0.9566——单看决定系数不能下全军令状,但测试集这个表现说明泛化倾向尚可,过拟合概率偏低。 练完别只停在 Python 里。转成 ONNX 丢给 MT5 外部调用,实盘里两个模型(分类+回归)一起跑,你能直接拿到「是否触发」加「大概打到哪一层」的双输出。外汇和贵金属波动受事件驱动,模型信号仅作概率参考,实盘仍属高风险。 下面这段就是把管线存成 ONNX 的核心代码,文件名按品种和周期拼,方便小布盯盘时按符号加载。
from sklearn.ensemble class="kw">import RandomForestRegressor from sklearn.metrics class="kw">import r2_score X = df.drop(columns=[ "Fibonacci Level" ]) y = df["Fibonacci Level"] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=class="num">0.3, random_state=class="num">42, shuffle=False) model = RandomForestRegressor(n_estimators=class="num">100, min_samples_split=class="num">2, max_depth=class="num">10, random_state=class="num">42 ) reg_pipeline = Pipeline(steps=[ ("scaler", RobustScaler()), ("rfr", model) ]) reg_pipeline.fit(X_train, y_train) y_train_pred = reg_pipeline.predict(X_train) print("Train accuracy score:",r2_score(y_train, y_train_pred)) y_test_pred = reg_pipeline.predict(X_test) print("Test accuracy score:",r2_score(y_test, y_test_pred)) # Define the initial type of the model’s input initial_type = [(&class="macro">#x27;input&class="macro">#x27;, FloatTensorType([None, X_train.shape[class="num">1]]))] # Convert the pipeline to ONNX onnx_model = convert_sklearn(reg_pipeline, initial_types=initial_type, target_opset=class="num">13) # Save the ONNX model to a file with open(f"{symbol}.{timeframe}.Fibonnacitarg-RFR.onnx", "wb") as f: f.write(onnx_model.SerializeToString())