Открыть на GitHub

Стратегия Color 3rd Generation XMA

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

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

Параметры

  • Length — период усреднения третьего поколения.
  • StartHour — час, в который разрешено открывать позиции.
  • StartMinute — минута внутри часа для открытия.
  • HoldMinutes — максимальное время удержания позиции.
  • Volume — объём заявки при входе.
  • StopLoss — расстояние стоп‑лосса в пунктах, 0 выключает стоп.
  • TakeProfit — расстояние тейк‑профита в пунктах, 0 выключает цель.
  • UseLongEntries — разрешение на открытие длинных позиций.
  • UseShortEntries — разрешение на открытие коротких позиций.
  • CloseLongBySignal — закрывать лонги при появлении сигнала на продажу.
  • CloseShortBySignal — закрывать шорты при появлении сигнала на покупку.
  • CandleType — таймфрейм свечей для расчётов.

Логика

  1. Подписка на свечи выбранного таймфрейма.
  2. Расчёт усреднителя третьего поколения на каждой свече.
  3. Определение роста или падения значения между соседними свечами.
  4. Сохранение сигнала на покупку или продажу в зависимости от направления.
  5. В указанное время открытие позиции в сторону сохранённого сигнала.
  6. Закрытие позиции при противоположном сигнале, по истечении времени удержания или при достижении стоп‑лосса/тейк‑профита.
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;

/// <summary>
/// Color 3rd Generation XMA strategy.
/// Uses two EMAs of different periods to approximate 3rd generation moving average.
/// Opens long when fast EMA crosses above slow EMA, short when crosses below.
/// </summary>
public class Color3RdGenXmaStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<decimal> _minSpread;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _isFirst = true;

	public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
	public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
	public decimal MinSpread { get => _minSpread.Value; set => _minSpread.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Color3RdGenXmaStrategy()
	{
		_fastLength = Param(nameof(FastLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "General");

		_slowLength = Param(nameof(SlowLength), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "General");
		_minSpread = Param(nameof(MinSpread), 20m)
			.SetGreaterThanZero()
			.SetDisplay("Min Spread", "Minimum EMA spread in price steps", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations", "General");
	}

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

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

		_prevFast = 0m;
		_prevSlow = 0m;
		_isFirst = true;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = 0m;
		_prevSlow = 0m;
		_isFirst = true;

		var fastEma = new ExponentialMovingAverage { Length = FastLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();

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

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

		if (_isFirst)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_isFirst = false;
			return;
		}

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

		var step = Security.PriceStep ?? 1m;
		var spread = Math.Abs(fast - slow);
		if (spread < MinSpread * step)
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		var prevAbove = _prevFast > _prevSlow;
		var curAbove = fast > slow;

		if (!prevAbove && curAbove && Position <= 0)
			BuyMarket();
		else if (prevAbove && !curAbove && Position >= 0)
			SellMarket();

		_prevFast = fast;
		_prevSlow = slow;
	}
}