Esta estrategia es una conversión de C# del asesor experto "Macd diver and rsi" MetaTrader 5. Mantiene la idea original de la señal de dos etapas: el índice de fuerza relativa (RSI) detecta extremos de sobreventa o sobrecompra, mientras que el histograma MACD confirma que el impulso está regresando en la dirección de la operación. Los lados largos y cortos se configuran de forma independiente para que el comportamiento se pueda ajustar para configuraciones alcistas y bajistas por separado.
La estrategia opera con una única suscripción de vela (período de tiempo configurable) y negocia el valor registrado directamente a través de órdenes de mercado. Todo el procesamiento de indicadores utiliza el StockSharp API de alto nivel a través de BindEx, que coincide con las reglas del proyecto.
Lógica de trading
Preparación de indicadores
Se crean dos indicadores RSI, uno para el tramo largo y otro para el tramo corto, con longitudes y umbrales individuales.
Dos indicadores MovingAverageConvergenceDivergenceSignal reflejan la configuración MACD para operaciones largas y cortas. Su componente de histograma se utiliza para confirmar las inversiones de impulso.
Reglas de entrada
Configuración larga: cuando el valor largo de RSI está en o por debajo del umbral de sobreventa y el histograma largo de MACD cruza por encima de cero (cambia de signo de negativo a positivo), se abre una posición alcista. Si una posición corta está activa, se cierra y se revierte en el mismo orden de mercado.
Configuración corta: cuando el valor corto de RSI está en o por encima del umbral de sobrecompra y el histograma corto de MACD cruza por debajo de cero, se abre una posición bajista. La exposición larga existente se aplana antes de que se establezca la nueva exposición corta.
Gestión de riesgos
Después de cada entrada, la estrategia registra el precio de cierre de la barra de señal como precio de referencia.
Los niveles de stop-loss y take-profit se proyectan a partir de ese precio utilizando distancias de pips definidas por separado para operaciones largas y cortas.
Los pips se convierten a unidades de precio con el instrumento PriceStep y se escalan automáticamente en 10 para símbolos con 3 o 5 decimales para reflejar el comportamiento de MT5.
En cada vela completa, el rango máximo/bajo se compara con estos niveles. Alcanzar cualquiera de los niveles cierra inmediatamente la posición con una orden de mercado.
Gestión comercial
El estado de la posición se borra cada vez que el tamaño de la posición vuelve a cero (ya sea porque se alcanzó un stop/take-profit o porque la estrategia fue revertida por una señal opuesta).
No se realizan salidas parciales ni ajustes de seguimiento; la posición se gestiona únicamente a través de los niveles estáticos de stop-loss y take-profit.
Parámetros
Parámetro
Descripción
CandleType
Periodo de suscripción de velas utilizado para las señales.
LongRsiPeriod, ShortRsiPeriod
RSI longitudes para detección larga y corta.
LongRsiThreshold, ShortRsiThreshold
RSI umbrales que permiten entradas (sobreventa para largos, sobrecompra para cortos).
Volumen comercial por señal. Al revertir, la estrategia agrega el volumen de apertura absoluto para que la orden única realice el cierre y la nueva apertura.
Distancia de las órdenes stop-loss y take-profit en pips. Cero desactiva el nivel respectivo.
Notas
La estrategia requiere instrumentos con un valor distinto de cero PriceStep. Si falta el paso, el cálculo del pip vuelve a 0,0001 para evitar la división por cero.
Dado que ambas partes utilizan instancias de indicadores independientes, es posible ajustar el comportamiento alcista y bajista por separado, por ejemplo, ajustando el umbral de sobrecompra y manteniendo el lado de sobreventa más permisivo.
El código agrega documentación y comentarios en inglés para aclarar el proceso comercial y satisfacer las pautas del proyecto.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MACD Diver And RSI strategy: RSI extremes + MACD histogram crossover.
/// Buys when RSI below 30 and MACD histogram crosses above zero.
/// Sells when RSI above 70 and MACD histogram crosses below zero.
/// </summary>
public class MacdDiverAndRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private decimal _prevHistogram;
private decimal _prevRsi;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public MacdDiverAndRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHistogram = 0;
_prevRsi = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd = { ShortMa = { Length = 12 }, LongMa = { Length = 26 } },
SignalMa = { Length = 9 }
};
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(macd, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (!macdValue.IsFinal || !rsiValue.IsFinal) return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;
var histogram = macdMain - signal;
var rsi = rsiValue.ToDecimal();
if (_hasPrev)
{
if (_prevHistogram <= 0 && histogram > 0 && _prevRsi < 35 && Position <= 0)
BuyMarket();
else if (_prevHistogram >= 0 && histogram < 0 && _prevRsi > 65 && Position >= 0)
SellMarket();
}
_prevHistogram = histogram;
_prevRsi = rsi;
_hasPrev = true;
}
}
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 MovingAverageConvergenceDivergenceSignal, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class macd_diver_and_rsi_strategy(Strategy):
def __init__(self):
super(macd_diver_and_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._prev_histogram = 0.0
self._prev_rsi = 0.0
self._has_prev = False
@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
def OnReseted(self):
super(macd_diver_and_rsi_strategy, self).OnReseted()
self._prev_histogram = 0.0
self._prev_rsi = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(macd_diver_and_rsi_strategy, self).OnStarted2(time)
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = 12
macd.Macd.LongMa.Length = 26
macd.SignalMa.Length = 9
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, rsi, self._process_candle).Start()
def _process_candle(self, candle, macd_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not rsi_value.IsFinal:
return
if macd_value.Macd is None or macd_value.Signal is None:
return
macd_main = float(macd_value.Macd)
signal = float(macd_value.Signal)
histogram = macd_main - signal
rsi_val = float(rsi_value)
if self._has_prev:
if self._prev_histogram <= 0 and histogram > 0 and self._prev_rsi < 35 and self.Position <= 0:
self.BuyMarket()
elif self._prev_histogram >= 0 and histogram < 0 and self._prev_rsi > 65 and self.Position >= 0:
self.SellMarket()
self._prev_histogram = histogram
self._prev_rsi = rsi_val
self._has_prev = True
def CreateClone(self):
return macd_diver_and_rsi_strategy()