日内交易:拉里·康纳斯(Larry Connors)RSI2均值回归策略·进阶篇
📉

日内交易:拉里·康纳斯(Larry Connors)RSI2均值回归策略·进阶篇

(2/3)· 从日线到30分钟,用代码把康纳斯的RSI2逻辑搬进标普500差价合约盘口

含代码示例 第 2/3 篇
多数交易者把康纳斯的RSI2结论锁死在日线美股,却从没试过把它压到30分钟框架跑日内。更低周期噪音翻倍,但样本量和机会也同步放大,值得用代码亲自验一遍。

平仓与开仓的触发逻辑

这段代码片段把趋势过滤和 RSI 超买超卖拧在了一起:持多单时若收盘价跌破快线均线、或上穿慢线均线,倾向直接平掉;持空单对称处理。 开仓侧只认「无持仓 + 价格站上均线 + RSI 低于上限」做多,或「无持仓 + 价格跌破均线 + RSI 高于下限」做空,不追单。外汇与贵金属波动剧烈,这种条件单也可能在滑点下失效,实盘前务必在 MT5 策略测试器跑一遍。 止损计算用市价乘系数:卖单 sl = bid*(1+slp),买单 sl = ask*(1-slp),再用 NormalizeDouble 对齐品种小数位。把 slp 设成 0.005 代表 50 点止损(以 1.000 报价计),调它就能压住单笔回撤。

MQL5 / C++
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL&&(lastClose<ma_fast[class="num">0]||lastClose>ma[class="num">0])))trade.PositionClose(pos);
}
if(rsi[class="num">0]<Max&&NotInPosition&&lastClose>ma[class="num">0])executeBuy();
if(rsi[class="num">0]>Min&&NotInPosition&&lastClose<ma[class="num">0])executeSell();
}
}
class="type">void executeSell() {
   class="type">class="kw">double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   bid = NormalizeDouble(bid,_Digits);
   class="type">class="kw">double sl = bid*(class="num">1+slp);
   sl = NormalizeDouble(sl, _Digits);
   trade.Sell(lot,_Symbol,bid,sl);
}
class="type">void executeBuy() {
   class="type">class="kw">double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   ask = NormalizeDouble(ask,_Digits);
   class="type">class="kw">double sl = ask*(class="num">1-slp);
   sl = NormalizeDouble(sl, _Digits);
   trade.Buy(lot,_Symbol,ask,sl);
}

◍ RSI2连续三根极端值才动手

把传统 RSI2 的阈值拉高,再强制要求连续三根 K 线都撞进极端区,信号质量会比单根触发干净得多。逻辑上,长期趋势品种若连吃三根急跌 K 线,市场更可能已进入恐慌抛售段,短期反转的概率会抬升。 做多需过去三根 RSI2 全小于 10,且收盘价在 200 周期均线上方;做空则三根全大于 90 且收盘在均线下方。离场不拖泥带水:价格突破前前一根 K 线高低点就平,实测这种反转 K 常伴随对前一根的穿透,能锁住 2~3 根 K 线的小幅利润。 US500 的 M30 上,2024.1.1–2025.3.1 回测显示交易频率比普通 RSI2 版本低,因连续三根极端值不易凑齐;多头胜率不算亮眼,主要吃亏在 2024 牛市里只啃到微小反弹。外汇和贵金属用这套,杠杆下 0.15% 止损间距极窄,高风险,建议先开 MT5 用策略测试器跑一遍再谈实盘。 代码里 handleRsi 周期为 2,CopyBuffer 从偏移 1 取 3 根,正好对应“过去三根”;平仓判断直接用 lastClose 与 lastlastHigh/Low 及 ma[0] 比,逻辑和上面规则一一对应。

MQL5 / C++
class=class="str">"cmt">//US500 M30
class="macro">#include <Trade/Trade.mqh>
CTrade trade;
input class="type">int Magic = class="num">0;
input class="type">class="kw">double lot = class="num">0.1;
class="type">int barsTotal = class="num">0;
class="type">int handleMa;
class="type">int handleRsi;
const class="type">int Max = class="num">10;
const class="type">int Min = class="num">90;
const class="type">int MaPeriods = class="num">200;
const class="type">class="kw">double slp = class="num">0.0015;
class="type">int OnInit()
  {
   trade.SetExpertMagicNumber(Magic);
   handleMa =iMA(_Symbol,PERIOD_CURRENT,MaPeriods,class="num">0,MODE_SMA,PRICE_CLOSE);
   handleRsi = iRSI(_Symbol,PERIOD_CURRENT,class="num">2,PRICE_CLOSE);
   class="kw">return(INIT_SUCCEEDED);
  }
