English Русский Deutsch 日本語
preview
日内交易:拉里·康纳斯(Larry Connors)RSI2均值回归策略

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

MetaTrader 5示例 |
920 0
Zhuo Kai Chen
Zhuo Kai Chen

概述

拉里·康纳斯(Larry Connors)是知名交易员与量化交易领域权威作家,其最著名的成果之一是2周期相对强弱指数(RSI2)策略。该指标通过捕捉短期超买超卖信号,辅助判断市场反转时机。在本文中,我们将首先阐述研究契机,随后在MQL5中复现康纳斯的三大经典策略,并应用于标普500指数差价合约(CFD)的日内交易场景。接下来,我们将逐一分析各策略的实盘表现,并引入交易中模型系统构建的核心概念。最后,我们将针对这些策略提出未来优化方向与改进建议。


契机

拉里·康纳斯在其职业生涯中开发了众多零售量化交易策略,并在个人网站上公开了相关研究。他的策略大多基于美股市场日线级别的数据测试,大量回测结果验证了其盈利能力。然而,鲜有交易者将其理念应用于更低时间框架的日内交易场景。 

本文通过在MQL5中编码康纳斯的三大经典策略,并在标普500指数差价合约(US500 CFD)的30分钟时间框架下进行测试,探索这一思路的可行性。研究目标在于验证其均值回归逻辑在高频交易中的有效性——尽管市场噪音增加,但交易机会与样本量同步扩大。我们选择US500指数CFD以匹配美股波动性,因康纳斯的原始策略设计初衷即针对股票市场。30分钟时间框架既能过滤部分短期噪音,又可保证足够的交易活跃度。回测将覆盖过去一年数据以确保时效性。  

RSI计算方法如下:

RSI计算

RSI通过统计特定周期内的上涨K线与下跌K线数量,并采用移动平均等平滑方法,量化市场运动的相对强度。周期越短,RSI 灵敏度越高,但噪音干扰也越显著。康纳斯利用这一特性,采用2周期RSI捕捉短期超卖/超买信号,作为顺应主趋势的均值回归交易触发条件。  

与传统均值回归策略(如布林带)相比,该方法存在以下关键差异:

  • RSI2更加简洁高效,对短期反转的反应速度远快于布林带的多步骤计算。
  • RSI2提供明确的超买(>90)与超卖(<10)信号水平,而布林带触碰边界的信号相对模糊。
  • RSI2 忽略价格区间与趋势背景,而布林带则能直观反映趋势和波动性的变化。

总体而言,该策略更侧重捕捉即时回调,而非极端价格偏离。


策略一:康纳斯RSI2经典版

康纳斯RSI2经典策略基于均值回归原理,通过捕捉已确立趋势中的短期回调获利。其核心逻辑是:即使强势趋势资产也会因获利回吐或市场噪音出现短暂下跌。我们采用2周期RSI,在30分钟K线上识别极端超卖(<5)/超买(>95)信号,并提示潜在的反弹机会。结合移动平均线确认趋势方向,提高回调为暂时性而非趋势反转的概率。  

该策略完整收录于《短期交易策略实战指南》(Short-Term Trading Strategies That Work, 2008),并由康纳斯与研究伙伴塞萨尔·阿尔瓦雷斯(Cesar Alvarez)进行过严格回测。我们旨在验证多年后其有效性是否依然存在。 

信号规则:

  • 做多条件:RSI2 < 5,且最新收盘价 > 200周期移动平均线,且当前无持仓。
  • 做空条件:RSI2 > 95,且最新收盘价 < 200周期移动平均线,且当前无持仓。
  • 平多条件:最新收盘价 > 5周期移动平均线,或最新收盘价 < 200周期移动平均线。
  • 平空条件:最新收盘价 < 5周期移动平均线,或最新收盘价 > 200周期移动平均线。
  • 止损设置:以当前价格0.15%为间距设置止损。

MQL5代码:

//US500 M30
#include <Trade/Trade.mqh>
CTrade trade;

input int Magic = 0;
input double lot = 0.1;

