Divergencia RSI de Vela Grande
Identifica velas inusualmente grandes en relación con las cinco barras anteriores y compara los valores de RSI rápido y lento. Las operaciones siguen la dirección de la vela y usan un stop trailing retrasado que se activa solo después de que el precio se mueva un número determinado de ticks en beneficio.
El stop trailing comienza una vez alcanzado el umbral de beneficio y luego sigue el precio a una distancia fija, mientras que un stop fijo inicial protege la operación desde el inicio.
Detalles
- Criterios de entrada:
- Largo: El cuerpo de la vela actual es mayor que los cinco anteriores y cierra al alza.
- Corto: El cuerpo de la vela actual es mayor que los cinco anteriores y cierra a la baja.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Stop inicial o stop trailing alcanzado.
- Stops: Sí, stop trailing retrasado.
- Valores predeterminados:
TrailStartTicks= 200TrailDistanceTicks= 150InitialStopLossTicks= 200CandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Reversión
- Dirección: Ambos
- Indicadores: RSI
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Intradía
- 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>
/// Big Candle Identifier with RSI divergence and trailing stops.
/// Enters when the current candle body is the largest of the last N candles.
/// Uses RSI fast/slow divergence as confirmation.
/// </summary>
public class BigCandleRsiDivergenceStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _trailStartPercent;
private readonly StrategyParam<decimal> _trailDistancePercent;
private readonly StrategyParam<int> _lookbackBars;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _bodies = new();
private decimal _entryPrice;
private decimal _highestSinceEntry;
private decimal _lowestSinceEntry;
private bool _trailingActive;
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public decimal TrailStartPercent { get => _trailStartPercent.Value; set => _trailStartPercent.Value = value; }
public decimal TrailDistancePercent { get => _trailDistancePercent.Value; set => _trailDistancePercent.Value = value; }
public int LookbackBars { get => _lookbackBars.Value; set => _lookbackBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BigCandleRsiDivergenceStrategy()
{
_stopLossPercent = Param(nameof(StopLossPercent), 0.3m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Initial stop loss percent", "Risk");
_trailStartPercent = Param(nameof(TrailStartPercent), 0.5m)
.SetGreaterThanZero()
.SetDisplay("Trail Start %", "Profit percent to activate trailing", "Risk");
_trailDistancePercent = Param(nameof(TrailDistancePercent), 0.2m)
.SetGreaterThanZero()
.SetDisplay("Trail Distance %", "Trailing stop distance percent", "Risk");
_lookbackBars = Param(nameof(LookbackBars), 3)
.SetGreaterThanZero()
.SetDisplay("Lookback Bars", "Number of bars for big candle comparison", "Strategy");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bodies.Clear();
_entryPrice = 0m;
_highestSinceEntry = 0m;
_lowestSinceEntry = 0m;
_trailingActive = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsiFast = new RelativeStrengthIndex { Length = 5 };
var rsiSlow = new RelativeStrengthIndex { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsiFast, rsiSlow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiFast, decimal rsiSlow)
{
if (candle.State != CandleStates.Finished)
return;
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
_bodies.Add(body);
if (_bodies.Count > LookbackBars + 1)
_bodies.RemoveAt(0);
if (_bodies.Count <= LookbackBars)
return;
// Check if current body is the largest in lookback window
var isBiggest = true;
for (var i = 0; i < _bodies.Count - 1; i++)
{
if (_bodies[i] >= body)
{
isBiggest = false;
break;
}
}
var isBullish = candle.ClosePrice > candle.OpenPrice;
var isBearish = candle.ClosePrice < candle.OpenPrice;
var rsiDivergence = rsiFast - rsiSlow;
if (Position == 0)
{
if (isBiggest && isBullish && rsiDivergence > 0)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_highestSinceEntry = candle.ClosePrice;
_trailingActive = false;
}
else if (isBiggest && isBearish && rsiDivergence < 0)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_lowestSinceEntry = candle.ClosePrice;
_trailingActive = false;
}
}
else if (Position > 0 && _entryPrice > 0)
{
_highestSinceEntry = Math.Max(_highestSinceEntry, candle.ClosePrice);
var profitPercent = (candle.ClosePrice - _entryPrice) / _entryPrice * 100m;
if (!_trailingActive && profitPercent >= TrailStartPercent)
_trailingActive = true;
if (_trailingActive)
{
var stop = _highestSinceEntry * (1 - TrailDistancePercent / 100m);
if (candle.ClosePrice <= stop)
{
SellMarket();
_entryPrice = 0m;
_trailingActive = false;
}
}
else
{
var stop = _entryPrice * (1 - StopLossPercent / 100m);
if (candle.ClosePrice <= stop)
{
SellMarket();
_entryPrice = 0m;
}
}
}
else if (Position < 0 && _entryPrice > 0)
{
_lowestSinceEntry = Math.Min(_lowestSinceEntry, candle.ClosePrice);
var profitPercent = (_entryPrice - candle.ClosePrice) / _entryPrice * 100m;
if (!_trailingActive && profitPercent >= TrailStartPercent)
_trailingActive = true;
if (_trailingActive)
{
var stop = _lowestSinceEntry * (1 + TrailDistancePercent / 100m);
if (candle.ClosePrice >= stop)
{
BuyMarket();
_entryPrice = 0m;
_trailingActive = false;
}
}
else
{
var stop = _entryPrice * (1 + StopLossPercent / 100m);
if (candle.ClosePrice >= stop)
{
BuyMarket();
_entryPrice = 0m;
}
}
}
}
}
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
from StockSharp.Algo.Strategies import Strategy
class big_candle_rsi_divergence_strategy(Strategy):
def __init__(self):
super(big_candle_rsi_divergence_strategy, self).__init__()
self._stop_loss_percent = self.Param("StopLossPercent", 0.3) \
.SetGreaterThanZero() \
.SetDisplay("Stop Loss %", "Initial stop loss percent", "Risk")
self._trail_start_percent = self.Param("TrailStartPercent", 0.5) \
.SetGreaterThanZero() \
.SetDisplay("Trail Start %", "Profit percent to activate trailing", "Risk")
self._trail_distance_percent = self.Param("TrailDistancePercent", 0.2) \
.SetGreaterThanZero() \
.SetDisplay("Trail Distance %", "Trailing stop distance percent", "Risk")
self._lookback_bars = self.Param("LookbackBars", 3) \
.SetGreaterThanZero() \
.SetDisplay("Lookback Bars", "Number of bars for big candle comparison", "Strategy")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bodies = []
self._entry_price = 0.0
self._highest_since_entry = 0.0
self._lowest_since_entry = 0.0
self._trailing_active = False
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(big_candle_rsi_divergence_strategy, self).OnReseted()
self._bodies = []
self._entry_price = 0.0
self._highest_since_entry = 0.0
self._lowest_since_entry = 0.0
self._trailing_active = False
def OnStarted2(self, time):
super(big_candle_rsi_divergence_strategy, self).OnStarted2(time)
rsi_fast = RelativeStrengthIndex()
rsi_fast.Length = 5
rsi_slow = RelativeStrengthIndex()
rsi_slow.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi_fast, rsi_slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, rsi_fast_val, rsi_slow_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
body = abs(close - open_p)
lookback = self._lookback_bars.Value
self._bodies.append(body)
if len(self._bodies) > lookback + 1:
self._bodies = self._bodies[1:]
if len(self._bodies) <= lookback:
return
is_biggest = True
for i in range(len(self._bodies) - 1):
if self._bodies[i] >= body:
is_biggest = False
break
is_bullish = close > open_p
is_bearish = close < open_p
rsi_divergence = float(rsi_fast_val) - float(rsi_slow_val)
sl_pct = float(self._stop_loss_percent.Value)
ts_pct = float(self._trail_start_percent.Value)
td_pct = float(self._trail_distance_percent.Value)
if self.Position == 0:
if is_biggest and is_bullish and rsi_divergence > 0:
self.BuyMarket()
self._entry_price = close
self._highest_since_entry = close
self._trailing_active = False
elif is_biggest and is_bearish and rsi_divergence < 0:
self.SellMarket()
self._entry_price = close
self._lowest_since_entry = close
self._trailing_active = False
elif self.Position > 0 and self._entry_price > 0:
if close > self._highest_since_entry:
self._highest_since_entry = close
profit_pct = (close - self._entry_price) / self._entry_price * 100.0
if not self._trailing_active and profit_pct >= ts_pct:
self._trailing_active = True
if self._trailing_active:
stop = self._highest_since_entry * (1.0 - td_pct / 100.0)
if close <= stop:
self.SellMarket()
self._entry_price = 0.0
self._trailing_active = False
else:
stop = self._entry_price * (1.0 - sl_pct / 100.0)
if close <= stop:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0 and self._entry_price > 0:
if close < self._lowest_since_entry:
self._lowest_since_entry = close
profit_pct = (self._entry_price - close) / self._entry_price * 100.0
if not self._trailing_active and profit_pct >= ts_pct:
self._trailing_active = True
if self._trailing_active:
stop = self._lowest_since_entry * (1.0 + td_pct / 100.0)
if close >= stop:
self.BuyMarket()
self._entry_price = 0.0
self._trailing_active = False
else:
stop = self._entry_price * (1.0 + sl_pct / 100.0)
if close >= stop:
self.BuyMarket()
self._entry_price = 0.0
def CreateClone(self):
return big_candle_rsi_divergence_strategy()