Auf GitHub ansehen

Eine Systemmeisterschaftsstrategie

Überblick

  • Port des MetaTrader 4-Expertenberaters „A System: Championship Strategy Final Edit“ (Datei ACB6.MQ4).
  • Erkennt bullische oder bärische Ausbrüche in einem konfigurierbaren primären Zeitrahmen und bestätigt die Dynamik mit Live-Geld-/Briefkursen.
  • Verwendet einen sekundären Zeitrahmen, um die Trailing-Stop-Distanz zu dimensionieren, und reproduziert die Multithread-Logik des Originals EA über zwei Kerzenströme.
  • Implementiert die Blöcke „Global Equity Stop“, „Trade Pause“ und „Adaptive Risk Sizing“, die im Quellroboter fest codiert waren.

Datenabonnements

  • Abonniert zwei Kerzenserien (PrimaryTimeFrame, SecondaryTimeFrame), um die für Ziele und Trailing Stops verwendeten Preisspannen neu aufzubauen.
  • Abonniert Kurse der Stufe 1, um die besten Geld-/Briefkurse zu lesen, die Einstiege, Stop-Loss-Prüfungen, Take-Profits und den Retracement-Ausstieg auslösen.

Teilnahmebedingungen

  1. Warten Sie, bis die primäre Kerze fertig ist, und berechnen Sie deren Spanne multipliziert mit TakeFactor.
  2. Gehen Sie long, wenn:
    • Die Kerze schließt über ihrem Mittelpunkt.
    • Der aktuelle Briefkurs durchbricht das Kerzenhoch.
    • Der Abstand zwischen dem Gebot und dem Kerzentief beträgt mehr als MinStopDistance.
  3. Gehen Sie short, wenn die entsprechenden Bedingungen für den Ausbruch nach unten zutreffen.
  4. Überspringen Sie Einträge, wenn die berechnete Take-Profit-Distanz kleiner als der minimale Stoppabstand ist.

Exit-Management

  • Anfängliche Schutzniveaus: Der Stop ist am vorherigen Kerzentief/-hoch verankert, während der Take-Profit dem Einstiegspreis plus/minus der Spanne multipliziert mit TakeFactor entspricht.
  • Retracement-Exit (FallLimit/FallFactor):
    • Verfolgen Sie den maximal günstigen Ausflug für die aktive Position.
    • Wenn die aktuelle Bewegung unter FallLimit * maxMove fällt und die Bewegung bereits über FallFactor * target fortgeschritten ist, schließen Sie den Handel zum Marktwert.
  • Trailing Stop (TrailFactor):
    • Die nachlaufende Distanz entspricht dem sekundären Zeitrahmenbereich multipliziert mit TrailFactor.
    • Der Stop bewegt sich nur in Handelsrichtung und überschreitet niemals den Take-Profit oder den minimalen Stop-Abstand.
  • Harte Stopps: Das Berühren des festgelegten Stop- oder Take-Levels durch den Preis führt zu einer sofortigen Liquidation mithilfe von Marktaufträgen.

Risikomanagement

  • Dynamische Positionsgröße: kombiniert RiskPerTrade mit dem aus Security.StepSize und Security.StepPrice abgeleiteten Pip-Wert. Das resultierende Volumen wird auf Wechselkursbeschränkungen gerundet und unterschreitet niemals BaseVolume.
  • Statistische Anpassung: Das Verhältnis LossesExpected/TradesExpected vom ursprünglichen EA moduliert das Risiko pro Trade, indem es mit der realisierten Verlustquote verglichen wird.
  • Equity Stop (SystemStop): Verfolgt den Aktienhöchststand und deaktiviert neue Trades, wenn der aktuelle Wert unter SystemStop * peak fällt. Informationsprotokolle markieren den Stopp der Aktivierung und Wiederherstellung.
  • Handelspause (TradePause): erzwingt ein Abkühlfenster nach jeder Marktorder, genau wie die MT4-Implementierung.

Parameter

Name Standard Beschreibung
PrimaryTimeFrame 1 Tag Höherer Zeitrahmen für die Ausbruchserkennung.
SecondaryTimeFrame 4 Stunden Zeitrahmen, der den Trailing-Stop-Bereich bereitstellt.
TakeFactor 0,8 Multiplikator, der bei der Erstellung des Take-Profits auf den primären Kerzenbereich angewendet wird.
TrailFactor 10 Multiplikator, der beim Aktualisieren des Trailing Stop auf den sekundären Kerzenbereich angewendet wird.
FallLimit 0,5 Verhältnis des maximalen Gewinns, der den Retracement-Ausstieg ermöglicht.
FallFactor 0,4 Mindestanteil des Gesamtziels, der erreicht werden muss, bevor ein Retracement-Ausstieg zulässig ist.
RiskPerTrade 0,02 Anteil des jedem Trade zugewiesenen Eigenkapitals vor Anpassungen.
BaseVolume 1 Fallback-Ordergröße, die verwendet wird, wenn die Risikogröße ein kleineres Volumen ergibt.
MinStopDistance 0 Abstandsbeschränkung der Börsenstopps, ausgedrückt in Preiseinheiten.
TradePause 5 Minuten Wartezeit nach jeder ausgeführten Bestellung.
SystemStop 0,8 Drawdown-Faktor für den Portfolio-Aktienstopp (z. B. 0,8 = 20 % zulässiger Drawdown).
LossesExpected 20 Erwartete Anzahl verlorener Trades zur Risikoanpassung.
TradesExpected 85 Erwartete Anzahl der gesamten Trades zur Risikoanpassung.

