Открыть на GitHub

Стратегия Exp DEMA Range Channel Tm Plus

Стратегия Exp DEMA Range Channel Tm Plus переносит одноимённого советника MetaTrader в инфраструктуру StockSharp. Она строит канал по двойным экспоненциальным скользящим средним (DEMA), рассчитанным по экстремумам свечей, и отслеживает «цвет» свечи, который выдаёт исходный индикатор DEMA Range Channel. Появление нового цвета интерпретируется как пробой канала и используется для открытия или закрытия позиций. Управление капиталом упрощено: применяется объём из свойства Volume, а стоп-ордера задаются только через параметры защиты.

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

  • Построение канала
    • DEMA по максимумам и минимумам свечей рассчитываются с одинаковым периодом MaPeriod.
    • Значения каналов сдвигаются вперёд на Shift баров, как и в оригинальном индикаторе, поэтому проверяется уровень, который существовал несколько баров назад.
    • Параметр PriceShiftPoints добавляет к верхней линии и вычитает от нижней линии заданный сдвиг в пунктах (PriceStep).
  • Цветовые состояния
    • Закрытие выше верхней линии трактуется как бычий сигнал. Если тело свечи бычье, цвет соответствует индексу 3, если медвежье — индексу 2.
    • Закрытие ниже нижней линии формирует медвежий сигнал (индекс 0 или 1 в зависимости от тела свечи).
  • Открытие позиций
    • Буфер цветов хранит последние значения, и стратегия анализирует цвет, появившийся SignalBar баров назад. Если предыдущий цвет был другим, событие считается новым пробоем.
    • При включённом EnableBuyEntry открывается длинная позиция, когда фиксируется свежий бычий пробой.
    • При включённом EnableSellEntry открывается короткая позиция при новом медвежьем пробое.
  • Закрытие позиций
    • EnableBuyExit позволяет закрывать длинные позиции при любом медвежьем сигнале.
    • EnableSellExit закрывает короткие позиции при бычьем сигнале.
    • Параметры UseHoldingLimit и HoldingMinutes реализуют тайм-аут из исходного советника: позиция закрывается, если удерживается дольше заданного количества минут.
  • Защитные приказы
    • При ненулевых StopLossPoints и/или TakeProfitPoints вызывается StartProtection. Расстояния переводятся в абсолютное изменение цены и используются для выставления защитных приказов с рыночным исполнением.

Параметры

Параметр Описание
MaPeriod Период DEMA для верхней и нижней границ канала.
Shift Число баров, на которое значения канала сдвигаются вперёд перед сравнением.
PriceShiftPoints Дополнительный отступ в пунктах (в долях PriceStep), расширяющий или сужающий канал.
SignalBar На сколько баров назад смотреть для определения свежего пробоя (0 — текущая свеча, 1 — последняя закрытая и т.д.).
EnableBuyEntry / EnableSellEntry Включают/выключают открытие длинных и коротких позиций.
EnableBuyExit / EnableSellExit Управляют закрытием длинных/коротких позиций по противоположным сигналам.
UseHoldingLimit Включает ограничение времени удержания позиции.
HoldingMinutes Максимальное время удержания в минутах. Значение 0 деактивирует тайм-аут при включённом флаге.
StopLossPoints / TakeProfitPoints Дистанции защитных приказов в пунктах. При значении > 0 переводятся в абсолютное изменение цены и используются в StartProtection.
CandleType Тип и таймфрейм свечей (по умолчанию 8-часовые, как в оригинальном файле).

Последовательность действий

  1. Подписаться на свечи CandleType и инициализировать индикаторы DEMA.
  2. Сохранять последние значения канала в очередях, чтобы иметь доступ к уровню, актуальному Shift баров назад.
  3. После закрытия свечи вычислить новый цвет и поместить его в буфер; проверить, появился ли новый пробой согласно SignalBar.
  4. Закрыть активные позиции при противоположном сигнале либо при превышении лимита удержания.
  5. Открывать новые сделки рыночными ордерами объёмом Volume + |Position|, что позволяет разворачиваться без накопления позиций.
  6. Обновлять метку времени открытия позиции, чтобы корректно считать тайм-аут.

Дополнительные замечания

  • Поток свечей должен поступать в хронологическом порядке; нарушение порядка исказит работу сдвига канала.
  • Перед запуском задайте желаемый объём через свойство Volume. Алгоритмы расчёта лота из MQL-версии в данном порте не используются.
  • При работе на реальном счёте рекомендуются явные значения стоп-лосса и тейк-профита для защиты от неожиданных движений.
  • Встроенные функции построения графика отображают свечи и сделки, что позволяет визуально проверить соответствие сигналов пробоя.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// DEMA channel breakout strategy.
/// Uses fast and slow DEMA crossover to detect trend changes.
/// </summary>
public class ExpDemaRangeChannelTmPlusStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public ExpDemaRangeChannelTmPlusStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast DEMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow DEMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = null;
		_prevSlow = null;

		var fastDema = new DoubleExponentialMovingAverage { Length = FastPeriod };
		var slowDema = new DoubleExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastDema, slowDema, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fastDema);
			DrawIndicator(area, slowDema);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;

		_prevFast = fast;
		_prevSlow = slow;

		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}