Las pruebas indican un retorno anual promedio de aproximadamente 85%. Funciona mejor en el mercado de criptomonedas.
RSI Divergence busca extremos de precio no confirmados por el oscilador RSI. Una divergencia alcista lleva a una compra y una divergencia bajista provoca una venta. La operación dura hasta que el RSI revierte o se activa un stop.
Las configuraciones de divergencia suelen aparecer cerca del final de tendencias largas. Al comparar el comportamiento del oscilador con la acción del precio, la estrategia intenta capturar reversiones tempranas con riesgo controlado.
Detalles
Criterios de entrada: Señales basadas en RSI.
Largo/Corto: Ambas direcciones.
Criterios de salida: Señal opuesta o stop.
Stops: Sí.
Valores predeterminados:
RsiPeriod = 14
StopLossPercent = 2m
CandleType = TimeSpan.FromMinutes(5)
Filtros:
Categoría: Tendencia
Dirección: Ambos
Indicadores: RSI
Stops: Sí
Complejidad: Básico
Marco temporal: Intradía (5m)
Estacionalidad: No
Neural Networks: No
Divergencia: Sí
Nivel de riesgo: Medio
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Trades divergences between consecutive confirmed price pivots and their RSI values.
/// A three-bar pivot is confirmed only after the bar to its right has closed.
/// </summary>
public class RsiDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal High, decimal Low, decimal Rsi)> _bars = new();
private decimal _previousLowPrice;
private decimal _previousLowRsi;
private decimal _previousHighPrice;
private decimal _previousHighRsi;
private bool _hasLow;
private bool _hasHigh;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RsiDivergenceStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetGreaterThanZero();
_stopLossPercent = Param(nameof(StopLossPercent), 2m).SetRange(0m, 100m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
ResetPivots();
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetPivots();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
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 ResetPivots()
{
_bars.Clear();
_previousLowPrice = _previousLowRsi = _previousHighPrice = _previousHighRsi = 0m;
_hasLow = _hasHigh = false;
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished || !IsFormedAndOnlineAndAllowTrading())
return;
_bars.Add((candle.HighPrice, candle.LowPrice, rsiValue));
if (_bars.Count < 3)
return;
var left = _bars[0];
var pivot = _bars[1];
var right = _bars[2];
var bullish = false;
var bearish = false;
if (pivot.Low < left.Low && pivot.Low < right.Low)
{
bullish = _hasLow && pivot.Low < _previousLowPrice && pivot.Rsi > _previousLowRsi;
_previousLowPrice = pivot.Low;
_previousLowRsi = pivot.Rsi;
_hasLow = true;
}
if (pivot.High > left.High && pivot.High > right.High)
{
bearish = _hasHigh && pivot.High > _previousHighPrice && pivot.Rsi < _previousHighRsi;
_previousHighPrice = pivot.High;
_previousHighRsi = pivot.Rsi;
_hasHigh = true;
}
_bars.RemoveAt(0);
if (bullish && Position <= 0m)
BuyMarket(Volume + Math.Abs(Position));
else if (bearish && Position >= 0m)
SellMarket(Volume + 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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class rsi_divergence_strategy(Strategy):
"""Trades confirmed three-bar price pivots unconfirmed by RSI, without future bars."""
def __init__(self):
super(rsi_divergence_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetGreaterThanZero()
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetRange(0.0, 100.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._reset_pivots()
def GetWorkingSecurities(self):
return [(self.Security, self._candle_type.Value)]
def OnReseted(self):
super(rsi_divergence_strategy, self).OnReseted()
self._reset_pivots()
def _reset_pivots(self):
self._bars = []
self._previous_low = None
self._previous_high = None
def OnStarted2(self, time):
super(rsi_divergence_strategy, self).OnStarted2(time)
self._reset_pivots()
self.StartProtection(Unit(), Unit(float(self._stop_loss_percent.Value), UnitTypes.Percent),
useMarketOrders=True, isLocalStop=True)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self._candle_type.Value)
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_value):
if candle.State != CandleStates.Finished or not self.IsFormedAndOnlineAndAllowTrading():
return
self._bars.append((candle.HighPrice, candle.LowPrice, rsi_value))
if len(self._bars) < 3:
return
left, pivot, right = self._bars
bullish = False
bearish = False
if pivot[1] < left[1] and pivot[1] < right[1]:
bullish = (self._previous_low is not None and
pivot[1] < self._previous_low[0] and pivot[2] > self._previous_low[1])
self._previous_low = (pivot[1], pivot[2])
if pivot[0] > left[0] and pivot[0] > right[0]:
bearish = (self._previous_high is not None and
pivot[0] > self._previous_high[0] and pivot[2] < self._previous_high[1])
self._previous_high = (pivot[0], pivot[2])
self._bars.pop(0)
if bullish and self.Position <= 0:
self.BuyMarket(self.Volume + Math.Abs(self.Position))
elif bearish and self.Position >= 0:
self.SellMarket(self.Volume + Math.Abs(self.Position))
def CreateClone(self):
return rsi_divergence_strategy()