int barsTotal = 0;
int handleMa;
int handleMaFast;
int handleRsi;
const int Max = 5;
const int Min = 95;
const int MaPeriods = 200;
const int MaPeriodsFast = 5;
const double slp = 0.0015;

int OnInit()
  {
   trade.SetExpertMagicNumber(Magic);
   handleMa =iMA(_Symbol,PERIOD_CURRENT,MaPeriods,0,MODE_SMA,PRICE_CLOSE);
   handleMaFast = iMA(_Symbol,PERIOD_CURRENT,MaPeriodsFast,0,MODE_SMA,PRICE_CLOSE);
   handleRsi = iRSI(_Symbol,PERIOD_CURRENT,2,PRICE_CLOSE);
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
  }  

void OnTick()
  {
  int bars = iBars(_Symbol,PERIOD_CURRENT);
  
  if (barsTotal!= bars){
     barsTotal = bars;
     bool NotInPosition = true;
     double ma[];
     double ma_fast[];
     double rsi[];
     CopyBuffer(handleMa,BASE_LINE,1,1,ma);
     CopyBuffer(handleMaFast,BASE_LINE,1,1,ma_fast);
     CopyBuffer(handleRsi,0,1,1,rsi);
     double lastClose = iClose(_Symbol, PERIOD_CURRENT, 1);
     for(int i = PositionsTotal()-1; i>=0; i--){
         ulong pos = PositionGetTicket(i);
         string symboll = PositionGetSymbol(i);
         if(PositionGetInteger(POSITION_MAGIC) == Magic&&symboll== _Symbol){
            NotInPosition = false;
            if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY&&(lastClose>ma_fast[0]||lastClose<ma[0]))
            ||(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL&&(lastClose<ma_fast[0]||lastClose>ma[0])))trade.PositionClose(pos);  
            }}
     if(rsi[0]<Max&&NotInPosition&&lastClose>ma[0])executeBuy();
     if(rsi[0]>Min&&NotInPosition&&lastClose<ma[0])executeSell();
    }
 }

void executeSell() {      
       double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
       bid = NormalizeDouble(bid,_Digits);
       double sl = bid*(1+slp);
       sl = NormalizeDouble(sl, _Digits);
       trade.Sell(lot,_Symbol,bid,sl);    
}
    
void executeBuy() {
       double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
       ask = NormalizeDouble(ask,_Digits);
       double sl = ask*(1-slp);
       sl = NormalizeDouble(sl, _Digits);
       trade.Buy(lot,_Symbol,ask,sl);
}

一次典型交易示例如下:

RSI2 V1演示版

以下为标普500指数(US500)30分钟(M30)时间框架下,2024年1月1日至2025年3月1日的回测结果。

RSI2 V1参数设置

参数

RSI2 V1净值曲线

RSI2 V1回测结果

与其他日内交易策略相比,该策略的交易频率明显偏高,按每年252个交易日计算,平均每日约产生1-2笔交易。这主要源于RSI2指标的超强敏感性——即使设定极端入场条件,仍能频繁生成信号。其平均盈利与平均亏损幅度基本持平,这对均值回归策略而言表现稳健(该类策略胜率通常高于50%)。尽管交易规则完全对称,但多头和空头的胜率存在差异:在2024年牛市中,空头交易胜率更高但交易次数更少,表明该策略在捕捉牛市回调时可能面临更大的挑战。


策略二:RSI2回调强化版 

RSI2回调强化策略通过要求连续多根极端RSI值,优化了均值回归交易逻辑。其核心假设是:处于长期趋势中的资产,如果经历了连续多根K线的急剧回调,则反弹概率将会显著提升。该策略在传统RSI2基础上提高阈值,并叠加"连续三根K线超阈值"的条件,使信号强度大幅提升——这表明市场可能出现恐慌性抛售,从而增加快速反转的可能性。

该策略基于拉里·康纳斯的框架改进,但是我做出了两处关键调整:增加连续多根极端RSI读数的强制要求和引入非常规的离场规则。当价格突破前一根K线的高点或低点时,我们立即平仓。这一离场逻辑源于观察发现:在短期反转行情中,反转K线常伴随对前一根K线高点或低点的突破,允许我们快速离场并锁定小额利润

