Стратегия Rsi Supertrend
Стратегия основана на индикаторах RSI и Supertrend. Длинная позиция открывается, когда RSI находится в зоне перепроданности (< 30) и цена выше линии Supertrend. Короткая — когда RSI в зоне перекупленности (> 70) и цена ниже Supertrend.
Тестирование показывает среднегодичную доходность около 112%. Стратегию лучше запускать на рынке Форекс.
Осциллятор RSI определяет крайние значения импульса, а Supertrend указывает преобладающее направление. Сделка совершается, когда значение RSI соответствует цвету Supertrend.
Подходит трейдерам, предпочитающим выход по трейлинг-стопу. Настройки ATR дополнительно страхуют позицию.
Подробности
- Условия входа:
- Длинная:
RSI < 30 && Close > Supertrend - Короткая:
RSI > 70 && Close < Supertrend
- Длинная:
- Long/Short: Оба
- Условия выхода: изменение Supertrend
- Стопы: плавающий стоп по Supertrend
- Параметры по умолчанию:
RsiPeriod= 14SupertrendPeriod= 10SupertrendMultiplier= 3.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Фильтры:
- Категория: Mean reversion
- Направление: Оба
- Индикаторы: RSI, Supertrend
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Среднесрочный
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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>
/// Strategy based on RSI and Supertrend indicators.
/// Enters long when RSI is oversold (< 30) and price is above Supertrend
/// Enters short when RSI is overbought (> 70) and price is below Supertrend
/// </summary>
public class RsiSupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<DataType> _candleType;
// Custom Supertrend indicator
private AverageTrueRange _atr;
private decimal _upValue;
private decimal _downValue;
private decimal _currentTrend;
private decimal _prevUpValue;
private decimal _prevDownValue;
private decimal _prevClose;
private bool _isFirstValue = true;
/// <summary>
/// RSI period
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Supertrend ATR period
/// </summary>
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
/// <summary>
/// Supertrend ATR multiplier
/// </summary>
public decimal SupertrendMultiplier
{
get => _supertrendMultiplier.Value;
set => _supertrendMultiplier.Value = value;
}
/// <summary>
/// Candle type for strategy calculation
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor
/// </summary>
public RsiSupertrendStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Period for RSI indicator", "Indicators")
.SetOptimize(10, 20, 2);
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Supertrend Period", "ATR period for Supertrend", "Indicators")
.SetOptimize(7, 14, 1);
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Supertrend Multiplier", "ATR multiplier for Supertrend", "Indicators")
.SetOptimize(2.0m, 4.0m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
// Reset state variables
_atr = null;
_isFirstValue = true;
_currentTrend = 1;
_downValue = 0;
_prevUpValue = 0;
_prevDownValue = 0;
_prevClose = 0;
_upValue = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create RSI indicator
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
// Create ATR indicator for Supertrend calculation
_atr = new AverageTrueRange { Length = SupertrendPeriod };
// Enable using Supertrend as a dynamic stop-loss
// We'll implement our own stop management based on Supertrend
// Subscribe to candles and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, _atr, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
// Separate area for RSI
var rsiArea = CreateChartArea();
if (rsiArea != null)
{
DrawIndicator(rsiArea, rsi);
}
// Note: We'll manually draw Supertrend lines in ProcessCandle method
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal atrValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Calculate Supertrend
var closePrice = candle.ClosePrice;
var highPrice = candle.HighPrice;
var lowPrice = candle.LowPrice;
// Basic bands calculation
var basicUpperBand = (highPrice + lowPrice) / 2 + SupertrendMultiplier * atrValue;
var basicLowerBand = (highPrice + lowPrice) / 2 - SupertrendMultiplier * atrValue;
if (_isFirstValue)
{
// Initialize values for the first candle
_upValue = basicUpperBand;
_downValue = basicLowerBand;
_prevUpValue = _upValue;
_prevDownValue = _downValue;
_prevClose = closePrice;
_isFirstValue = false;
return;
}
// Calculate final upper and lower bands
_upValue = basicUpperBand;
if (_upValue < _prevUpValue || _prevClose > _prevUpValue)
_upValue = _prevUpValue;
_downValue = basicLowerBand;
if (_downValue > _prevDownValue || _prevClose < _prevDownValue)
_downValue = _prevDownValue;
// Determine trend direction
var prevTrend = _currentTrend;
if (_prevClose <= _prevUpValue)
_currentTrend = -1; // Downtrend
if (_prevClose >= _prevDownValue)
_currentTrend = 1; // Uptrend
// Store values for next iteration
_prevUpValue = _upValue;
_prevDownValue = _downValue;
_prevClose = closePrice;
// Get Supertrend value based on current trend
var supertrendValue = _currentTrend == 1 ? _downValue : _upValue;
// Trading logic
var isTrendChange = prevTrend != _currentTrend;
// Long condition: RSI oversold and price above Supertrend
if (rsiValue < 30 && _currentTrend == 1 && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
// Note: We're using Supertrend as our stop-loss level,
// so we don't need to set a separate stop-loss order
}
// Short condition: RSI overbought and price below Supertrend
else if (rsiValue > 70 && _currentTrend == -1 && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
// Exit conditions - based on Supertrend direction change
else if (isTrendChange)
{
if (_currentTrend == -1 && Position > 0)
{
// Trend changed to down - exit long
SellMarket(Position);
}
else if (_currentTrend == 1 && Position < 0)
{
// Trend changed to up - exit short
BuyMarket(Math.Abs(Position));
}
}
}
}
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
from StockSharp.Algo.Indicators import RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class rsi_supertrend_strategy(Strategy):
"""
Strategy based on RSI and Supertrend indicators.
Enters long when RSI is oversold (< 30) and price is above Supertrend
Enters short when RSI is overbought (> 70) and price is below Supertrend
"""
def __init__(self):
super(rsi_supertrend_strategy, self).__init__()
# Initialize strategy parameters
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("RSI Period", "Period for RSI indicator", "Indicators") \
.SetCanOptimize(True) \
.SetOptimize(10, 20, 2)
self._supertrend_period = self.Param("SupertrendPeriod", 10) \
.SetGreaterThanZero() \
.SetDisplay("Supertrend Period", "ATR period for Supertrend", "Indicators") \
.SetCanOptimize(True) \
.SetOptimize(7, 14, 1)
self._supertrend_multiplier = self.Param("SupertrendMultiplier", 3.0) \
.SetGreaterThanZero() \
.SetDisplay("Supertrend Multiplier", "ATR multiplier for Supertrend", "Indicators") \
.SetCanOptimize(True) \
.SetOptimize(2.0, 4.0, 0.5)
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Timeframe for strategy", "General")
# Custom Supertrend indicator
self._atr = None
self._up_value = 0.0
self._down_value = 0.0
self._current_trend = 0.0
self._prev_up_value = 0.0
self._prev_down_value = 0.0
self._prev_close = 0.0
self._is_first_value = True
@property
def rsi_period(self):
"""RSI period"""
return self._rsi_period.Value
@rsi_period.setter
def rsi_period(self, value):
self._rsi_period.Value = value
@property
def supertrend_period(self):
"""Supertrend ATR period"""
return self._supertrend_period.Value
@supertrend_period.setter
def supertrend_period(self, value):
self._supertrend_period.Value = value
@property
def supertrend_multiplier(self):
"""Supertrend ATR multiplier"""
return self._supertrend_multiplier.Value
@supertrend_multiplier.setter
def supertrend_multiplier(self, value):
self._supertrend_multiplier.Value = value
@property
def candle_type(self):
"""Candle type for strategy calculation"""
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
"""
Resets internal state when strategy is reset.
"""
super(rsi_supertrend_strategy, self).OnReseted()
self._atr = None
self._is_first_value = True
self._current_trend = 1
self._down_value = 0
self._prev_up_value = 0
self._prev_down_value = 0
self._prev_close = 0
self._up_value = 0
def OnStarted2(self, time):
"""
Called when the strategy starts. Sets up indicators, subscriptions, and charting.
:param time: The time when the strategy started.
"""
super(rsi_supertrend_strategy, self).OnStarted2(time)
# Create RSI indicator
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
# Create ATR indicator for Supertrend calculation
self._atr = AverageTrueRange()
self._atr.Length = self.supertrend_period
# Enable using Supertrend as a dynamic stop-loss
# We'll implement our own stop management based on Supertrend
# Subscribe to candles and bind indicators
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self._atr, self.ProcessCandle).Start()
# Setup chart visualization if available
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
# Separate area for RSI
rsi_area = self.CreateChartArea()
if rsi_area is not None:
self.DrawIndicator(rsi_area, rsi)
# Note: We'll manually draw Supertrend lines in ProcessCandle method
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, rsi_value, atr_value):
"""
Process candle and execute trading logic based on RSI and Supertrend.
:param candle: The processed candle message.
:param rsi_value: The current RSI value.
:param atr_value: The current ATR value.
"""
# Skip unfinished candles
if candle.State != CandleStates.Finished:
return
# Check if strategy is ready to trade
# Calculate Supertrend
close_price = float(candle.ClosePrice)
high_price = float(candle.HighPrice)
low_price = float(candle.LowPrice)
# Basic bands calculation
basic_upper_band = (high_price + low_price) / 2 + self.supertrend_multiplier * atr_value
basic_lower_band = (high_price + low_price) / 2 - self.supertrend_multiplier * atr_value
if self._is_first_value:
# Initialize values for the first candle
self._up_value = basic_upper_band
self._down_value = basic_lower_band
self._prev_up_value = self._up_value
self._prev_down_value = self._down_value
self._prev_close = close_price
self._is_first_value = False
return
# Calculate final upper and lower bands
self._up_value = basic_upper_band
if self._up_value < self._prev_up_value or self._prev_close > self._prev_up_value:
self._up_value = self._prev_up_value
self._down_value = basic_lower_band
if self._down_value > self._prev_down_value or self._prev_close < self._prev_down_value:
self._down_value = self._prev_down_value
# Determine trend direction
prev_trend = self._current_trend
if self._prev_close <= self._prev_up_value:
self._current_trend = -1 # Downtrend
if self._prev_close >= self._prev_down_value:
self._current_trend = 1 # Uptrend
# Store values for next iteration
self._prev_up_value = self._up_value
self._prev_down_value = self._down_value
self._prev_close = close_price
# Get Supertrend value based on current trend
supertrend_value = self._down_value if self._current_trend == 1 else self._up_value
# Trading logic
is_trend_change = prev_trend != self._current_trend
# Long condition: RSI oversold and price above Supertrend
if rsi_value < 30 and self._current_trend == 1 and self.Position <= 0:
self.BuyMarket(self.Volume + Math.Abs(self.Position))
# Note: We're using Supertrend as our stop-loss level,
# so we don't need to set a separate stop-loss order
# Short condition: RSI overbought and price below Supertrend
elif rsi_value > 70 and self._current_trend == -1 and self.Position >= 0:
self.SellMarket(self.Volume + Math.Abs(self.Position))
# Exit conditions - based on Supertrend direction change
elif is_trend_change:
if self._current_trend == -1 and self.Position > 0:
# Trend changed to down - exit long
self.SellMarket(self.Position)
elif self._current_trend == 1 and self.Position < 0:
# Trend changed to up - exit short
self.BuyMarket(Math.Abs(self.Position))
def CreateClone(self):
"""
!! REQUIRED!! Creates a new instance of the strategy.
"""
return rsi_supertrend_strategy()