Ver en GitHub

Estrategia de Reversión a la Media Consecutive Close High1

Estrategia solo en corto que cuenta los cierres consecutivos por encima del máximo anterior y vende una vez que el conteo alcanza un umbral. La posición se cierra cuando el precio cae por debajo del mínimo anterior. El filtro EMA 200 opcional confirma la tendencia bajista.

Detalles

  • Criterios de entrada: los cierres consecutivos por encima del máximo anterior alcanzan el umbral
  • Largo/Corto: Corto
  • Criterios de salida: cierre por debajo del mínimo anterior
  • Stops: No
  • Valores predeterminados:
    • Threshold = 3
    • EmaPeriod = 200
  • Filtros:
    • Categoría: Reversión a la media
    • Dirección: Corto
    • Indicadores: EMA
    • Stops: No
    • Complejidad: Básico
    • Marco temporal: Intradía
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
using System;
using System.Linq;
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>
/// Short strategy based on consecutive closes above previous highs.
/// </summary>
public class ConsecutiveCloseHigh1MeanReversionStrategy : Strategy
{
	private readonly StrategyParam<int> _threshold;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private int _bullCount;
	private decimal _prevHigh;
	private decimal _prevLow;
	private bool _isReady;

	public int Threshold { get => _threshold.Value; set => _threshold.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ConsecutiveCloseHigh1MeanReversionStrategy()
	{
		_threshold = Param(nameof(Threshold), 3)
			.SetGreaterThanZero()
			.SetDisplay("Threshold", "Consecutive closes above prior high", "Parameters");

		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA length for trend filter", "Filters");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_bullCount = 0;
		_prevHigh = 0;
		_prevLow = 0;
		_isReady = false;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

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

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

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

		if (!_isReady)
		{
			_prevHigh = candle.HighPrice;
			_prevLow = candle.LowPrice;
			_isReady = true;
			return;
		}

		if (candle.ClosePrice > _prevHigh)
			_bullCount++;
		if (candle.ClosePrice < _prevLow)
			_bullCount = 0;

		// Short: consecutive closes above prior high, below EMA
		if (_bullCount >= Threshold && candle.ClosePrice < emaValue && Position >= 0)
			SellMarket();
		else if (Position < 0 && candle.ClosePrice < _prevLow)
			BuyMarket();

		_prevHigh = candle.HighPrice;
		_prevLow = candle.LowPrice;
	}
}