Ver en GitHub

ABE BE Stochastic Estrategia envolvente

Esta estrategia traslada el Expert Advisor de MetaTrader Expert_ABE_BE_Stoch al API de alto nivel de StockSharp. Combina el análisis de velas japonesas con la confirmación del impulso para cronometrar las reversiones alrededor de las zonas de sobreventa y sobrecompra. La señal principal busca una vela envolvente alcista respaldada por un oscilador estocástico profundamente sobrevendido, o una vela envolvente bajista confirmada por una lectura de oscilador de sobrecompra. Una vez abierta una posición, la estrategia se basa en cruces de umbrales estocásticos para gestionar las salidas, replicando la mecánica de "voto" del experto original.

La táctica está diseñada para una participación tanto larga como corta. Evalúa sólo velas completas y, por lo tanto, permanece inmune al ruido intrabar. El tamaño de las operaciones permanece bajo el control de la propiedad Volume del marco, mientras que las protecciones opcionales de limitación de pérdidas y toma de ganancias convierten la configuración de riesgo original basada en puntos en objetos StockSharp Unit.

como funciona

  1. Suscripción de datos: la estrategia se suscribe al tipo de vela configurado y crea un StochasticOscillator con tres parámetros ajustables (%K, %D y el factor de desaceleración).
  2. Detección de patrones: en cada vela terminada, el algoritmo comprueba si la última barra envuelve el cuerpo de la anterior. Dos métodos auxiliares reproducen las definiciones envolventes alcistas y bajistas utilizadas en MetaTrader.
  3. Confirmación de impulso: la línea %D del estocástico sirve como filtro de confirmación. Se requieren valores por debajo del umbral de sobreventa (predeterminado 30) para operaciones envolventes alcistas, mientras que valores por encima del umbral de sobrecompra (predeterminado 70) se requieren para señales bajistas.
  4. Gestión de posición: el valor %D anterior se almacena en caché. Si la nueva lectura cruza hacia arriba a través de 20 u 80, cualquier exposición corta se cierra. Por el contrario, los cruces a la baja a través de 80 o 20 liquidan la exposición larga. Estos umbrales reflejan los votos "cerrados" adicionales producidos por la lógica MQL.
  5. Manejo de riesgos: cuando se proporcionan distancias positivas de stop-loss o take-profit (expresadas en incrementos de precio), la estrategia las convierte a UnitTypes.Price y habilita StartProtection. De lo contrario, la protección StockSharp predeterminada se activa con StartProtection().

Reglas comerciales

  • Entrada larga: la vela anterior es bajista, la vela actual es alcista y el cuerpo de la vela actual envuelve al cuerpo anterior. El valor estocástico %D debe estar por debajo del EntryOversoldLevel (predeterminado 30). Cualquier corto existente se cierra y se abre un nuevo largo a través de BuyMarket.
  • Entrada breve: La vela anterior es alcista, la vela actual es bajista y el cuerpo de la vela actual envuelve al cuerpo anterior. El valor estocástico %D debe exceder el EntryOverboughtLevel (predeterminado 70). Cualquier posición larga existente se cierra y se abre una nueva posición corta a través de SellMarket.
  • Salida larga: Con una apertura larga, si %D cruza hacia abajo a través de ExitUpperLevel (80 predeterminado) o ExitLowerLevel (20 predeterminado), la posición se cierra con SellMarket.
  • Salida corta: Con una apertura corta, si %D cruza hacia arriba a través de ExitLowerLevel o ExitUpperLevel, la posición se cubre usando BuyMarket.
  • Paradas/objetivos: StopLossPoints y TakeProfitPoints opcionales convierten distancias basadas en puntos en compensaciones de precios absolutos cuando el instrumento expone un valor distinto de cero PriceStep.

Parámetros

