RSI перекупленности/перепроданности
Эта система торгует развороты, используя индекс относительной силы (RSI). Когда RSI опускается ниже уровня перепроданности, система покупает, закрыв все короткие позиции. Когда RSI поднимается выше уровня перекупленности, продаёт после закрытия лонгов.
Тестирование показывает среднегодичную доходность около 61%. Стратегию лучше запускать на крипторынке.
Позиции закрываются, когда RSI возвращается в нейтральную зону либо срабатывает стоп-лосс.
Детали
- Условия входа: RSI ниже
OversoldLevelили вышеOverboughtLevel. - Длинные/короткие позиции: Оба направления.
- Условия выхода: RSI пересекает
NeutralLevelили стоп. - Стопы: Да.
- Значения по умолчанию:
RsiPeriod= 14OverboughtLevel= 70OversoldLevel= 30NeutralLevel= 50CandleType= TimeSpan.FromMinutes(5)StopLossPercent= 2.0m
- Фильтры:
- Категория: Oscillator
- Направление: Оба
- Индикаторы: RSI
- Стопы: Да
- Сложность: Базовая
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Да
- Уровень риска: Средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RSI Overbought/Oversold strategy.
/// Buys when RSI is oversold, sells when RSI is overbought.
/// </summary>
public class RsiOverboughtOversoldStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _overboughtLevel;
private readonly StrategyParam<int> _oversoldLevel;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private int _cooldown;
/// <summary>
/// RSI calculation period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI level considered overbought.
/// </summary>
public int OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// RSI level considered oversold.
/// </summary>
public int OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Type of candles to use.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="RsiOverboughtOversoldStrategy"/>.
/// </summary>
public RsiOverboughtOversoldStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetRange(5, 30)
.SetDisplay("RSI Period", "Period for RSI calculation", "Indicators");
_overboughtLevel = Param(nameof(OverboughtLevel), 70)
.SetRange(60, 80)
.SetDisplay("Overbought Level", "RSI overbought threshold", "Indicators");
_oversoldLevel = Param(nameof(OversoldLevel), 30)
.SetRange(20, 40)
.SetDisplay("Oversold Level", "RSI oversold threshold", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldown = 0;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
if (Position == 0 && rsiValue <= OversoldLevel)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && rsiValue >= OverboughtLevel)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && rsiValue >= OverboughtLevel)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && rsiValue <= OversoldLevel)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class rsi_overbought_oversold_strategy(Strategy):
"""
RSI Overbought/Oversold strategy.
Buys when RSI is oversold, sells when RSI is overbought.
"""
def __init__(self):
super(rsi_overbought_oversold_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetDisplay("RSI Period", "Period for RSI calculation", "Indicators")
self._overbought_level = self.Param("OverboughtLevel", 70).SetDisplay("Overbought Level", "RSI overbought threshold", "Indicators")
self._oversold_level = self.Param("OversoldLevel", 30).SetDisplay("Oversold Level", "RSI oversold threshold", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(rsi_overbought_oversold_strategy, self).OnReseted()
self._cooldown = 0
def OnStarted2(self, time):
super(rsi_overbought_oversold_strategy, self).OnStarted2(time)
self._cooldown = 0
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def _process_candle(self, candle, rsi_val):
if candle.State != CandleStates.Finished:
return
if self._cooldown > 0:
self._cooldown -= 1
return
rv = float(rsi_val)
ob = self._overbought_level.Value
os_level = self._oversold_level.Value
cd = self._cooldown_bars.Value
if self.Position == 0 and rv <= os_level:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and rv >= ob:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and rv >= ob:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and rv <= os_level:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return rsi_overbought_oversold_strategy()