信号规则:

  • 做多条件:过去三根K线的RSI2值均小于10;最新收盘价 > 200周期移动平均线,且当前无持仓。
  • 做空条件:过去三根K线的RSI2值均大于90,最新收盘价 < 200周期移动平均线,且当前无持仓。
  • 平多条件:最新收盘价 > 倒数第二根K线的高点,或者最新收盘价 < 200周期移动平均线。
  • 平空条件:最新收盘价 < 倒数第二根K线的低点,或者最新收盘价 > 200周期移动平均线。
  • 止损设置:以当前价格0.15%为间距设置止损。

MQL5代码:

//US500 M30
#include <Trade/Trade.mqh>
CTrade trade;

input int Magic = 0;
input double lot = 0.1;

int barsTotal = 0;
int handleMa;
int handleRsi;
const int Max = 10;
const int Min = 90;
const int MaPeriods = 200;
const double slp = 0.0015;

int OnInit()
  {
   trade.SetExpertMagicNumber(Magic);
   handleMa =iMA(_Symbol,PERIOD_CURRENT,MaPeriods,0,MODE_SMA,PRICE_CLOSE);
   handleRsi = iRSI(_Symbol,PERIOD_CURRENT,2,PRICE_CLOSE);
   return(INIT_SUCCEEDED);
  }

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

void executeSell() {      
       double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
       bid = NormalizeDouble(bid,_Digits);
       double sl = bid*(1+slp);
       sl = NormalizeDouble(sl, _Digits);
       trade.Sell(lot,_Symbol,bid,sl);    
}
    
void executeBuy() {
       double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
       ask = NormalizeDouble(ask,_Digits);
       double sl = ask*(1-slp);
       sl = NormalizeDouble(sl, _Digits);
       trade.Buy(lot,_Symbol,ask,sl);
}

一次典型交易示例如下:

RSI2 V2演示版

以下为标普500指数(US500)30分钟(M30)时间框架下,2024年1月1日至2025年3月1日的回测结果。

RSI2 V2参数设置

参数

RSI2 V2净值曲线

RSI2 V2回测结果

该策略的交易频率较前一种策略有所降低,主要因为入场条件要求连续三根K线出现极端RSI值。多头交易的胜率表现并不突出。正如我们在前一种策略中提到的,由于该策略旨在捕捉微小的反弹行情(通常仅持续2-3根K线),我们可能未能充分把握2024年牛市中的大幅波动机会。若能在更长周期内进行测试,收集不同市场环境下的数据,或许能更全面地评估其表现。


策略三:RSI2超买/超卖策略

RSI2超买/超卖策略具备更强的灵活性,其离场水平会根据资产的趋势特性动态调整。该策略同样基于极端RSI2读数意味着股价已过度偏离合理区间、即将反转的假设,允许交易者逢低买入(超卖)或逢高做空(超买)。与前两种策略不同,本策略采用可调节的RSI阈值实现动态离场。此方式可能面临肥尾风险 ——即便使用2周期RSI,该指标仍经过平滑处理且滞后于价格波动。因此,如果交易方向迅速逆转,唯有止损单能够保护仓位。

此外,200周期移动平均线通常用于判断牛市中的长期趋势。这也是拉里·康纳斯在前两种策略中仅设计多头交易的原因。鉴于本文聚焦差价合约(CFD)日内交易,我已经将所有策略调整为可双向交易(多和空皆可)。然而,拉里曾指出该策略本身即支持双向操作,包括股票做空。改用50周期(代替200周期)移动平均线进行趋势过滤,能更敏锐捕捉趋势转折,因为做空交易往往与短期突变相关,而非长期股市趋势

本策略源自拉里·康纳斯的研究成果,他在著作和研讨会中强调,这是一种灵活运用RSI指标的方法,可根据市场情况灵活选择多头或空头交易。

信号规则:

  • 做多条件:RSI2 < 5,且最新收盘价 > 50周期移动平均线,且当前无持仓。
  • 做空条件:RSI2 > 95,且最新收盘价 < 50周期移动平均线,且当前无持仓。
  • 平多条件:RSI2 > 70。
  • 平空条件:RSI2 < 30。
  • 止损设置:以当前价格1%为间距设置止损。

