Estrategia Double RSI
Double RSI utiliza dos cálculos del Índice de Fuerza Relativa: uno en el gráfico de trading y otro en un marco temporal superior. Las operaciones se realizan solo cuando ambas lecturas de RSI apoyan la misma dirección, alineando las entradas de corto plazo con el impulso de más largo plazo.
El marco temporal principal busca que el RSI cruce fuera de zonas de sobrecompra o sobreventa. Si el RSI del marco temporal superior confirma el movimiento, la estrategia abre una posición. Una toma de ganancias opcional puede asegurar las ganancias después de un movimiento predefinido.
Detalles
- Datos: Velas de precio en dos marcos temporales.
- Criterios de entrada:
- Largo: RSI de marco temporal inferior sale de sobreventa Y RSI de marco temporal superior es alcista.
- Corto: RSI de marco temporal inferior sale de sobrecompra Y RSI de marco temporal superior es bajista.
- Criterios de salida: Señal RSI opuesta o toma de ganancias si
UseTPes verdadero. - Stops: Ninguno por defecto.
- Valores predeterminados:
CandleType= tf(5)RSILength= 14MTFTimeframe= tf(15)UseTP= False
- Filtros:
- Categoría: Momentum
- Dirección: Largo/Corto
- Indicadores: RSI (multi‑timeframe)
- Complejidad: Moderado
- 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>
/// Double RSI Strategy.
/// Uses a short RSI and a long RSI for confirmation.
/// Buys when both RSIs are oversold and sells when both are overbought.
/// </summary>
public class DoubleRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleTypeParam;
private readonly StrategyParam<int> _rsiShortLength;
private readonly StrategyParam<int> _rsiLongLength;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<int> _cooldownBars;
private RelativeStrengthIndex _rsiShort;
private RelativeStrengthIndex _rsiLong;
private int _cooldownRemaining;
public DoubleRsiStrategy()
{
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General");
_rsiShortLength = Param(nameof(RSIShortLength), 7)
.SetGreaterThanZero()
.SetDisplay("Short RSI", "Short RSI period", "RSI");
_rsiLongLength = Param(nameof(RSILongLength), 21)
.SetGreaterThanZero()
.SetDisplay("Long RSI", "Long RSI period", "RSI");
_oversold = Param(nameof(Oversold), 35m)
.SetDisplay("Oversold", "RSI oversold level", "RSI");
_overbought = Param(nameof(Overbought), 65m)
.SetDisplay("Overbought", "RSI overbought level", "RSI");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
public int RSIShortLength
{
get => _rsiShortLength.Value;
set => _rsiShortLength.Value = value;
}
public int RSILongLength
{
get => _rsiLongLength.Value;
set => _rsiLongLength.Value = value;
}
public decimal Oversold
{
get => _oversold.Value;
set => _oversold.Value = value;
}
public decimal Overbought
{
get => _overbought.Value;
set => _overbought.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_rsiShort = null;
_rsiLong = null;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_rsiShort = new RelativeStrengthIndex { Length = RSIShortLength };
_rsiLong = new RelativeStrengthIndex { Length = RSILongLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsiShort, _rsiLong, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal rsiShort, decimal rsiLong)
{
if (candle.State != CandleStates.Finished)
return;
if (!_rsiShort.IsFormed || !_rsiLong.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
// Buy: both RSIs oversold
if (rsiShort < Oversold && rsiLong < Oversold && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: both RSIs overbought
else if (rsiShort > Overbought && rsiLong > Overbought && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: short RSI overbought
else if (Position > 0 && rsiShort > Overbought)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: short RSI oversold
else if (Position < 0 && rsiShort < Oversold)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = 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, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class double_rsi_strategy(Strategy):
"""Double RSI Strategy. Uses short and long RSI for entry/exit signals."""
def __init__(self):
super(double_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General")
self._rsi_short_length = self.Param("RSIShortLength", 7) \
.SetDisplay("Short RSI", "Short RSI period", "RSI")
self._rsi_long_length = self.Param("RSILongLength", 21) \
.SetDisplay("Long RSI", "Long RSI period", "RSI")
self._oversold = self.Param("Oversold", 35.0) \
.SetDisplay("Oversold", "RSI oversold level", "RSI")
self._overbought = self.Param("Overbought", 65.0) \
.SetDisplay("Overbought", "RSI overbought level", "RSI")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._rsi_short = None
self._rsi_long = None
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(double_rsi_strategy, self).OnReseted()
self._rsi_short = None
self._rsi_long = None
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(double_rsi_strategy, self).OnStarted2(time)
self._rsi_short = RelativeStrengthIndex()
self._rsi_short.Length = int(self._rsi_short_length.Value)
self._rsi_long = RelativeStrengthIndex()
self._rsi_long.Length = int(self._rsi_long_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._rsi_short, self._rsi_long, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, rsi_short_val, rsi_long_val):
if candle.State != CandleStates.Finished:
return
if not self._rsi_short.IsFormed or not self._rsi_long.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
rs = float(rsi_short_val)
rl = float(rsi_long_val)
oversold = float(self._oversold.Value)
overbought = float(self._overbought.Value)
cooldown = int(self._cooldown_bars.Value)
if rs < oversold and rl < oversold and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif rs > overbought and rl > overbought and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and rs > overbought:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and rs < oversold:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
def CreateClone(self):
return double_rsi_strategy()