Auf GitHub ansehen

Strategie-Basis-Vorlage

Dieser Ordner bietet ein minimales Gerüst zum Aufbau eigener Trading-Ideen. Die Strategie berechnet nur einen einzigen exponentiellen gleitenden Durchschnitt und stellt eine breite Palette gängiger Parameter bereit: Long- oder Short-Trades aktivieren, optionales Take Profit und Stop Loss sowie Optimierungsbereiche. Entwickler können ihre eigene Einstiegs- und Ausstiegslogik in die Platzhalter einfügen, um neue Systeme schnell zu prototypisieren.

Die Vorlage zeigt auch, wie das integrierte Schutzmodul mit prozentualen Zielen gestartet werden kann, was das Experimentieren mit verschiedenen Risikoeinstellungen erleichtert. Da keine echten Signale enthalten sind, soll dieses Skript nicht direkt gehandelt werden, sondern als Ausgangspunkt für weitere Forschung dienen.

Details

  • Einstiegskriterien: Nicht implementiert – durch eigene Regeln ersetzen.
  • Long/Short: Über Parameter konfigurierbar.
  • Ausstiegskriterien: Nicht implementiert – durch eigene Regeln ersetzen.
  • Stops: Optionaler prozentualer Take Profit und Stop Loss über das Schutzmodul.
  • Standardwerte:
    • EMA-Länge = 10.
    • Take Profit = 1.2%, Stop Loss = 1.8% (standardmäßig deaktiviert).
  • Filter:
    • Kategorie: Vorlage
    • Richtung: Konfigurierbar
    • Indikatoren: EMA
    • Stops: Optional
    • Komplexität: Niedrig
    • Zeitrahmen: Beliebig
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Benutzerdefiniert
namespace StockSharp.Samples.Strategies;

using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

/// <summary>
/// Strategy Base - EMA trend following strategy.
/// Buys when price crosses above EMA, sells when price crosses below EMA.
/// </summary>
public class StratBaseStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _cooldownBars;

	private ExponentialMovingAverage _ema;

	private decimal _prevClose;
	private decimal _prevEma;
	private int _cooldownRemaining;

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

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	public StratBaseStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");

		_emaLength = Param(nameof(EmaLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "EMA period", "Moving Averages");

		_cooldownBars = Param(nameof(CooldownBars), 10)
			.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_ema = null;
		_prevClose = 0;
		_prevEma = 0;
		_cooldownRemaining = 0;
	}

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

		_ema = new ExponentialMovingAverage { Length = EmaLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_ema, OnProcess)
			.Start();

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

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

		if (!_ema.IsFormed)
		{
			_prevClose = candle.ClosePrice;
			_prevEma = emaVal;
			return;
		}

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevClose = candle.ClosePrice;
			_prevEma = emaVal;
			return;
		}

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevClose = candle.ClosePrice;
			_prevEma = emaVal;
			return;
		}

		if (_prevClose == 0 || _prevEma == 0)
		{
			_prevClose = candle.ClosePrice;
			_prevEma = emaVal;
			return;
		}

		// Price crosses above EMA
		var crossUp = candle.ClosePrice > emaVal && _prevClose <= _prevEma;
		// Price crosses below EMA
		var crossDown = candle.ClosePrice < emaVal && _prevClose >= _prevEma;

		if (crossUp && Position <= 0)
		{
			if (Position < 0)
				BuyMarket(Math.Abs(Position));
			BuyMarket(Volume);
			_cooldownRemaining = CooldownBars;
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0)
				SellMarket(Math.Abs(Position));
			SellMarket(Volume);
			_cooldownRemaining = CooldownBars;
		}

		_prevClose = candle.ClosePrice;
		_prevEma = emaVal;
	}
}