ADX MACD Deev Strategy — порт оригинального советника для MetaTrader. Стратегия объединяет силу тренда по индикатору Average Directional Index (ADX) и импульс по Moving Average Convergence Divergence (MACD). Сделки открываются только при одновременном согласии двух индикаторов, что помогает отсекать слабые сигналы и работать только с устойчивыми движениями.
Логика работы
Подготовка индикаторов
ADX рассчитывается с настраиваемым периодом усреднения. Хранятся последние значения ADX, и стратегия проверяет, чтобы они последовательно росли (для покупок) или снижались (для продаж) в течение заданного числа баров.
MACD строится на основе экспоненциальных средних (fast, slow, signal). Для входа необходимо, чтобы гистограмма и сигнальная линия одновременно двигались в нужном направлении в течение указанного интервала.
Вход в позицию
Покупка — когда значение MACD превышает порог MACD Minimum (pips), гистограмма и сигнальная линия последовательно растут, а ADX находится выше минимума и тоже растёт.
Продажа — когда MACD опускается ниже отрицательного порога, обе линии MACD снижаются, а ADX остаётся выше минимума и одновременно уменьшается.
В рынке одновременно может быть открыта только одна позиция.
Управление рисками
Начальные уровни Stop Loss и Take Profit рассчитываются в ценовых пунктах на основе PriceStep инструмента и выбранных значений в пунктах (pips).
Активируйте трейлинг-стоп, чтобы переносить защитный уровень после прохождения ценой расстояния Trailing Stop + Trailing Step.
Опция Take Half Profit позволяет закрыть половину позиции при достижении тейк-профита, оставшаяся часть сопровождается трейлингом.
Параметры
Группа
Название
Описание
Trading
Order Volume
Объём рыночного ордера.
Risk
Stop Loss (pips)
Расстояние начального стоп-лосса.
Risk
Take Profit (pips)
Расстояние начального тейк-профита.
Risk
Trailing Stop (pips)
Дистанция трейлинг-стопа, 0 — выключен.
Risk
Trailing Step (pips)
Дополнительный шаг перед очередным смещением трейлинга.
Risk
Take Half Profit
Включить частичную фиксацию половины позиции.
Indicators
ADX Period
Период усреднения ADX.
Indicators
ADX Bars Interval
Сколько последних баров ADX должны следовать тренду.
Indicators
ADX Minimum
Минимальное значение ADX для входа.
Indicators
MACD Fast EMA
Период быстрой EMA для MACD.
Indicators
MACD Slow EMA
Период медленной EMA для MACD.
Indicators
MACD Signal EMA
Период сигнальной EMA.
Indicators
MACD Bars Interval
Количество баров MACD, подтверждающих направление.
Indicators
MACD Minimum (pips)
Минимальная величина MACD в пипсах.
General
Candle Type
Тип/таймфрейм свечей.
Рекомендации
Для корректного пересчёта пипсов инструмент должен иметь ненулевой PriceStep. При PriceStep = 0 пороги MACD оцениваются в абсолютных значениях.
Частичные закрытия округляются в соответствии с VolumeStep инструмента.
Трейлинг-стоп пересчитывается только на закрытых свечах.
Стратегия использует высокоуровневое API (SubscribeCandles().BindEx(...)) и не обращается напрямую к буферам индикаторов.
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;
public class AdxMacdDeevStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public AdxMacdDeevStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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_macd_deev_strategy(Strategy):
"""
ADX MACD Deev: dual EMA crossover with stop-loss/take-profit in price steps.
"""
def __init__(self):
super(adx_macd_deev_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12) \
.SetGreaterThanZero() \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetGreaterThanZero() \
.SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@StopLossPoints.setter
def StopLossPoints(self, value):
self._stop_loss_points.Value = value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@TakeProfitPoints.setter
def TakeProfitPoints(self, value):
self._take_profit_points.Value = value
def OnReseted(self):
super(adx_macd_deev_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(adx_macd_deev_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(tf(5))
subscription.Bind(fast, slow, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_value
self._prev_slow = slow_value
return
close = float(candle.ClosePrice)
step = 1.0
if self.Position > 0 and self._entry_price > 0:
if self.StopLossPoints > 0 and close <= self._entry_price - self.StopLossPoints * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
if self.TakeProfitPoints > 0 and close >= self._entry_price + self.TakeProfitPoints * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
elif self.Position < 0 and self._entry_price > 0:
if self.StopLossPoints > 0 and close >= self._entry_price + self.StopLossPoints * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
if self.TakeProfitPoints > 0 and close <= self._entry_price - self.TakeProfitPoints * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
if self._prev_fast <= self._prev_slow and fast_value > slow_value and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_value < slow_value and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return adx_macd_deev_strategy()