Данная стратегия представляет собой порт эксперта MetaTrader ADX_MA (fortrader) на платформу StockSharp.
Она сочетает сглаженную скользящую среднюю (SMMA) и индикатор среднего направленного движения (ADX),
чтобы сделки открывались только при подтверждённом пересечении и достаточной силе тренда.
Как и оригинал, порт использует несимметричное управление рисками: для покупок задан увеличенный
зазор стопов и трейлинга, для продаж параметры значительно более жёсткие.
Логика работы
Строится SMMA по медианной цене свечей и ADX с заданными периодами.
Сигналы рассчитываются только на закрытых свечах, имитируя вызовы iClose(...,1) и iClose(...,2) в MQL4.
Покупка выполняется, когда предыдущая свеча закрылась выше SMMA, свеча до неё — ниже, а ADX выше порога.
Продажа выполняется, когда предыдущая свеча закрылась ниже SMMA, ещё более ранняя — выше, и ADX превышает порог.
Управление позицией включает:
закрытие при смене направления относительно SMMA;
индивидуальные уровни стоп-лосса и тейк-профита в пунктах;
опциональный трейлинг, который подтягивается по мере движения цены в нужную сторону.
Все ценовые смещения пересчитываются из пунктов по шагу цены инструмента. Если шаг не задан, используется значение 1.
Параметры
Название
Описание
SMMA Period
Период сглаженной скользящей средней (по умолчанию 21).
ADX Period
Период индикатора ADX (по умолчанию 14).
ADX Threshold
Минимальное значение ADX для разрешения входа (по умолчанию 16).
Long Take Profit (pips)
Тейк-профит для длинных позиций в пунктах (по умолчанию 1300).
Long Stop Loss (pips)
Стоп-лосс для длинных позиций в пунктах (по умолчанию 30).
Long Trailing Stop (pips)
Трейлинг-стоп для длинных позиций в пунктах (по умолчанию 270).
Short Take Profit (pips)
Тейк-профит для коротких позиций в пунктах (по умолчанию 160).
Short Stop Loss (pips)
Стоп-лосс для коротких позиций в пунктах (по умолчанию 50).
Short Trailing Stop (pips)
Трейлинг-стоп для коротких позиций в пунктах (по умолчанию 20).
Volume
Объём заявки при открытии новой позиции (по умолчанию 0.1).
Candle Type
Тип свечей, используемых в расчётах (по умолчанию минутные).
Все параметры доступны для оптимизации, а значения по умолчанию соответствуют настройкам оригинального советника.
Дополнительные замечания
Трейлинг активируется только после того, как цена пройдёт в прибыль не меньше указанного расстояния.
Противоположный сигнал закрывает текущую позицию перед открытием новой.
При наличии области графика стратегия автоматически отображает свечи, индикаторы и собственные сделки.
Автоматические тесты не поставляются; рекомендуется провести собственное тестирование в терминале или на истории.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class AdxMaStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AdxMaStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA lookback", "Indicators");
_smaPeriod = Param(nameof(SmaPeriod), 50).SetDisplay("SMA Period", "SMA trend filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }
if (_prevClose <= _prevEma && close > ema && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevClose >= _prevEma && close < ema && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); }
_prevClose = close; _prevEma = ema;
}
}
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 CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class adx_ma_strategy(Strategy):
"""
ADX MA strategy: EMA crossover with price for trend-following entries.
"""
def __init__(self):
super(adx_ma_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 14) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._sma_period = self.Param("SmaPeriod", 50) \
.SetDisplay("SMA Period", "SMA trend filter", "Indicators")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def SmaPeriod(self):
return self._sma_period.Value
@SmaPeriod.setter
def SmaPeriod(self, value):
self._sma_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(adx_ma_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(adx_ma_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if not self._has_prev:
self._prev_close = close
self._prev_ema = ema
self._has_prev = True
return
if self._prev_close <= self._prev_ema and close > ema and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close >= self._prev_ema and close < ema and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_ema = ema
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return adx_ma_strategy()