La estrategia ABE BE RSI es una adaptación del MetaTrader asesor experto Expert_ABE_BE_RSI. El sistema combina patrones clásicos de inversión de velas con la confirmación del impulso del índice de fuerza relativa (RSI). Dos velas consecutivas deben formar un patrón envolvente alcista o bajista, y la vela completada más reciente debe mostrar una lectura RSI dentro de umbrales predefinidos. Se aplican reglas cruzadas RSI adicionales para aplanar o revertir posiciones existentes, lo que refleja fielmente la lógica de decisión de la implementación MQL original.
Lógica de trading
Detección de patrones envolventes
La estrategia evalúa las dos últimas velas completadas. Una señal alcista requiere:
La vela t-2 cierra por debajo de su apertura (cuerpo bajista).
La vela t-1 cierra más alto de lo que abre (cuerpo alcista).
El tamaño del cuerpo de la vela t-1 excede el promedio móvil de los tamaños de cuerpo recientes (cinco barras por defecto).
La vela t-1 cierra por encima de la apertura de la vela t-2 y se abre por debajo de su cierre, lo que garantiza un verdadero evento envolvente.
El punto medio de la vela t-2 está por debajo de la media móvil de los precios de cierre, lo que confirma una tendencia bajista a corto plazo.
Una señal envolvente bajista utiliza condiciones simétricas: la vela más antigua es alcista, la vela más nueva es bajista con un cuerpo más grande que el promedio y la vela más nueva envuelve completamente el cuerpo anterior mientras que el punto medio de la barra más antigua se ubica por encima del promedio móvil para confirmar el agotamiento de la tendencia bajista.
RSI Confirmación
Las entradas largas requieren que el RSI de la vela cerrada más recientemente esté por debajo del nivel de entrada alcista configurado (predeterminado 40).
Las entradas cortas requieren que el RSI de la vela cerrada más recientemente esté por encima del nivel de entrada bajista (predeterminado 60).
Gestión de salida
Se monitorean RSI cruces en dos niveles para cerrar posiciones existentes:
Las posiciones cortas se cubren cuando RSI supera el umbral de salida inferior (predeterminado 30) o superior (predeterminado 70) después de estar por debajo de él en la vela anterior.
Las posiciones largas se cierran cuando RSI cae por debajo de cualquiera de los umbrales después de haber estado por encima de él en la vela anterior.
Ejecución de órdenes
Las órdenes de mercado se utilizan tanto para entradas como para salidas. Al invertir, la estrategia primero cierra la exposición actual y luego entra en la nueva dirección con el volumen base configurado. El tamaño de la posición imita el modelo de lote fijo del experto MQL.
Parámetros
Nombre
Descripción
Predeterminado
Volume
Tamaño del pedido en contratos.
0.1
RsiPeriod
Número de barras utilizadas por el filtro RSI.
11
MovingAveragePeriod
Período para el tamaño del cuerpo de la vela y las medias móviles del precio de cierre.
5
BullishEntryLevel
Valor máximo RSI que aún valida una entrada envolvente alcista.
40
BearishEntryLevel
Valor mínimo RSI requerido para una entrada envolvente bajista.
60
ExitLowerLevel
Baje el nivel de cruce RSI para posiciones planas.
30
ExitUpperLevel
Nivel de cruce superior RSI para posiciones de aplanamiento.
70
CandleType
Serie de velas procesadas por la estrategia.
1 hour time frame
Todos los parámetros se pueden optimizar dentro de Designer o Runner gracias a los contenedores StrategyParam.
Tubería de indicadores
Índice de fuerza relativa (RSI): calcula el impulso sobre el RsiPeriod configurable y proporciona umbrales de entrada/salida.
Promedio móvil simple de precios de cierre: proporciona un contexto de tendencia utilizado para validar patrones envolventes.
Promedio móvil simple de tamaños de cuerpo de velas: garantiza que la vela envolvente sea más grande que el tamaño de cuerpo promedio en las últimas MovingAveragePeriod barras.
Notas de uso
La estrategia sólo actúa sobre velas completamente completadas (CandleStates.Finished). Los datos de la barra parcial se ignoran para evitar señales prematuras.
El historial de velas se almacena internamente para evaluar las condiciones envolventes sin atravesar grandes colecciones, respetando las pautas de conversión de todo el proyecto.
StartProtection() está habilitado para que los mecanismos de protección base StockSharp se activen cuando la exposición de la posición no es cero.
Diferencias frente al Expert Advisor original
El Asesor Experto original se basa en el sistema de votación de señales de MetaTrader. En este puerto, los votos se traducen en acciones directas de entrada y salida que replican las mismas condiciones.
La administración del dinero se simplifica a un único parámetro Volume, que refleja el tamaño de lote fijo (Money_FixLot_Lots) utilizado por el experto en fuentes.
La compatibilidad con trailing-stop no está incluida, ya que la versión MT5 utilizaba un módulo "sin seguimiento".
Pruebas recomendadas
Adjunte la estrategia a un gráfico en Designer o API Runner con un símbolo que históricamente reacciona a las reversiones envolventes (por ejemplo, los principales pares de divisas).
Verifique RSI y los parámetros de promedio móvil antes de ejecutar sesiones en vivo; los valores predeterminados reproducen la configuración del asesor experto publicada.
Utilice las funciones de optimización integradas para explorar umbrales RSI alternativos o períodos promedio para diferentes mercados.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// ABE BE RSI strategy: Engulfing pattern with RSI confirmation.
/// Bullish engulfing + oversold RSI for long, bearish engulfing + overbought RSI for short.
/// </summary>
public class AbeBeRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<int> _signalCooldownCandles;
private readonly List<ICandleMessage> _candles = new();
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public AbeBeRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_oversold = Param(nameof(Oversold), 40m)
.SetDisplay("Oversold", "RSI oversold level", "Signals");
_overbought = Param(nameof(Overbought), 60m)
.SetDisplay("Overbought", "RSI overbought level", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
_candles.Add(candle);
if (_candles.Count > 5)
_candles.RemoveAt(0);
if (_candles.Count >= 2)
{
var curr = _candles[^1];
var prev = _candles[^2];
var bullishEngulfing = prev.OpenPrice > prev.ClosePrice
&& curr.ClosePrice > curr.OpenPrice
&& curr.OpenPrice <= prev.ClosePrice
&& curr.ClosePrice >= prev.OpenPrice;
var bearishEngulfing = prev.ClosePrice > prev.OpenPrice
&& curr.OpenPrice > curr.ClosePrice
&& curr.OpenPrice >= prev.ClosePrice
&& curr.ClosePrice <= prev.OpenPrice;
if (bullishEngulfing && rsiValue < Oversold && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (bearishEngulfing && rsiValue > Overbought && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
}
}
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 abe_be_rsi_strategy(Strategy):
def __init__(self):
super(abe_be_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._oversold = self.Param("Oversold", 40.0)
self._overbought = self.Param("Overbought", 60.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._candles = []
self._candles_since_trade = 6
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def Oversold(self):
return self._oversold.Value
@Oversold.setter
def Oversold(self, value):
self._oversold.Value = value
@property
def Overbought(self):
return self._overbought.Value
@Overbought.setter
def Overbought(self, value):
self._overbought.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(abe_be_rsi_strategy, self).OnReseted()
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(abe_be_rsi_strategy, self).OnStarted2(time)
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
rsi_val = float(rsi_value)
self._candles.append(candle)
if len(self._candles) > 5:
self._candles.pop(0)
if len(self._candles) >= 2:
curr = self._candles[-1]
prev = self._candles[-2]
bullish_engulfing = (float(prev.OpenPrice) > float(prev.ClosePrice)
and float(curr.ClosePrice) > float(curr.OpenPrice)
and float(curr.OpenPrice) <= float(prev.ClosePrice)
and float(curr.ClosePrice) >= float(prev.OpenPrice))
bearish_engulfing = (float(prev.ClosePrice) > float(prev.OpenPrice)
and float(curr.OpenPrice) > float(curr.ClosePrice)
and float(curr.OpenPrice) >= float(prev.ClosePrice)
and float(curr.ClosePrice) <= float(prev.OpenPrice))
if bullish_engulfing and rsi_val < self.Oversold and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif bearish_engulfing and rsi_val > self.Overbought and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return abe_be_rsi_strategy()