数据科学与机器学习(第四十部分):斐波那契回调位在机器学习中的应用·综合运用
(3/3)·前面铺垫了数列本源与特征工程,这一篇直接上策略测试器看模型到底能不能跑出概率优势
把随机森林塞进EA跑样本外验证
做这类斐波那契+机器学习的EA,第一步是把训练好的ONNX模型当资源挂进来,分类器和回归器各一份,再引一个随机森林库去加载它们。训练时用过的lookahead_window和lookback_window必须原样搬进EA,这两个值直接决定持仓用几根K线平掉。 分类器模型在当前周期走过lookahead_window根K线后平仓,回归器则走lookback_window根K线平仓,逻辑和Python里造目标变量时一致。原文训练数据取自2005-01-01至2023-01-01,样本外测试用的是2023全年,回归模型在样本外胜率达到57.42%,表现相对更稳。 人工画斐波那契常凭感觉定高低点区间,没有清晰规则,容易自我误导。机器学习版强制用回溯/前瞻窗口把规律固化,假设模型已在指定窗口上学到了价格回撤规律,EA直接开仓并按K线数持有即可,不必等趋势确认信号——那往往已到末端。 为了实用,我把回归模型连续输出转成了二元信号,避开手动交易滞后开仓的坑。想深挖斐波那契在ML目标构建里的有效性,重点就是优化前瞻与回溯窗口这两个参数。
class="macro">#resource "\Files\EURUSD.PERIOD_H4.Fibonnacitarg-RFC.onnx" as class="type">uchar rfc_onnx[] class="macro">#resource "\Files\EURUSD.PERIOD_H4.Fibonnacitarg-RFR.onnx" as class="type">uchar rfr_onnx[] class="macro">#include <Random Forest.mqh> CRandomForestClassifier rfc; CRandomForestRegressor rfr; input group "Models configs"; input target_var_type fib_target = CLASSIFIER; class=class="str">"cmt">//Model type input class="type">int lookahead_window = class="num">5; input class="type">int lookback_window = class="num">10; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- Setting the symbol and timeframe if (!MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_DEBUG)) if (!ChartSetSymbolPeriod(class="num">0, symbol_, timeframe_)) { printf("%s failed to set symbol %s and timeframe %s",__FUNCTION__,symbol_,EnumToString(timeframe_)); class="kw">return INIT_FAILED; } class=class="str">"cmt">//--- m_trade.SetExpertMagicNumber(magic_number); m_trade.SetDeviationInPoints(slippage); m_trade.SetMarginMode(); m_trade.SetTypeFillingBySymbol(Symbol()); class=class="str">"cmt">//--- class="kw">switch(fib_target) { case REGRESSOR: if (!rfr.Init(rfr_onnx)) { printf("%s failed to initialize the random forest regressor",__FUNCTION__); class="kw">return INIT_FAILED; } break; case CLASSIFIER: if (!rfc.Init(rfc_onnx)) { printf("%s failed to initialize the random forest classifier",__FUNCTION__); class="kw">return INIT_FAILED; } break; } class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); }
「把模型信号接进 OnTick 实盘逻辑」
EA 的核心调度落在 OnTick:先用 isNewBar 拦掉旧柱的重复触发,只在每根 K 线开盘后跑一次推理,避免同一根 bar 内反复开仓刷手续费。 特征向量 x 取前一根完结 bar 的 O/H/L/C 四个值,用 iOpen/iHigh/iLow/iClose 带参数 1 拉取。这个输入维度很轻,适合在 MT5 实盘里低延迟跑随机森林类模型。 fib_target 切换两种模式:REGRESSOR 下用 rfr.predict 出斐波那契预测值,若预测值大于当前收盘价(参数 0)则 signal=1 偏多,否则 signal=0 偏空;CLASSIFIER 则直接取 rfc.predict(x).cls 的类别做信号。外汇与贵金属波动剧烈,信号仅代表概率倾向,不等于方向必现。 下单前用 SymbolInfoTick 取实时 ask/bid,volume_ 取 SYMBOL_VOLUME_MIN 做最小手数。signal==1 且无双向持仓时 m_trade.Buy 市价多;signal==0 同理 m_trade.Sell。CloseTradeAfterTime 按训练周期换算秒数平仓:分类器用 lookahead_window,回归器用 lookback_window,这是把样本外偏移锁死在可控时间窗里的关键。
class="type">void OnTick() { class=class="str">"cmt">//--- Getting signals from the model if (!isNewBar()) class="kw">return; vector x = { iOpen(Symbol(), Period(), class="num">1), iHigh(Symbol(), Period(), class="num">1), iLow(Symbol(), Period(), class="num">1), iClose(Symbol(), Period(), class="num">1) }; class="type">long signal = class="num">0; class="kw">switch(fib_target) { case REGRESSOR: { class="type">class="kw">double pred_fib = rfr.predict(x); signal = pred_fib>iClose(Symbol(), Period(), class="num">0)?class="num">1:class="num">0; class=class="str">"cmt">//If the predicted fibonacci is greater than the current close price, thats bullish otherwise thats bearish signal } break; case CLASSIFIER: signal = rfc.predict(x).cls; break; } class=class="str">"cmt">//--- Trading based on the signals received from the model class="type">MqlTick ticks; if (!SymbolInfoTick(Symbol(), ticks)) { printf("Failed to obtain ticks information, Error = %d",GetLastError()); class="kw">return; } class="type">class="kw">double volume_ = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN); if (signal == class="num">1) { if (!PosExists(POSITION_TYPE_BUY) && !PosExists(POSITION_TYPE_SELL)) m_trade.Buy(volume_, Symbol(), ticks.ask); } if (signal == class="num">0) { if (!PosExists(POSITION_TYPE_SELL) && !PosExists(POSITION_TYPE_BUY)) m_trade.Sell(volume_, Symbol(), ticks.bid); } class=class="str">"cmt">//--- Closing trades class="kw">switch(fib_target) { case CLASSIFIER: CloseTradeAfterTime((Timeframe2Minutes(Period())*lookahead_window)*class="num">60); class=class="str">"cmt">//Close the trade after a certain lookahead and according the the trained timeframe break; case REGRESSOR: CloseTradeAfterTime((Timeframe2Minutes(Period())*lookback_window)*class="num">60); class=class="str">"cmt">//Close the trade after a certain lookahead and according the the trained timeframe
◍ 预测斐波那契与现价交叉判定信号
这段逻辑收口在一个条件赋值上:把前面循环算出的预测斐波那契值 pred_fib 和当前 K 线收盘价做比较。若 pred_fib 大于 iClose(Symbol(), Period(), 0) 返回的即时收盘价,signal 置 1,视为偏多信号;否则置 0,视为偏空信号。 外汇与贵金属市场受杠杆与跳空影响,这类基于历史回看窗口的线性外推信号只在趋势连续时概率占优,震荡段假信号会明显增多,实盘前务必在 MT5 策略测试器用至少 3 个月 tick 数据回测。 下方代码就是该判定的原文实现,循环 break 后直接一句话完成多空标记,没有额外平滑处理。
break; } } signal = pred_fib>iClose(Symbol(), Period(), class="num">0)?class="num">1:class="num">0; class=class="str">"cmt">//If the predicted Fibonacci is greater than the current close price, that&class="macro">#x27;s bullish otherwise that&class="macro">#x27;s bearish signal
画得少,看得清
回归测试里,只用 OHLC 四个原始字段喂给随机森林,模型在斐波那契水平上的判别表现明显甩开随机猜测,这说明简单输入也能榨出结构信息。 当前这套框架还没吃满特征维度,把指标数值和策略确认信号补进训练集,或换一组斐波那契位做实验,才可能抓到更复杂的走势。 股票与指数市场在长牛里的规律回调、日线这种低噪音周期,都是更值得拿 ONNX 模型去验的场子;外汇和贵金属波动更野,直接上实盘前先在 MT5 用 Experts\Fibonacci AI based.mq5 跑一遍回测。 附件里的 Random Forest.mqh 和 Python 脚本已经把训练到部署的链路铺好了,改两个 csv 就能复现,剩下的只是调特征和周期。