MQL5代码:

//US500 M30
#include <Trade/Trade.mqh>
CTrade trade;

input int Magic = 0;
input double lot = 0.1;

const int Max = 5;
const int Min = 95;
const int MaPeriods = 50;
const double slp = 0.01;

int barsTotal = 0;
int handleMa;
int handleRsi;

int OnInit()
  {
   trade.SetExpertMagicNumber(Magic);
   handleMa =iMA(_Symbol,PERIOD_CURRENT,MaPeriods,0,MODE_SMA,PRICE_CLOSE);
   handleRsi = iRSI(_Symbol,PERIOD_CURRENT,2,PRICE_CLOSE);
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
  }
  
void OnTick()
  {
  int bars = iBars(_Symbol,PERIOD_CURRENT);
  
  if (barsTotal!= bars){
     barsTotal = bars;
     bool NotInPosition = true;
     double ma[];
     double rsi[];
     CopyBuffer(handleMa,BASE_LINE,1,1,ma);
     CopyBuffer(handleRsi,0,1,1,rsi);
     double lastClose = iClose(_Symbol, PERIOD_CURRENT, 1);
     for(int i = PositionsTotal()-1; i>=0; i--){
         ulong pos = PositionGetTicket(i);
         string symboll = PositionGetSymbol(i);
         if(PositionGetInteger(POSITION_MAGIC) == Magic&&symboll== _Symbol){
            NotInPosition = false;
            if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY&&rsi[0]>70)
            ||(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL&&rsi[0]<30))trade.PositionClose(pos);  
            }}
     if(rsi[0]<Max&&NotInPosition&&lastClose>ma[0])executeBuy();
     if(rsi[0]>Min&&NotInPosition&&lastClose<ma[0])executeSell();
    }
 }

void executeSell() {      
       double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
       bid = NormalizeDouble(bid,_Digits);
       double sl = bid*(1+slp);
       sl = NormalizeDouble(sl, _Digits);
       trade.Sell(lot,_Symbol,bid,sl);    
}
    
void executeBuy() {
       double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
       ask = NormalizeDouble(ask,_Digits);
       double sl = ask*(1-slp);
       sl = NormalizeDouble(sl, _Digits);
       trade.Buy(lot,_Symbol,ask,sl);
}

一次典型交易示例如下:

RSI2 V3演示版

以下为标普500指数(US500)30分钟(M30)时间框架下,2024年1月1日至2025年3月1日的回测结果。

RSI2 V3参数设置

参数

RSI2 V3净值曲线

RSI2 V3回测结果

与前两种策略相比,该策略虽展现出更高的胜率,但净值曲线(如图中绿色线条所示)也呈现出更大的权益回撤浮动区间。这与前文提及的肥尾风险直接相关,且需要设置比常规更宽的止损幅度。肥尾风险描述的是分布中极端事件发生的概率显著高于正态分布预期的现象——对于依赖价格回归历史均值的均值回归策略而言,这类极端波动可能引发重大亏损。这些策略中,肥尾分布超预期的大幅价格波动更为频繁,这些波动可能阻碍预期中的价格反转,导致实际风险或损失远超正态分布模型预测的水平。尽管该策略盈利可观,但是如果要将其转化为可实际操作的交易策略,仍需有效控制回撤幅度。

肥尾分布


反思

回顾我们探讨的三种策略,其代码逻辑与信号规则颇为相似。这主要源于它们均基于“RSI2均值回归”模型体系。一旦构建起稳健的模型体系,仅需微调部分规则即可衍生出多样化的策略,简单直观。让我们来剖析CTA交易中“模型体系”与“单一策略”的差异。

单一策略通常绑定特定时间框架与交易品种,其信号规则精细化且难以迁移。而模型体系则是一个宽泛的起点,基于均值回归、趋势跟踪、动量或突破等被历史验证的有效概念。以本文为例,具体模型体系即“RSI2均值回归”,它整合了关键信号源与核心概念。模型体系的优势在于跨时间框架、品种与信号规则的灵活性 ,可高效生成多策略并构建多元化投资组合。

