Auf GitHub ansehen

X Trader-Strategie

Diese Strategie implementiert ein konträres System aus gleitenden Durchschnitts-Kreuzungen, das ursprünglich in MQL als X trader geschrieben wurde. Es verwendet zwei einfache gleitende Durchschnitte und eröffnet Positionen entgegen der Kreuzungsrichtung. Das Risiko wird mithilfe fester Take-Profit- und Stop-Loss-Werte in absoluten Punkten über StartProtection verwaltet.

Funktionsweise

  1. Kerzdaten des angegebenen Zeitrahmens abonnieren.
  2. Zwei gleitende Durchschnitte mit konfigurierbaren Perioden berechnen.
  3. Die letzten zwei Werte jedes Durchschnitts verfolgen, um eine Kreuzung zu erkennen.
  4. Wenn der schnelle Durchschnitt den langsamen von unten kreuzt und zwei Balken lang darüber bleibt, während er vor zwei Balken darunter war, wird eine Short-Position eröffnet.
  5. Wenn der schnelle Durchschnitt den langsamen von oben kreuzt und zwei Balken lang darunter bleibt, während er vor zwei Balken darüber war, wird eine Long-Position eröffnet.
  6. Es kann jeweils nur eine Position offen sein. Der Schutz schließt Trades automatisch, wenn sich der Preis um den konfigurierten Take-Profit- oder Stop-Loss-Betrag bewegt.

Parameter

  • CandleType – zu verwendende Kerzenserie.
  • Ma1Period – Periode des ersten gleitenden Durchschnitts.
  • Ma2Period – Periode des zweiten gleitenden Durchschnitts.
  • TakeProfitPoints – Gewinnziel in Preispunkten.
  • StopLossPoints – Verlustlimit in Preispunkten.

Indikator

  • SimpleMovingAverage – zweimal mit unterschiedlichen Perioden verwendet.

Risikomanagement

StartProtection wird in OnStarted aktiviert und wendet die Take-Profit- und Stop-Loss-Werte auf alle Positionen an.

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>
/// X Trader Strategy - contrarian moving average cross.
/// </summary>
public class XTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _ma1Period;
	private readonly StrategyParam<int> _ma2Period;

	private decimal _ma1Prev;
	private decimal _ma1Prev2;
	private decimal _ma2Prev;
	private decimal _ma2Prev2;
	private bool _hasPrev2;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int Ma1Period { get => _ma1Period.Value; set => _ma1Period.Value = value; }
	public int Ma2Period { get => _ma2Period.Value; set => _ma2Period.Value = value; }

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

		_ma1Period = Param(nameof(Ma1Period), 16)
			.SetGreaterThanZero()
			.SetDisplay("MA1 Period", "Period of the first moving average", "Parameters");

		_ma2Period = Param(nameof(Ma2Period), 10)
			.SetGreaterThanZero()
			.SetDisplay("MA2 Period", "Period of the second moving average", "Parameters");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_ma1Prev = 0;
		_ma1Prev2 = 0;
		_ma2Prev = 0;
		_ma2Prev2 = 0;
		_hasPrev2 = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ma1 = new ExponentialMovingAverage { Length = Ma1Period };
		var ma2 = new ExponentialMovingAverage { Length = Ma2Period };

		SubscribeCandles(CandleType)
			.Bind(ma1, ma2, ProcessCandle)
			.Start();
	}

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

		if (_ma1Prev == 0)
		{
			_ma1Prev = ma1Value;
			_ma2Prev = ma2Value;
			return;
		}

		if (!_hasPrev2)
		{
			_ma1Prev2 = _ma1Prev;
			_ma2Prev2 = _ma2Prev;
			_ma1Prev = ma1Value;
			_ma2Prev = ma2Value;
			_hasPrev2 = true;
			return;
		}

		// Contrarian: sell when MA1 crosses above MA2, buy when MA1 crosses below
		var sellSignal = ma1Value > ma2Value && _ma1Prev > _ma2Prev && _ma1Prev2 < _ma2Prev2;
		var buySignal = ma1Value < ma2Value && _ma1Prev < _ma2Prev && _ma1Prev2 > _ma2Prev2;

		if (sellSignal && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}
		else if (buySignal && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}

		_ma1Prev2 = _ma1Prev;
		_ma2Prev2 = _ma2Prev;
		_ma1Prev = ma1Value;
		_ma2Prev = ma2Value;
	}
}