Открыть на GitHub

Стратегия XDPO Candle

Данная стратегия представляет собой конверсию эксперта MQL5 Exp_XDPOCandle. Она строит синтетические свечи, выполняя двойное экспоненциальное сглаживание цен открытия и закрытия. Цвет полученной свечи (бычий, медвежий или нейтральный) определяет торговые решения.

Логика стратегии

  1. Каждая входящая свеча дважды сглаживается:
    • Первое сглаживание — EMA длиной FastLength;
    • Второе сглаживание — EMA длиной SlowLength, применённая к результату первого.
  2. Если сглаженная цена закрытия выше цены открытия — свеча бычья;
  3. Если сглаженная цена закрытия ниже цены открытия — свеча медвежья;
  4. При появлении бычьей свечи после небычьей открывается длинная позиция. При появлении медвежьей свечи после немедвежьей открывается короткая позиция.
  5. Противоположные позиции закрываются автоматически за счёт переворота через рыночные заявки.

Параметры

Имя Описание
FastLength Длина первой EMA, применяемой к ценам.
SlowLength Длина второй EMA, применяемой к результату первой.
CandleType Тип и таймфрейм свечей, используемых в расчётах.

Использование

  1. Подключите стратегию к нужному инструменту в среде StockSharp;
  2. При необходимости скорректируйте параметры. Значения по умолчанию соответствуют оригинальным настройкам эксперта;
  3. Запустите стратегию — она подпишется на указанные свечи и будет совершать сделки при смене цвета сглаженных свечей.

Примечания

  • Защита позиций запускается через StartProtection() с настройками по умолчанию. При необходимости задайте объём сделки и параметры защиты отдельно;
  • В репозитории присутствует только версия на C#. Python-версия пока отсутствует.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;



/// <summary>
/// XDPO candle strategy that trades on color changes of double smoothed candles.
/// </summary>
public class XdpoCandleStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _emaOpen1;
	private decimal? _emaOpen2;
	private decimal? _emaClose1;
	private decimal? _emaClose2;
	private int? _previousColor;

	/// <summary>
	/// Length of the first exponential moving average.
	/// </summary>
	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	/// <summary>
	/// Length of the second exponential moving average.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	/// <summary>
	/// Candle type used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="XdpoCandleStrategy"/>.
	/// </summary>
	public XdpoCandleStrategy()
	{
		_fastLength = Param(nameof(FastLength), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Length", "Length of the first EMA", "Parameters")
			;

		_slowLength = Param(nameof(SlowLength), 5)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Length of the second EMA", "Parameters")
			;

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

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

		_emaOpen1 = _emaOpen2 = _emaClose1 = _emaClose2 = null;
		_previousColor = null;
	}

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

		var warmup = new StockSharp.Algo.Indicators.ExponentialMovingAverage { Length = FastLength };
		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(warmup, ProcessCandle)
			.Start();

	}

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

		var open1 = CalcEma(candle.OpenPrice, ref _emaOpen1, FastLength);
		var open2 = CalcEma(open1, ref _emaOpen2, SlowLength);
		var close1 = CalcEma(candle.ClosePrice, ref _emaClose1, FastLength);
		var close2 = CalcEma(close1, ref _emaClose2, SlowLength);

		var color = open2 < close2 ? 2 : open2 > close2 ? 0 : 1;
		var goLong = color == 2 && _previousColor != 2;
		var goShort = color == 0 && _previousColor != 0;

		if (IsFormedAndOnlineAndAllowTrading())
		{
			if (goLong && Position <= 0)
				BuyMarket();
			else if (goShort && Position >= 0)
				SellMarket();
		}

		_previousColor = color;
	}

	private static decimal CalcEma(decimal price, ref decimal? prev, int length)
	{
		var k = 2m / (length + 1m);
		var result = prev.HasValue ? price * k + prev.Value * (1m - k) : price;
		prev = result;
		return result;
	}
}