Ver en GitHub

Estrategia de IMF AH HM

Resumen

La estrategia AH HM MFI negocia patrones de velas de martillo y hombre colgado que son confirmados por el Índice de flujo de dinero (IMF). Cuando aparece un martillo alcista en una tendencia bajista a corto plazo y la IMF se mantiene por debajo del umbral de sobreventa, la estrategia abre una posición larga. Cuando se forma un hombre colgado bajista en una tendencia alcista mientras el MFI está por encima de un umbral de sobrecompra, abre una posición corta. Las salidas protectoras se activan cuando la IMF cruza límites superiores o inferiores predefinidos.

Lógica principal

  1. Suscríbase a las velas de marco temporal configuradas y calcule dos indicadores:
    • Índice de flujo de dinero con un período configurable (predeterminado: 47).
    • Promedio móvil simple de precios de cierre para aproximar el filtro de tendencia de la estrategia MQL original (longitud predeterminada: 5).
  2. Detecta patrones de martillo y hombre colgado:
    • Cuerpo de vela situado en el tercio superior de la gama.
    • Sombra inferior larga en relación con el cuerpo real.
    • Brecha en la dirección de la tendencia en comparación con la vela anterior.
    • Confirmación de tendencia utilizando el punto medio de la vela anterior frente a la media móvil.
  3. Confirmar entradas con umbrales de IMF:
    • Ingrese largo si se detecta un martillo y la MFI está en o por debajo del nivel de sobreventa configurado (predeterminado: 40).
    • Ingrese en corto si se detecta un ahorcado y la MFI está en o por encima del nivel de sobrecompra configurado (predeterminado: 60).
  4. Gestione las salidas mediante los cruces de las IMF:
    • Cierre las posiciones cortas cuando la IMF cruce hacia arriba por encima de los niveles de salida inferior o superior (valores predeterminados: 30 y 70).
    • Cierre las posiciones largas cuando la IMF cruce hacia arriba por encima del nivel de salida superior o hacia abajo por debajo del nivel de salida inferior.
  5. Inicie el módulo de protección de riesgos incorporado para manejar paradas de emergencia.

Parámetros

Nombre Descripción Predeterminado
CandleType Tipo de datos de vela y período de tiempo utilizados para la detección de patrones. plazo de 30 minutos
MfiPeriod Período retrospectivo para el cálculo de la IMF. 47
MaPeriod Longitud del SMA aplicado a los precios de cierre para confirmación de tendencia. 5
HammerEntryThreshold Valor máximo de MFI permitido antes de entrar en una señal de martillo. 40
HangingEntryThreshold Valor mínimo de MFI requerido antes de entrar en una señal de ahorcado. 60
MfiUpperExitLevel Límite superior de las IMF; cruzar por encima cierra cualquier posición abierta. 70
MfiLowerExitLevel Límite inferior de las IMF; cruzar por debajo cierra posiciones largas, mientras que cruzar por encima cierra posiciones cortas. 30

