区域方法·综合运用
(3/3)·常规 RSI 用法要等四个信号才下单,区域方法只盯 50 线交叉后的累积区,本篇把它写成指标和 EA 并跑通多品种回测
多数交易者把 RSI 困在 70/30 的超买超卖框里,等背离和失败摇摆凑齐才动手,信号少且迟。区域方法换了个角度:只统计上一次穿 50 线后指标在单方停留的累积量,越过阈值就反向布局。这套思路诞生于 2004 年,本篇用 MQL5 在现代盘面重做并验证。
◍ RSI 区域偏移与建仓触发的代码骨架
这段逻辑把 RSI 偏离 50 中线的累积值当成「区域面积」,当正向面积超过阈值或反向低于负阈值时,才允许 EA 在 OnTick 里动手。 for(shift=BeginShift+1;shift<limit;shift++) { rsivalue=arr_rsi[shift]-50;
| if((result>0 && rsivalue<-3) | (result<0 && rsivalue>3)) |
|---|
{ RSIAreaShift=shift; break; } result+=rsivalue; } return(result); 上面这段是区域累计的核心:从 BeginShift+1 开始逐根 K 线扫,rsivalue 是单根 RSI 减 50 的偏离;一旦 result 符号与当前 rsivalue 反向且越过 ±3,就记下 shift 并跳出,否则不断累加。 void OnTick() { static int RSIAreaShift=0; int shift; double RSICurrent,RSILocalMin,RSILocalMax,value; double arr_rsi[1],rsi; MqlTick last_tick; if(CopyBuffer(handle,0,0,1,arr_rsi)==-1) { Print("从iRSI CopyBuffer 失败,没有数据。"); return; } rsi=arr_rsi[0]; if(!SymbolInfoTick(Symbol(),last_tick)) Print("SymbolInfoTick() 失败, 错误编号 = ",GetLastError()); } OnTick 里先用 CopyBuffer 抓最新一根 RSI 到 arr_rsi[0],失败就打印并退出;接着取最新 tick 报价,供后续买卖单填充 ask/bid。 if(!PositionSelect(Symbol())) { RSIArea=RSIAreaFunc(RSIAreaShift,0); if(RSIArea<-AreaCondition) { my_trade.Buy(1.0,NULL,last_tick.ask,0.0,0.0,NULL); RSIOpen=rsi; return; } if(RSIArea>AreaCondition) { my_trade.Sell(1.0,NULL,last_tick.bid,0.0,0.0,NULL); RSIOpen=rsi; return; } RSIAreaShift=0; } 无持仓时调用 RSIAreaFunc 算区域面积:低于 -AreaCondition 倾向买、高于 AreaCondition 倾向卖,开仓后把当前 rsi 存进 RSIOpen 并 return,否则把偏移复位为 0。外汇与贵金属杠杆高,这类信号只代表概率倾向,实盘前请在 MT5 策略测试器用历史数据验证 AreaCondition 与 ±3 的敏感度和滑点表现。 RSICurrent=rsi; if(RSIOpen>50 && RSICurrent>50) return; if(RSIOpen<50 && RSICurrent<50) return; RSILocalMin = RSICurrent; RSILocalMax = RSICurrent; 持仓监控段先锁定当前 RSI:若开仓时与现在同侧于 50 中线,直接 return 不处理;否则把 RSILocalMin/Max 初始化为当前值,留给后续极值跟踪。
for(shift=BeginShift+class="num">1;shift<limit;shift++) { rsivalue=arr_rsi[shift]-class="num">50; if((result>class="num">0 && rsivalue<-class="num">3) || (result<class="num">0 && rsivalue>class="num">3)) { RSIAreaShift=shift; break; } result+=rsivalue; } class="kw">return(result); class="type">void OnTick() { class="kw">static class="type">int RSIAreaShift=class="num">0; class="type">int shift; class="type">class="kw">double RSICurrent,RSILocalMin,RSILocalMax,value; class="type">class="kw">double arr_rsi[class="num">1],rsi; class="type">MqlTick last_tick; if(CopyBuffer(handle,class="num">0,class="num">0,class="num">1,arr_rsi)==-class="num">1) { Print("从iRSI CopyBuffer 失败,没有数据。"); class="kw">return; } rsi=arr_rsi[class="num">0]; if(!SymbolInfoTick(Symbol(),last_tick)) Print("SymbolInfoTick() 失败, 错误编号 = ",GetLastError()); } if(!PositionSelect(Symbol())) { RSIArea=RSIAreaFunc(RSIAreaShift,class="num">0); if(RSIArea<-AreaCondition) { my_trade.Buy(class="num">1.0,NULL,last_tick.ask,class="num">0.0,class="num">0.0,NULL); RSIOpen=rsi; class="kw">return; } if(RSIArea>AreaCondition) { my_trade.Sell(class="num">1.0,NULL,last_tick.bid,class="num">0.0,class="num">0.0,NULL); RSIOpen=rsi; class="kw">return; } RSIAreaShift=class="num">0; } RSICurrent=rsi; if(RSIOpen>class="num">50 && RSICurrent>class="num">50) class="kw">return; if(RSIOpen<class="num">50 && RSICurrent<class="num">50) class="kw">return; RSILocalMin = RSICurrent; RSILocalMax = RSICurrent;
RSI 局部极值与回滚平仓判定
这段逻辑干的事是在一段 RSI 区域内捞局部最小/最大值,并用它们去卡持仓的回滚离场点。前提是 RSIAreaShift 大于 1,才会把最近 RSIAreaShift 根 K 的 RSI 缓冲拷进数组按时间倒序排,逐根比较刷新极值。 局部极值刷新有方向限制:做多区域(RSIArea>0)只更新 RSILocalMin,做空区域(RSIArea<0)只更新 RSILocalMax,避免反方向噪声干扰阈值判断。 回滚平仓的硬条件是差值与中轴位置同时满足。多单要求 RSILocalMax 较当前 RSI 高出至少 4 点且大于 50,空单要求 RSILocalMin 较当前低至少 4 点且小于 50,触发后以 20 点偏差尝试市价平掉当前符号持仓。外汇与贵金属杠杆高,这类基于 RSI 回滚的离场在快速反转中可能滑点放大,实盘前应在 MT5 策略测试器用真实点差验证。 直接把下面代码贴进 EA 的 OnTick 区域计算段,改 RSIAreaShift 与那个 4 点阈值,能立刻看到平仓触发频率的变化。
RSILocalMin = RSICurrent; RSILocalMax = RSICurrent; class=class="str">"cmt">//--- 搜索局部最小值/最大值 if(RSIAreaShift>class="num">1) { class="type">class="kw">double arr_rsi_1[]; ArrayResize(arr_rsi_1,RSIAreaShift); ArraySetAsSeries(arr_rsi_1,true); if(CopyBuffer(handle,class="num">0,class="num">0,RSIAreaShift,arr_rsi_1)==-class="num">1) { Print("从 iRSI CopyBuffer 失败,没有数据"); class="kw">return; } for(shift=class="num">1; shift<RSIAreaShift; shift++) { value=arr_rsi_1[shift]; if(value<RSILocalMin && RSIArea>class="num">0) RSILocalMin=value; if(value>RSILocalMax && RSIArea<class="num">0) RSILocalMax=value; } } class=class="str">"cmt">//--- 检查回滚 if(PositionSelect(Symbol())) { if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) { class=class="str">"cmt">//--- 检查是否是平仓时间 if(RSILocalMax>=RSICurrent+class="num">4 && RSILocalMax>class="num">50) my_trade.PositionClose(Symbol(),class="num">20); } if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL) { class=class="str">"cmt">//--- 检查是否是平仓时间 if(RSILocalMin<=RSICurrent-class="num">4 && RSILocalMin<class="num">50) my_trade.PositionClose(Symbol(),class="num">20); } } class="kw">return;
「七个货币对里区域策略谁更扛打」
把 RSIAreaExpert 1.00 丢进 MT5 回测,样本窗锁在 2015.01.05–2016.01.05,时段从 M10 拉到 H6,区域间隔 100–800 一口气扫完。这套参数跨度明显比早年 H1 单图表粗暴,毕竟 2004 年之后波动率抬升,旧结论不能直接搬。 AUDCAD 上 H2、H3 看着结果密度还行,但一年交易数只到 50,错单比例偏高,区域法在这对上基本可以判不及格。AUDUSD 同理,H2/H3 的 AreaCondition 在 250–400 浮动,年成交数依旧很低,不值得上手。 EURUSD 是真正的甜区:M10 获利密度集中在 AreaCondition 400–550,M12 与 M15 落在 300–400;H1 以上全年笔数太少直接弃用。M10–M15 的成交规模足以支撑「区域法能赚钱」的判断,这对适合拿来跑。 GBPUSD 的密集获利在 M20,参数 300–500,年交易 140–250 笔,频率不炸但够看,普通账户也能用。USDCAD 只在 M30 有密集成交(参数 280–550),年笔数 90–200,偏少,不推荐。USDJPY 分叉明显:M10 参数 320–650、年成交 150–200,M30 参数 550–600、年成交 50–150,整体不够稳,谨慎对待。 外汇与贵金属属高风险品类,上述回测只是历史样本,实盘可能因点差和滑点走形,开 MT5 用相同品种和时段复跑一遍再决定仓位。
◍ 区域法在EURUSD的时段选择
区域方法不是随便挂个周期就能跑的,H1 在当下行情里用这套系统大概率是亏的,但早前文献[1]的回测里它还能盈利,说明市场结构变了,旧参数得重验。 实测下来,EURUSD 的 M10、M12、M15 三个短周期是目前最出活儿的窗口,区域法在这上面被证明获利效率最高。 针对这个货币对,测试显示每年能跑出足够数量的交易,样本量够做统计,不是偶然几单。外汇和贵金属杠杆高,周期越短噪音越大,实盘前务必用 MT5 策略测试器按年份重跑一遍。
把工具请下神坛
这套 RSI 面积算法在 4.2 之后版本的 EA 里由辅助函数 RSIAreaFunc 承接,面积按矩形法近似,矩形宽度固定为 1,读者若翻代码找不到 area 字样,多半是只看到了极值搜索段,没定位到该函数。 解包 Indicators.zip(3.91 KB)与 Experts.zip(5.37 KB)后,直接丢进数据目录下的 MQL5 文件夹就能挂上终端验证,不必神化作者给的俄文老资料。 外汇与贵金属波动受杠杆放大,任何指标都只是概率参考;真正该做的是开 MT5 把 RSIAreaFunc 跑一遍,看矩形累加和你手算的偏差在哪。