Ver en GitHub

Estrategia de Ruptura de Barra Interior

Una barra interior se forma cuando el rango de una vela está completamente contenido dentro del máximo y el mínimo de la barra anterior. Señala una indecisión de corto plazo que puede llevar a una ruptura una vez que el precio supera el patrón. Esta estrategia espera esa ruptura y luego opera en la dirección de la expansión.

Las pruebas indican un rendimiento anual promedio de aproximadamente el 118%. Funciona mejor en el mercado de acciones.

Cada nueva vela se compara con la anterior. Si aparece una barra interior, el sistema marca su máximo y mínimo y observa un cierre fuera de esos niveles. Una ruptura alcista abre una posición larga con un stop por debajo del mínimo del patrón, mientras que una ruptura bajista activa un corto con un stop por encima del máximo del patrón.

Si el precio no logra romper inmediatamente, la estrategia gestiona las posiciones existentes saliendo si la siguiente vela se mueve en contra de la operación más allá de los extremos de la barra anterior.

Detalles

  • Criterios de entrada: Ruptura del máximo o mínimo de una barra interior.
  • Largo/Corto: Ambos.
  • Criterios de salida: Precio cruzando el extremo de la vela anterior o stop-loss.
  • Stops: Sí, colocados más allá del patrón.
  • Valores predeterminados:
    • CandleType = 5 minute
    • StopLossPercent = 1
  • Filtros:
    • Categoría: Ruptura
    • Dirección: Ambos
    • Indicadores: Candlestick
    • Stops: Sí
    • Complejidad: Intermedio
    • Marco temporal: Intradía
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
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>
/// Inside Bar Breakout strategy.
/// Detects inside bar patterns (high lower than previous high, low higher than previous low).
/// Enters on breakout of the inside bar's high (buy) or low (sell).
/// Uses SMA for exit signals.
/// </summary>
public class InsideBarBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cooldownBars;

	private ICandleMessage _prevCandle;
	private ICandleMessage _insideBar;
	private bool _waitingForBreakout;
	private int _cooldown;

	/// <summary>
	/// MA Period.
	/// </summary>
	public int MAPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

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

	/// <summary>
	/// Cooldown bars.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public InsideBarBreakoutStrategy()
	{
		_maPeriod = Param(nameof(MAPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Period for SMA", "Indicators");

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

		_cooldownBars = Param(nameof(CooldownBars), 500)
			.SetRange(1, 1000)
			.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCandle = null;
		_insideBar = null;
		_waitingForBreakout = false;
		_cooldown = default;
	}

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

		_prevCandle = null;
		_insideBar = null;
		_waitingForBreakout = false;
		_cooldown = 0;

		var sma = new SimpleMovingAverage { Length = MAPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevCandle = candle;
			_waitingForBreakout = false;
			return;
		}

		if (_prevCandle == null)
		{
			_prevCandle = candle;
			return;
		}

		// Check for breakout of a previously detected inside bar
		if (_waitingForBreakout && _insideBar != null && Position == 0)
		{
			if (candle.HighPrice > _insideBar.HighPrice)
			{
				BuyMarket();
				_cooldown = CooldownBars;
				_waitingForBreakout = false;
			}
			else if (candle.LowPrice < _insideBar.LowPrice)
			{
				SellMarket();
				_cooldown = CooldownBars;
				_waitingForBreakout = false;
			}
		}

		// Check if current candle is an inside bar
		if (candle.HighPrice < _prevCandle.HighPrice && candle.LowPrice > _prevCandle.LowPrice)
		{
			_insideBar = candle;
			_waitingForBreakout = true;
		}

		// Exit logic using SMA
		if (Position > 0 && candle.ClosePrice < smaValue)
		{
			SellMarket();
			_cooldown = CooldownBars;
		}
		else if (Position < 0 && candle.ClosePrice > smaValue)
		{
			BuyMarket();
			_cooldown = CooldownBars;
		}

		_prevCandle = candle;
	}
}