Стратегия X2MA Digit DM 361
Стратегия комбинирует две скользящие средние с индикатором Average Directional Index (ADX). Длинная позиция открывается, когда быстрая средняя выше медленной и положительный направленный индекс (+DI) превышает отрицательный (-DI). Короткая позиция открывается, когда быстрая средняя ниже медленной и -DI превышает +DI.
Стратегия использует процентные уровни стоп-лосса и тейк-профита. Для расчётов применяются свечи заданного таймфрейма.
Параметры
- Fast MA Length – период быстрой скользящей средней.
- Slow MA Length – период медленной скользящей средней.
- ADX Length – период индикатора ADX.
- Stop Loss % – размер стоп-лосса в процентах от цены входа.
- Take Profit % – размер тейк-профита в процентах от цены входа.
- Candle Type – таймфрейм свечей для обработки.
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()