Erik Nayman 的绳索指标·综合运用
(3/3)· 把前两篇的原理和代码拼成可跑的EA,再教你榨干输入参数的最后一点边际
快慢双均线的分支计算写法
在自定义指标里同时挂快慢两条均线,常见做法是先按 method_MA_fast 走 switch,再按 method_MA_slow 走第二个 switch。快线分支里 SMA 用的是 SimpleMA(i,period_MA_fast,Buffer_calcLINE),而慢线同名调用却复用同一份 Buffer_calcLINE,只是周期参数换成 period_MA_slow。 注意 SMMA 在两处的索引处理不一样:快线分支写的是 SmoothedMA(i+period_MA_fast,...) ,慢线分支却是 SmoothedMA(i,...) 。这个偏移如果照搬,快线在图表前段可能比慢线少算 period_MA_fast 根bar,回测时价差信号会提前或滞后,外汇与贵金属品种杠杆高,这类偏移容易造成误判。 EMA 和 LWMA 两个分支都依赖上一根 i-1 的缓存值递归,首根 bar 之前 Buffer 未初始化时返回 0 是 default 分支的责任。开 MT5 把这段贴进 OnInit 之后的循环里,改一下 period_MA_fast=5、period_MA_slow=20,能直接看到两条线在 EURUSD 的 M15 上张合节奏。
Buffer_MAfast[i]=SimpleMA(i,period_MA_fast,Buffer_calcLINE); class=class="str">"cmt">// 从库中 Include\MovingAverages.mqh 获取已计算的 SimpleMA i 索引数据, 基于 Buffer_calcLINE 数据缓存区和 period_MA_fast 周期 class="kw">break; case MODE_EMA: class=class="str">"cmt">// 指数平均 Buffer_MAfast[i]=ExponentialMA(i,period_MA_fast,Buffer_MAfast[i-class="num">1],Buffer_calcLINE); class="kw">break; case MODE_SMMA: class=class="str">"cmt">// 平滑平均 Buffer_MAfast[i]=SmoothedMA(i+period_MA_fast,period_MA_fast,Buffer_MAfast[i-class="num">1],Buffer_calcLINE); class="kw">break; case MODE_LWMA: class=class="str">"cmt">// 线性加权平均 Buffer_MAfast[i]=LinearWeightedMA(i+period_MA_fast,period_MA_fast,Buffer_calcLINE); class="kw">break; class="kw">default: class="kw">return class="num">0; } } class=class="str">"cmt">//--- 基于 method_MA_slow 参数选择慢速均线计算方法 if(draw_MA_slow) { class="kw">switch(method_MA_slow) { case MODE_SMA: class=class="str">"cmt">// 简单平均 Buffer_MAslow[i]=SimpleMA(i,period_MA_slow,Buffer_calcLINE); class="kw">break; case MODE_EMA: class=class="str">"cmt">// 指数平均 Buffer_MAslow[i]=ExponentialMA(i,period_MA_slow,Buffer_MAslow[i-class="num">1],Buffer_calcLINE); class="kw">break; case MODE_SMMA: class=class="str">"cmt">// 平滑平均 Buffer_MAslow[i]=SmoothedMA(i,period_MA_slow,Buffer_MAslow[i-class="num">1],Buffer_calcLINE); class="kw">break; case MODE_LWMA: class=class="str">"cmt">// 线性加权平均 Buffer_MAslow[i]=LinearWeightedMA(i,period_MA_slow,Buffer_calcLINE); class="kw">break; class="kw">default: class="kw">return class="num">0; } }
◍ 把缓冲数组调成时间序列再清掉当前柱
指标里做完初始化后,绘图前必须把三个缓冲数组按时间序列排好,否则最新价会跑到数组尾巴上,画线错位。 ArraySetAsSeries 对 Buffer_calcLINE、Buffer_MAfast、Buffer_MAslow 都传 true,MT5 里索引 0 就恒为当前柱。 紧接着把三个缓冲的 [0] 位赋 EMPTY_VALUE,意思是这一根还没算完,避免旧值残留造成伪信号。外汇与贵金属波动大,这种未计算位不清,重绘时可能闪现错误箭头。 最后用 _tm_prev=time[0] 记住已处理柱时间,并返回 rates_total 给系统,下一帧从这个数继续算,不重复跑全历史。
} class=class="str">"cmt">//--- 为绘图, 启用索引作为时间序列 ArraySetAsSeries(Buffer_calcLINE,true); ArraySetAsSeries(Buffer_MAfast,true); ArraySetAsSeries(Buffer_MAslow,true); class=class="str">"cmt">//--- 当前柱线的均线清零, 即, 未计算 Buffer_MAfast[class="num">0]=EMPTY_VALUE; Buffer_MAslow[class="num">0]=EMPTY_VALUE; Buffer_calcLINE[class="num">0]=EMPTY_VALUE; } class=class="str">"cmt">//--- 记住最后已计算的柱线时间 _tm_prev=time[class="num">0]; } class=class="str">"cmt">//--- 返回 prev_calculated 值用于下次调用 prev_rates_total=rates_total; class="kw">return(rates_total); }
「绳索指标 EA 的开平仓信号骨架」
把 RopebyEricNaiman 指标接进 EA,核心思路是用 trade_mode 变量切换四种开仓逻辑:主线穿零轴、主线变色(灰转绿买/灰转红卖)、主线穿快线 MAfast、双均线交叉。平仓不跟开仓绑死,单独提供 4 个布尔开关,默认 close1(穿零轴平买)和 close4(双均线死叉平买)为 true,close2/close3 为 false,实盘里按品种波动调可能更顺。 EA 里 OnInit 做句柄与变量初始化,OnTick 调度开平仓;Check_Indi_Open 负责把指标缓冲拉进来扫信号,Check_Indi_Close 按四种平仓设置迭代。Copy_indi_Buffer 封装了 CopyBuffer,TakeLastOpenTime 比对柱线开盘时间,避免一根 K 线重复开仓——外汇和贵金属杠杆高,这种重复触发在滑点行情里容易把风险敞口放歪。 下面这段输入与开仓判断是 EA 的硬骨头。平仓设置里 close1/close4 默认开,意味着穿零轴和双线死叉都会成为买单退出条件;Check_Indi_Open 的 case 0 取缓冲 4 的前两根已完成柱,若 _arr_ind_1[0]>0 且 [1]<=0 返回 0(买),反之 [0]<0 且 [1]>=0 返回 1(卖),当前未收线那根不参与。
class=class="str">"cmt">//--- 平仓设置 class="kw">input class="type">class="kw">string section_5="___ 平仓设置"; class=class="str">"cmt">//--- 当主线下穿零轴时买单平仓 class="kw">input class="type">bool close1=true; class=class="str">"cmt">// 主线与零轴交叉平仓 class=class="str">"cmt">//--- 当颜色转为与开仓颜色相反时平仓, 当变为红色时买单平仓 class="kw">input class="type">bool close2=class="kw">false; class=class="str">"cmt">// 平仓主线颜色 class=class="str">"cmt">//--- 在主线与均线交汇时平仓, 当主线下穿均线时买单平仓 class="kw">input class="type">bool close3=class="kw">false; class=class="str">"cmt">// 主线与 MAfast 交叉时平仓 class=class="str">"cmt">//--- 两条均线交汇时平仓, 快速均线下穿慢速均线时买单平仓 class="kw">input class="type">bool close4=true; class=class="str">"cmt">// 两条均线交叉时平仓 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check_Indi_Open | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int Check_Indi_Open() { class=class="str">"cmt">//--- 声明获取指标数据的数组 class="type">int copy=class="num">0; class="type">class="kw">double _arr_ind_1[]; class="type">class="kw">double mafast[]; class="type">class="kw">double mainline[]; class="type">class="kw">double maslow[]; class=class="str">"cmt">//--- 使用 class="kw">switch 函数并基于外部变量参数 trade_mode 来选择开仓方法 class="kw">switch((class="type">int)trade_mode) { case class="num">0: class=class="str">"cmt">//--- 指标的主线在最后两根柱线上进行比较, 排除当前那根 copy=Copy_indi_Buffer(RbEN_handle,class="num">4,class="num">1,class="num">2,_arr_ind_1,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">4; if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]>class="num">0 && _arr_ind_1[class="num">1]<=class="num">0) { class="kw">return class="num">0; } if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]<class="num">0 && _arr_ind_1[class="num">1]>=class="num">0) { class="kw">return class="num">1; } class="kw">break; case class="num">1: class=class="str">"cmt">//--- 从指标的第 class="num">5 个缓存区获取指标最后两根柱线的颜色索引, 排除当前那根 copy=Copy_indi_Buffer(RbEN_handle,class="num">5,class="num">1,class="num">2,_arr_ind_1,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">5;
状态机里如何判指标穿越
在 EA 的信号判定里,用 switch-case 把不同指标逻辑拆开是常见做法。下面这段针对 RbEN 指标做了三种情形的返回:情形 1 看 _arr_ind_1 数组当前根与前一根是否从非零变零(返回 0)或从非 1 变 1(返回 1),情形 2 与 3 则拉取指标缓冲区做均线交叉判定。 情形 2 里先取 buffer 6(mafast)和 buffer 4(mainline),各取从索引 1 开始的两根,排除正在形成的当前柱。若 mainline[0] > mafast[0] 且 mainline[1] <= mafast[1],视为上穿返回 0;反向则返回 1。 情形 3 把 buffer 7(maslow)替下 mainline 做同样结构的快线慢线比较,copy 失败分别返回 8 或 9。开 MT5 把这段塞进你的信号函数,把 RbEN_handle 换成实际指标句柄,就能直接验证交叉信号触发点。外汇与贵金属波动剧烈,这类穿越信号仅作概率参考,实盘须控仓。
if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]==class="num">0 && _arr_ind_1[class="num">1]!=class="num">0) { class="kw">return class="num">0; } if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]==class="num">1 && _arr_ind_1[class="num">1]!=class="num">1) { class="kw">return class="num">1; } class="kw">break; case class="num">2: class=class="str">"cmt">//--- 接收并比较最后两根柱线的 mafast(指标主线的均线) 和 mainline(指标主线) 的数值, 排除当前那根。 copy=Copy_indi_Buffer(RbEN_handle,class="num">6,class="num">1,class="num">2,mafast,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">6; copy=Copy_indi_Buffer(RbEN_handle,class="num">4,class="num">1,class="num">2,mainline,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">7; if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]!=EMPTY_VALUE && mainline[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]>mafast[class="num">0] && mainline[class="num">1]<=mafast[class="num">1]) { class="kw">return class="num">0; } if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]!=EMPTY_VALUE && mainline[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]<mafast[class="num">0] && mainline[class="num">1]>=mafast[class="num">1]) { class="kw">return class="num">1; } class="kw">break; case class="num">3: class=class="str">"cmt">//--- 接收并比较最后两根柱线的 mafast(指标主线的快速均线) 和 maslow(指标主线的快速均线) 的数值, 排除当前那根。 copy=Copy_indi_Buffer(RbEN_handle,class="num">6,class="num">1,class="num">2,mafast,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">8; copy=Copy_indi_Buffer(RbEN_handle,class="num">7,class="num">1,class="num">2,maslow,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">9;
◍ 快慢均线死叉活叉与指标平仓判定
这段逻辑把双均线交叉和自定义指标 RbEN 的平仓信号揉在一个函数里返回整数码,0 代表平多、1 代表平空,调用层拿到码直接下单。注意它刻意跳过当前柱(索引 1 和 2 而非 0 和 1),只用已闭合的两根柱确认,能过滤掉实时价格波动造成的假交叉。 先看双均线分支:mafast 与 maslow 必须四个值都不是 EMPTY_VALUE,否则不判。maslow[0]<mafast[0] 且 maslow[1]>=mafast[1] 说明慢线从上方穿到下方,快线转强,返回 0 倾向平掉空单;反过来 maslow[0]>mafast[0] 且 maslow[1]<=mafast[1] 则是金叉形态,返回 1 倾向平掉多单。 平仓函数 Check_Indi_Close 里,close1 开关打开时会从 RbEN 的第 4 号缓冲区拷 2 根历史值。若拷贝数不等于 2 直接返回 4 报错;否则看 _arr_ind_1[0]>0 且 [1]<=0 为线上穿零轴返回 0,[0]<0 且 [1]>=0 为线下穿零轴返回 1,并在 _str_close 写死“主线与零轴交叉平仓”方便日志排查。 close2 分支则从同一指标第 5 号缓冲区取颜色索引,同样排除当前柱取两根;拷贝失败返回 5。这种把‘均线交叉’和‘零轴交叉’分开关控制的结构,实盘里可以只开一个过滤噪音,外汇与贵金属波动大、滑点高,信号确认慢半根柱往往少亏几个点。
if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && maslow[class="num">0]!=EMPTY_VALUE && maslow[class="num">1]!=EMPTY_VALUE && maslow[class="num">0]<mafast[class="num">0] && maslow[class="num">1]>=mafast[class="num">1]) { class="kw">return class="num">0; } if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && maslow[class="num">0]!=EMPTY_VALUE && maslow[class="num">1]!=EMPTY_VALUE && maslow[class="num">0]>mafast[class="num">0] && maslow[class="num">1]<=mafast[class="num">1]) { class="kw">return class="num">1; } class="kw">break; class="kw">default: class="kw">return class="num">3; } class=class="str">"cmt">//--- class="kw">return class="num">2; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check_Indi_Close | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int Check_Indi_Close() { class=class="str">"cmt">//--- 声明获取指标数据的数组 class="type">int copy=class="num">0; class="type">class="kw">double _arr_ind_1[]; class="type">class="kw">double mafast[]; class="type">class="kw">double mainline[]; class="type">class="kw">double maslow[]; _str_close=""; class=class="str">"cmt">//--- 接收并比较最后两根柱线的零轴和主线数值, 排除当前那根。 if(close1) { copy=Copy_indi_Buffer(RbEN_handle,class="num">4,class="num">1,class="num">2,_arr_ind_1,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">4; _str_close="主线与零轴交叉平仓"; if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]>class="num">0 && _arr_ind_1[class="num">1]<=class="num">0) { class="kw">return class="num">0; } if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]<class="num">0 && _arr_ind_1[class="num">1]>=class="num">0) { class="kw">return class="num">1; } } class=class="str">"cmt">//--- 从指标的第 class="num">5 个缓存区获取指标最后两根柱线的颜色索引, 排除当前那根 if(close2) { copy=Copy_indi_Buffer(RbEN_handle,class="num">5,class="num">1,class="num">2,_arr_ind_1,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">5;
「平仓信号的三种交叉判定」
平仓逻辑里最容易被忽略的是「排除当前柱」这件事。上面这段把索引 1 当作上一根已闭合柱、索引 0 当作次上一根,从缓冲区拷 2 根而不是 1 根,就是为了避开实时价格波动造成的假交叉。 第一种判定看指标主线自身状态跳变:当 _arr_ind_1[0]==0 且 _arr_ind_1[1]!=0 时返回 0(平多),_arr_ind_1[0]==1 且 _arr_ind_1[1]!=1 时返回 1(平空)。这里 EMPTY_VALUE 的双重校验是必须的,否则在指标加载初期会误触发。 第二种走主线与 MAfast 的交叉:mainline[0]>mafast[0] 且 mainline[1]<=mafast[1] 判平多,反过来 mainline[0]<mafast[0] 且 mainline[1]>=mafast[1] 判平空。Copy_indi_Buffer 的返回值若不等于 2 直接 return 错误码 6 或 7,说明拷 buffer 失败就别硬算。 第三种是 mafast 与 maslow 两条均线互叉,逻辑同第二种但 buffer 编号换到 7。错误码 8、9 分别对应两次拷贝失败。外汇与贵金属杠杆高,这类交叉平仓在滑点行情中可能比信号慢 1~2 个点,实盘前建议在 MT5 策略测试器用 2023 年 XAUUSD 的 M15 跑一遍看成交偏移。
_str_close="主线平仓颜色"; if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]==class="num">0 && _arr_ind_1[class="num">1]!=class="num">0) { class="kw">return class="num">0; } if(_arr_ind_1[class="num">0]!=EMPTY_VALUE && _arr_ind_1[class="num">1]!=EMPTY_VALUE && _arr_ind_1[class="num">0]==class="num">1 && _arr_ind_1[class="num">1]!=class="num">1) { class="kw">return class="num">1; } } class=class="str">"cmt">//--- 接收并比较最后两根柱线的 mafast(指标主线的均线) 和 mainline(指标主线) 的数值, 排除当前那根。 if(close3) { copy=Copy_indi_Buffer(RbEN_handle,class="num">6,class="num">1,class="num">2,mafast,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">6; copy=Copy_indi_Buffer(RbEN_handle,class="num">4,class="num">1,class="num">2,mainline,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">7; _str_close="主线与 MAfast 交叉平仓"; if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]!=EMPTY_VALUE && mainline[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]>mafast[class="num">0] && mainline[class="num">1]<=mafast[class="num">1]) { class="kw">return class="num">0; } if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]!=EMPTY_VALUE && mainline[class="num">1]!=EMPTY_VALUE && mainline[class="num">0]<mafast[class="num">0] && mainline[class="num">1]>=mafast[class="num">1]) { class="kw">return class="num">1; } } class=class="str">"cmt">//--- 接收并比较最后两根柱线的 mafast(指标主线的快速均线) 和 maslow(指标主线的快速均线) 的数值, 排除当前那根。 if(close4) { copy=Copy_indi_Buffer(RbEN_handle,class="num">6,class="num">1,class="num">2,mafast,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">8; copy=Copy_indi_Buffer(RbEN_handle,class="num">7,class="num">1,class="num">2,maslow,"RbEN"); if(copy!=class="num">2) class="kw">return class="num">9; _str_close="两条均线交叉平仓"; if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && maslow[class="num">0]!=EMPTY_VALUE && maslow[class="num">1]!=EMPTY_VALUE &&
快慢均线死叉活叉的返回值判定
这段逻辑只干一件事:用两根均线(慢线 maslow 与快线 mafast)的当前根与前一根位置关系,给行情状态打标签。当前慢线低于快线、且前一根慢线大于等于快线,意味着快线刚从上方穿越下来,判定为死叉信号,直接 return 0。 反之若四根数值均非 EMPTY_VALUE,且慢线由下往上穿过快线(当前 maslow>mafast 而前一根 maslow<=mafast),则返回 1,对应活叉。EMPTY_VALUE 的过滤很关键,避免在指标未初始化或数据缺口时误触发。 都不满足时落到函数末尾 return 2,通常表示无明确交叉、处于纠缠或等待状态。把这段塞进 MT5 的自定义指标里,切换 EURUSD 的 M15 图,肉眼对照 K 线拐点和 return 值变化,能验证信号延迟大约在一根 bar 以内。外汇与贵金属杠杆高,信号仅作概率参考,实盘须控仓。
maslow[class="num">0]<mafast[class="num">0] && maslow[class="num">1]>=mafast[class="num">1]) { class="kw">return class="num">0; } if(mafast[class="num">0]!=EMPTY_VALUE && mafast[class="num">1]!=EMPTY_VALUE && maslow[class="num">0]!=EMPTY_VALUE && maslow[class="num">1]!=EMPTY_VALUE && maslow[class="num">0]>mafast[class="num">0] && maslow[class="num">1]<=mafast[class="num">1]) { class="kw">return class="num">1; } } class=class="str">"cmt">//--- class="kw">return class="num">2; }
◍ EURUSD H1 十年样本下的四种开仓逻辑调参
在把智能交易程序丢进实盘前,先把核心输入参数跑一遍优化。这里用 EURUSD H1、2005–2015 共十年数据,遗传算法跑全样本,四种开仓类型各自独立优化,不混在一起。 第一种是主线穿越零轴平仓:上穿开买、下穿开卖。StopLoss 与 TakeProfit 均从 0 到 10000 以 50 步进(各 201 步),_period 从 1 到 200 以 1 步进,close1 布尔开关。总通过组合数 16,160,400,结果落在 optimization.zip 的 test1 目录。 第二种看主线颜色切换:灰变绿买、灰变红卖。参数网格与第一种完全一致,总通过同样为 16,160,400,最佳结果在 test2 目录。 第三种引入快线 MA:主线上穿快 MA 买、下穿卖。比前两类多一个 period_MA_fast(1–300,300 步),总通过跳到 4,848,120,000,存于 test3 目录。 第四种是双 MA 交叉:快线上穿慢线买、下穿卖。在第三类基础上再加 period_MA_slow(1–400,400 步),总通过暴增至 1,939,248,000,000,对应 test4 目录。外汇与贵金属品种波动剧烈,这类大网格优化仅代表历史样本拟合,实盘失效概率不低,须以 MT5 自带优化器自行复核。
「把工具请下神坛」
回测优化跑下来,这套基于多空活力静态评估的逻辑确实能跑通,而且智能交易程序没挂任何资金管理的花活,纯靠指标信号过滤和触发。作者用的核心思路是在固定周期里量化多头和空头的动能,把它同时当过滤器与开仓依据,小范围实盘已经显出基本工作能力。 附件里 ropebyericnaiman.mq5(52.61 KB)和 earopebyericnaiman.mq5(40.7 KB)是可直接在 MT5 打开的源码,想验证的人把 optimization.zip(2230.41 KB)解压丢进终端测一遍就行。外汇和贵金属杠杆高、滑点跳空频繁,这类纯逻辑策略只解决方向判定,仓位和止损仍需自己兜底,别把 ea 当印钞壳。 它本质只是把 Eric Naiman 那套价格速率判趋势的想法落成了代码,你能改周期也能换活力算法。工具下神坛之后,剩下的是你愿不愿意动手调参、跑历史、看它什么时候失灵。