Nombre Tipo Predeterminado Descripción
CandleType DataType TimeSpan.FromHours(1).TimeFrame() Fuente de vela utilizada para la detección de patrones.
StochasticPeriodK int 47 Período retrospectivo para el cálculo rápido %K.
StochasticPeriodD int 9 Período de suavizado para la línea de señal %D.
StochasticPeriodSlow int 13 Se aplicó un suavizado adicional a %K antes de que se convierta en %D.
EntryOversoldLevel decimal 30 Límite superior de %D que permite operaciones envolventes alcistas.
EntryOverboughtLevel decimal 70 Límite inferior de %D que permite operaciones envolventes bajistas.
ExitLowerLevel decimal 20 Nivel que, al cruzarse hacia arriba, obliga a salidas cortas; cuando se cruza hacia abajo, cierra largos.
ExitUpperLevel decimal 80 El límite superior se utiliza de la misma manera que el nivel inferior pero para territorio de sobrecompra.
TakeProfitPoints decimal 0 Distancia en pasos de precio para la orden de toma de ganancias (0 la desactiva).
StopLossPoints decimal 0 Distancia en pasos de precio para la orden stop-loss (0 la desactiva).

Notas

  • Funciona con cualquier instrumento que suministre OHLC velas; los valores predeterminados asumen barras horarias.
  • Todos los cálculos se basan en velas cerradas para mantenerse alineados con la lógica de marco temporal del experto MQL.
  • El tamaño de la posición debe configurarse a través de la estrategia base Volume propiedad o gestión de cartera de nivel superior.
namespace StockSharp.Samples.Strategies;

using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// ABE BE Stoch strategy: Engulfing pattern with Stochastic confirmation.
/// Bullish engulfing + oversold stochastic for long, bearish engulfing + overbought for short.
/// </summary>
public class AbeBeStochStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _stochPeriod;
	private readonly StrategyParam<decimal> _oversold;
	private readonly StrategyParam<decimal> _overbought;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private readonly List<ICandleMessage> _candles = new();
	private decimal _prevK;
	private bool _hasPrevK;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int StochPeriod { get => _stochPeriod.Value; set => _stochPeriod.Value = value; }
	public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
	public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public AbeBeStochStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_stochPeriod = Param(nameof(StochPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Stoch Period", "Stochastic K period", "Indicators");
		_oversold = Param(nameof(Oversold), 30m)
			.SetDisplay("Oversold", "Stochastic oversold level", "Signals");
		_overbought = Param(nameof(Overbought), 70m)
			.SetDisplay("Overbought", "Stochastic overbought level", "Signals");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candles.Clear();
		_prevK = 0m;
		_hasPrevK = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candles.Clear();
		_hasPrevK = false;
		_candlesSinceTrade = SignalCooldownCandles;
		var stoch = new StochasticOscillator { K = { Length = StochPeriod }, D = { Length = 3 } };
		var subscription = SubscribeCandles(CandleType);
		subscription.BindEx(stoch, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		var stochTyped = stochValue as StochasticOscillatorValue;
		if (stochTyped?.K is not decimal kValue) return;

		_candles.Add(candle);
		if (_candles.Count > 5)
			_candles.RemoveAt(0);

		if (_candles.Count >= 2)
		{
			var curr = _candles[^1];
			var prev = _candles[^2];

			// Bullish engulfing: prev bearish, curr bullish, curr body engulfs prev body
			var bullishEngulfing = prev.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice > curr.OpenPrice
				&& curr.OpenPrice <= prev.ClosePrice
				&& curr.ClosePrice >= prev.OpenPrice;

			// Bearish engulfing: prev bullish, curr bearish, curr body engulfs prev body
			var bearishEngulfing = prev.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice > curr.ClosePrice
				&& curr.OpenPrice >= prev.ClosePrice
				&& curr.ClosePrice <= prev.OpenPrice;

			if (bullishEngulfing && kValue < Oversold && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (bearishEngulfing && kValue > Overbought && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		// Exit on stochastic cross
		if (_hasPrevK)
		{
			if (Position > 0 && _prevK >= Overbought && kValue < Overbought && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
			else if (Position < 0 && _prevK <= Oversold && kValue > Oversold && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevK = kValue;
		_hasPrevK = true;
	}
}