Esta estrategia transfiere el asesor experto MetaTrader "Divergencia + ema + rsi solo compra cercana" al asesor experto de alto nivel de StockSharp API. Actúa sobre velas de 5 minutos mientras consulta datos horarios y diarios para confirmar la alineación de la tendencia y las condiciones de sobreventa. Los pedidos son sólo largos. Las entradas requieren una divergencia alcista del histograma MACD que se confirma mediante un cruce estocástico horario dentro de una estrecha banda de sobreventa y por una estructura diaria ascendente EMA. Las salidas se basan en un exceso fijo de RSI combinado con una protección opcional de stop-loss y take-profit administrada por el marco.
Lógica de trading
Filtro de tendencias de marco temporal más alto
El EMA(9) diario debe estar por encima de EMA(20) para garantizar una tendencia alcista predominante.
El último cierre de 5 minutos debe permanecer por debajo del EMA(9) diario para que se intenten entradas largas desde retrocesos.
Confirmación estocástica horaria
El valor %K estocástico horario completado más reciente debe estar entre StochasticLowerBound (predeterminado 0) y StochasticUpperBound (predeterminado 40).
%K debe haber cruzado por encima de %D en la última barra horaria (%K actual > %D mientras que el %K anterior ≤ %D anterior).
MACD activador de divergencia (5 minutos)
El histograma MACD (línea MACD menos línea de señal) debe mejorar al menos MacdThreshold mientras que el cierre de 5 minutos establece un mínimo más bajo en comparación con la vela anterior. Esto se aproxima a la divergencia alcista utilizada por el EA original.
Ejecución de entrada
Cuando todos los filtros se alinean y no hay ninguna posición larga abierta, la estrategia envía una compra de mercado. Si existe una posición corta inesperada, el volumen solicitado aumenta para neutralizarla antes de pasar a largo.
Reglas de salida
Una salida protectora RSI cierra la larga cuando el RSI de 5 minutos cruza por encima de RsiExitLevel (por defecto 77).
StartProtection activa los niveles de stop-loss y take-profit convertidos de pips en distancias de precios siempre que los parámetros correspondientes sean positivos.
Gestión de pedidos
Todas las órdenes activas se cancelan antes de enviar una nueva orden de compra de mercado para evitar ejecuciones duplicadas.
El volumen predeterminado es el parámetro TradeVolume y se puede ajustar para optimización.
Parámetros
Nombre
Descripción
Predeterminado
CandleType
Plazo principal para MACD, RSI y ejecución.
velas de 5 minutos
HourTimeFrame
Marco de tiempo horario utilizado por el filtro estocástico.
1 hora
DayTimeFrame
Plazo diario para la confirmación de tendencia de EMA.
Distancia de stop-loss en pips (0 desactivaciones).
100
TakeProfitPips
Distancia de toma de ganancias en pips (0 inhabilitaciones).
200
Notas
La estrategia se suscribe a tres flujos de datos: el período de tiempo principal configurado, una serie horaria y una serie diaria. Cada flujo impulsa su propio conjunto de indicadores a través de Bind/BindEx para mantener la implementación concisa y basada en eventos.
Los valores del indicador solo se procesan en velas terminadas para reflejar los parámetros de cambio del EA original.
La detección de divergencia MACD utiliza el cierre de la barra anterior y el valor del histograma como una aproximación simple pero sólida de la lógica generada por el constructor a partir del archivo fuente MQL.
StartProtection maneja el stop-loss y la toma de ganancias para permanecer sincronizados con los llenados del corredor y admitir pruebas retrospectivas o operaciones en vivo sin replicación manual de órdenes.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Divergence EMA RSI Close Buy Only" MetaTrader expert.
/// Long-only strategy: buys when price pulls back below fast EMA with RSI oversold,
/// exits when RSI reaches overbought level.
/// </summary>
public class DivergenceEmaRsiCloseBuyOnlyStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiEntry;
private readonly StrategyParam<decimal> _rsiExit;
private ExponentialMovingAverage _ema;
private RelativeStrengthIndex _rsi;
private decimal? _prevRsi;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiEntry
{
get => _rsiEntry.Value;
set => _rsiEntry.Value = value;
}
public decimal RsiExit
{
get => _rsiExit.Value;
set => _rsiExit.Value = value;
}
public DivergenceEmaRsiCloseBuyOnlyStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signals", "General");
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period for trend filter", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period for entry/exit", "Indicators");
_rsiEntry = Param(nameof(RsiEntry), 35m)
.SetDisplay("RSI Entry", "RSI level to enter long", "Signals");
_rsiExit = Param(nameof(RsiExit), 65m)
.SetDisplay("RSI Exit", "RSI level to exit long", "Signals");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ema = new ExponentialMovingAverage { Length = EmaPeriod };
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_prevRsi = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ema, _rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_ema.IsFormed || !_rsi.IsFormed)
{
_prevRsi = rsiValue;
return;
}
if (_prevRsi is null)
{
_prevRsi = rsiValue;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
var close = candle.ClosePrice;
// Exit: RSI crosses above exit level
if (Position > 0 && _prevRsi.Value < RsiExit && rsiValue >= RsiExit)
{
SellMarket(Position);
}
// Entry: RSI crosses below entry level and price is near/below EMA (buy the dip)
if (Position <= 0 && _prevRsi.Value > RsiEntry && rsiValue <= RsiEntry && close <= emaValue * 1.005m)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(volume);
}
_prevRsi = rsiValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_ema = null;
_rsi = null;
_prevRsi = null;
base.OnReseted();
}
}
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 ExponentialMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class divergence_ema_rsi_close_buy_only_strategy(Strategy):
def __init__(self):
super(divergence_ema_rsi_close_buy_only_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._ema_period = self.Param("EmaPeriod", 20)
self._rsi_period = self.Param("RsiPeriod", 7)
self._rsi_entry = self.Param("RsiEntry", 35.0)
self._rsi_exit = self.Param("RsiExit", 65.0)
self._prev_rsi = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def RsiEntry(self):
return self._rsi_entry.Value
@RsiEntry.setter
def RsiEntry(self, value):
self._rsi_entry.Value = value
@property
def RsiExit(self):
return self._rsi_exit.Value
@RsiExit.setter
def RsiExit(self, value):
self._rsi_exit.Value = value
def OnReseted(self):
super(divergence_ema_rsi_close_buy_only_strategy, self).OnReseted()
self._prev_rsi = None
def OnStarted2(self, time):
super(divergence_ema_rsi_close_buy_only_strategy, self).OnStarted2(time)
self._prev_rsi = None
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, rsi, self._process_candle).Start()
def _process_candle(self, candle, ema_value, rsi_value):
if candle.State != CandleStates.Finished:
return
ema_val = float(ema_value)
rsi_val = float(rsi_value)
close = float(candle.ClosePrice)
if self._prev_rsi is None:
self._prev_rsi = rsi_val
return
rsi_entry = float(self.RsiEntry)
rsi_exit = float(self.RsiExit)
# Exit: RSI crosses above exit level
if self.Position > 0 and self._prev_rsi < rsi_exit and rsi_val >= rsi_exit:
self.SellMarket()
# Entry: RSI crosses below entry level and price is near/below EMA
if self.Position <= 0 and self._prev_rsi > rsi_entry and rsi_val <= rsi_entry and close <= ema_val * 1.005:
self.BuyMarket()
self._prev_rsi = rsi_val
def CreateClone(self):
return divergence_ema_rsi_close_buy_only_strategy()