Открыть на GitHub

Стратегия XMA Candles

Описание

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

  • Когда появляется новая бычья свеча после небычьей, стратегия закрывает короткую позицию и открывает длинную.
  • Когда появляется новая медвежья свеча после немедвежьей, стратегия закрывает длинную позицию и открывает короткую.

Параметры

  • Length – период сглаживания цен открытия и закрытия.
  • CandleType – таймфрейм используемых свечей.
  • BuyPosOpen – разрешение на открытие длинных позиций.
  • SellPosOpen – разрешение на открытие коротких позиций.
  • BuyPosClose – разрешение на закрытие длинных позиций при появлении медвежьего сигнала.
  • SellPosClose – разрешение на закрытие коротких позиций при появлении бычьего сигнала.
  • StopLoss – защитный стоп в процентах.
  • TakeProfit – цель по прибыли в процентах.

Правила торговли

  1. Дождаться завершения каждой свечи выбранного таймфрейма.
  2. Рассчитать экспоненциальные средние для цен открытия и закрытия.
  3. Определить цвет свечи:
    • Зеленая (бычья), если сглаженная цена открытия < сглаженной цены закрытия.
    • Красная (медвежья), если сглаженная цена открытия > сглаженной цены закрытия.
  4. При смене цвета на бычий закрыть шорт и при необходимости открыть лонг.
  5. При смене цвета на медвежий закрыть лонг и при необходимости открыть шорт.
  6. Защитные стопы и цели по прибыли управляются встроенными механизмами риск-менеджмента.

Стратегия является конверсией оригинального советника MQL5 «Exp_XMACandles».

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on XMA Candles indicator.
/// Opens a long position when smoothed candles turn bullish and
/// opens a short position when smoothed candles turn bearish.
/// </summary>
public class XmaCandlesStrategy : Strategy
{
	private readonly StrategyParam<int> _length;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<bool> _buyPosOpen;
	private readonly StrategyParam<bool> _sellPosOpen;
	private readonly StrategyParam<bool> _buyPosClose;
	private readonly StrategyParam<bool> _sellPosClose;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;

	private ExponentialMovingAverage _openMa;
	private ExponentialMovingAverage _closeMa;
	private int _prevColor = -1;

	/// <summary>
	/// Length of smoothing for moving averages.
	/// </summary>
	public int Length
	{
		get => _length.Value;
		set => _length.Value = value;
	}

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

	/// <summary>
	/// Allows opening long positions.
	/// </summary>
	public bool BuyPosOpen
	{
		get => _buyPosOpen.Value;
		set => _buyPosOpen.Value = value;
	}

	/// <summary>
	/// Allows opening short positions.
	/// </summary>
	public bool SellPosOpen
	{
		get => _sellPosOpen.Value;
		set => _sellPosOpen.Value = value;
	}

	/// <summary>
	/// Allows closing long positions.
	/// </summary>
	public bool BuyPosClose
	{
		get => _buyPosClose.Value;
		set => _buyPosClose.Value = value;
	}

	/// <summary>
	/// Allows closing short positions.
	/// </summary>
	public bool SellPosClose
	{
		get => _sellPosClose.Value;
		set => _sellPosClose.Value = value;
	}

	/// <summary>
	/// Stop loss in percent.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// Take profit in percent.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

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

	/// <summary>
	/// Initialize <see cref="XmaCandlesStrategy"/>.
	/// </summary>
	public XmaCandlesStrategy()
	{
		_length = Param(nameof(Length), 12)
			.SetDisplay("Length", "Smoothing length", "Parameters")
			.SetGreaterThanZero();

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "Parameters");

		_buyPosOpen = Param(nameof(BuyPosOpen), true)
			.SetDisplay("Buy Open", "Allow opening long positions", "Parameters");

		_sellPosOpen = Param(nameof(SellPosOpen), true)
			.SetDisplay("Sell Open", "Allow opening short positions", "Parameters");

		_buyPosClose = Param(nameof(BuyPosClose), true)
			.SetDisplay("Buy Close", "Allow closing long positions", "Parameters");

		_sellPosClose = Param(nameof(SellPosClose), true)
			.SetDisplay("Sell Close", "Allow closing short positions", "Parameters");

		_stopLoss = Param(nameof(StopLoss), 2m)
			.SetDisplay("Stop Loss %", "Stop loss in percent", "Protection");

		_takeProfit = Param(nameof(TakeProfit), 4m)
			.SetDisplay("Take Profit %", "Take profit in percent", "Protection");
	}

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

		_prevColor = -1;
	}

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

		_prevColor = -1;

		_openMa = new EMA { Length = Length };
		_closeMa = new EMA { Length = Length };

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

		StartProtection(
			stopLoss: new Unit(StopLoss, UnitTypes.Percent),
			takeProfit: new Unit(TakeProfit, UnitTypes.Percent)
		);
	}

	private void ProcessCandle(ICandleMessage candle)
	{
		// process only finished candles
		if (candle.State != CandleStates.Finished)
			return;

		var t = candle.ServerTime;
		var openValue = _openMa.Process(candle.OpenPrice, t, true);
		var closeValue = _closeMa.Process(candle.ClosePrice, t, true);

		if (!_openMa.IsFormed || !_closeMa.IsFormed)
			return;

		var openMa = openValue.GetValue<decimal>();
		var closeMa = closeValue.GetValue<decimal>();

		// determine candle color based on smoothed values
		var currentColor = openMa < closeMa ? 2 : openMa > closeMa ? 0 : 1;

		if (currentColor == 2 && _prevColor != 2)
		{
			// bullish change
			if (Position <= 0)
				BuyMarket();
		}
		else if (currentColor == 0 && _prevColor != 0)
		{
			// bearish change
			if (Position >= 0)
				SellMarket();
		}

		_prevColor = currentColor;
	}
}