Открыть на GitHub

Стратегия ColorXPWMA Digit Multi-Timeframe

Обзор

Стратегия переносит советника MetaTrader 5 Exp_ColorXPWMA_Digit_NN3_MMRec на высокоуровневый API StockSharp. Оригинальный робот состоит из трёх независимых модулей, которые работают на разных таймфреймах и анализируют изменение цвета скользящей средней ColorXPWMA. Порт сохранил эту логику: каждый модуль следит за своей серией свечей, закрывает позиции при смене цвета индикатора и при необходимости открывает сделку в новом направлении.

Конфигурация по умолчанию совпадает с MT5:

Модуль Таймфрейм Стоп‑лосс (пункты) Тейк‑профит (пункты)
A 8 часов 3000 10000
B 4 часа 2000 6000
C 1 час 1000 3000

Для каждого модуля предусмотрены отдельные флаги разрешения на открытие и закрытие длинных и коротких позиций. Стратегия ведёт раздельный учёт виртуальных позиций, поэтому одновременные сделки разных таймфреймов не конфликтуют между собой.

Индикатор ColorXPWMA Digit

Индикатор реализует алгоритм MT5. Для каждой завершённой свечи выполняются следующие шаги:

  1. Строится степенное взвешенное среднее выбранной цены (Period, Power).
  2. Значение сглаживается выбранным типом скользящей средней (SmoothMethods, SmoothLength).
  3. Результат округляется до заданного количества знаков (Digit).
  4. Определяется цвет: 2 при росте значения, 0 при падении, в противном случае используется предыдущий цвет.

Параметр SignalBar задаёт, какую свечу анализировать. Значение 0 использует последнюю закрытую свечу, 1 — предыдущую и т.д. Сигнал на покупку возникает, если выбранная свеча окрашивается в цвет 2, а предыдущая имела другой цвет. Сигнал на продажу формируется при переходе в цвет 0 после другого цвета.

Соответствие методов сглаживания StockSharp:

  • Sma, Ema, Smma, Lwma, Jjma → одноимённые индикаторы StockSharp.
  • T3 → встроенная реализация Tillson T3.
  • Vidya → встроенная реализация VIDYA на основе осциллятора Чанде.
  • Ama → Kaufman Adaptive Moving Average.
  • Неподдерживаемые варианты (JurX, Parabolic) возвращаются к простому среднему, что соответствует поведению MT5 при отсутствии экзотических методов сглаживания.

Управление сделками и риск

Каждый модуль хранит две виртуальные позиции (лонг и шорт). При появлении сигнала на закрытие стратегия выставляет рыночную заявку на полный объём соответствующей виртуальной позиции. Сигналы на открытие игнорируются, пока открыта противоположная позиция.

Размер позиции повторяет логику MT5:

  • NormalMM — базовый объём.
  • SmallMM используется, если в последних TotalTrigger сделках набралось как минимум LossTrigger убыточных сделок в данном направлении.

Учёт ведётся отдельно для длинных и коротких серий. Результат сделки вычисляется по средней цене исполнения при полном закрытии виртуальной позиции модуля.

Риск-менеджмент реализован в ценовых шагах инструмента:

  • Для лонга позиция закрывается, если минимум свечи пробивает entry - StopLoss * PriceStep.
  • При достижении entry + TakeProfit * PriceStep фиксируется прибыль.
  • Для шорта правила зеркальны (entry + StopLoss — защита, entry - TakeProfit — цель).

Параметры

Все настройки доступны через StrategyParam<T> и могут оптимизироваться в дизайнере StockSharp. Параметры сгруппированы по модулям (A, B, C). В таблице приведены значения для произвольного модуля X:

Параметр Описание
X_CandleType Серия свечей, используемая модулем.
X_Period, X_Power Длина окна и показатель степени для взвешивания цены.
X_SmoothMethod, X_SmoothLength, X_SmoothPhase Настройки сглаживания. SmoothPhase сохранён для совместимости с JJMA.
X_AppliedPrice Источник цены (close, open, high, low, median, typical, weighted, simple, quarter, TrendFollow, DeMark).
X_Digit Количество знаков при округлении.
X_SignalBar Смещение свечи, используемой для сигнала.
X_BuyMagic, X_SellMagic Идентификаторы сделок (используются в комментариях заявок).
X_BuyTotalTrigger, X_BuyLossTrigger Пороговые значения для уменьшения объёма в лонгах.
X_SellTotalTrigger, X_SellLossTrigger Аналогичные параметры для шортов.
X_SmallMM, X_NormalMM Размеры позиции для двух режимов.
X_MarginMode, X_Deviation Зарезервированы для совместимости, на заявки не влияют.
X_StopLoss, X_TakeProfit Расстояния стоп‑лосса и тейк‑профита в шагах цены.
X_BuyOpen, X_SellOpen, X_SellClose, X_BuyClose Разрешения на действия модуля.

Примечания

  • Комментарии заявок содержат ключ вида A|BuyOpen, что облегчает сопоставление сделок с модулем.
  • Обработка выполняется только для завершённых свечей, поэтому необходимость в проверке IsNewBar отпадает.
  • Если несколько модулей активируются на одной свече, их объёмы обрабатываются по очереди на основе собственных виртуальных позиций.
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>
/// ColorXPWMA Digit Multi-Timeframe strategy. Uses WMA crossover.
/// </summary>
public class ColorXpWmaDigitMultiTimeframeStrategy : 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 ColorXpWmaDigitMultiTimeframeStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 25)
			.SetGreaterThanZero()
			.SetDisplay("Slow WMA", "Slow WMA 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 fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fastVal > slowVal;

		_prevFast = fastVal;
		_prevSlow = slowVal;

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