Auf GitHub ansehen

Volatilitäts-Ausbruch-Strategie

Die Volatilitäts-Ausbruch-Strategie sucht nach starken gerichteten Bewegungen, wenn der Preis aus seinem durchschnittlichen Bereich ausbricht. Durch die Messung des Abstands von einem einfachen gleitenden Durchschnitt mithilfe des ATR definiert der Algorithmus Ausbruchsschwellen, die mit der Volatilität skalieren.

Tests zeigen eine durchschnittliche jährliche Rendite von etwa 97%. Sie funktioniert am besten auf dem Kryptomarkt.

Ein Kaufauftrag wird ausgelöst, wenn der Schlusskurs die SMA um mehr als Multiplier mal den ATR übersteigt. Ein Verkaufssignal erscheint, wenn der Schlusskurs um denselben Abstand unter die SMA fällt. Positionen bleiben offen, bis ein entgegengesetzter Ausbruch auftritt oder ein Schutz-Stop getroffen wird.

Diese Technik eignet sich für Intraday-Trader, die von Momentum-Schüben profitieren. ATR-basierte Schwellen helfen, Rauschen herauszufiltern, sodass nur signifikante Bewegungen Trades erzeugen.

Details

  • Einstiegskriterien:
    • Long: Close > SMA + Multiplier * ATR
    • Short: Close < SMA - Multiplier * ATR
  • Long/Short: Beide Seiten.
  • Ausstiegskriterien:
    • Long: Ausstieg, wenn ein entgegengesetzter Ausbruch ausgelöst wird oder Stop-Loss getroffen wird
    • Short: Ausstieg, wenn ein entgegengesetzter Ausbruch ausgelöst wird oder Stop-Loss getroffen wird
  • Stops: Ja, Stop-Loss bei Multiplier * ATR vom Einstieg.
  • Standardwerte:
    • Period = 20
    • Multiplier = 2.0m
    • CandleType = TimeSpan.FromMinutes(5)
  • Filter:
    • Kategorie: Ausbruch
    • Richtung: Beide
    • Indikatoren: SMA, ATR
    • Stops: Ja
    • Komplexität: Mittel
    • Zeitrahmen: Intraday
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;
	
/// <summary>
/// Volatility Breakout strategy. Enters trades when price breaks out from average price with volatility threshold.
/// </summary>
public class VolatilityBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _periodParam;
	private readonly StrategyParam<decimal> _multiplierParam;
	private readonly StrategyParam<DataType> _candleTypeParam;

	private SimpleMovingAverage _sma;
	private AverageTrueRange _atr;
	
	private decimal _prevSma;
	private decimal _prevAtr;

	/// <summary>
	/// Period for SMA and ATR calculations.
	/// </summary>
	public int Period
	{
		get => _periodParam.Value;
		set => _periodParam.Value = value;
	}

	/// <summary>
	/// Volatility multiplier for breakout threshold.
	/// </summary>
	public decimal Multiplier
	{
		get => _multiplierParam.Value;
		set => _multiplierParam.Value = value;
	}

	/// <summary>
	/// Candle type for strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleTypeParam.Value;
		set => _candleTypeParam.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public VolatilityBreakoutStrategy()
	{
		_periodParam = Param(nameof(Period), 20)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Period for SMA and ATR", "Parameters")
			
			.SetOptimize(10, 50, 5);

		_multiplierParam = Param(nameof(Multiplier), 2.0m)
			.SetRange(0.1m, decimal.MaxValue)
			.SetDisplay("Multiplier", "Volatility multiplier for breakout threshold", "Parameters")
			
			.SetOptimize(1.0m, 3.0m, 0.5m);

		_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for strategy", "Common");
	}

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

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

		_sma = null;
		_atr = null;
		_prevSma = 0;
		_prevAtr = 0;
	}

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

// Create indicators
		_sma = new SMA { Length = Period };
		_atr = new AverageTrueRange { Length = Period };

		// Create subscription and bind indicators
		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_sma, _atr, ProcessCandle)
			.Start();

		// Setup chart visualization if available
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _sma);
			DrawOwnTrades(area);
		}
		
		// Enable position protection
		StartProtection(
			takeProfit: new Unit(0, UnitTypes.Absolute), // No take profit
			stopLoss: new Unit(Multiplier, UnitTypes.Absolute) // Stop loss at 2*ATR
		);
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;
		
		// Save values for the next candle
		var currentSma = smaValue;
		var currentAtr = atrValue;
		
		// Skip first candle after indicators become formed
		if (_prevSma == 0 || _prevAtr == 0)
		{
			_prevSma = currentSma;
			_prevAtr = currentAtr;
			return;
		}
		
		// Calculate volatility threshold
		var threshold = Multiplier * currentAtr;
		
		// Check for long setup - price breaks above SMA + threshold
		if (candle.ClosePrice > currentSma + threshold && Position <= 0)
		{
			// Close any short position and open long
			BuyMarket(Volume + Math.Abs(Position));
		}
		// Check for short setup - price breaks below SMA - threshold
		else if (candle.ClosePrice < currentSma - threshold && Position >= 0)
		{
			// Close any long position and open short
			SellMarket(Volume + Math.Abs(Position));
		}
		
		// Update previous values for next candle
		_prevSma = currentSma;
		_prevAtr = currentAtr;
	}
}