Ver en GitHub

Estrategia Reversals With Pin Bars

Visión general

Esta estrategia es un port C# del asesor experto de MetaTrader "Reversals With Pin Bars". El EA original busca velas de rechazo con mechas largas (pin bars) y las confirma con un filtro de momentum, una comprobación de tendencia mediante media móvil ponderada lineal (LWMA) de marco superior y un filtro direccional MACD. El port conserva esta estructura multimarco, se apoya exclusivamente en indicadores StockSharp y expone los controles de riesgo más importantes como parámetros.

La implementación se centra en la API StockSharp de alto nivel: las velas del marco principal impulsan las entradas, mientras suscripciones adicionales alimentan indicadores de marcos superiores. La gestión de riesgo se expresa en pips y admite automatización opcional de trailing-stop y break-even.

Lógica de entrada

  • Detección de pin bar: la vela anterior terminada debe tener una mecha que represente al menos el 50% de su rango completo.
    • Configuración larga: la sombra superior es dominante (coincide con la comprobación original de "hanging man").
    • Configuración corta: la sombra inferior es dominante.
  • Filtro de tendencia: la LWMA rápida (longitud = FastMaPeriod) debe estar por encima/debajo de la LWMA lenta (SlowMaPeriod) en el marco superior.
  • Filtro de momentum: la distancia absoluta del valor de momentum frente a 100 en cualquiera de las tres últimas barras del marco superior debe superar MomentumThreshold.
  • Filtro MACD: la línea principal MACD debe estar por encima/debajo de la línea de señal en el marco MACD.
  • Límites de posición: la exposición neta no puede superar MaxTrades * Volume. Las nuevas operaciones usan el ajuste alineado Volume.

Gestión de riesgo

  • Stop-loss / Take-profit: distancias fijas en pips (StopLossPips, TakeProfitPips) desde el cierre de entrada.
  • Break-even: si está activado, el stop se mueve a entry +/- BreakEvenOffsetPips cuando el precio avanza BreakEvenTriggerPips.
  • Trailing stop: si está activado, el trailing mantiene una distancia de TrailingStopPips desde el último cierre.
  • Aplanamiento automático: alcanzar el stop o el objetivo calculado sale de toda la posición con una orden de mercado.

Parámetros

Parámetro Descripción
TradeVolume Volumen usado para cada nueva entrada, alineado al paso del instrumento.
MaxTrades Número máximo de entradas en la misma dirección (límite de volumen agregado).
StopLossPips Distancia de stop-loss en pips.
TakeProfitPips Distancia de take-profit en pips.
EnableTrailing / TrailingStopPips Activa y configura la distancia del trailing-stop.
EnableBreakEven / BreakEvenTriggerPips / BreakEvenOffsetPips Activación de break-even y ajustes de búfer.
FastMaPeriod / SlowMaPeriod Longitudes de las LWMA del marco superior.
MomentumPeriod / MomentumThreshold Longitud de momentum y distancia absoluta mínima desde 100.
MacdFastPeriod / MacdSlowPeriod / MacdSignalPeriod Configuración MACD para el filtro de largo plazo.
CandleType Serie principal de velas para detectar pin bars.
HigherCandleType Serie de velas usada para LWMAs y momentum.
MacdCandleType Serie de velas usada para MACD.

Diferencias frente a la versión MetaTrader

  • Se omitieron opciones de take-profit monetario, trailing monetario y stop de patrimonio; el riesgo se expresa mediante pips.
  • Las confirmaciones de líneas fractales que requerían objetos de gráfico se reemplazaron por condiciones basadas en indicadores.
  • Se eliminaron todas las notificaciones (alertas, correos, mensajes push); la versión StockSharp se centra en la lógica de trading.

Notas de uso

  1. Asigne la estrategia a una cartera e instrumento, luego ajuste los tres tipos de vela para su configuración multimarco deseada.
  2. Asegúrese de que el paso de precio del instrumento refleje la definición de pip (valor alternativo predeterminado: 0.0001).
  3. Inicie la estrategia; stops, objetivos, trailing y gestión de break-even se realizan automáticamente al cierre de vela.
  4. Supervise los resultados; ajuste las longitudes de momentum y LWMA al perfil de volatilidad del instrumento.
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;

public class ReversalsWithPinBarsStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ReversalsWithPinBarsStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}