在 MQL5 中实现广义赫斯特指数和方差比检验·综合运用
◍ 用 Z 分数把价格压回零轴附近
Z 分数(z-score)算的是价格偏离其均值多少个标准差,本质是把行情做归一化,让指标在 0 上下波动而不是跟着绝对价位跑。把这段逻辑写成指标后,曲线形态会比裸价更贴近正态分布,方便用统计阈值而不是肉眼判断极值。
当 Z 值大幅脱离 0、超过按历史波动定的阈值,就有可能出现均值回复机会:极负倾向做多,极正倾向做空,所以需要一负一正两个阈值分别管入场。出场可以用对称思路——空头等 Z 回到 0 附近平掉,多头从极端负值弹回 0 时也退场,不另设止损止盈。
下面这段 MQL5 是 Zscore 指标核心:默认周期 10,独立子窗口画一条蓝线。注意 OnCalculate 里用 vector 承接区间价格再做标准化,改 z_period 会直接挪动 PLOT_DRAW_BEGIN,新手可先调这个参数看曲线灵敏度。外汇与贵金属杠杆高,这类统计信号失效时回撤可能很快,实盘前务必在 MT5 用历史数据验证。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Zscore.mq5 | class=class="str">"cmt">//| Copyright class="num">2023, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2023, MetaQuotes Ltd." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#include<VectorMatrixTools.mqh> class="macro">#class="kw">property indicator_separate_window class="macro">#class="kw">property indicator_buffers class="num">1 class="macro">#class="kw">property indicator_plots class="num">1 class=class="str">"cmt">//--- plot Zscore class="macro">#class="kw">property indicator_label1 "Zscore" class="macro">#class="kw">property indicator_type1 DRAW_LINE class="macro">#class="kw">property indicator_color1 clrBlue class="macro">#class="kw">property indicator_style1 STYLE_SOLID class="macro">#class="kw">property indicator_width1 class="num">1 class=class="str">"cmt">//--- class="kw">input parameters class="kw">input class="type">int z_period = class="num">10; class=class="str">"cmt">//--- indicator buffers class="type">class="kw">double ZscoreBuffer[]; vector vct; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Custom indicator initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- indicator buffers mapping SetIndexBuffer(class="num">0,ZscoreBuffer,INDICATOR_DATA); class=class="str">"cmt">//---- PlotIndexSetDouble(class="num">0,PLOT_EMPTY_VALUE,class="num">0); class=class="str">"cmt">//--- PlotIndexSetInteger(class="num">0,PLOT_DRAW_BEGIN,z_period-class="num">1); class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Custom indicator iteration function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnCalculate(class="kw">const class="type">int rates_total, class="kw">const class="type">int prev_calculated, class="kw">const class="type">class="kw">datetime &time[],
Z分数计算与均值回归EA的参数骨架
这段自定义指标接口把 OHLC、成交量、点差数组以引用方式传入,对应 MT5 的 OnCalculate 标准签名。若可用 K 线数 rates_total 小于回看窗口 z_period,直接打印 Insufficient history 并返回 -1,避免后续除零或空向量运算。 循环里用 vct.Init 按 z_period 长度截取 close 子区间,当向量尺寸等于窗口才计算 ZscoreBuffer[i] = (close[i] - vct.Mean()) / vct.Std(),否则写 0.0。注意 limit 在首次计算时设为 z_period-1,后续用 prev_calculated-1 增量刷新,减少重复遍历。 EA 主体通过 #resource 引入编译好的 Zscore.ex5,输入参数给出明确可改点:PeriodLength=10 为 Z 分数回看周期,LongOpenLevel=-2.0 表示价格偏离均值超 2 个标准差时倾向开多,ShortOpenLevel=2.0 对称;平仓阈值收窄到 ±0.5。LotsSize=0.01、SlippagePoints=10、MagicNumber=123456 均为可直抄的默认档。 外汇与贵金属杠杆高,均值回归在趋势市会连续触发反向单,实盘前务必在 MT5 策略测试器用对应品种历史数据验证阈值灵敏度。
class="kw">const class="type">class="kw">double &open[], class="kw">const class="type">class="kw">double &high[], class="kw">const class="type">class="kw">double &low[], class="kw">const class="type">class="kw">double &close[], class="kw">const class="type">long &tick_volume[], class="kw">const class="type">long &volume[], class="kw">const class="type">int &spread[]) { class=class="str">"cmt">//--- if(rates_total<z_period) { Print("Insufficient history"); class="kw">return -class="num">1; } class=class="str">"cmt">//--- class="type">int limit; if(prev_calculated<=class="num">0) limit = z_period - class="num">1; else limit = prev_calculated - class="num">1; class=class="str">"cmt">//--- for(class="type">int i = limit; i<rates_total; i++) { vct.Init(class="type">ulong(z_period),assign,close,class="type">ulong(i-(z_period-class="num">1)),i,class="num">1); if(vct.Size()==class="type">ulong(z_period)) ZscoreBuffer[i] = (close[i] - vct.Mean())/vct.Std(); else ZscoreBuffer[i]=class="num">0.0; } class=class="str">"cmt">//--- class="kw">return value of prev_calculated for next call class="kw">return(rates_total); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| MeanReversion.mq5 | class=class="str">"cmt">//| Copyright class="num">2024, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2024, MetaQuotes Ltd." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#resource "\Indicators\Zscore.ex5" class="macro">#include<ExpertTools.mqh> class=class="str">"cmt">//---Input parameters class="kw">input class="type">int PeriodLength = class="num">10; class="kw">input class="type">class="kw">double LotsSize = class="num">0.01; class="kw">input class="type">class="kw">double LongOpenLevel = -class="num">2.0; class="kw">input class="type">class="kw">double ShortOpenLevel = class="num">2.0; class="kw">input class="type">class="kw">double LongCloseLevel = -class="num">0.5; class="kw">input class="type">class="kw">double ShortCloseLevel = class="num">0.5; class="kw">input class="type">ulong SlippagePoints = class="num">10; class="kw">input class="type">ulong MagicNumber = class="num">123456; class=class="str">"cmt">//---
「EA 骨架里怎么挂 Z-score 指标」
这段 MT5 专家顾问的初始化与 tick 逻辑,核心是把自编的 Zscore.ex5 指标句柄在安全重试机制下挂上,再在每笔报价里取信号、管持仓。外汇与贵金属杠杆高,回测通过不代表实盘能跑赢,任何信号都只是概率倾向。 OnInit 先卡死 PeriodLength 小于 2 的非法参数,直接返回 INIT_FAILED;随后调 InitializeIndicator(),失败也同样中断。OnTick 里用 GetSignal() 拿信号,若同魔法码同品种已有持仓就只在信号归零时平仓,否则开新仓——这是典型的单品种单策略互斥结构。 InitializeIndicator 用 while 循环最多重试 10 次去 iCustom 加载指标,句柄无效且剩余次数大于 0 就继续。注意原文判断写的是 if(try<0) 才报失败,但循环条件是 try>0,所以 try 最小到 0 就停,实际走到 try<0 的分支在逻辑上几乎不会触发,复制代码时建议改成 try<=0 才更严谨。
class="type">int indi_handle; class=class="str">"cmt">//--- class="type">class="kw">double zscore[class="num">2]; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- if(PeriodLength<class="num">2) { Print("Invalid parameter value for PeriodLength"); class="kw">return INIT_FAILED; } class=class="str">"cmt">//--- if(!InitializeIndicator()) class="kw">return INIT_FAILED; class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(class="kw">const class="type">int reason) { class=class="str">"cmt">//--- } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- class="type">int signal = GetSignal(); class=class="str">"cmt">//--- if(SumMarketOrders(MagicNumber,_Symbol,-class="num">1)) { if(signal==class="num">0) CloseAll(MagicNumber,_Symbol,-class="num">1); class="kw">return; } else OpenPosition(signal); class=class="str">"cmt">//--- } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Initialize indicator | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool InitializeIndicator(class="type">void) { indi_handle = INVALID_HANDLE; class=class="str">"cmt">//--- class="type">int try = class="num">10; class=class="str">"cmt">//--- while(indi_handle == INVALID_HANDLE && try>class="num">0) { indi_handle = (indi_handle==INVALID_HANDLE)?iCustom(NULL,PERIOD_CURRENT,"::Indicators\\Zscore.ex5",PeriodLength):indi_handle; try--; } class=class="str">"cmt">//--- if(try<class="num">0) { Print("Failed to initialize Zscore indicator "); class="kw">return false; } class=class="str">"cmt">//--- class="kw">return true; }
◍ 信号函数与下单闸门的实现细节
把 Z-Score 指标缓冲读进数组后,真正的交易逻辑其实就藏在两段函数里。GetSignal 负责判定穿越,OpenPosition 负责拦掉重复开仓并发送订单,两者解耦后回测和实盘都能直接复用。 GetSignal 默认取 sig_shift=1,也就是用倒数第二根和倒数第一根做比较。CopyBuffer 只拉 2 根(sig_shift 起、长度 2),若返回值小于 2 说明拷贝失败,直接 Print 错误并返回 INT_MIN,避免脏信号进场。 进场判定很直白:上一根 zscore 低于 LongOpenLevel 且当前根上穿,返回 1(多);上一根高于 ShortOpenLevel 且当前根下穿,返回 -1(空)。平仓判定则看 LongCloseLevel / ShortCloseLevel 的反向穿越,返回 0。其余情况一律 INT_MIN,表示「这根不动」。 OpenPosition 先调 LastOrderOpenTime 比对本周期 K 线开盘时间 iTime(NULL,0,0),若同根已有同魔术码订单就 false 退出——这根闸门能挡掉一根 K 线内反复追单。确认无单后,sig=1 发 ORDER_TYPE_BUY,sig=-1 发 ORDER_TYPE_SELL,手数和滑点由 LotsSize、SlippagePoints 控制。 外汇与贵金属杠杆高、滑点跳空频繁,这套闸门只是过滤重复信号,不保证胜率;上 MT5 把 LongOpenLevel 等阈值打印出来核对,再跑一轮历史回放更稳妥。
class="type">int GetSignal(class="kw">const class="type">int sig_shift=class="num">1) { class=class="str">"cmt">//--- if( CopyBuffer(indi_handle,class="type">int(class="num">0),sig_shift,class="type">int(class="num">2),zscore)<class="num">2) { Print(__FUNCTION__," Error copying from indicator buffers: ", GetLastError()); class="kw">return INT_MIN; } class=class="str">"cmt">//--- if(zscore[class="num">1]<LongOpenLevel && zscore[class="num">0]>LongOpenLevel) class="kw">return (class="num">1); class=class="str">"cmt">//--- if(zscore[class="num">1]>ShortOpenLevel && zscore[class="num">0]<ShortOpenLevel) class="kw">return (-class="num">1); class=class="str">"cmt">//--- if((zscore[class="num">1]>LongCloseLevel && zscore[class="num">0]<LongCloseLevel) || (zscore[class="num">1]<ShortCloseLevel && zscore[class="num">0]>ShortCloseLevel)) class="kw">return (class="num">0); class=class="str">"cmt">//--- class="kw">return INT_MIN; class=class="str">"cmt">//--- } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Go class="type">long or class="type">short | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool OpenPosition(class="kw">const class="type">int sig) { class="type">long pid; class=class="str">"cmt">//--- if(LastOrderOpenTime(pid,NULL,MagicNumber)>=iTime(NULL,class="num">0,class="num">0)) class="kw">return false; class=class="str">"cmt">//--- if(sig==class="num">1) class="kw">return SendOrder(_Symbol,class="num">0,ORDER_TYPE_BUY,LotsSize,SlippagePoints,class="num">0,class="num">0,NULL,MagicNumber); else if(sig==-class="num">1) class="kw">return SendOrder(_Symbol,class="num">0,ORDER_TYPE_SELL,LotsSize,SlippagePoints,class="num">0,class="num">0,NULL,MagicNumber); class=class="str">"cmt">//--- class="kw">return false; }
用半衰期判断该不该做均值回归
半衰期衡量价格偏离历史均值后,回到均值一半位置所需的时间。公式上 HL = -log(2) / lambda,lambda 是回归速度:lambda 越负、绝对值越大,半衰期越短,回归越快;lambda 为正就别碰均值回归,连接近零的负 lambda 也不建议上,因为那代表半衰期长到策略基本无效。 实盘筛选时,把 GHE、VRT 和半衰期三件套跑在 EURUSD、GBPUSD、USDCHF、USDJPY 的日线样本上,USDCHF 在所选日期内的测试结果最理想,于是用它优化 EA。有趣的是,优化出来的最佳 Zscore 周期和计算出的半衰期非常接近,这至少说明历史样本里均值回归特征自洽。 但样本外测试表现并不好,外汇和贵金属本身高风险,市场状态漂移会让优化期学到的特征失效。需要更动态的进场退出阈值来跟住基础波动变化,或者把工具搬去价差配对交易,用两个协整品种的价差算 Zscore 而非单序列。 下面这段 MQL5 是半衰期的核心实现,思路是对价格序列做差分后回归,lambda 取回归 beta,再用 -log(2)/lambda 得出结果: //+------------------------------------------------------------------+
| // | Calculate Half life of Mean reversion |
|---|
//+------------------------------------------------------------------+ double mean_reversion_half_life(vector &data, double &lambda) { //--- vector yy,zz; matrix xx; //--- OLS ols_reg; //--- yy.Init(data.Size()-1,slice,data,1,data.Size()-1,1); //--- zz.Init(data.Size()-1,slice,data,0,data.Size()-2,1); //---
| if(!xx.Init(zz.Size(),2) | !xx.Col(zz,0) | !xx.Col(vector::Ones(zz.Size()),1) | !ols_reg.Fit(yy-zz,xx)) |
|---|
{ Print(__FUNCTION__," Error in calculating half life of mean reversion ", GetLastError()); return 0; } //--- vector params = ols_reg.ModelParameters(); lambda = params[0]; //--- return (-log(2)/lambda); //--- } 逐行拆解:yy 取原序列从第 1 位到末尾的子向量,zz 取第 0 位到倒数第 2 位的滞后一期子向量;xx 是两列矩阵,第一列放 zz,第二列放全 1 做截距;ols_reg.Fit(yy-zz, xx) 实际是对「当期减前期」的差分序列做带截距回归;params[0] 即 beta 也就是 lambda;最后 -log(2)/lambda 直接出半衰期。 配套测试脚本头部长这样,改 Symbols 和起止日期就能换品种扫一遍: //+------------------------------------------------------------------+
| // | SymbolTester.mq5 |
|---|---|
| // | Copyright 2024, MetaQuotes Ltd. |
| // | [MQL5官方文档] |
//+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "[MQL5官方文档] #property version "1.00" #property script_show_inputs #include<MeanReversionUtilities.mqh> #include<GHE.mqh> #include<VRT.mqh> //--- input parameters input string Symbols = "EURUSD,GBPUSD,USDCHF,USDJPY";//Comma separated list of symbols to test input ENUM_TIMEFRAMES TimeFrame = PERIOD_D1; input datetime StartDate=D'2020.01.02 00:00:01'; input datetime StopDate=D'2015.01.18 00:00:01'; 注意 StopDate 写在了 StartDate 之前,实跑前先把这两个日期改对,否则序列取出来是空的。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//|Calculate Half life of Mean reversion | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double mean_reversion_half_life(vector &data, class="type">class="kw">double &lambda) { class=class="str">"cmt">//--- vector yy,zz; matrix xx; class=class="str">"cmt">//--- OLS ols_reg; class=class="str">"cmt">//--- yy.Init(data.Size()-class="num">1,slice,data,class="num">1,data.Size()-class="num">1,class="num">1); class=class="str">"cmt">//--- zz.Init(data.Size()-class="num">1,slice,data,class="num">0,data.Size()-class="num">2,class="num">1); class=class="str">"cmt">//--- if(!xx.Init(zz.Size(),class="num">2) || !xx.Col(zz,class="num">0) || !xx.Col(vector::Ones(zz.Size()),class="num">1) || !ols_reg.Fit(yy-zz,xx)) { Print(__FUNCTION__," Error in calculating half life of mean reversion ", GetLastError()); class="kw">return class="num">0; } class=class="str">"cmt">//--- vector params = ols_reg.ModelParameters(); lambda = params[class="num">0]; class=class="str">"cmt">//--- class="kw">return (-log(class="num">2)/lambda); class=class="str">"cmt">//--- } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| SymbolTester.mq5 | class=class="str">"cmt">//| Copyright class="num">2024, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2024, MetaQuotes Ltd." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property script_show_inputs class="macro">#include<MeanReversionUtilities.mqh> class="macro">#include<GHE.mqh> class="macro">#include<VRT.mqh> class=class="str">"cmt">//--- class="kw">input parameters class="kw">input class="type">class="kw">string Symbols = "EURUSD,GBPUSD,USDCHF,USDJPY";class=class="str">"cmt">//Comma separated list of symbols to test class="kw">input ENUM_TIMEFRAMES TimeFrame = PERIOD_D1; class="kw">input class="type">class="kw">datetime StartDate=D&class="macro">#x27;class="num">2020.01.class="num">02 class="num">00:class="num">00:class="num">01&class="macro">#x27;; class="kw">input class="type">class="kw">datetime StopDate=D&class="macro">#x27;class="num">2015.01.class="num">18 class="num">00:class="num">00:class="num">01&class="macro">#x27;;
「把方差比和赫斯特塞进同一段脚本」
这段脚本把单品种的方差比检验(Variance Ratio)与广义赫斯特指数(GHE)跑在同一个 OnStart 里,省去来回切图表。输入参数里 Q_parameter=2 控制 GHE 的 q 阶矩,MinimumLag=2 与 MaximumLag=100 分别作为方差比检验的短、长滞后窗口,ApplyLogTransformation=true 会对收盘价先做对数变换再检验。 外层循环用 StringSplit 按逗号拆解 Symbols 列表,逐个品种取 Close 序列。若列表末尾带逗号,代码会 num_symbols-- 丢掉空串;若拆分后不足 1 个品种则直接 Print 报错退出,避免空跑。 每个品种先 CopyClose 拉数据,可选走 MathLog;随后两次调用 vrt.Vrt(prices, lag) —— 分别传 MinimumLag 与 MaximumLag,取出 vlower、vupper 两个 VRatio 值。接着 general_hurst 算 GHE,mean_reversion_half_life 算均值回复半衰期 hl 与衰减系数 lb,最后一行 Print 把 GHE、双边界方差比、HalfLife、Lambda 全部打印到日志。 复制时留意:StartDate/StopDate 与 TimeFrame 应在别处声明,原文未贴;若 StartDate<=StopDate 会触发「Invalid input」并 return,实际应保证起始索引大于终止索引(MT5 历史读取惯例)。外汇与贵金属属高杠杆品种,半衰期与方差比仅描述历史统计特征,样本外可能失效,勿直接当作方向依据。
class="kw">input class="type">int Q_parameter = class="num">2; class="kw">input class="type">int MinimumLag = class="num">2; class="kw">input class="type">int MaximumLag = class="num">100; class="kw">input class="type">bool ApplyLogTransformation = true; class=class="str">"cmt">//--- CVarianceRatio vrt; class="type">class="kw">double ghe,hl,lb,vlower,vupper; class="type">class="kw">double prices[]; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class=class="str">"cmt">//---Check Size class="kw">input value if(StartDate<=StopDate) { Print("Invalid class="kw">input for StartDater or StopDate"); class="kw">return; } class=class="str">"cmt">//---array for symbols class="type">class="kw">string symbols[]; class=class="str">"cmt">//---process list of symbols from user class="kw">input class="type">int num_symbols = StringSplit(Symbols,StringGetCharacter(",",class="num">0),symbols); class=class="str">"cmt">//---incase list contains ending comma if(symbols[num_symbols-class="num">1]=="") num_symbols--; class=class="str">"cmt">//---in case there are less than two symbols specified if(num_symbols<class="num">1) { Print("Invalid class="kw">input. Please list at least one symbol"); class="kw">return; } class=class="str">"cmt">//---loop through all paired combinations from list for(class="type">uint i=class="num">0; i<symbols.Size(); i++) { class=class="str">"cmt">//--- get prices for the pair of symbols if(CopyClose(symbols[i],TimeFrame,StartDate,StopDate,prices)<class="num">1) { Print("Failed to copy close prices ", ::GetLastError()); class="kw">return; } class=class="str">"cmt">//--- if(ApplyLogTransformation && !MathLog(prices)) { Print("Mathlog error ", GetLastError()); class="kw">return; } class=class="str">"cmt">//--- if(!vrt.Vrt(prices,MinimumLag)) class="kw">return; class=class="str">"cmt">//--- vlower = vrt.VRatio(); class=class="str">"cmt">//--- if(!vrt.Vrt(prices,MaximumLag)) class="kw">return; class=class="str">"cmt">//--- vupper = vrt.VRatio(); class=class="str">"cmt">//--- ghe = general_hurst(prices,Q_parameter,MinimumLag,MaximumLag); class=class="str">"cmt">//--- hl = mean_reversion_half_life(prices,lb); class=class="str">"cmt">//--- output the results Print(symbols[i], " GHE: ", DoubleToString(ghe)," | Vrt: ",DoubleToString(vlower)," ** ",DoubleToString(vupper)," | HalfLife ",DoubleToString(hl)," | Lambda: ",DoubleToString(lb)); } }
◍ USDCHF日线下的跨品种半衰期扫描
在 MT5 策略测试器里以 USDCHF 的 D1 周期跑 SymbolTester,能直接拿到一组跨品种协整特征数。下面四条日志是同一批次的输出,时间戳集中在 19:31:03 秒内,说明计算开销极低。 EURUSD 的 GHE 读数为 0.44755644,HalfLife 85.6 根 K 线,Lambda -0.008097;GBPUSD 的 HalfLife 拉长到 201.38,Lambda 仅 -0.00344199,均值回复更慢。USDCHF 自身 HalfLife 28.9 最短,Lambda -0.02397976 绝对值最大,日线级别回归倾向最强。USDJPY 的 Vrt 与另一乘积项分别为 0.99875744 与 1.06103587,HalfLife 132.66。 这些数字只描述历史样本的统计属性,不预示未来。外汇与贵金属杠杆高,实盘前务必用 MT5 自测一遍参数,别直接信别人贴的日志。
class="num">19:class="num">31:class="num">03.143 SymbolTester(USDCHF,D1) EURUSD GHE: class="num">0.44755644 | Vrt: class="num">0.97454284 ** class="num">0.61945905 | HalfLife class="num">85.60548208 | Lambda: -class="num">0.00809700 class="num">19:class="num">31:class="num">03.326 SymbolTester(USDCHF,D1) GBPUSD GHE: class="num">0.46304381 | Vrt: class="num">1.01218672 ** class="num">0.82086185 | HalfLife class="num">201.38001205 | Lambda: -class="num">0.00344199 class="num">19:class="num">31:class="num">03.509 SymbolTester(USDCHF,D1) USDCHF GHE: class="num">0.42689382 | Vrt: class="num">1.02233286 ** class="num">0.47888803 | HalfLife class="num">28.90550869 | Lambda: -class="num">0.02397976 class="num">19:class="num">31:class="num">03.694 SymbolTester(USDCHF,D1) USDJPY GHE: class="num">0.49198795 | Vrt: class="num">0.99875744 ** class="num">1.06103587 | HalfLife class="num">132.66433924 | Lambda: -class="num">0.00522482
画得少,看得清
把广义赫斯特指数、方差比检验和半衰期三件工具塞进 MT5,核心文件其实就那几个:GHE.mqh 装指数计算,VRT.mqh 封装方差比类,MeanReversionUtilities.mqh 里藏着半衰期函数,外加 SymbolTester.mq5 脚本可直接对交易品种跑均值回归探测。 真要验证,下 GHE.ex5(约 342 KB)挂到图表,切几个货币对和 XAUUSD 看 H 值落点;H 明显小于 0.5 的品种才倾向有均值回复特征,外汇与贵金属杠杆高、回撤可能超预期,别凭单一指标下重仓。 文件清单里 Zscore.mq5 才 2.68 KB,却撑起了 EA 的标准分监控——工具轻量,逻辑透明,剩下的只是你愿不愿意亲手跑一遍。