要成功构建模型体系并衍生策略,建议遵循以下原则:

  • 通过标准化或价格百分比计算信号或者价格间距,确保在不同品种与时间框架下更具可扩展性
  • 在代码中避免固定时间框架与交易品种。使用_Symbol与PERIOD_CURRENT实现对不同回测条件的自动适配。
  • 将策略拆解为清晰的入场与离场规则,列出所有的可能选项,并保留核心逻辑驱动的替代规则。
  • 将可复用代码封装为函数,保持代码整洁高效,便于后续信号规则调整。

在理解模型思维而非单一策略思维后,以下是优化RSI2均值回归模型、提升策略实操性的建议:

  • 在除US500 M30之外的品种与时间框架中回测,挖掘更优参数组合。确保所有发现基于样本内数据以避免前瞻偏差。
  • 尝试更换动量或趋势指标,例如用ROC或VIX替代RSI,或用卡尔曼滤波替代移动平均线。
  • 结合其他均值回归策略的入场规则(如布林带),同时保留本文的离场逻辑,实现优势互补。

这些方法正是资深CTA量化研究员高效构建策略的核心技巧。策略创新并非追求颠覆性突破。而是通过调整或组合现有成熟模型——而这些模型本身或许盈利不足。这部分工作抽象到机器无法取代,却又结构化到足以让人按流程系统化地挖掘数据。


结论

本文首先阐释了选择RSI2均值回归构建日内策略的逻辑。接下来,复现了拉里·康纳斯的三种经典策略,详解其信号规则、出入场条件,并在MetaTrader 5中完成回测。进而引入模型体系思维,提供实操建议,并展望了优化RSI2均值回归策略的方向。整体而言,本文为交易者构建了清晰的框架:从公开策略中汲取灵感,微调后通过MQL5回测验证,以便持续优化。这一流程易于掌握,可助力交易者加速策略迭代。

文件表

文件名 文件使用
RSI2_V1.mq5 首个策略EA
RSI2_V2.mq5 第二个策略EA
RSI2_V3.mq5 第三个策略EA

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/17636

附加的文件 |
RSI2.zip (3.1 KB)
数据科学和机器学习(第 33 部分):MQL5 中的 Pandas 数据帧,为机器学习收集数据更加容易 数据科学和机器学习(第 33 部分):MQL5 中的 Pandas 数据帧,为机器学习收集数据更加容易
当与机器学习模型共事时,确保用于训练、验证和测试的数据一致性必不可少。在本文中,我们将创建我们自己的 MQL5 版本 Pandas 函数库,确保使用统一方式来处理机器学习数据;这样做是为确保在 MQL5 内部和外部应用相同的数据,其中大部分发生在训练阶段。
在 MQL5 中构建自优化EA(第六部分):自适应交易规则(二) 在 MQL5 中构建自优化EA(第六部分):自适应交易规则(二)
本文探讨了如何优化 RSI 的水平和周期,以获得更好的交易信号。我们介绍了估算最优 RSI 值的方法,并使用网格搜索和统计模型来自动选择周期。最后,我们在 MQL5 中实现了该解决方案,同时利用 Python 进行分析。我们的方法力求务实和直接,旨在以简单的方式帮助您解决潜在复杂的问题。
从基础到中级:模板和类型名称(二) 从基础到中级:模板和类型名称(二)
本文解释了如何处理您可能遇到的最困难的编程情况之一:在同一个函数或过程模板中使用不同的类型。尽管我们大部分时间只关注函数,但这里介绍的所有内容都是有用的,并且可以应用于过程。
MQL5 交易工具包(第 6 部分):使用最新成交的挂单函数扩展历史管理 EX5 库 MQL5 交易工具包(第 6 部分):使用最新成交的挂单函数扩展历史管理 EX5 库
了解如何创建可导出函数的 EX5 模块,无缝查询和保存最近填写的挂单数据。在本全面的分步指南中,我们将通过开发专用和分隔的函数来检索最后填写的挂单的基本属性,从而增强历史管理 EX5 库。这些属性包括订单类型、设置时间、执行时间、填充类型以及有效管理和分析挂单交易历史所需的其他关键细节。