Hinweise zur Implementierung

  • Die Sperr-/Absicherungsthreads aus der MQL-Version werden weggelassen, da StockSharp-Strategien auf einer Nettoposition arbeiten. Risikokontrolle und Trailing-Logik bieten einen gleichwertigen Kapitalschutzmechanismus.
  • Stop- und Take-Level werden innerhalb der Strategie verfolgt, anstatt separate native Orders zu verwenden, um mit der Backtesting-Engine in Einklang zu bleiben.
  • Stellen Sie sicher, dass die verbundene Sicherheit StepSize, StepPrice, MinVolume und VolumeStep verfügbar macht. andernfalls fällt die Größenanpassung auf BaseVolume zurück.
  • Die Strategie sollte mit aktivierten Echtzeitkursen ausgeführt werden. Andernfalls werden nur kerzengesteuerte Aktualisierungen ausgeführt und die Stopplogik reagiert mit Kerzenlatenz.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Multi-timeframe breakout strategy converted from the original MetaTrader "A System" expert advisor.
/// Enters on momentum breakouts when close is above/below the midpoint of the previous candle range.
/// Uses ATR-based trailing stop for position management.
/// </summary>
public class ASystemChampionshipStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _takeFactor;
	private readonly StrategyParam<decimal> _trailFactor;

	private decimal _prevHigh;
	private decimal _prevLow;
	private decimal _prevClose;
	private bool _hasPrev;
	private decimal _entryPrice;
	private decimal _stopPrice;

	public ASystemChampionshipStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for breakout detection.", "General");

		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetDisplay("ATR Period", "Period for ATR used in trailing stop.", "Indicators");

		_takeFactor = Param(nameof(TakeFactor), 2.5m)
			.SetDisplay("Take Factor", "ATR multiplier for take profit.", "Risk");

		_trailFactor = Param(nameof(TrailFactor), 1.5m)
			.SetDisplay("Trail Factor", "ATR multiplier for trailing stop.", "Risk");
	}

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

	public int AtrPeriod
	{
		get => _atrPeriod.Value;
		set => _atrPeriod.Value = value;
	}

	public decimal TakeFactor
	{
		get => _takeFactor.Value;
		set => _takeFactor.Value = value;
	}

	public decimal TrailFactor
	{
		get => _trailFactor.Value;
		set => _trailFactor.Value = value;
	}

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

		_prevHigh = 0;
		_prevLow = 0;
		_prevClose = 0;
		_hasPrev = false;
		_entryPrice = 0;
		_stopPrice = 0;
	}

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

		_prevHigh = 0;
		_prevLow = 0;
		_prevClose = 0;
		_hasPrev = false;
		_entryPrice = 0;
		_stopPrice = 0;

		var atr = new AverageTrueRange { Length = AtrPeriod };

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

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

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

		if (atrValue <= 0)
		{
			SaveCandle(candle);
			return;
		}

		// Manage open position
		if (Position > 0)
		{
			// Trail stop up
			var newStop = candle.ClosePrice - atrValue * TrailFactor;
			if (newStop > _stopPrice)
				_stopPrice = newStop;

			if (candle.LowPrice <= _stopPrice)
			{
				SellMarket();
				ResetPosition();
			}
			else if (_entryPrice > 0 && candle.HighPrice >= _entryPrice + atrValue * TakeFactor)
			{
				SellMarket();
				ResetPosition();
			}
		}
		else if (Position < 0)
		{
			// Trail stop down
			var newStop = candle.ClosePrice + atrValue * TrailFactor;
			if (_stopPrice == 0 || newStop < _stopPrice)
				_stopPrice = newStop;

			if (candle.HighPrice >= _stopPrice)
			{
				BuyMarket();
				ResetPosition();
			}
			else if (_entryPrice > 0 && candle.LowPrice <= _entryPrice - atrValue * TakeFactor)
			{
				BuyMarket();
				ResetPosition();
			}
		}

		// Entry logic
		if (_hasPrev && Position == 0)
		{
			var mid = (_prevHigh + _prevLow) / 2m;

			if (_prevClose > mid && candle.ClosePrice > _prevHigh)
			{
				// Bullish breakout
				BuyMarket();
				_entryPrice = candle.ClosePrice;
				_stopPrice = candle.ClosePrice - atrValue * TrailFactor;
			}
			else if (_prevClose < mid && candle.ClosePrice < _prevLow)
			{
				// Bearish breakout
				SellMarket();
				_entryPrice = candle.ClosePrice;
				_stopPrice = candle.ClosePrice + atrValue * TrailFactor;
			}
		}

		SaveCandle(candle);
	}

	private void SaveCandle(ICandleMessage candle)
	{
		_prevHigh = candle.HighPrice;
		_prevLow = candle.LowPrice;
		_prevClose = candle.ClosePrice;
		_hasPrev = true;
	}

	private void ResetPosition()
	{
		_entryPrice = 0;
		_stopPrice = 0;
	}
}