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 El stop se coloca este porcentaje más allá del lado opuesto de la barra interior; tanto él como la salida por el extremo de la vela anterior se comprueban al cierre de las velas.
  • 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.
/// An inside bar's range lies within the previous candle's high and low. While flat, a close above the latest inside bar's
/// high buys and a close below its low sells. The stop lies StopLossPercent percent beyond the opposite side of the pattern,
/// and a close beyond the previous candle's extreme against the position also exits.
/// </summary>
public class InsideBarBreakoutStrategy : Strategy
{
	private readonly StrategyParam<decimal> _stopLossPercent;
	private readonly StrategyParam<DataType> _candleType;

	private (decimal High, decimal Low)? _prevCandle;
	private (decimal High, decimal Low)? _insideBar;
	private decimal _stopPrice;

	/// <summary>
	/// Distance of the stop beyond the pattern, in percent.
	/// </summary>
	public decimal StopLossPercent
	{
		get => _stopLossPercent.Value;
		set => _stopLossPercent.Value = value;
	}

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

	/// <summary>
	/// Constructor.
	/// </summary>
	public InsideBarBreakoutStrategy()
	{
		_stopLossPercent = Param(nameof(StopLossPercent), 1m)
			.SetNotNegative()
			.SetDisplay("Stop Loss %", "Distance of the stop beyond the pattern, in percent", "Risk");

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

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

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

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

		_prevCandle = null;
		_insideBar = null;
		_stopPrice = default;

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

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

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

		var previous = _prevCandle;
		var pattern = _insideBar;

		_prevCandle = (candle.HighPrice, candle.LowPrice);

		var isInside = previous is { } prev && candle.HighPrice <= prev.High && candle.LowPrice >= prev.Low;
		var close = candle.ClosePrice;

		// A close outside the pattern uses it up; a new inside bar replaces it.
		if (pattern is { } bar && (close > bar.High || close < bar.Low))
			_insideBar = null;

		if (isInside)
			_insideBar = (candle.HighPrice, candle.LowPrice);

		if (previous is not { } prior || !IsFormedAndOnlineAndAllowTrading())
			return;

		if (Position > 0)
		{
			if (close <= _stopPrice || close < prior.Low)
				SellMarket(Position);
		}
		else if (Position < 0)
		{
			if (close >= _stopPrice || close > prior.High)
				BuyMarket(-Position);
		}
		else if (pattern is { } inside)
		{
			if (close > inside.High)
			{
				BuyMarket(Volume);
				_stopPrice = inside.Low * (1 - StopLossPercent / 100m);
			}
			else if (close < inside.Low)
			{
				SellMarket(Volume);
				_stopPrice = inside.High * (1 + StopLossPercent / 100m);
			}
		}
	}
}