Estrategia de Todas las Divergencias
La Estrategia de Todas las Divergencias busca divergencias alcistas y bajistas del RSI filtradas por la tendencia de una media móvil. Se abre una posición larga cuando el precio marca un mínimo más bajo mientras el RSI forma un mínimo más alto por encima de la media móvil. Se abre una posición corta cuando el precio marca un máximo más alto mientras el RSI forma un máximo más bajo por debajo de la media móvil. Una protección opcional de stop-loss y take-profit puede cerrar posiciones automáticamente, y un control de riesgo por media móvil sale tras varios cierres contra la tendencia.
Detalles
- Criterios de entrada:
- La posición del precio respecto a la media móvil define la tendencia.
- Largo: el precio hace un mínimo más bajo, el RSI un mínimo más alto, el precio por encima de la MA.
- Corto: el precio hace un máximo más alto, el RSI un máximo más bajo, el precio por debajo de la MA.
- Largo/Corto: Ambos lados.
- Criterios de salida:
- Señal opuesta o salida por riesgo de MA.
- Stops: Stop-loss y take-profit opcionales.
- Valores predeterminados:
MaLength= 50RsiLength= 14MaRiskCandles= 3UseProtection= False
- Filtros:
- Categoría: Divergencia
- Dirección: Ambos
- Indicadores: RSI, Moving Average
- Stops: Opcional
- Complejidad: Moderado
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: Sí
- 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>
/// All Divergences strategy - trades RSI divergences filtered by moving average.
/// Bullish divergence: price makes lower low but RSI makes higher low.
/// Bearish divergence: price makes higher high but RSI makes lower high.
/// </summary>
public class AllDivergencesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _lookbackBars;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevLowPrice;
private decimal _prevLowRsi;
private decimal _prevHighPrice;
private decimal _prevHighRsi;
private decimal _curLowPrice;
private decimal _curLowRsi;
private decimal _curHighPrice;
private decimal _curHighRsi;
private int _barsSinceExtreme;
private int _cooldownRemaining;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int LookbackBars { get => _lookbackBars.Value; set => _lookbackBars.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public AllDivergencesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_maLength = Param(nameof(MaLength), 50)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Length of moving average", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_lookbackBars = Param(nameof(LookbackBars), 20)
.SetGreaterThanZero()
.SetDisplay("Lookback Bars", "Bars to look back for divergence", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevLowPrice = 0;
_prevLowRsi = 0;
_prevHighPrice = 0;
_prevHighRsi = 0;
_curLowPrice = decimal.MaxValue;
_curLowRsi = 100;
_curHighPrice = 0;
_curHighRsi = 0;
_barsSinceExtreme = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var ma = new SimpleMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal maValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Track current lows and highs
if (candle.LowPrice < _curLowPrice)
{
_curLowPrice = candle.LowPrice;
_curLowRsi = rsiValue;
}
if (candle.HighPrice > _curHighPrice)
{
_curHighPrice = candle.HighPrice;
_curHighRsi = rsiValue;
}
_barsSinceExtreme++;
// Reset extremes periodically
if (_barsSinceExtreme >= LookbackBars)
{
_prevLowPrice = _curLowPrice;
_prevLowRsi = _curLowRsi;
_prevHighPrice = _curHighPrice;
_prevHighRsi = _curHighRsi;
_curLowPrice = decimal.MaxValue;
_curLowRsi = 100;
_curHighPrice = 0;
_curHighRsi = 0;
_barsSinceExtreme = 0;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
if (_prevLowPrice == 0 || _prevHighPrice == 0)
return;
// Bullish divergence: lower low in price, higher low in RSI + price above MA
var bullishDiv = candle.LowPrice < _prevLowPrice && rsiValue > _prevLowRsi && candle.ClosePrice > maValue;
// Bearish divergence: higher high in price, lower high in RSI + price below MA
var bearishDiv = candle.HighPrice > _prevHighPrice && rsiValue < _prevHighRsi && candle.ClosePrice < maValue;
if (bullishDiv && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
else if (bearishDiv && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_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
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class all_divergences_strategy(Strategy):
def __init__(self):
super(all_divergences_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._ma_length = self.Param("MaLength", 50) \
.SetGreaterThanZero() \
.SetDisplay("MA Length", "Length of moving average", "Indicators")
self._rsi_length = self.Param("RsiLength", 14) \
.SetGreaterThanZero() \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._lookback_bars = self.Param("LookbackBars", 20) \
.SetGreaterThanZero() \
.SetDisplay("Lookback Bars", "Bars to look back for divergence", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._prev_low_price = 0.0
self._prev_low_rsi = 0.0
self._prev_high_price = 0.0
self._prev_high_rsi = 0.0
self._cur_low_price = 1e18
self._cur_low_rsi = 100.0
self._cur_high_price = 0.0
self._cur_high_rsi = 0.0
self._bars_since_extreme = 0
self._cooldown_remaining = 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 cooldown_bars(self):
return self._cooldown_bars.Value
@cooldown_bars.setter
def cooldown_bars(self, value):
self._cooldown_bars.Value = value
def OnReseted(self):
super(all_divergences_strategy, self).OnReseted()
self._prev_low_price = 0.0
self._prev_low_rsi = 0.0
self._prev_high_price = 0.0
self._prev_high_rsi = 0.0
self._cur_low_price = 1e18
self._cur_low_rsi = 100.0
self._cur_high_price = 0.0
self._cur_high_rsi = 0.0
self._bars_since_extreme = 0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(all_divergences_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
ma = SimpleMovingAverage()
ma.Length = self._ma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, ma, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, rsi_val, ma_val):
if candle.State != CandleStates.Finished:
return
rsi_v = float(rsi_val)
ma_v = float(ma_val)
low = float(candle.LowPrice)
high = float(candle.HighPrice)
close = float(candle.ClosePrice)
if low < self._cur_low_price:
self._cur_low_price = low
self._cur_low_rsi = rsi_v
if high > self._cur_high_price:
self._cur_high_price = high
self._cur_high_rsi = rsi_v
self._bars_since_extreme += 1
lookback = self._lookback_bars.Value
if self._bars_since_extreme >= lookback:
self._prev_low_price = self._cur_low_price
self._prev_low_rsi = self._cur_low_rsi
self._prev_high_price = self._cur_high_price
self._prev_high_rsi = self._cur_high_rsi
self._cur_low_price = 1e18
self._cur_low_rsi = 100.0
self._cur_high_price = 0.0
self._cur_high_rsi = 0.0
self._bars_since_extreme = 0
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
if self._prev_low_price == 0 or self._prev_high_price == 0:
return
bullish_div = low < self._prev_low_price and rsi_v > self._prev_low_rsi and close > ma_v
bearish_div = high > self._prev_high_price and rsi_v < self._prev_high_rsi and close < ma_v
if bullish_div and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_bars
elif bearish_div and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_bars
def CreateClone(self):
return all_divergences_strategy()