Ver no GitHub

Estratégia XMA Candles

Descrição

A estratégia XMA Candles monitora a direção de velas suavizadas calculadas a partir da XMA (Média Móvel Exponencial) dos preços de abertura e fechamento. Uma vela é considerada de alta quando o preço de abertura suavizado está abaixo do preço de fechamento suavizado, e de baixa quando o preço de abertura suavizado está acima. A estratégia reage às mudanças de cor dessas velas suavizadas.

  • Quando uma nova vela de alta aparece após uma vela não-alta, a estratégia fecha qualquer posição vendida e abre uma posição comprada.
  • Quando uma nova vela de baixa aparece após uma vela não-baixa, a estratégia fecha qualquer posição comprada e abre uma posição vendida.

Parâmetros

  • Length – número de períodos para suavizar os preços de abertura e fechamento.
  • CandleType – período das velas utilizadas nos cálculos.
  • BuyPosOpen – permite abrir posições compradas.
  • SellPosOpen – permite abrir posições vendidas.
  • BuyPosClose – permite fechar posições compradas quando aparece sinal de baixa.
  • SellPosClose – permite fechar posições vendidas quando aparece sinal de alta.
  • StopLoss – stop de proteção em percentagem.
  • TakeProfit – alvo de lucro em percentagem.

Regras de trading

  1. Aguardar o fechamento de cada vela do período selecionado.
  2. Calcular as médias móveis exponenciais para os preços de abertura e fechamento.
  3. Determinar a cor da vela:
    • Verde (alta) se abertura suavizada < fechamento suavizado.
    • Vermelha (baixa) se abertura suavizada > fechamento suavizado.
  4. Se a cor mudar para alta, fechar vendidos e opcionalmente abrir uma posição comprada.
  5. Se a cor mudar para baixa, fechar comprados e opcionalmente abrir uma posição vendida.
  6. Stops de proteção e alvos são gerenciados pelos controles de risco integrados.

Esta estratégia é uma conversão do expert MQL5 original "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;
	}
}