Открыть на GitHub

Стратегия ADX MACD Deev

Общее описание

ADX MACD Deev Strategy — порт оригинального советника для MetaTrader. Стратегия объединяет силу тренда по индикатору Average Directional Index (ADX) и импульс по Moving Average Convergence Divergence (MACD). Сделки открываются только при одновременном согласии двух индикаторов, что помогает отсекать слабые сигналы и работать только с устойчивыми движениями.

Логика работы

  1. Подготовка индикаторов
    • ADX рассчитывается с настраиваемым периодом усреднения. Хранятся последние значения ADX, и стратегия проверяет, чтобы они последовательно росли (для покупок) или снижались (для продаж) в течение заданного числа баров.
    • MACD строится на основе экспоненциальных средних (fast, slow, signal). Для входа необходимо, чтобы гистограмма и сигнальная линия одновременно двигались в нужном направлении в течение указанного интервала.
  2. Вход в позицию
    • Покупка — когда значение MACD превышает порог MACD Minimum (pips), гистограмма и сигнальная линия последовательно растут, а ADX находится выше минимума и тоже растёт.
    • Продажа — когда MACD опускается ниже отрицательного порога, обе линии MACD снижаются, а ADX остаётся выше минимума и одновременно уменьшается.
    • В рынке одновременно может быть открыта только одна позиция.
  3. Управление рисками
    • Начальные уровни 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;
	}
}