Estrategia X2MA Digit DM 361
Esta estrategia combina dos medias móviles con el Índice de Dirección Promedio (ADX). Se abre una posición larga cuando la media móvil rápida está por encima de la lenta y el índice direccional positivo (+DI) es mayor que el negativo (-DI). Se abre una posición corta cuando la media móvil rápida está por debajo de la lenta y -DI es mayor que +DI.
La estrategia utiliza protecciones de stop-loss y take-profit basadas en porcentajes. Las velas para los cálculos se toman del marco temporal especificado.
Parámetros
- Fast MA Length – longitud de la media móvil rápida.
- Slow MA Length – longitud de la media móvil lenta.
- ADX Length – período para el cálculo del Índice de Dirección Promedio.
- Stop Loss % – tamaño del stop-loss en porcentaje del precio de entrada.
- Take Profit % – tamaño del take-profit en porcentaje del precio de entrada.
- Candle Type – marco temporal de las velas utilizadas para el procesamiento.
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>
/// Strategy based on two moving averages and directional movement index.
/// Long when fast MA is above slow MA and +DI exceeds -DI.
/// Short when fast MA is below slow MA and -DI exceeds +DI.
/// </summary>
public class X2MaDigitDm361Strategy : Strategy
{
private readonly StrategyParam<int> _fastMaLength;
private readonly StrategyParam<int> _slowMaLength;
private readonly StrategyParam<int> _adxLength;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
/// <summary>
/// Fast moving average length.
/// </summary>
public int FastMaLength
{
get => _fastMaLength.Value;
set => _fastMaLength.Value = value;
}
/// <summary>
/// Slow moving average length.
/// </summary>
public int SlowMaLength
{
get => _slowMaLength.Value;
set => _slowMaLength.Value = value;
}
/// <summary>
/// ADX calculation length.
/// </summary>
public int AdxLength
{
get => _adxLength.Value;
set => _adxLength.Value = value;
}
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Stop loss percent.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Take profit percent.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="X2MaDigitDm361Strategy"/>.
/// </summary>
public X2MaDigitDm361Strategy()
{
_fastMaLength = Param(nameof(FastMaLength), 5)
.SetGreaterThanZero()
.SetDisplay("Fast MA Length", "Length of fast moving average", "Moving Averages")
.SetOptimize(5, 25, 1);
_slowMaLength = Param(nameof(SlowMaLength), 12)
.SetGreaterThanZero()
.SetDisplay("Slow MA Length", "Length of slow moving average", "Moving Averages")
.SetOptimize(3, 15, 1);
_adxLength = Param(nameof(AdxLength), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Length", "Length of Average Directional Index", "Directional Movement")
.SetOptimize(7, 28, 7);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles timeframe", "General");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Stop loss percent", "Risk Management")
.SetOptimize(0.5m, 3m, 0.5m);
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
.SetGreaterThanZero()
.SetDisplay("Take Profit %", "Take profit percent", "Risk Management")
.SetOptimize(1m, 5m, 0.5m);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = new SMA { Length = FastMaLength };
var slowMa = new SMA { Length = SlowMaLength };
var adx = new AverageDirectionalIndex { Length = AdxLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(fastMa, slowMa, adx, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(TakeProfitPercent, UnitTypes.Percent),
stopLoss: new Unit(StopLossPercent, UnitTypes.Percent),
isStopTrailing: false,
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawIndicator(area, adx);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue fastMaValue, IIndicatorValue slowMaValue, IIndicatorValue adxValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!fastMaValue.IsFinal || !slowMaValue.IsFinal || !adxValue.IsFinal)
return;
var fast = fastMaValue.ToDecimal();
var slow = slowMaValue.ToDecimal();
var adx = (AverageDirectionalIndexValue)adxValue;
var plusDi = adx.Dx.Plus;
var minusDi = adx.Dx.Minus;
if (plusDi is null || minusDi is null)
return;
if (fast > slow && plusDi > minusDi && Position <= 0)
{
BuyMarket();
}
else if (fast < slow && minusDi > plusDi && Position >= 0)
{
SellMarket();
}
}
}
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 SimpleMovingAverage, AverageDirectionalIndex
from StockSharp.Algo.Strategies import Strategy
class x2_ma_digit_dm_361_strategy(Strategy):
def __init__(self):
super(x2_ma_digit_dm_361_strategy, self).__init__()
self._fast_ma_length = self.Param("FastMaLength", 5) \
.SetDisplay("Fast MA Length", "Length of fast moving average", "Moving Averages")
self._slow_ma_length = self.Param("SlowMaLength", 12) \
.SetDisplay("Slow MA Length", "Length of slow moving average", "Moving Averages")
self._adx_length = self.Param("AdxLength", 14) \
.SetDisplay("ADX Length", "Length of Average Directional Index", "Directional Movement")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles timeframe", "General")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0) \
.SetDisplay("Stop Loss %", "Stop loss percent", "Risk Management")
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0) \
.SetDisplay("Take Profit %", "Take profit percent", "Risk Management")
@property
def fast_ma_length(self):
return self._fast_ma_length.Value
@property
def slow_ma_length(self):
return self._slow_ma_length.Value
@property
def adx_length(self):
return self._adx_length.Value
@property
def candle_type(self):
return self._candle_type.Value
@property
def stop_loss_percent(self):
return self._stop_loss_percent.Value
@property
def take_profit_percent(self):
return self._take_profit_percent.Value
def OnStarted2(self, time):
super(x2_ma_digit_dm_361_strategy, self).OnStarted2(time)
fast_ma = SimpleMovingAverage()
fast_ma.Length = int(self.fast_ma_length)
slow_ma = SimpleMovingAverage()
slow_ma.Length = int(self.slow_ma_length)
adx = AverageDirectionalIndex()
adx.Length = int(self.adx_length)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(fast_ma, slow_ma, adx, self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(float(self.take_profit_percent), UnitTypes.Percent),
stopLoss=Unit(float(self.stop_loss_percent), UnitTypes.Percent),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawIndicator(area, adx)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast_ma_value, slow_ma_value, adx_value):
if candle.State != CandleStates.Finished:
return
if not fast_ma_value.IsFinal or not slow_ma_value.IsFinal or not adx_value.IsFinal:
return
fast = float(fast_ma_value)
slow = float(slow_ma_value)
adx_typed = adx_value
plus_di = adx_typed.Dx.Plus
minus_di = adx_typed.Dx.Minus
if plus_di is None or minus_di is None:
return
plus_di = float(plus_di)
minus_di = float(minus_di)
if fast > slow and plus_di > minus_di and self.Position <= 0:
self.BuyMarket()
elif fast < slow and minus_di > plus_di and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return x2_ma_digit_dm_361_strategy()