Estrategia Rsi Stochastic
Estrategia que combina el RSI y el Oscilador Stochastic para doble confirmación de condiciones de sobreventa y sobrecompra.
Las pruebas indican un retorno anual promedio de aproximadamente 181%. Funciona mejor en el mercado de criptomonedas.
El RSI proporciona una visión más amplia del momentum, mientras que el Stochastic da señales más rápidas cerca de los extremos. Las operaciones cambian cuando el oscilador cruza niveles dentro del contexto del RSI.
Ideal para traders ágiles que prefieren configuraciones de osciladores. La estrategia se apoya en un stop de ATR para contener el riesgo.
Detalles
- Criterios de entrada:
- Largo:
RSI < RsiOversold && StochK < StochOversold - Corto:
RSI > RsiOverbought && StochK > StochOverbought
- Largo:
- Largo/Corto: Ambos
- Criterios de salida:
- Largo:
RSI > 50 - Corto:
RSI < 50
- Largo:
- Stops: Basado en porcentaje en
StopLossPercent - Valores predeterminados:
RsiPeriod= 14RsiOversold= 30mRsiOverbought= 70mStochPeriod= 14StochK= 3StochD= 3StochOversold= 20mStochOverbought= 80mStopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoría: Reversión a la media
- Dirección: Ambos
- Indicadores: RSI, Stochastic Oscillator
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Medio plazo
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Strategy combining RSI with EMA trend filter for oversold/overbought trading.
/// </summary>
public class RsiStochasticStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _cooldownBars;
private decimal _emaValue;
private int _cooldown;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// EMA period for trend filter.
/// </summary>
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Strategy constructor.
/// </summary>
public RsiStochasticStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetRange(7, 21)
.SetDisplay("RSI Period", "Period of the RSI indicator", "Indicators");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetRange(10, 50)
.SetDisplay("EMA Period", "EMA period for trend filter", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 100)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_emaValue = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
// Bind EMA to capture value
subscription.Bind(ema, OnEma);
// Bind RSI for main logic
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
var rsiArea = CreateChartArea();
if (rsiArea != null)
DrawIndicator(rsiArea, rsi);
}
}
private void OnEma(ICandleMessage candle, decimal ema)
{
_emaValue = ema;
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_emaValue == 0)
return;
var close = candle.ClosePrice;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Long: RSI oversold
if (rsiValue < RsiOversold && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Short: RSI overbought
else if (rsiValue > RsiOverbought && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit long: RSI returns to neutral
if (Position > 0 && rsiValue > 50)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short: RSI returns to neutral
else if (Position < 0 && rsiValue < 50)
{
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, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class rsi_stochastic_strategy(Strategy):
"""
Strategy combining RSI with EMA trend filter for oversold/overbought trading.
"""
def __init__(self):
super(rsi_stochastic_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetRange(7, 21) \
.SetDisplay("RSI Period", "Period of the RSI indicator", "Indicators")
self._rsi_oversold = self.Param("RsiOversold", 30.0) \
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators")
self._rsi_overbought = self.Param("RsiOverbought", 70.0) \
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators")
self._ema_period = self.Param("EmaPeriod", 20) \
.SetRange(10, 50) \
.SetDisplay("EMA Period", "EMA period for trend filter", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 100) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General") \
.SetRange(5, 500)
self._ema_value = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def rsi_oversold(self):
return self._rsi_oversold.Value
@property
def rsi_overbought(self):
return self._rsi_overbought.Value
@property
def ema_period(self):
return self._ema_period.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
def OnStarted2(self, time):
super(rsi_stochastic_strategy, self).OnStarted2(time)
self._ema_value = 0.0
self._cooldown = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
# Bind EMA to capture value
subscription.Bind(ema, self.OnEma)
# Bind RSI for main logic
subscription.Bind(rsi, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
rsi_area = self.CreateChartArea()
if rsi_area is not None:
self.DrawIndicator(rsi_area, rsi)
def OnEma(self, candle, ema_val):
self._ema_value = float(ema_val)
def ProcessCandle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if self._ema_value == 0:
return
if self._cooldown > 0:
self._cooldown -= 1
return
rv = float(rsi_value)
# Long: RSI oversold
if rv < self.rsi_oversold and self.Position == 0:
self.BuyMarket()
self._cooldown = self.cooldown_bars
# Short: RSI overbought
elif rv > self.rsi_overbought and self.Position == 0:
self.SellMarket()
self._cooldown = self.cooldown_bars
# Exit long: RSI returns to neutral
if self.Position > 0 and rv > 50:
self.SellMarket()
self._cooldown = self.cooldown_bars
# Exit short: RSI returns to neutral
elif self.Position < 0 and rv < 50:
self.BuyMarket()
self._cooldown = self.cooldown_bars
def OnReseted(self):
super(rsi_stochastic_strategy, self).OnReseted()
self._ema_value = 0.0
self._cooldown = 0
def CreateClone(self):
return rsi_stochastic_strategy()