Auf GitHub ansehen

Strategie für Nachrichten-Pending-Orders

Diese Strategie platziert ein Paar ausstehender Stop-Orders rund um den aktuellen Preis und verwaltet sie, während sich der Markt entwickelt. Sie ist für den Handel während Nachrichtenveröffentlichungen konzipiert, bei denen starke Bewegungen erwartet werden.

Funktionsweise

  • Bei flacher Position platziert die Strategie:
    • Eine Buy-Stop-Order bei Ask + Step.
    • Eine Sell-Stop-Order bei Bid - Step.
  • Ausstehende Orders werden alle TimeModify Sekunden neu bepreist, wenn sich der Markt um mindestens StepTrail bewegt hat.
  • Wenn eine Order ausgeführt wird, wird die entgegengesetzte ausstehende Order storniert.
  • Ein Schutz-Stop-Loss und ein optionaler Take-Profit werden auf Basis des Einstiegspreises erstellt.
  • Der Stop-Loss kann nach einem definierten Gewinn auf Break-Even verschoben werden und dann dem Preis folgen.

Die Strategie arbeitet mit Level1-Daten und stützt sich auf keine Indikatoren.

Parameter

Parameter Standard Beschreibung
Step 10 Abstand in Ticks für ausstehende Stop-Orders.
StopLoss 10 Initialer Stop-Loss in Ticks.
TakeProfit 50 Take-Profit in Ticks (0 deaktiviert).
TrailingStop 10 Trailing-Stop-Abstand in Ticks.
TrailingStart 0 Gewinn in Ticks vor Aktivierung des Trailings.
StepTrail 2 Mindestänzug im Stop-Preis (in Ticks) für eine neue Stop-Order.
BreakEven false Stop nach Erreichen von MinProfitBreakEven auf Einstieg verschieben.
MinProfitBreakEven 0 Gewinn in Ticks zum Verschieben des Stops auf Break-Even.
TimeModify 30 Sekunden zwischen Neubepreisungsversuchen.

Hinweise

  • Orders werden über die High-Level-API von StockSharp verwaltet.
  • Die Strategie storniert Schutzorders, wenn die Position geschlossen wird.
  • Nur die C#-Version wird bereitgestellt; keine Python-Implementierung enthalten.
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;

/// <summary>
/// News-style volatility breakout strategy.
/// Enters on ATR expansion with momentum confirmation via EMA.
/// </summary>
public class NewsPendingOrdersStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMult;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevAtr;
	private decimal _entryPrice;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public decimal AtrMult { get => _atrMult.Value; set => _atrMult.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public NewsPendingOrdersStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend period", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period", "Indicators");
		_atrMult = Param(nameof(AtrMult), 1.5m)
			.SetDisplay("ATR Mult", "ATR expansion multiplier", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevAtr = 0;
		_entryPrice = 0;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var atr = new StandardDeviation { Length = AtrPeriod };

		SubscribeCandles(CandleType).Bind(ema, atr, ProcessCandle).Start();
	}

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

		if (_prevAtr <= 0) { _prevAtr = atr; return; }

		var close = candle.ClosePrice;
		var bodySize = Math.Abs(candle.ClosePrice - candle.OpenPrice);

		// Volatility expansion: big body candle relative to stddev
		var expansion = bodySize > atr * 0.5m;

		if (expansion && close > ema && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_entryPrice = close;
		}
		else if (expansion && close < ema && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_entryPrice = close;
		}
		// Exit long
		else if (Position > 0)
		{
			if (close < ema || (_entryPrice > 0 && close <= _entryPrice - atr * 2))
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		// Exit short
		else if (Position < 0)
		{
			if (close > ema || (_entryPrice > 0 && close >= _entryPrice + atr * 2))
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		_prevAtr = atr;
	}
}