Estrategia DMI Power Move
Estrategia basada en movimientos de poder del DMI (Índice de Movimiento Direccional)
Las pruebas indican un retorno anual promedio de aproximadamente 76%. Funciona mejor en el mercado de forex.
DMI Power Move combina las diferencias del indicador direccional con el ADX para capturar tendencias poderosas. Las operaciones entran cuando +DI supera notablemente a -DI (o viceversa) y el ADX es fuerte. Salen cuando el ADX se debilita o la diferencia entre DI se estrecha.
Este enfoque filtra las señales débiles al requerir tanto un movimiento direccional fuerte como un ADX en ascenso. El resultado son menos operaciones, pero potencialmente de mayor calidad en tendencia.
Detalles
- Criterios de entrada: Señales basadas en ADX, ATR, DMI.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Señal opuesta o stop.
- Stops: Sí.
- Valores predeterminados:
DmiPeriod= 14DiDifferenceThreshold= 5mAdxThreshold= 30mAdxExitThreshold= 25mAtrMultiplier= 2mCandleType= TimeSpan.FromMinutes(15)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: ADX, ATR, DMI
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Intradía (15m)
- Estacionalidad: No
- Neural Networks: No
- Divergencia: No
- Nivel de riesgo: Medio
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;
/// <summary>
/// Strategy based on DMI (Directional Movement Index) power moves.
/// Enters long when +DI exceeds -DI by threshold and ADX is strong.
/// Enters short when -DI exceeds +DI by threshold and ADX is strong.
/// </summary>
public class DmiPowerMoveStrategy : Strategy
{
private readonly StrategyParam<int> _dmiPeriod;
private readonly StrategyParam<decimal> _diDifferenceThreshold;
private readonly StrategyParam<decimal> _adxThreshold;
private readonly StrategyParam<DataType> _candleType;
private int _prevSignal; // -1 bearish, 0 neutral, 1 bullish
/// <summary>
/// Period for DMI calculation.
/// </summary>
public int DmiPeriod
{
get => _dmiPeriod.Value;
set => _dmiPeriod.Value = value;
}
/// <summary>
/// Minimum difference between +DI and -DI to generate a signal.
/// </summary>
public decimal DiDifferenceThreshold
{
get => _diDifferenceThreshold.Value;
set => _diDifferenceThreshold.Value = value;
}
/// <summary>
/// Minimum ADX value to consider trend strong enough for entry.
/// </summary>
public decimal AdxThreshold
{
get => _adxThreshold.Value;
set => _adxThreshold.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the DMI Power Move strategy.
/// </summary>
public DmiPowerMoveStrategy()
{
_dmiPeriod = Param(nameof(DmiPeriod), 14)
.SetDisplay("DMI Period", "Period for DMI calculation", "Indicators")
.SetOptimize(10, 20, 2);
_diDifferenceThreshold = Param(nameof(DiDifferenceThreshold), 3m)
.SetDisplay("DI Difference Threshold", "Min difference between +DI and -DI", "Trading parameters")
.SetOptimize(2, 8, 1);
_adxThreshold = Param(nameof(AdxThreshold), 15m)
.SetDisplay("ADX Threshold", "Minimum ADX value for entry", "Trading parameters")
.SetOptimize(10, 25, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSignal = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var dmi = new AverageDirectionalIndex { Length = DmiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(dmi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, dmi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue dmiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (dmiValue is not AverageDirectionalIndexValue adxTyped)
return;
decimal adx, plusDi, minusDi;
try
{
if (adxTyped.MovingAverage is not decimal a ||
adxTyped.Dx.Plus is not decimal p ||
adxTyped.Dx.Minus is not decimal m)
return;
adx = a;
plusDi = p;
minusDi = m;
}
catch (IndexOutOfRangeException)
{
return;
}
var diDiff = plusDi - minusDi;
// Determine current directional signal (ignoring neutral)
int signal;
if (diDiff > DiDifferenceThreshold && adx > AdxThreshold)
signal = 1; // bullish
else if (diDiff < -DiDifferenceThreshold && adx > AdxThreshold)
signal = -1; // bearish
else
signal = _prevSignal; // keep previous signal when neutral
// Trade only on directional change
if (signal != _prevSignal && signal != 0)
{
if (signal == 1 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
}
else if (signal == -1 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
}
_prevSignal = signal;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageDirectionalIndex
from StockSharp.Algo.Strategies import Strategy
class dmi_power_move_strategy(Strategy):
"""
Strategy based on DMI (Directional Movement Index) power moves.
Enters long when +DI exceeds -DI by threshold and ADX is strong.
Enters short when -DI exceeds +DI by threshold and ADX is strong.
"""
def __init__(self):
super(dmi_power_move_strategy, self).__init__()
self._dmi_period = self.Param("DmiPeriod", 14) \
.SetDisplay("DMI Period", "Period for DMI calculation", "Indicators")
self._di_difference_threshold = self.Param("DiDifferenceThreshold", 3.0) \
.SetDisplay("DI Difference Threshold", "Min difference between +DI and -DI", "Trading parameters")
self._adx_threshold = self.Param("AdxThreshold", 15.0) \
.SetDisplay("ADX Threshold", "Minimum ADX value for entry", "Trading parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_signal = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(dmi_power_move_strategy, self).OnReseted()
self._prev_signal = 0
def OnStarted2(self, time):
super(dmi_power_move_strategy, self).OnStarted2(time)
dmi = AverageDirectionalIndex()
dmi.Length = self._dmi_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(dmi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, dmi)
self.DrawOwnTrades(area)
def _process_candle(self, candle, dmi_value):
if candle.State != CandleStates.Finished:
return
if dmi_value.MovingAverage is None:
return
if dmi_value.Dx is None or dmi_value.Dx.Plus is None or dmi_value.Dx.Minus is None:
return
adx = float(dmi_value.MovingAverage)
plus_di = float(dmi_value.Dx.Plus)
minus_di = float(dmi_value.Dx.Minus)
di_diff = plus_di - minus_di
if di_diff > self._di_difference_threshold.Value and adx > self._adx_threshold.Value:
signal = 1
elif di_diff < -self._di_difference_threshold.Value and adx > self._adx_threshold.Value:
signal = -1
else:
signal = self._prev_signal
if signal != self._prev_signal and signal != 0:
if signal == 1 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif signal == -1 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._prev_signal = signal
def CreateClone(self):
return dmi_power_move_strategy()