Ver no GitHub

Estratégia de Rompimento Stochastic

Esta abordagem de rompimento monitora o oscilador Stochastic em busca de movimentos bruscos afastados de sua média recente. Quando a linha %K rompe acima ou abaixo de um limiar ajustado pela volatilidade, sinaliza uma explosão de momentum que pode iniciar uma tendência.

Os testes indicam um retorno anual médio de cerca de 181%. Funciona melhor no mercado de criptomoedas.

Uma posição comprada é acionada quando %K cruza acima do limiar superior após um período de contração. Uma posição vendida é tomada quando %K rompe abaixo do limiar inferior. A operação é fechada quando o oscilador deriva de volta em direção à sua média ou atinge um stop protetor.

A estratégia é projetada para traders intradiários que desejam entrar cedo nas oscilações de momentum. O uso de bandas baseadas em volatilidade ajuda a filtrar o ruído para que apenas movimentos decisivos criem sinais.

Detalhes

  • Critérios de entrada:
    • Comprado: %K > Avg + DeviationMultiplier * StdDev
    • Vendido: %K < Avg - DeviationMultiplier * StdDev
  • Comprado/Vendido: Ambos os lados.
  • Critérios de saída:
    • Comprado: Sair quando %K < Avg
    • Vendido: Sair quando %K > Avg
  • Stops: Sim, stop-loss percentual.
  • Valores padrão:
    • StochasticPeriod = 14
    • KPeriod = 3
    • DPeriod = 3
    • LookbackPeriod = 20
    • DeviationMultiplier = 2.0m
    • CandleType = TimeSpan.FromMinutes(5)
  • Filtros:
    • Categoria: Rompimento
    • Direção: Ambos
    • Indicadores: Stochastic Oscillator
    • Stops: Sim
    • Complexidade: Intermediário
    • Período: Intradiário
    • Sazonalidade: Não
    • Redes neurais: Não
    • Divergência: Não
    • Nível de risco: Médio
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>
/// Stochastic Breakout Strategy.
/// This strategy identifies breakouts based on the Stochastic oscillator values compared to their historical average.
/// </summary>
public class StochasticBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _stochasticPeriod;
	private readonly StrategyParam<int> _kPeriod;
	private readonly StrategyParam<int> _dPeriod;
	private readonly StrategyParam<int> _lookbackPeriod;
	private readonly StrategyParam<decimal> _deviationMultiplier;
	private readonly StrategyParam<DataType> _candleType;
	
	private StochasticOscillator _stochastic;
	private SimpleMovingAverage _stochAverage;
	private StandardDeviation _stochStdDev;
	
	private decimal _prevStochValue;
	private decimal _prevStochAverage;
	private decimal _prevStochStdDev;

	/// <summary>
	/// Stochastic oscillator period.
	/// </summary>
	public int StochasticPeriod
	{
		get => _stochasticPeriod.Value;
		set => _stochasticPeriod.Value = value;
	}

	/// <summary>
	/// Stochastic %K smoothing period.
	/// </summary>
	public int KPeriod
	{
		get => _kPeriod.Value;
		set => _kPeriod.Value = value;
	}

	/// <summary>
	/// Stochastic %D smoothing period.
	/// </summary>
	public int DPeriod
	{
		get => _dPeriod.Value;
		set => _dPeriod.Value = value;
	}

	/// <summary>
	/// Lookback period for calculating the average and standard deviation.
	/// </summary>
	public int LookbackPeriod
	{
		get => _lookbackPeriod.Value;
		set => _lookbackPeriod.Value = value;
	}

	/// <summary>
	/// Deviation multiplier for breakout detection.
	/// </summary>
	public decimal DeviationMultiplier
	{
		get => _deviationMultiplier.Value;
		set => _deviationMultiplier.Value = value;
	}

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

	/// <summary>
	/// Constructor.
	/// </summary>
	public StochasticBreakoutStrategy()
	{
		_stochasticPeriod = Param(nameof(StochasticPeriod), 14)
			.SetDisplay("Stochastic Period", "Stochastic oscillator period", "Stochastic")
			
			.SetOptimize(5, 30, 5);

		_kPeriod = Param(nameof(KPeriod), 3)
			.SetDisplay("K Period", "Stochastic %K smoothing period", "Stochastic")
			
			.SetOptimize(1, 5, 1);

		_dPeriod = Param(nameof(DPeriod), 3)
			.SetDisplay("D Period", "Stochastic %D smoothing period", "Stochastic")
			
			.SetOptimize(1, 5, 1);

		_lookbackPeriod = Param(nameof(LookbackPeriod), 20)
			.SetDisplay("Lookback Period", "Lookback period for calculating the average and standard deviation", "Breakout")
			
			.SetOptimize(10, 50, 5);

		_deviationMultiplier = Param(nameof(DeviationMultiplier), 2.0m)
			.SetDisplay("Deviation Multiplier", "Deviation multiplier for breakout detection", "Breakout")
			
			.SetOptimize(1.0m, 3.0m, 0.5m);

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

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

		_prevStochValue = 0;
		_prevStochAverage = 0;
		_prevStochStdDev = 0;
	}


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

		// Initialize indicators
		_stochastic = new StochasticOscillator
		{
			K = { Length = StochasticPeriod },
			D = { Length = DPeriod },
		};

		_stochAverage = new SMA { Length = LookbackPeriod };
		_stochStdDev = new StandardDeviation { Length = LookbackPeriod };
		
		Indicators.Add(_stochastic);

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

		// Setup chart visualization if available
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _stochastic);
			DrawOwnTrades(area);
		}
		
		// Start position protection
		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(2, UnitTypes.Percent)
		);
	}

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

		var stochResult = _stochastic.Process(candle);
		if (!_stochastic.IsFormed)
			return;

		var stochTyped = (StochasticOscillatorValue)stochResult;
		if (stochTyped.K is not decimal stochK)
			return;

		// Calculate average and standard deviation of stochastic
		var stochAvgValue = _stochAverage.Process(new DecimalIndicatorValue(_stochAverage, stochK, candle.ServerTime) { IsFinal = true }).ToDecimal();
		var tempStdDevValue = _stochStdDev.Process(new DecimalIndicatorValue(_stochStdDev, stochK, candle.ServerTime) { IsFinal = true }).ToDecimal();

		if (!_stochAverage.IsFormed || !_stochStdDev.IsFormed)
		{
			_prevStochValue = stochK;
			_prevStochAverage = stochAvgValue;
			_prevStochStdDev = tempStdDevValue;
			return;
		}

		// First values initialization - skip trading decision
		if (_prevStochValue == 0)
		{
			_prevStochValue = stochK;
			_prevStochAverage = stochAvgValue;
			_prevStochStdDev = tempStdDevValue;
			return;
		}

		// Calculate breakout thresholds
		var upperThreshold = _prevStochAverage + _prevStochStdDev * DeviationMultiplier;
		var lowerThreshold = _prevStochAverage - _prevStochStdDev * DeviationMultiplier;

		// Buy when stochastic breaks above upper threshold
		if (stochK > upperThreshold && _prevStochValue <= upperThreshold && Position == 0)
		{
			BuyMarket();
		}
		// Sell when stochastic breaks below lower threshold
		else if (stochK < lowerThreshold && _prevStochValue >= lowerThreshold && Position == 0)
		{
			SellMarket();
		}

		// Store current values for next comparison
		_prevStochValue = stochK;
		_prevStochAverage = stochAvgValue;
		_prevStochStdDev = tempStdDevValue;
	}
}