Auf GitHub ansehen

Ausstehende Limit-Grid-Strategie (MQL/8147 Conversion)

Überblick

Die Pending Limit Grid Strategy reproduziert das Verhalten des MetaTrader-Experten gespeichert in MQL/8147. Die Strategie baut ein symmetrisches Raster aus ausstehenden Limit-Orders auf um die aktuellen Geld-/Briefkurse herum. Es hält das Netz aktiv, während der Gewinn schwankt bleibt innerhalb eines konfigurierten Gewinnziels und einer Drawdown-Schwelle. Wenn einer der Schwellenwerte werden überschritten, alle Aufträge werden storniert, offene Positionen werden abgeflacht und Das Raster wird unter Verwendung des neuen Kontokapitals als Basis neu aufgebaut.

Handelslogik

  1. Abonnieren Sie Level-One-Daten, um die besten Geld- und Briefkurse zu verfolgen.
  2. Erfassen Sie das Kontoguthaben beim ersten Empfang von Live-Daten und speichern Sie es als die Sitzungsbasislinie.
  3. Platzieren Sie LevelsPerSide Verkaufslimits über dem Markt und die gleiche Anzahl an Käufen Grenzen unterhalb des Marktes. Der Abstand zwischen den Gitterebenen wird durch gesteuert GridStepPoints in den Instrumentenpreisschritt umgerechnet.
  4. Halten Sie die ausstehenden Aufträge zurück, ohne neue Aufträge erneut auszugeben, wenn sie ausgeführt werden. Die Das Raster wird erst nach einem vollständigen Reset neu erstellt.
  5. Floating PnL kontinuierlich überwachen:
    • Wenn der Gewinn ProfitTargetCurrency erreicht, alle Engagements schließen und zurücksetzen.
    • Wenn der Drawdown MaxDrawdownCurrency überschreitet, glätten Sie das Buch und setzen Sie es zurück.
  6. Nach jedem Zurücksetzen wird das Grundkapital erneut erfasst und das Raster neu aufgebaut unter Verwendung des aktuellsten Bid/Ask-Snapshots.

Parameter

Parameter Beschreibung
ProfitTargetCurrency Nettogewinn (in Kontowährung), der einen vollständigen Reset des Rasters auslöst.
MaxDrawdownCurrency Maximal tolerierter Floating-Verlust, bevor die gesamte Exposition geschlossen wird.
GridStepPoints Abstand zwischen aufeinanderfolgenden Rasterebenen, ausgedrückt in Brokerpunkten.
LevelsPerSide Anzahl der ausstehenden Aufträge, die über und unter dem Marktwert erstellt wurden.
OrderVolume Das jeder ausstehenden Limit-Order zugewiesene Volumen.

Risikomanagement

Die Strategie sieht keine Stopps oder Ziele pro Order vor. Stattdessen überwacht es die aggregierter Gewinn und Verlust. Der RequestFlatten-Helfer storniert ausstehende Orders und verwendet Marktaufträge (über ClosePosition), um alle offenen Positionen zu entfernen. Nach dem Wenn die Abflachung abgeschlossen ist, werden der Gitterstatus und die Grundliniengerechtigkeit vor dem Platzieren zurückgesetzt neue Aufträge.

Notizen

  • Die Preise werden bis Security.ShrinkPrice normalisiert, um den Umtausch zu berücksichtigen Preisschritt.
  • Der „Punkt“-Wert MetaTrader wird durch Analyse des Instruments PriceStep emuliert. um vier- und fünfstellige Anführungszeichen abzugleichen.
  • Die Strategie vermeidet das erneute Senden von Grid-Bestellungen, sobald sie platziert wurden, und ahmt dies nach ursprünglicher Experte, der sich auf Flag-Variablen stützte, um jedes Level bis dahin einzigartig zu halten Es erfolgt ein manueller oder automatischer Reset.
using System;

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

namespace StockSharp.Samples.Strategies;

public class PendingLimitGridStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cooldownBars;

	private decimal _prevClose;
	private decimal _prevMid;
	private bool _hasPrev;
	private int _barsSinceLastTrade;

	public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }

	public PendingLimitGridStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 24).SetDisplay("Channel Period", "Grid channel lookback", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
		_cooldownBars = Param(nameof(CooldownBars), 200).SetDisplay("Cooldown Bars", "Minimum bars between trades", "Risk");
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevMid = 0;
		_hasPrev = false;
		_barsSinceLastTrade = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		_barsSinceLastTrade = 0;
		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(highest, lowest, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;
		var mid = (highest + lowest) / 2;

		if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }

		_barsSinceLastTrade++;

		if (_barsSinceLastTrade >= CooldownBars)
		{
			if (_prevClose <= _prevMid && close > mid && Position <= 0)
			{
				if (Position < 0) BuyMarket();
				BuyMarket();
				_barsSinceLastTrade = 0;
			}
			else if (_prevClose >= _prevMid && close < mid && Position >= 0)
			{
				if (Position > 0) SellMarket();
				SellMarket();
				_barsSinceLastTrade = 0;
			}
		}

		_prevClose = close;
		_prevMid = mid;
	}
}