class="type">void OnDeinit(const class="type">int reason)
  {
  }

class="type">void OnTick()
  {
  class="type">int bars = iBars(_Symbol,PERIOD_CURRENT);

  if (barsTotal!= bars){
    barsTotal = bars;
    class="type">bool NotInPosition = true;
    class="type">class="kw">double ma[];
    class="type">class="kw">double rsi[];
    CopyBuffer(handleMa,BASE_LINE,class="num">1,class="num">1,ma);
    CopyBuffer(handleRsi,class="num">0,class="num">1,class="num">3,rsi);
    class="type">class="kw">double lastClose = iClose(_Symbol, PERIOD_CURRENT, class="num">1);
    class="type">class="kw">double lastlastHigh = iHigh(_Symbol,PERIOD_CURRENT,class="num">2);
    class="type">class="kw">double lastlastLow = iLow(_Symbol,PERIOD_CURRENT,class="num">2);
    for(class="type">int i = PositionsTotal()-class="num">1; i>=class="num">0; i--){
        class="type">ulong pos = PositionGetTicket(i);
        class="type">class="kw">string symboll = PositionGetSymbol(i);
        if(PositionGetInteger(POSITION_MAGIC) == Magic&&symboll== _Symbol){
          NotInPosition = false;
          if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY&&(lastClose>lastlastHigh||lastClose<ma[class="num">0]))
          ||(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL&&(lastClose<lastlastLow||lastClose>ma[class="num">0])))trade.PositionClose(pos);   
          }}

「RSI 三连低位配合均线的进出场触发」

这段逻辑把 RSI 连续三期受压和价格相对均线的位置捆绑成触发条件。买侧要求 rsi[0]、rsi[1]、rsi[2] 同时低于 Max,且当前无持仓、最后收盘价站在 ma[0] 上方,才调用 executeBuy;卖侧镜像处理,三期限 RSI 高于 Min 且收盘价跌破均线才 executeSell。 进场函数的止损用比例参数 slp 直接算:卖单 sl = bid*(1+slp),买单 sl = ask*(1-slp),再用 NormalizeDouble 按品种小数位对齐。这样写省去手动算点值,但 slp 若设 0.005 在 XAUUSD 上约对应 5 美金止损,外汇贵金属波动大,实盘前需在 MT5 策略测试器按品种校准。 别把 RSI 阈值当死规矩 Max/Min 和 slp 都是外部量,回测里 RSI 三连低于 30 常出现在震荡假突破后,配合均线过滤能砍掉部分逆势单,但趋势市里可能连续踏空。把代码贴进 EA 跑 2023 年 EURUSD M15,观察被 NotInPosition 拦掉的重叠信号占比,再决定要不要放宽三周期限制。

MQL5 / C++
if(rsi[class="num">0]<Max&&rsi[class="num">1]<Max&&rsi[class="num">2]<Max&&NotInPosition&&lastClose>ma[class="num">0])executeBuy();
if(rsi[class="num">0]>Min&&rsi[class="num">1]>Min&&rsi[class="num">2]>Min&&NotInPosition&&lastClose<ma[class="num">0])executeSell();
}
}
class="type">void executeSell() {      
      class="type">class="kw">double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      bid = NormalizeDouble(bid,_Digits);
      class="type">class="kw">double sl = bid*(class="num">1+slp);
      sl = NormalizeDouble(sl, _Digits);
      trade.Sell(lot,_Symbol,bid,sl);     
}
  
class="type">void executeBuy() {
      class="type">class="kw">double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      ask = NormalizeDouble(ask,_Digits);
      class="type">class="kw">double sl = ask*(class="num">1-slp);
      sl = NormalizeDouble(sl, _Digits);
      trade.Buy(lot,_Symbol,ask,sl);
}

RSI2双向阈值与50均线过滤的实战写法

