Auf GitHub ansehen

Hoop Master Breakout-Strategie

Überblick

  • Konvertiert vom MetaTrader-5-Expert-Advisor „Hoop master 2" von Vladimir Karputov.
  • Baut eine Ausbruchsbox um den aktuellen Preis und bewaffnet sowohl Kauf- als auch Verkaufsstop-Orders jedes Mal, wenn eine neue Kerze schließt.
  • Reproduziert automatisch das MT5-Verhalten, die Lotgröße nach einem Verlust-Trade zu verdoppeln und nach einem profitablen Zyklus zurückzusetzen.

Handelslogik

  1. Die konfigurierte Kerzenserie abonnieren und nur abgeschlossene Kerzen abwarten. Eine neue Kerze fungiert als „Tick", der die ausstehenden Orders neu bewaffnet.
  2. Wenn die Strategie flach ist:
    • Ein Buy-Stop IndentPips Punkte über dem letzten Schluss platzieren.
    • Ein Sell-Stop IndentPips Punkte unter dem letzten Schluss platzieren.
    • MetaTrader-Pips in absolute Preiseinheiten umwandeln mit dem Instrument-PriceStep und der Bruchziffern-Anpassung (×10 für 3 oder 5 Dezimalstellen-Kurse).
  3. Jede ausstehende Order speichert ihre eigenen Stop-Loss- und Take-Profit-Niveaus. Sobald die Order ausgeführt wird, wird die gegenüberliegende Order storniert und der gespeicherte Schutz mit nativen Börsenorders neu erstellt (SellStop/SellLimit für Longs, BuyStop/BuyLimit für Shorts).
  4. Wenn eine Schutzorder die Position schließt, wird die verbleibende angehängte Order storniert, um doppelte Ausstiege zu vermeiden.
  5. Optionale Trailing-Stop-Logik bewegt den Schutz-Stop zugunsten des Trades, sobald der Preis mindestens TrailingStopPips vorgerückt ist und die Verbesserung TrailingStepPips überschreitet.
  6. Nach jedem flach-zu-flach-Handelszyklus wird der realisierte PnL ausgewertet. Ein negativer Zyklus multipliziert das Arbeitsvolumen mit LossMultiplier; andernfalls wird das Volumen auf das Basis-Volume zurückgesetzt.

Parameter

Parameter Beschreibung Standard Hinweise
Volume Basis-Ordergröße beim Bewaffnen neuer ausstehender Orders. Strategie-Volume-Eigenschaft Verdoppelt nach einem Verlustzyklus gemäß LossMultiplier.
StopLossPips Stop-Loss-Abstand in MetaTrader-Pips. 25 Mit Pip-Größen-Helfer in Preis umgewandelt. 0 deaktiviert den Stop.
TakeProfitPips Take-Profit-Abstand in MetaTrader-Pips. 70 In Preis umgewandelt. 0 deaktiviert das Ziel.
TrailingStopPips Abstand zwischen Preis und Trailing-Stop. 0 Auf 0 setzen zum Deaktivieren des Trailings.
TrailingStepPips Mindestverbesserung bevor der Trailing-Stop bewegt wird. 5 Nur verwendet wenn TrailingStopPips größer als null ist.
IndentPips Offset zum letzten Schluss beim Bewaffnen ausstehender Orders. 15 Stellt sicher, dass Stop-Orders außerhalb des unmittelbaren Preisrauschens sitzen.
LossMultiplier Multiplikator für den nächsten Zyklus nach einem Verlust. 2 Implementiert die Martingal-Positionsgrößengebung des MT5-EA.
CandleType Kerzentyp/-zeitrahmen, der das Neu-Bewaffnen auslöst. 1-Stunden-Zeitrahmen Ändern, um dem bei Tests verwendeten Chart zu entsprechen.

Geldmanagement und Schutz

  • Jeder ausgeführte Einstieg baut sofort seinen Stop-Loss und Take-Profit als echte Börsenorders neu auf, damit die Schutzmaßnahmen auch bei Strategietrennung funktionieren.
  • StartProtection() wird beim Start aufgerufen, um verirrte Positionen aus vorherigen Läufen zu liquidieren.
  • Trailing-Logik passt bestehende Stop-Orders statt Marktausstiege zu senden an, was das Verhalten konsistent mit MT5-Modifikationen hält.

Implementierungshinweise

  • Folgt der hochrangigen StockSharp-API: Kerzenabonnements, BuyStop/SellStop für Einstiege und BuyLimit/SellLimit für Take-Profit-Orders.
  • Alle Textkommentare im Code sind auf Englisch, während externe Dokumentation (dieses README und Übersetzungen) detaillierte Beschreibungen für Benutzer bereitstellt.
  • MetaTrader-Pip-Konvertierung berücksichtigt Bruchziffern-Symbole (3 oder 5 Dezimalstellen) durch Multiplizieren des Broker-Schritts mit 10, entsprechend der m_adjusted_point-Logik des ursprünglichen EA.
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;

public class HoopMasterBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public HoopMasterBreakoutStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}