La estrategia de Divergencia de Momentum compara las lecturas de momentum con la dirección del precio para detectar señales tempranas de una reversión. Las divergencias ocurren cuando el precio alcanza un nuevo extremo pero el indicador de momentum no lo confirma, sugiriendo un debilitamiento de la fuerza.
Las pruebas indican un retorno anual promedio de aproximadamente 106%. Funciona mejor en el mercado de acciones.
Una configuración alcista ocurre cuando el precio registra un mínimo más bajo mientras el oscilador de momentum imprime un mínimo más alto. Una configuración bajista se forma cuando el precio empuja a un máximo más alto pero el momentum no sigue. Las posiciones se cierran cuando el momentum cruza de vuelta a través de cero o la divergencia se invalida.
Este enfoque atrae a traders que buscan anticipar puntos de inflexión en lugar de seguir tendencias. Los stops se utilizan para controlar el riesgo en caso de que el mercado continúe moviéndose en contra de la señal de divergencia.
Detalles
Criterios de entrada:
Largo: El precio hace un mínimo más bajo && El Momentum muestra un mínimo más alto
Corto: El precio hace un máximo más alto && El Momentum muestra un máximo más bajo
Largo/Corto: Ambos lados.
Criterios de salida:
Largo: Salir cuando el momentum cruza por debajo de cero
Corto: Salir cuando el momentum cruza por encima de cero
Stops: Sí, stop-loss fijo.
Valores predeterminados:
MomentumPeriod = 14
MaPeriod = 20
CandleType = TimeSpan.FromMinutes(5)
Filtros:
Categoría: Reversión
Dirección: Ambos
Indicadores: Momentum
Stops: Sí
Complejidad: Intermedio
Marco temporal: Intradía
Estacionalidad: No
Redes neuronales: No
Divergencia: Sí
Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Momentum Divergence strategy.
/// Trades based on divergence between price and momentum.
/// </summary>
public class MomentumDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _momentumPeriodParam;
private readonly StrategyParam<int> _maPeriodParam;
private readonly StrategyParam<DataType> _candleTypeParam;
private Momentum _momentum;
private SimpleMovingAverage _sma;
private decimal _prevPrice;
private decimal _prevMomentum;
private decimal _currentPrice;
private decimal _currentMomentum;
/// <summary>
/// Momentum indicator period.
/// </summary>
public int MomentumPeriod
{
get => _momentumPeriodParam.Value;
set => _momentumPeriodParam.Value = value;
}
/// <summary>
/// Moving average period.
/// </summary>
public int MaPeriod
{
get => _maPeriodParam.Value;
set => _maPeriodParam.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public MomentumDivergenceStrategy()
{
_momentumPeriodParam = Param(nameof(MomentumPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Momentum Period", "Period for Momentum indicator", "Parameters")
.SetOptimize(10, 30, 5);
_maPeriodParam = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for Moving Average", "Parameters")
.SetOptimize(10, 50, 10);
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "Common");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevPrice = 0;
_prevMomentum = 0;
_currentPrice = 0;
_currentMomentum = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
_momentum = new Momentum { Length = MomentumPeriod };
_sma = new SMA { Length = MaPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_momentum, _sma, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _momentum);
DrawIndicator(area, _sma);
DrawOwnTrades(area);
}
// Enable position protection
StartProtection(
takeProfit: new Unit(0, UnitTypes.Absolute), // No take profit
stopLoss: new Unit(2, UnitTypes.Percent) // 2% stop loss
);
}
private void ProcessCandle(ICandleMessage candle, decimal momentumValue, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Store previous values before updating current ones
_prevPrice = _currentPrice;
_prevMomentum = _currentMomentum;
// Update current values
_currentPrice = candle.ClosePrice;
_currentMomentum = momentumValue;
// Skip first candle after indicators become formed
if (_prevPrice == 0 || _prevMomentum == 0)
return;
// Detect bullish divergence (price makes lower low but momentum makes higher low)
bool bullishDivergence = _currentPrice < _prevPrice && _currentMomentum > _prevMomentum;
// Detect bearish divergence (price makes higher high but momentum makes lower high)
bool bearishDivergence = _currentPrice > _prevPrice && _currentMomentum < _prevMomentum;
// Trading signals
if (bullishDivergence && Position <= 0)
{
// Bullish divergence - buy signal
BuyMarket(Volume + Math.Abs(Position));
}
else if (bearishDivergence && Position >= 0)
{
// Bearish divergence - sell signal
SellMarket(Volume + Math.Abs(Position));
}
// Exit when price crosses MA in the opposite direction
else if (Position > 0 && candle.ClosePrice < smaValue)
{
// Exit long position
SellMarket(Position);
}
else if (Position < 0 && candle.ClosePrice > smaValue)
{
// Exit short position
BuyMarket(Math.Abs(Position));
}
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import Momentum, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class momentum_divergence_strategy(Strategy):
"""
Momentum Divergence: trades based on divergence between price and momentum.
"""
def __init__(self):
super(momentum_divergence_strategy, self).__init__()
self._momentum_period = self.Param("MomentumPeriod", 14).SetDisplay("Momentum Period", "Period for Momentum", "Parameters")
self._ma_period = self.Param("MaPeriod", 20).SetDisplay("MA Period", "Period for SMA", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "Common")
self._prev_price = 0.0
self._prev_momentum = 0.0
self._current_price = 0.0
self._current_momentum = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(momentum_divergence_strategy, self).OnReseted()
self._prev_price = 0.0
self._prev_momentum = 0.0
self._current_price = 0.0
self._current_momentum = 0.0
def OnStarted2(self, time):
super(momentum_divergence_strategy, self).OnStarted2(time)
mom = Momentum()
mom.Length = self._momentum_period.Value
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(mom, sma, self._process_candle).Start()
self.StartProtection(None, Unit(2, UnitTypes.Percent))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, mom)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, mom_val, sma_val):
if candle.State != CandleStates.Finished:
return
self._prev_price = self._current_price
self._prev_momentum = self._current_momentum
self._current_price = float(candle.ClosePrice)
self._current_momentum = float(mom_val)
if self._prev_price == 0 or self._prev_momentum == 0:
return
bullish_div = self._current_price < self._prev_price and self._current_momentum > self._prev_momentum
bearish_div = self._current_price > self._prev_price and self._current_momentum < self._prev_momentum
sma = float(sma_val)
if bullish_div and self.Position <= 0:
self.BuyMarket()
elif bearish_div and self.Position >= 0:
self.SellMarket()
elif self.Position > 0 and float(candle.ClosePrice) < sma:
self.SellMarket()
elif self.Position < 0 and float(candle.ClosePrice) > sma:
self.BuyMarket()
def CreateClone(self):
return momentum_divergence_strategy()