RSI 突破策略
该策略观察 RSI 相对于其均值的急剧变化,以捕捉动能爆发。
测试表明年均收益约为 88%,该策略在股票市场表现最佳。
当 RSI 高于均值加 Multiplier 倍标准差时买入,低于均值减同样倍数时做空。RSI 回到均值附近或触及止损时离场。
此策略适合日内交易者利用 RSI 的突破信号操作。
详细信息
- 入场条件:
- 做多: RSI > Avg + Multiplier * StdDev
- 做空: RSI < Avg - Multiplier * StdDev
- 多空方向: 双向
- 退出条件:
- 做多: Exit when RSI < Avg
- 做空: Exit when RSI > Avg
- 止损: 是
- 默认值:
RsiPeriod= 14AveragePeriod= 20Multiplier= 2.0mCandleType= TimeSpan.FromMinutes(5)
- 筛选条件:
- 类别: 突破
- 方向: 双向
- 指标: RSI
- 止损: 是
- 复杂度: 中等
- 时间框架: 日内
- 季节性: 否
- 神经网络: 否
- 背离: 否
- 风险等级: 中等
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RSI Breakout Strategy (247).
/// Enter when RSI breaks out above/below its average by a certain multiple of standard deviation.
/// Exit when RSI returns to its average.
/// </summary>
public class RsiBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _averagePeriod;
private readonly StrategyParam<decimal> _multiplier;
private readonly StrategyParam<DataType> _candleType;
private RelativeStrengthIndex _rsi;
private SimpleMovingAverage _rsiAverage;
private StandardDeviation _rsiStdDev;
private decimal _prevRsiValue;
private decimal _currentRsiValue;
private decimal _currentRsiAvg;
private decimal _currentRsiStdDev;
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Period for RSI average calculation.
/// </summary>
public int AveragePeriod
{
get => _averagePeriod.Value;
set => _averagePeriod.Value = value;
}
/// <summary>
/// Standard deviation multiplier for entry.
/// </summary>
public decimal Multiplier
{
get => _multiplier.Value;
set => _multiplier.Value = value;
}
/// <summary>
/// Type of candles to use.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="RsiBreakoutStrategy"/>.
/// </summary>
public RsiBreakoutStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Period for RSI calculation", "Strategy Parameters")
.SetOptimize(10, 20, 2);
_averagePeriod = Param(nameof(AveragePeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Average Period", "Period for RSI average calculation", "Strategy Parameters")
.SetOptimize(10, 30, 5);
_multiplier = Param(nameof(Multiplier), 2.0m)
.SetGreaterThanZero()
.SetDisplay("StdDev Multiplier", "Standard deviation multiplier for entry", "Strategy Parameters")
.SetOptimize(1.0m, 3.0m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "Strategy Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsiValue = default;
_currentRsiValue = default;
_currentRsiAvg = default;
_currentRsiStdDev = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_rsiAverage = new SMA { Length = AveragePeriod };
_rsiStdDev = new StandardDeviation { Length = AveragePeriod };
// Create candle subscription
var subscription = SubscribeCandles(CandleType);
// Bind RSI to candles
subscription
.Bind(_rsi, ProcessRsi)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _rsi);
DrawIndicator(area, _rsiAverage);
DrawOwnTrades(area);
}
// Enable position protection
StartProtection(
takeProfit: new Unit(5, UnitTypes.Percent),
stopLoss: new Unit(2, UnitTypes.Percent)
);
}
private void ProcessRsi(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
// Store previous and current RSI value
_prevRsiValue = _currentRsiValue;
_currentRsiValue = rsiValue;
// Process RSI through average and standard deviation indicators
var avgValue = _rsiAverage.Process(new DecimalIndicatorValue(_rsiAverage, rsiValue, candle.ServerTime) { IsFinal = true });
var stdDevValue = _rsiStdDev.Process(new DecimalIndicatorValue(_rsiStdDev, rsiValue, candle.ServerTime) { IsFinal = true });
_currentRsiAvg = avgValue.ToDecimal();
_currentRsiStdDev = stdDevValue.ToDecimal();
if (!_rsiAverage.IsFormed || !_rsiStdDev.IsFormed)
return;
// Calculate bands
var upperBand = _currentRsiAvg + Multiplier * _currentRsiStdDev;
var lowerBand = _currentRsiAvg - Multiplier * _currentRsiStdDev;
LogInfo($"RSI: {_currentRsiValue}, RSI Avg: {_currentRsiAvg}, Upper: {upperBand}, Lower: {lowerBand}");
// Entry logic - BREAKOUT
if (Position == 0)
{
if (_currentRsiValue > upperBand)
{
BuyMarket();
}
else if (_currentRsiValue < lowerBand)
{
SellMarket();
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class rsi_breakout_strategy(Strategy):
"""
RSI Breakout Strategy (247).
Enter when RSI breaks out above/below its average by a certain multiple of standard deviation.
Exit when RSI returns to its average.
"""
def __init__(self):
super(rsi_breakout_strategy, self).__init__()
# Initialize strategy parameters
self._rsiPeriod = self.Param("RsiPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("RSI Period", "Period for RSI calculation", "Strategy Parameters") \
.SetCanOptimize(True) \
.SetOptimize(10, 20, 2)
self._averagePeriod = self.Param("AveragePeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("Average Period", "Period for RSI average calculation", "Strategy Parameters") \
.SetCanOptimize(True) \
.SetOptimize(10, 30, 5)
self._multiplier = self.Param("Multiplier", 2.0) \
.SetGreaterThanZero() \
.SetDisplay("StdDev Multiplier", "Standard deviation multiplier for entry", "Strategy Parameters") \
.SetCanOptimize(True) \
.SetOptimize(1.0, 3.0, 0.5)
self._candleType = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "Strategy Parameters")
# Internal indicators
self._rsi = None
self._rsiAverage = None
self._rsiStdDev = None
# State variables
self._prevRsiValue = 0.0
self._currentRsiValue = 0.0
self._currentRsiAvg = 0.0
self._currentRsiStdDev = 0.0
@property
def RsiPeriod(self):
"""RSI period."""
return self._rsiPeriod.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsiPeriod.Value = value
@property
def AveragePeriod(self):
"""Period for RSI average calculation."""
return self._averagePeriod.Value
@AveragePeriod.setter
def AveragePeriod(self, value):
self._averagePeriod.Value = value
@property
def Multiplier(self):
"""Standard deviation multiplier for entry."""
return self._multiplier.Value
@Multiplier.setter
def Multiplier(self, value):
self._multiplier.Value = value
@property
def CandleType(self):
"""Type of candles to use."""
return self._candleType.Value
@CandleType.setter
def CandleType(self, value):
self._candleType.Value = value
def GetWorkingSecurities(self):
"""!! REQUIRED!! Return securities and candle types used."""
return [(self.Security, self.CandleType)]
def OnReseted(self):
"""Resets internal state when strategy is reset."""
super(rsi_breakout_strategy, self).OnReseted()
self._prevRsiValue = 0.0
self._currentRsiValue = 0.0
self._currentRsiAvg = 0.0
self._currentRsiStdDev = 0.0
def OnStarted2(self, time):
"""Called when the strategy starts."""
super(rsi_breakout_strategy, self).OnStarted2(time)
# Create indicators
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiPeriod
self._rsiAverage = SimpleMovingAverage()
self._rsiAverage.Length = self.AveragePeriod
self._rsiStdDev = StandardDeviation()
self._rsiStdDev.Length = self.AveragePeriod
# Create candle subscription
subscription = self.SubscribeCandles(self.CandleType)
# Bind RSI to candles
subscription.Bind(self._rsi, self.ProcessRsi).Start()
# Setup chart visualization if available
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._rsi)
self.DrawIndicator(area, self._rsiAverage)
self.DrawOwnTrades(area)
# Enable position protection
self.StartProtection(
takeProfit=Unit(5, UnitTypes.Percent),
stopLoss=Unit(2, UnitTypes.Percent)
)
def ProcessRsi(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
# Store previous and current RSI value
self._prevRsiValue = self._currentRsiValue
self._currentRsiValue = rsi_value
# Process RSI through average and standard deviation indicators
avg_value = process_float(self._rsiAverage, rsi_value, candle.ServerTime, candle.State == CandleStates.Finished)
std_dev_value = process_float(self._rsiStdDev, rsi_value, candle.ServerTime, candle.State == CandleStates.Finished)
self._currentRsiAvg = float(avg_value)
self._currentRsiStdDev = float(std_dev_value)
if not self._rsiAverage.IsFormed or not self._rsiStdDev.IsFormed:
return
# Calculate bands
upper_band = self._currentRsiAvg + self.Multiplier * self._currentRsiStdDev
lower_band = self._currentRsiAvg - self.Multiplier * self._currentRsiStdDev
self.LogInfo(
"RSI: {0}, RSI Avg: {1}, Upper: {2}, Lower: {3}".format(
self._currentRsiValue, self._currentRsiAvg, upper_band, lower_band))
# Entry logic - BREAKOUT only when flat (no exit logic in CS)
if self.Position == 0:
if self._currentRsiValue > upper_band:
self.BuyMarket()
elif self._currentRsiValue < lower_band:
self.SellMarket()
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return rsi_breakout_strategy()