La estrategia Cryptocurrency Divergence busca divergencias clásicas de momentum entre la acción del precio y el Relative Strength Index (RSI), confirmando la dirección de tendencia con medias móviles y MACD. El asesor experto original de MetaTrader dependía de comprobaciones de momentum multimarco, gestión monetaria y una lógica amplia de trailing. Este port StockSharp conserva el espíritu del sistema al:
Detectar divergencias alcistas cuando el precio marca un mínimo más bajo pero el RSI forma un mínimo más alto.
Detectar divergencias bajistas cuando el precio crea un máximo más alto pero el RSI imprime un máximo más bajo.
Validar configuraciones con medias móviles rápida/lenta y la línea MACD frente a la señal.
Gestionar posiciones mediante stop loss, take profit, break-even y trailing stop configurables expresados en pasos de precio.
La estrategia está diseñada para criptomonedas al contado, pero puede aplicarse a cualquier instrumento que entregue suficiente volatilidad y puntos de giro claros.
Indicadores
Media móvil simple (SMA): una SMA rápida y una lenta proporcionan el filtro principal de tendencia.
Relative Strength Index (RSI): suministra los valores de pivote de momentum usados para medir la fuerza de divergencia.
Moving Average Convergence Divergence (MACD): confirma que el momentum coincide con la dirección de divergencia detectada.
Todos los indicadores se enlazan mediante la API de alto nivel, por lo que no se requiere búfer manual.
Lógica de negociación
Suscribirse al tipo de vela configurado y calcular valores SMA, RSI y MACD en cada barra terminada.
Seguir los swing highs y lows más recientes junto con sus valores RSI. Solo las extensiones monotónicas (nuevos máximos más altos o mínimos más bajos) actualizan los datos de swing.
Una divergencia alcista aparece cuando un nuevo mínimo más bajo del precio se combina con un mínimo RSI más alto. La operación también requiere que la SMA rápida esté por encima de la lenta, que la línea MACD supere su señal y que el RSI permanezca por debajo del nivel neutral (45 por defecto) para asegurar condiciones de sobreventa.
Una divergencia bajista requiere un nuevo máximo más alto en precio con un máximo RSI más bajo, SMA rápida por debajo de la lenta, línea MACD bajo su señal y RSI por encima del nivel bajista neutral (55 por defecto).
La estrategia abre solo una posición neta a la vez. Las reversiones cierran la posición existente y entran inmediatamente en la dirección opuesta cuando las señales se alinean.
Gestión de riesgo
Volumen: tamaño de operación definido por el usuario y aplicado a todas las órdenes de mercado.
Stop Loss / Take Profit: expresados en pasos de precio y adjuntados después de cada ejecución usando el precio real de ejecución.
Movimiento a break-even: opcionalmente reemplaza el stop loss con un desplazamiento por encima/debajo de la entrada una vez que el precio recorre una distancia configurable.
Trailing Stop: opcionalmente se ajusta detrás del cierre a una distancia fija medida en pasos. El trailing stop tiene prioridad sobre el stop loss original después de activarse.
Los stops y objetivos se evalúan en cada vela terminada, garantizando un comportamiento determinista que coincide entre backtests y ejecución en tiempo real.
Parámetros
Nombre
Descripción
CandleType
Serie de velas usada para el análisis (marco de 15 minutos por defecto).
TradeVolume
Volumen de orden aplicado a todas las entradas.
FastMaLength / SlowMaLength
Periodos de las SMA rápida y lenta.
RsiLength
Longitud de cálculo del RSI.
RsiBullishLevel / RsiBearishLevel
Umbrales RSI que definen zonas de sobreventa y sobrecompra para confirmar divergencias.
Cada parámetro se expone mediante StrategyParam<T> para poder optimizarlo dentro del diseñador de StockSharp.
Notas de uso
Adjunte la estrategia a un símbolo de criptomoneda y asegúrese de que el instrumento tenga PriceStep y Board definidos. Sin paso de precio la estrategia no puede calcular stops.
Alinee el tipo de vela con el mercado que opera (por ejemplo, 15m, 1h). La detección de divergencias es sensible al marco temporal.
Ajuste las distancias de stop y objetivo a la volatilidad del instrumento. Los pares cripto con cinco decimales suelen requerir recuentos de pasos más grandes.
Active break-even o trailing solo después de observar suficiente colchón de beneficio en pruebas históricas; un trailing agresivo puede sacar operaciones demasiado pronto.
Supervise la estrategia en el diseñador de StockSharp o el panel de datos de mercado para visualizar la alineación de indicadores y operaciones ejecutadas.
Diferencias frente a la versión MQL
El trailing basado en dinero y las protecciones de stop de patrimonio se simplifican en una gestión de stops basada en pasos de precio.
Las comprobaciones de momentum multimarco se reemplazan por confirmación MACD de marco único para mayor claridad.
Se omiten efectos secundarios de email/notificación porque se gestionan externamente en los ecosistemas StockSharp.
A pesar de estos ajustes, la detección central de divergencias y la lógica protectora permanecen fieles a la intención del asesor experto original.
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;
public class CryptocurrencyDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public CryptocurrencyDivergenceStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class cryptocurrency_divergence_strategy(Strategy):
def __init__(self):
super(cryptocurrency_divergence_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(cryptocurrency_divergence_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(cryptocurrency_divergence_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return cryptocurrency_divergence_strategy()