Auf GitHub ansehen

Negativer-Spread-Strategie

Die Negative Spread-Strategie nutzt seltene Momente aus, wenn der beste Briefkurs unter den besten Geldkurs fällt und so einen negativen Spread erzeugt. Wenn diese Fehlbewertung auftritt, verkauft die Strategie zum Marktpreis und versucht, den abnormalen Spread zu erfassen. Nachdem die Short-Position eröffnet wurde, wird sie beim nächsten Orderbuch-Update geschlossen, sobald der Markt in einen normalen Zustand zurückkehrt.

Das System hört ausschließlich auf Orderbuch-Ereignisse und verlässt sich nicht auf Kerzen oder Indikatoren. Optionale Stop-Loss- und Take-Profit-Parameter werden als Sicherheitsmaßnahmen bereitgestellt und werden in Pips unter Verwendung der Tick-Größe des Instruments berechnet.

Details

  • Einstiegskriterien: BestAsk < BestBid und keine aktive Position.
  • Long/Short: Nur Short.
  • Ausstiegskriterien: Die Position wird unmittelbar nach der Eröffnung geschlossen.
  • Stops: Optionaler Stop-Loss und Take-Profit in Pips.
  • Standardwerte:
    • Volume = 1
    • TakeProfitPips = 5000
    • StopLossPips = 5000
  • Filter:
    • Kategorie: Arbitrage
    • Richtung: Short
    • Indikatoren: Keine
    • Stops: Optional
    • Komplexität: Grundlegend
    • Zeitrahmen: Tick
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Hoch
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>
/// Strategy that detects price dislocations using Bollinger Bands
/// and trades mean reversion when price extends beyond bands.
/// </summary>
public class NegativeSpreadStrategy : Strategy
{
	private readonly StrategyParam<int> _bbPeriod;
	private readonly StrategyParam<decimal> _bbWidth;
	private readonly StrategyParam<DataType> _candleType;

	public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
	public decimal BbWidth { get => _bbWidth.Value; set => _bbWidth.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public NegativeSpreadStrategy()
	{
		_bbPeriod = Param(nameof(BbPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");

		_bbWidth = Param(nameof(BbWidth), 1.5m)
			.SetDisplay("BB Width", "Bollinger Bands deviation", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var bb = new BollingerBands { Length = BbPeriod, Width = BbWidth };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bb, ProcessCandle)
			.Start();

		StartProtection(
			takeProfit: new Unit(1, UnitTypes.Percent),
			stopLoss: new Unit(0.5m, UnitTypes.Percent)
		);

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

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!bbValue.IsFormed)
			return;

		var bb = (BollingerBandsValue)bbValue;
		if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower)
			return;

		var close = candle.ClosePrice;

		// Mean reversion: sell when above upper band, buy when below lower band
		if (close > upper && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}
		else if (close < lower && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
	}
}