Auf GitHub ansehen

CloseDeleteEA-Strategie

Überblick

Die CloseDeleteEA-Strategie reproduziert das MetaTrader-Hilfsprogramm, das Positionen massenhaft schließt und Pending Orders entfernt. Sie durchsucht regelmäßig das ausgewählte Portfolio und sendet Marktorders oder Stornierungsanfragen gemäß benutzerdefinierten Filtern. Dadurch eignet sie sich für Notliquidationen oder Bereinigungsszenarien, wenn manuelles Ordermanagement zu langsam ist.

Hauptfunktionen

  • Schließt Long- und/oder Short-Exposure mit Marktorders.
  • Storniert Pending Orders, die den konfigurierten Filtern entsprechen.
  • Optionale Gewinn-/Verlustfilter, um bestimmte Positionen nicht zu berühren.
  • Beschränkt den Scan auf das aktuelle Wertpapier oder verarbeitet das gesamte Portfolio.
  • Filtert Positionen und Orders nach Strategiekennung.

Parameter

Name Beschreibung
CloseBuyPositions Schließt Long-Exposure, die den Filtern entspricht.
CloseSellPositions Schließt Short-Exposure, die den Filtern entspricht.
CloseMarketPositions Aktiviert das Modul zum Schließen von Marktpositionen.
CancelPendingOrders Aktiviert das Stornieren von Pending Orders.
CloseOnlyProfitable Schließt Positionen nur, wenn der aktuelle PnL nicht negativ ist.
CloseOnlyLosing Schließt Positionen nur, wenn der aktuelle PnL nicht positiv ist.
ApplyToCurrentSecurity Wenn true, wird nur das Strategiewertpapier durchsucht. Andernfalls werden alle Wertpapiere im Portfolio verarbeitet.
TargetStrategyId Optionaler Filter für Strategiekennung (leerer Wert passt auf alles).
TimerInterval Timerfrequenz für die Verwaltungsschleife.

Nutzungshinweise

  1. Binden Sie die Strategie an einen Connector mit zugewiesenem Portfolio.
  2. Konfigurieren Sie optional Filter, bevor Sie die Strategie starten.
  3. Starten Sie die Strategie, um den Close/Delete-Zyklus auszulösen. Die Strategie stoppt automatisch, sobald keine passenden Positionen oder Orders verbleiben.
  4. Beachten Sie, dass Stornierungsanfragen nur Orders betreffen können, die für die Strategie über den Connector sichtbar sind.

Unterschiede zur MQL-Version

  • StockSharp arbeitet mit aggregierten Positionen; daher wird individuelle Ticketkontrolle durch volumenbasiertes Nettoexposure-Management ersetzt.
  • Strategie-ID-Filterung imitiert das ursprüngliche Magic-Number-Konzept.
  • Visuelle Chart-Bereinigungselemente aus MetaTrader werden nicht reproduziert.
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 CloseDeleteEaStrategy : 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 CloseDeleteEaStrategy()
	{
		_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;
	}
}