Auf GitHub ansehen

Zone-Recovery-Button-Strategie

Die Zone-Recovery-Button-Strategie ist eine direkte Umwandlung des MetaTrader Expert Advisors "ZONE RECOVERY BUTTON VER1" (MQL/25347). Der ursprüngliche Roboter stützte sich auf BUY/SELL-Schaltflächen im Chart, um einen gehedgten Basket zu starten. In dieser StockSharp-Portierung wird das manuelle Panel durch Parameter ersetzt, während Recovery-Logik, Money-/Prozent-Take-Profits, Trailing Stop in Währung und Equity-Stop-Schutz erhalten bleiben.

Sobald die Strategie eine Startrichtung erhält, eröffnet sie eine initiale Marktorder. Immer wenn der Preis die konfigurierte Zonenbreite durchläuft, stapelt das System einen Gegentrade mit erhöhtem Volumen. Der Basket wird geschlossen, wenn der Referenz-Take-Profit erreicht ist, der schwebende Gewinn das konfigurierte Geld-/Prozentziel erreicht, der Trailing Stop zu viel Gewinn zurückgibt oder die Equity-Stop-Schwelle verletzt wird.

Handelsregeln

  1. Startrichtung - emuliert das Drücken der BUY- oder SELL-Schaltfläche. Die Strategie eröffnet die erste Order sofort, sobald sie Daten erhält und handeln darf. Nach dem Schließen des Baskets kann sie automatisch mit derselben Richtung neu starten.
  2. Zone Recovery - bei jedem Recovery-Schritt wechselt der Algorithmus die Richtung. Für Long-Zyklen verkauft er, sobald der Preis unter Base Price - Zone Width fällt, und kauft dann wieder, wenn der Markt über die Basis zurückkehrt. Für Short-Zyklen ist die Logik gespiegelt.
  3. Volumenskalierung - jeder zusätzliche Hedge multipliziert entweder das vorherige Volumen oder fügt einen festen Zuwachs hinzu und reproduziert damit die "Lots"/"Multiply"-Einstellungen des EA.
  4. Take-Profit-Steuerungen - der Basket wird geschlossen durch:
    • pipbasierten Take-Profit, gemessen vom Referenzpreis;
    • Geldziel in Kontowährung;
    • Prozentziel, berechnet aus dem aktuellen Portfoliowert;
    • Trailing-Logik, die Gewinne sperrt, sobald der schwebende Gewinn eine Schwelle überschreitet und danach mehr als den erlaubten Drawdown zurückgibt;
    • Notfall-Equity-Stop, der den aktuellen schwebenden Verlust mit der höchsten während des Zyklus beobachteten Equity vergleicht.

Parameter

Parameter Standard Beschreibung
CandleType TimeSpan.FromMinutes(5) Kerzentyp zur Überwachung von Preisbewegungen.
StartDirection Buy Anfängliche Zyklusrichtung (BUY/SELL/NONE).
AutoRestart true Startet automatisch einen neuen Zyklus, nachdem der vorherige Basket geschlossen wurde.
TakeProfitPips 200 Pip-Distanz zwischen Basispreis und pipbasiertem Take-Profit-Ziel.
ZoneRecoveryPips 10 Pip-Distanz, die den nächsten Hedge in Gegenrichtung auslöst.
InitialVolume 0.01 Volumen (Lots) des ersten Trades.
UseVolumeMultiplier true Wenn aktiviert, multipliziert jeder Hedge das vorherige Volumen; andernfalls wird VolumeIncrement addiert.
VolumeMultiplier 2 Multiplikator, der angewendet wird, wenn UseVolumeMultiplier true ist.
VolumeIncrement 0.01 Volumenzuwachs, wenn UseVolumeMultiplier false ist.
MaxTrades 100 Maximale Anzahl von Trades im Basket.
UseMoneyTakeProfit false Aktiviert das Schließen, wenn schwebender Gewinn MoneyTakeProfit überschreitet.
MoneyTakeProfit 40 Gewinnziel in Kontowährung.
UsePercentTakeProfit false Aktiviert das Schließen, wenn schwebender Gewinn PercentTakeProfit Prozent des Saldos überschreitet.
PercentTakeProfit 10 Gewinnziel in Prozent des aktuellen Portfoliowerts.
EnableTrailing true Aktiviert Gewinn-Trailing in Währung.
TrailingProfitThreshold 40 Gewinnniveau, das Trailing aktiviert.
TrailingDrawdown 10 Zulässiger Drawdown vom höchsten schwebenden Gewinn vor dem Schließen des Baskets.
UseEquityStop true Aktiviert den Notfall-Equity-Stop.
TotalEquityRiskPercent 1 Maximaler schwebender Verlust (in Prozent des Equity-Hochs) vor dem Glattstellen.

Hinweise

  • Die Strategie arbeitet mit jedem Instrument, das PriceStep- und StepPrice-Werte bereitstellt. Diese Parameter werden benötigt, um Pip-Distanzen in Preis- und Währungseinheiten umzuwandeln.
  • Da StockSharp ein Nettopositionsmodell verwendet, wird das Hedging-Grid intern simuliert. Die Strategie führt eine eigene Liste von Tradeschritten, um die MetaTrader-Gewinnberechnung zu reproduzieren.
  • Die Trailing-Logik arbeitet auf dem schwebenden Gewinn des aktiven Baskets. Sie verwendet keine orderbasierten Trailing Stops.
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 ZoneRecoveryButtonStrategy : 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 ZoneRecoveryButtonStrategy()
	{
		_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;
	}
}