Auf GitHub ansehen

Turbo Scaler Grid-Strategie

Überblick

Die Turbo Scaler Grid-Strategie ist eine High-Level-StockSharp-Implementierung des MQL5-Expertenberaters „Turbo Scaler Grid Pending“. Die Strategie konzentriert sich auf die Verwaltung ausstehender Stop-Raster um vordefinierte Preisniveaus, den dynamischen Schutz offener Positionen mit Break-Even- und Trailing-Logik sowie die Überwachung des Kontokapitals, um Positionen zu schließen, wenn Gewinn- oder Verlustschwellen erreicht werden.

Die Logik funktioniert in mehreren Zeitrahmen gleichzeitig:

  • Ein konfigurierbarer Trigger-Zeitrahmen überwacht Preisnähesignale, die das ausstehende Raster aktivieren.
  • Zusätzliche 30-Minuten-, 2-Stunden- und Tageskerzen dienen als Bestätigung für optionale bedingte Auslöser.
  • Level1-Daten liefern die neuesten Geld-/Briefwerte, die zur Positionierung ausstehender Aufträge und zur Verwaltung von Trailing Stops verwendet werden.

Handelsregeln

  1. Ausstehendes Raster
    • Buy-Stop- und Sell-Stop-Orders werden aus konfigurierbaren Ankerpreisen (BuyStopEntry und SellStopEntry) platziert.
    • Die Bestellungen haben einen Abstand von PendingStepPoints und sind auf PendingQuantity begrenzt.
    • Der Preisauslöser überprüft die letzten Kerzen im Auslösezeitrahmen, um zu bestätigen, dass sich der Preis mit ausreichender Dynamik dem Ankerniveau angenähert hat.
    • Der Bedingungsauslöser validiert zusätzliche Multi-Timeframe-Filter (tägliche Blockbereiche, H2- und M30-Kerzenrichtung und mittleres Bereichsniveau), bevor ausstehende Aufträge erteilt werden.
  2. Positionssicherung
    • Der anfängliche Stop-Loss wird aus StopLossPoints (oder Festpreisüberschreibungen) berechnet.
    • Wenn der Preis um BreakevenTriggerPoints steigt, wird der Stop auf den Einstiegspreis plus BreakevenOffsetPoints (für Long-Positionen) oder abzüglich des Offsets (für Short-Positionen) verschoben.
    • Ein Trailing Stop wird erst aktiviert, nachdem die Gewinnschwelle erreicht ist, und wird aktualisiert, sobald der Preis den vorherigen Stop um TrailMultiplier * TrailPoints überschreitet.
  3. Aktienaufsicht
    • Die Strategie überwacht den schwebenden PnL und erzwingt die Positionsauflösung, wenn der Drawdown MaxFloatLoss überschreitet (skaliert auf das ausgewählte Auftragsvolumen).
    • Ein variabler Gewinnauslöser sperrt Gewinne, indem er eine interne Eigenkapitallinie bei EquityBreakeven platziert und diese um EquityTrail nachzieht, sobald der Gewinn EquityTrigger übersteigt.

Parameter

Name Beschreibung
StopLossPoints Anfängliche Stop-Loss-Distanz in Punkten.
BreakevenTriggerPoints Erforderliche Punkte, um die Break-Even-Bewegung zu aktivieren.
BreakevenOffsetPoints Der Offset wird dem Einstiegspreis hinzugefügt, wenn der Stop auf die Gewinnschwelle verschoben wird.
TrailPoints Distanz, die für das Nachlaufen nach der Gewinnschwelle verwendet wird.
TrailMultiplier Der Multiplikator wird angewendet, bevor ein neuer Trailing Stop gesetzt wird.
BuyStopLossPrice / SellStopLossPrice Optionale feste Stop-Preise für Long-/Short-Positionen.
BuyStopEntry / SellStopEntry Grundpreise für die ausstehenden Stoppgitter.
OrderVolume Volumen pro ausstehender Bestellung.
PendingQuantity Maximale Anzahl aktiver ausstehender Bestellungen.
PendingStepPoints Abstand zwischen aufeinanderfolgenden ausstehenden Bestellungen.
TriggerCandleType Kerzenserie, die für die Preisauslöselogik verwendet wird.
PendingPriceTrigger Aktiviert den Preisnähe-Trigger.
PendingConditionTrigger Aktiviert den Multi-Timeframe-Bestätigungstrigger.
OrderBuyBlockStart / OrderBuyBlockEnd Täglicher Low-Block zur Validierung langer Setups.
OrderSellBlockStart / OrderSellBlockEnd Täglicher hoher Block zur Validierung kurzer Setups.
MaxFloatLoss Maximal zulässiger Floating-Verlust (skaliert nach Volumen).
EquityBreakeven Das Eigenkapitalniveau bleibt erhalten, nachdem der Gewinnauslöser aktiviert wurde.
EquityTrigger Zur Schaffung der Eigenkapitalsperre ist ein variabler Gewinn erforderlich.
EquityTrail Auf die Equity-Sperre angewendete Nachlaufdistanz.

Notizen

  • Das Bestellvolumen wird so skaliert, dass es dem ursprünglichen EA-Verhalten entspricht (0.01-Lots werden als Basisschritt behandelt).
  • Alle Kommentare im Code sind auf Englisch verfasst, während dieses Dokument eine detaillierte Beschreibung für ein schnelles Onboarding bietet.
  • Die Strategie verwendet nur High-Level-StockSharp-APIs (SubscribeCandles, Bind, BuyStop, SellStop, SellMarket, BuyMarket) entsprechend den Projektanforderungen.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "Turbo Scaler Grid" MetaTrader expert.
/// Uses EMA crossover with RSI confirmation for scalping entries.
/// </summary>
public class TurboScalerGridStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpper;
	private readonly StrategyParam<decimal> _rsiLower;

	private ExponentialMovingAverage _fastEma;
	private ExponentialMovingAverage _slowEma;
	private RelativeStrengthIndex _rsi;
	private decimal? _prevFast;
	private decimal? _prevSlow;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal RsiUpper
	{
		get => _rsiUpper.Value;
		set => _rsiUpper.Value = value;
	}

	public decimal RsiLower
	{
		get => _rsiLower.Value;
		set => _rsiLower.Value = value;
	}

	public TurboScalerGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for scalping", "General");

		_fastPeriod = Param(nameof(FastPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("Slow SMA", "Slow SMA period (computed manually)", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");

		_rsiUpper = Param(nameof(RsiUpper), 60m)
			.SetDisplay("RSI Upper", "RSI level for buy confirmation", "Signals");

		_rsiLower = Param(nameof(RsiLower), 40m)
			.SetDisplay("RSI Lower", "RSI level for sell confirmation", "Signals");
	}

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

		_prevFast = null;
		_prevSlow = null;

		_fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		_slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_fastEma, _slowEma, _rsi, ProcessCandle)
			.Start();

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

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

		if (!_fastEma.IsFormed || !_slowEma.IsFormed || !_rsi.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_prevFast is null || _prevSlow is null)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var crossUp = _prevFast.Value <= _prevSlow.Value && fastValue > slowValue;
		var crossDown = _prevFast.Value >= _prevSlow.Value && fastValue < slowValue;

		if (crossUp && rsiValue > RsiUpper)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (crossDown && rsiValue < RsiLower)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_fastEma = null;
		_slowEma = null;
		_rsi = null;
		_prevFast = null;
		_prevSlow = null;

		base.OnReseted();
	}
}