把2周期RSI压到5和95做进出场阈值,比传统30/70更极端,赌的是价格短期过度偏离后回头。离场用RSI2穿70平多、穿30平空,趋势过滤从康纳斯的200均线改成50均线——做空本就吃短期突变,50均线对转折更敏感。 这套在US500的M30上跑过:2024.1.1至2025.3.1回测,胜率比前两种均值回归写法高,但权益曲线回撤浮动区间明显更大。根子是肥尾风险,2周期RSI仍被平滑、滞后于价格,方向骤反时只有硬止损能兜住,原文给的是市价1%间距止损,实盘外汇/贵金属波动更野,这间距可能偏窄,需自测。 别把正态当圣经 均值回归策略最怕极端波动比正态预期频繁得多,价格不回头反而继续扯,亏损会超模型。US500回测里绿线回撤放大就是这现象,真上MT5跑之前先把止损宽度和手数压住。 代码里OnTick只在新bar触发,用PositionsTotal扫同Magic同品种持仓,无仓才开。开多要rsi[0]<5且上根收盘>50均线,开空反之。直接把下面片段丢进MT5策略测试器,品种切US500、周期M30就能复现信号逻辑。

MQL5 / C++
class=class="str">"cmt">//US500 M30
class="macro">#include <Trade/Trade.mqh>
CTrade trade;
input class="type">int Magic = class="num">0;
input class="type">class="kw">double lot = class="num">0.1;
const class="type">int Max = class="num">5;
const class="type">int Min = class="num">95;
const class="type">int MaPeriods = class="num">50;
const class="type">class="kw">double slp = class="num">0.01;
class="type">int barsTotal = class="num">0;
class="type">int handleMa;
class="type">int handleRsi;
class="type">int OnInit()
  {
   trade.SetExpertMagicNumber(Magic);
   handleMa =iMA(_Symbol,PERIOD_CURRENT,MaPeriods,class="num">0,MODE_SMA,PRICE_CLOSE);
   handleRsi = iRSI(_Symbol,PERIOD_CURRENT,class="num">2,PRICE_CLOSE);
   class="kw">return(INIT_SUCCEEDED);
  }
class="type">void OnDeinit(const class="type">int reason)
  {
  }

class="type">void OnTick()
  {
  class="type">int bars = iBars(_Symbol,PERIOD_CURRENT);

  if (barsTotal!= bars){
    barsTotal = bars;
    class="type">bool NotInPosition = true;
    class="type">class="kw">double ma[];
    class="type">class="kw">double rsi[];
    CopyBuffer(handleMa,BASE_LINE,class="num">1,class="num">1,ma);
    CopyBuffer(handleRsi,class="num">0,class="num">1,class="num">1,rsi);
    class="type">class="kw">double lastClose = iClose(_Symbol, PERIOD_CURRENT, class="num">1);
    for(class="type">int i = PositionsTotal()-class="num">1; i>=class="num">0; i--){
        class="type">ulong pos = PositionGetTicket(i);
        class="type">class="kw">string symboll = PositionGetSymbol(i);
        if(PositionGetInteger(POSITION_MAGIC) == Magic&&symboll== _Symbol){
          NotInPosition = false;
          if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY&&rsi[class="num">0]>class="num">70)
          ||(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL&&rsi[class="num">0]<class="num">30))trade.PositionClose(pos);   
          }}
    if(rsi[class="num">0]<Max&&NotInPosition&&lastClose>ma[class="num">0])executeBuy();
    if(rsi[class="num">0]>Min&&NotInPosition&&lastClose<ma[class="num">0])executeSell();
    }
}
把回测扫描交给小布盯盘
这些诊断小布盯盘的AIGC已内置,打开对应品种页即可看到RSI2极端信号的分布与命中率,你只管判断当下该不该跟单。

常见问题

原策略针对股票波动设计,30分钟CFD匹配美股波动且过滤部分噪音,同时保证交易活跃度,便于验证均值回归在高频下的有效性,但外汇贵金属属高风险品种,参数需重测。
可以,小布盯盘的AIGC模块已内置该类短期超买超卖信号诊断,打开US500或对应品种页即能看到,不必自己跑终端。
阈值越极端,信号越少但假突破概率可能更低,本文在30分钟框架用<5/>95以提高回调为暂时性的置信度,实际表现依赖回测。
RSI2忽略价格区间与趋势背景、反应更快且水平明确;布林带反映波动与趋势但边界信号模糊,前者抓即时回调而非极端偏离。