Открыть на GitHub

Стратегия ColorX2MA Digit NN3 MMRec

Описание

  • Переносит советник на основе индикатора ColorX2MA Digit с тремя таймфреймами.
  • Использует собственный индикатор двойного сглаживания, повторяющий X2MA с выбором метода сглаживания (Simple, Exponential, Smoothed, Linear Weighted, Jurik, Kaufman Adaptive).
  • Для каждого набора A/B/C создаётся отдельный экземпляр индикатора (по умолчанию 12h, 6h и 3h), который независимо управляет длинными и короткими позициями по заданным флагам.
  • Суммарный целевой объём всех трёх наборов сравнивается с текущей позицией, и стратегия выставляет рыночную заявку на разницу, чтобы итоговая позиция совпадала с суммой сигналов.
  • Сигнал подтверждается после SignalBars подряд идущих свечей с одинаковым направлением наклона, что имитирует параметр SignalBar оригинального MQL-советника.
  • Для каждого таймфрейма предусмотрены переключатели разрешения открытия/закрытия лонгов и шортов, соответствующие полям Must Trade.

Параметры

  • A/B/C Candle Type – тип свечей (таймфрейм) для расчёта индикатора.
  • Fast/Slow Method – метод сглаживания первой и второй скользящих средних внутри X2MA.
  • Fast/Slow Length – периоды соответствующих скользящих средних (по умолчанию 12 и 5).
  • Signal Bars – количество свечей, необходимое для подтверждения нового направления (по умолчанию 1).
  • Digits – количество знаков после запятой для округления значения индикатора перед вычислением наклона.
  • Price Type – источник цены (Close, Open, Median, Typical, Weighted, Simpl, Quarter, TrendFollow, Demark).
  • Allow Long/Short Entry/Exit – флаги, разрешающие или запрещающие открытие и закрытие длинных/коротких позиций для конкретного таймфрейма.
  • Volume – объём, который добавляется в суммарную позицию при активном сигнале данного таймфрейма.

Логика сигналов

  1. Индикатор обрабатывает только закрытые свечи и вычисляет новое значение.
  2. Если наклон двойного сглаженного среднего становится положительным и удерживается заданное число свечей, набор переводится в бычий режим:
    • Текущий шорт закрывается, если разрешён Allow Short Exit.
    • Если разрешён Allow Long Entry, открывается лонг на указанный объём.
  3. При отрицательном наклоне набор становится медвежьим:
    • Длинная позиция закрывается, если разрешён Allow Long Exit.
    • При разрешённом Allow Short Entry открывается шорт на заданный объём.
  4. После каждого изменения целевых объёмов стратегия пересчитывает суммарную позицию и отправляет рыночный ордер, чтобы текущая позиция совпадала с суммой трёх сигналов.

Примечания

  • Методы сглаживания JurX, ParMA, T3 и VIDYA/AMA из оригинальной библиотеки не реализованы; при необходимости их можно добавить вручную.
  • Индикатор округляет значения согласно параметру Digits и работает только на закрытых свечах, что исключает перерисовку.
  • Защита капитала (стоп-лосс/тейк-профит) не добавлялась, поскольку оригинал полагался на MMRec; объём задаётся параметрами Volume.
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>
/// Double-smoothed moving average slope strategy.
/// Uses two SMAs (fast and slow). Trades on slope direction changes.
/// </summary>
public class ColorX2MaDigitNn3MmrecStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;

	private decimal? _prevFast;
	private decimal? _prevSlow;
	private int _prevSignal;

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

	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

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

		_fastLength = Param(nameof(FastLength), 8)
			.SetGreaterThanZero()
			.SetDisplay("Fast Length", "Fast SMA period", "Indicators");

		_slowLength = Param(nameof(SlowLength), 21)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow SMA period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = null;
		_prevSlow = null;
		_prevSignal = 0;
	}

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

		var fastSma = new ExponentialMovingAverage { Length = FastLength };
		var slowSma = new ExponentialMovingAverage { Length = SlowLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastSma, slowSma, ProcessCandle)
			.Start();

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

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

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

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

		// Determine signal based on fast vs slow crossover
		var signal = fastVal > slowVal ? 1 : fastVal < slowVal ? -1 : _prevSignal;

		_prevFast = fastVal;
		_prevSlow = slowVal;

		if (signal == _prevSignal)
			return;

		var oldSignal = _prevSignal;
		_prevSignal = signal;

		if (signal == 1 && oldSignal <= 0)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (signal == -1 && oldSignal >= 0)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}