Auf GitHub ansehen

Auftragsexperte-Strategie (1916)

Diese Strategie eröffnet eine Marktposition, wenn der Preis des Instruments vordefinierte Niveaus erreicht. Sie ahmt das Verhalten des ursprünglichen MQL-Experten nach, der Aufträge über Chart-Linien verwaltete.

Funktionsweise

  • Abonniert Kerzen eines konfigurierbaren Zeitrahmens.
  • Wenn der Schlusskurs die Schwellen BuyLevel oder SellLevel kreuzt, wird eine Long- oder Short-Marktposition eröffnet.
  • Stop-Loss- und Take-Profit-Werte werden vom Einstiegspreis aus mit StopLossPip und TakeProfitPip berechnet.
  • Ein optionaler Trailing-Stop verschiebt den Stop-Loss in Richtung des aktuellen Preises, wenn dieser sich in eine günstige Richtung bewegt.

Parameter

  • TakeProfitPip – Abstand vom Einstiegspreis zum Take Profit in Pips.
  • StopLossPip – Abstand vom Einstiegspreis zum Stop Loss in Pips.
  • EnableTrailingStop – Trailing-Stop-Logik aktivieren oder deaktivieren.
  • CandleType – Kerzentyp für Berechnungen.
  • BuyLevel – Preisniveau, das den Long-Einstieg auslöst (0 deaktiviert).
  • SellLevel – Preisniveau, das den Short-Einstieg auslöst (0 deaktiviert).

Hinweise

  • Die Strategie verwendet die High-Level-API und verarbeitet nur abgeschlossene Kerzen.
  • Das Schutzsystem wird beim Start aktiviert, um versehentlich große Positionen zu vermeiden.
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>
/// Order expert strategy that uses EMA crossover to enter positions
/// and manages them with stop-loss, take-profit and trailing stop.
/// </summary>
public class OrderExpertStrategy : Strategy
{
	private readonly StrategyParam<decimal> _takeProfitPct;
	private readonly StrategyParam<decimal> _stopLossPct;
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<int> _cooldownBars;
	private readonly StrategyParam<DataType> _candleType;

	private ExponentialMovingAverage _slowEma;
	private decimal _prevFast;
	private decimal _prevSlow;
	private int _barsSinceTrade;
	private bool _isFirst = true;

	public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
	public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
	public int FastEmaPeriod { get => _fastEmaPeriod.Value; set => _fastEmaPeriod.Value = value; }
	public int SlowEmaPeriod { get => _slowEmaPeriod.Value; set => _slowEmaPeriod.Value = value; }
	public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public OrderExpertStrategy()
	{
		_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
			.SetDisplay("Take Profit %", "Take profit percentage", "Risk");

		_stopLossPct = Param(nameof(StopLossPct), 2m)
			.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");

		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");

		_cooldownBars = Param(nameof(CooldownBars), 6)
			.SetGreaterThanZero()
			.SetDisplay("Cooldown Bars", "Bars between trades", "Trading");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_barsSinceTrade = CooldownBars;
		_isFirst = true;
	}

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

		var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
		_slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };

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

		StartProtection(
			stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
			takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent)
		);

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

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

		_barsSinceTrade++;

		var slowResult = _slowEma.Process(candle.ClosePrice, candle.OpenTime, true);
		if (!slowResult.IsFormed)
			return;

		var slow = slowResult.ToDecimal();

		if (_isFirst)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_isFirst = false;
			return;
		}

		// EMA cross up -> buy
		if (_prevFast <= _prevSlow && fast > slow && Position == 0 && _barsSinceTrade >= CooldownBars)
		{
			BuyMarket();
			_barsSinceTrade = 0;
		}
		// EMA cross down -> sell
		else if (_prevFast >= _prevSlow && fast < slow && Position == 0 && _barsSinceTrade >= CooldownBars)
		{
			SellMarket();
			_barsSinceTrade = 0;
		}

		_prevFast = fast;
		_prevSlow = slow;
	}
}