Auf GitHub ansehen

XMA Candles-Strategie

Beschreibung

Die XMA Candles-Strategie überwacht die Richtung geglätteter Kerzen, die aus dem XMA (Exponential Moving Average) der Eröffnungs- und Schlusskurse berechnet werden. Eine Kerze gilt als bullisch, wenn der geglättete Eröffnungskurs unter dem geglätteten Schlusskurs liegt, und als bärisch, wenn der geglättete Eröffnungskurs darüber liegt. Die Strategie reagiert auf Farbwechsel dieser geglätteten Kerzen.

  • Wenn eine neue bullische Kerze nach einer nicht-bullischen erscheint, schließt die Strategie alle Short-Positionen und öffnet eine Long-Position.
  • Wenn eine neue bärische Kerze nach einer nicht-bärischen erscheint, schließt die Strategie alle Long-Positionen und öffnet eine Short-Position.

Parameter

  • Length – Anzahl der Perioden zur Glättung von Eröffnungs- und Schlusskursen.
  • CandleType – Zeitrahmen der für Berechnungen verwendeten Kerzen.
  • BuyPosOpen – erlaubt das Öffnen von Long-Positionen.
  • SellPosOpen – erlaubt das Öffnen von Short-Positionen.
  • BuyPosClose – erlaubt das Schließen von Long-Positionen bei bärischem Signal.
  • SellPosClose – erlaubt das Schließen von Short-Positionen bei bullischem Signal.
  • StopLoss – Schutz-Stop in Prozent.
  • TakeProfit – Gewinnziel in Prozent.

Handelsregeln

  1. Auf den Abschluss jeder Kerze des gewählten Zeitrahmens warten.
  2. Exponentielle gleitende Durchschnitte für Eröffnungs- und Schlusskurse berechnen.
  3. Kerzenfarbe bestimmen:
    • Grün (bullisch), wenn geglättete Eröffnung < geglätteter Schluss.
    • Rot (bärisch), wenn geglättete Eröffnung > geglätteter Schluss.
  4. Bei Farbwechsel zu bullisch: Shorts schließen und optional eine Long-Position eröffnen.
  5. Bei Farbwechsel zu bärisch: Longs schließen und optional eine Short-Position eröffnen.
  6. Schutz-Stops und Ziele werden durch integrierte Risikokontrollen verwaltet.

Diese Strategie ist eine Konvertierung des ursprünglichen MQL5-Experten „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;
	}
}