Ver en GitHub

Estrategia de Reversión Upthrust

La Reversión Upthrust es el complemento bajista del spring y ocurre cuando el precio rompe brevemente por encima de la resistencia pero cae rápidamente de nuevo. El movimiento elimina a los compradores tardíos antes de revertir a la baja.

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

Esta estrategia vende en corto una vez que el precio cae de nuevo por debajo del nivel de rompimiento, esperando que la oferta supere a la demanda.

Un stop justo por encima del máximo del upthrust gestiona el riesgo y las posiciones salen si el precio se recupera por encima de ese nivel.

Detalles

  • Criterios de entrada: señal de indicador
  • Largo/Corto: Ambos
  • Criterios de salida: stop-loss o señal opuesta
  • Stops: Sí, basados en porcentaje
  • Valores predeterminados:
    • CandleType = 15 minute
    • LookbackPeriod = 20
    • StopLossPercent = 2 La resistencia es el máximo más alto de las LookbackPeriod velas anteriores. La estrategia solo vende: una vela bajista que supera la resistencia y cierra de nuevo por debajo. El stop se coloca StopLossPercent por encima del máximo del upthrust y la posición se cierra cuando una vela cierra por encima.
  • Filtros:
    • Categoría: Reversión
    • Dirección: Ambos
    • Indicadores: Wyckoff
    • 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 System.Linq;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Upthrust Reversal strategy.
/// Resistance is the highest high of the previous LookbackPeriod candles. A bearish candle that breaks above resistance and closes back below it
/// is an upthrust and sells while flat. The stop lies StopLossPercent above the upthrust high, and a close above it closes the position.
/// </summary>
public class UpthrustReversalStrategy : Strategy
{
	private readonly StrategyParam<int> _lookbackPeriod;
	private readonly StrategyParam<decimal> _stopLossPercent;
	private readonly StrategyParam<DataType> _candleType;

	private readonly List<(decimal High, decimal Low)> _candles = [];
	private decimal _stopPrice;

	/// <summary>
	/// Number of previous candles that form the level.
	/// </summary>
	public int LookbackPeriod
	{
		get => _lookbackPeriod.Value;
		set => _lookbackPeriod.Value = value;
	}

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

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

	/// <summary>
	/// Constructor.
	/// </summary>
	public UpthrustReversalStrategy()
	{
		_lookbackPeriod = Param(nameof(LookbackPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("LookbackPeriod", "Number of previous candles that form the level", "Pattern");

		_stopLossPercent = Param(nameof(StopLossPercent), 2m)
			.SetNotNegative()
			.SetDisplay("Stop Loss %", "Distance of the stop beyond the level, in percent", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).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();
		_candles.Clear();
		_stopPrice = default;
	}

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

		_candles.Clear();
		_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;

		// The level is formed by the candles before this one.
		var ready = _candles.Count == LookbackPeriod;
		var high = ready ? _candles.Max(c => c.High) : 0m;
		var low = ready ? _candles.Min(c => c.Low) : 0m;

		_candles.Add((candle.HighPrice, candle.LowPrice));

		if (_candles.Count > LookbackPeriod)
			_candles.RemoveAt(0);

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var close = candle.ClosePrice;

		if (Position < 0)
		{
			if (close >= _stopPrice)
				BuyMarket(-Position);

			return;
		}

		if (Position != 0 || !ready || !(candle.HighPrice > high && close < high && close < candle.OpenPrice))
			return;

		SellMarket(Volume);
		_stopPrice = candle.HighPrice * (1 + StopLossPercent / 100m);
	}
}