Notas

  • La estrategia evalúa solo velas terminadas para evitar actuar sobre información incompleta.
  • La detección del martillo y del ahorcado es conservadora: se requiere tanto una larga sombra inferior como un cuerpo situado cerca de la vela alta.
  • La media móvil reemplaza el filtro MetaTrader 5 CloseAvg del asesor experto original, lo que garantiza que las entradas se alineen con la tendencia más amplia.
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Hammer/hanging-man lower-shadow patterns confirmed by previous SMA trend and MFI.
/// </summary>
public class AhHmMfiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _mfiPeriod;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<decimal> _hammerEntryThreshold;
	private readonly StrategyParam<decimal> _hangingEntryThreshold;
	private readonly StrategyParam<decimal> _mfiUpperExitLevel;
	private readonly StrategyParam<decimal> _mfiLowerExitLevel;

	private MoneyFlowIndex _mfi;
	private SimpleMovingAverage _ma;
	private ICandleMessage _previousCandle;
	private decimal? _previousMa;
	private decimal? _previousMfi;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
	public decimal HammerEntryThreshold { get => _hammerEntryThreshold.Value; set => _hammerEntryThreshold.Value = value; }
	public decimal HangingEntryThreshold { get => _hangingEntryThreshold.Value; set => _hangingEntryThreshold.Value = value; }
	public decimal MfiUpperExitLevel { get => _mfiUpperExitLevel.Value; set => _mfiUpperExitLevel.Value = value; }
	public decimal MfiLowerExitLevel { get => _mfiLowerExitLevel.Value; set => _mfiLowerExitLevel.Value = value; }

	public AhHmMfiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame());
		_mfiPeriod = Param(nameof(MfiPeriod), 47).SetGreaterThanZero();
		_maPeriod = Param(nameof(MaPeriod), 5).SetGreaterThanZero();
		_hammerEntryThreshold = Param(nameof(HammerEntryThreshold), 40m);
		_hangingEntryThreshold = Param(nameof(HangingEntryThreshold), 60m);
		_mfiUpperExitLevel = Param(nameof(MfiUpperExitLevel), 70m);
		_mfiLowerExitLevel = Param(nameof(MfiLowerExitLevel), 30m);
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		ResetRuntime();
	}

	private void ResetRuntime()
	{
		_previousCandle = null;
		_previousMa = null;
		_previousMfi = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		ResetRuntime();
		_mfi = new MoneyFlowIndex { Length = MfiPeriod };
		_ma = new SimpleMovingAverage { Length = MaPeriod };
		SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
	}

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

		var mfiValue = _mfi.Process(candle);
		var maValue = _ma.Process(candle.ClosePrice, candle.OpenTime, true);

		if (!mfiValue.IsFormed || !maValue.IsFormed)
		{
			Remember(candle, maValue.IsFormed ? maValue.ToDecimal() : null,
				mfiValue.IsFormed ? mfiValue.ToDecimal() : null);
			return;
		}

		var mfi = mfiValue.ToDecimal();
		var ma = maValue.ToDecimal();
		if (_previousMfi is decimal previousMfi)
		{
			if (Position > 0m &&
				((previousMfi <= MfiUpperExitLevel && mfi > MfiUpperExitLevel) ||
				 (previousMfi >= MfiLowerExitLevel && mfi < MfiLowerExitLevel)))
			{
				ClosePosition();
				Remember(candle, ma, mfi);
				return;
			}

			if (Position < 0m &&
				((previousMfi <= MfiLowerExitLevel && mfi > MfiLowerExitLevel) ||
				 (previousMfi <= MfiUpperExitLevel && mfi > MfiUpperExitLevel)))
			{
				ClosePosition();
				Remember(candle, ma, mfi);
				return;
			}
		}

		if (Position == 0m && _previousCandle is { } previous && _previousMa is decimal previousMa)
		{
			var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
			var range = candle.HighPrice - candle.LowPrice;
			if (body > 0m && range > 0m)
			{
				var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
				var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;
				var bodyInUpperThird = Math.Min(candle.OpenPrice, candle.ClosePrice) >= candle.HighPrice - range / 3m;
				var lowerTailPattern = bodyInUpperThird && lowerShadow >= body * 2.5m && upperShadow <= body * 0.5m;
				var previousMidpoint = (previous.OpenPrice + previous.ClosePrice) / 2m;

				if (lowerTailPattern && candle.OpenPrice < previous.ClosePrice &&
					previousMidpoint < previousMa && mfi <= HammerEntryThreshold)
					BuyMarket();
				else if (lowerTailPattern && candle.OpenPrice > previous.ClosePrice &&
					previousMidpoint > previousMa && mfi >= HangingEntryThreshold)
					SellMarket();
			}
		}

		Remember(candle, ma, mfi);
	}

	private void Remember(ICandleMessage candle, decimal? ma, decimal? mfi)
	{
		_previousCandle = candle;
		_previousMa = ma;
		_previousMfi = mfi;
	}
}