Auf GitHub ansehen

X-Trail-Strategie

Diese Strategie erzeugt Trades, wenn ein schneller und ein langsamer einfacher gleitender Durchschnitt, berechnet auf dem Median-Preis, sich kreuzen. Die Logik spiegelt das ursprüngliche MQL-Skript X_trail.mq4 wider, das bei solchen Kreuzungen Alarme auslöste.

Eine Long-Position wird eröffnet, wenn der schnelle MA auf der aktuellen und der vorherigen Kerze über dem langsamen MA liegt, während er zwei Kerzen zuvor darunter lag. Das umgekehrte Muster löst eine Short-Position aus. Positionen werden bei jedem neuen Signal umgekehrt.

Details

  • Einstiegskriterien:
    • Long: Schneller MA > langsamer MA auf den letzten zwei abgeschlossenen Kerzen und schneller MA lag zwei Kerzen zuvor unter dem langsamen MA.
    • Short: Schneller MA < langsamer MA auf den letzten zwei abgeschlossenen Kerzen und schneller MA lag zwei Kerzen zuvor über dem langsamen MA.
  • Long/Short: Beide.
  • Ausstiegskriterien:
    • Gegenläufige Kreuzung (Positionsumkehr).
  • Stops: Keine.
  • Indikatoren:
    • Zwei einfache gleitende Durchschnitte, berechnet auf dem Median-Preis.
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>
/// Moving average crossover strategy based on median price.
/// Enters long when fast MA crosses above slow MA.
/// Enters short when fast MA crosses below slow MA.
/// </summary>
public class XTrailStrategy : Strategy
{
	private readonly StrategyParam<int> _ma1Length;
	private readonly StrategyParam<int> _ma2Length;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int Ma1Length
	{
		get => _ma1Length.Value;
		set => _ma1Length.Value = value;
	}

	public int Ma2Length
	{
		get => _ma2Length.Value;
		set => _ma2Length.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public XTrailStrategy()
	{
		_ma1Length = Param(nameof(Ma1Length), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA Length", "Length of the fast moving average", "General");

		_ma2Length = Param(nameof(Ma2Length), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA Length", "Length of the slow moving average", "General");

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

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var ma1 = new SimpleMovingAverage { Length = Ma1Length };
		var ma2 = new SimpleMovingAverage { Length = Ma2Length };

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

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, ma1);
			DrawIndicator(area, ma2);
			DrawOwnTrades(area);
		}
	}

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

		if (_hasPrev)
		{
			var crossUp = _prevFast <= _prevSlow && fast > slow;
			var crossDown = _prevFast >= _prevSlow && fast < slow;

			if (crossUp && Position <= 0)
				BuyMarket();
			else if (crossDown && Position >= 0)
				SellMarket();
		}

		_prevFast = fast;
		_prevSlow = slow;
		_hasPrev = true;
	}
}