Ver no GitHub

Estratégia de IMF AH HM

Resumo

A estratégia AH HM MFI negocia padrões de velas de martelo e homem enforcado que são confirmados pelo Money Flow Index (MFI). Quando um martelo de alta aparece numa tendência descendente de curto prazo e a IMF permanece abaixo de um limite de sobrevenda, a estratégia abre uma posição longa. Quando um homem pendente de baixa se forma em uma tendência de alta enquanto a IMF está acima do limite de sobrecompra, ele abre uma posição curta. As saídas de proteção são acionadas quando a IMF ultrapassa limites superiores ou inferiores predefinidos.

Lógica principal

  1. Assine as velas de período de tempo configuradas e calcule dois indicadores:
    • Índice de Fluxo de Dinheiro com período configurável (padrão: 47).
    • Média Móvel Simples dos preços de fechamento para aproximar o filtro de tendência da estratégia MQL original (comprimento padrão: 5).
  2. Detecte padrões de martelo e homem enforcado:
    • Corpo da vela localizado no terço superior da faixa.
    • Sombra inferior longa em relação ao corpo real.
    • Gap na direção da tendência em comparação com a vela anterior.
    • Confirmação da tendência usando o ponto médio da vela anterior versus a média móvel.
  3. Confirme as entradas com limites de IMF:
    • Insira longo se um martelo for detectado e o MFI estiver no nível de sobrevenda configurado ou abaixo dele (padrão: 40).
    • Digite short se um homem enforcado for detectado e a MFI estiver no nível de sobrecompra configurado ou acima dele (padrão: 60).
  4. Gerenciar saídas usando cruzamentos de IMF:
    • Fechar posições curtas quando a IMF cruzar para cima acima dos níveis de saída inferior ou superior (padrões: 30 e 70).
    • Fechar posições longas quando a IMF cruzar para cima acima do nível de saída superior ou para baixo abaixo do nível de saída inferior.
  5. Inicie o módulo integrado de proteção contra riscos para lidar com paradas de emergência.

Parâmetros

Nome Descrição Padrão
CandleType Tipo de dados de vela e período de tempo usado para detecção de padrão. Período de 30 minutos
MfiPeriod Período retrospectivo para o cálculo da IFM. 47
MaPeriod Comprimento do SMA aplicado aos preços de fechamento para confirmação da tendência. 5
HammerEntryThreshold Valor máximo de MFI permitido antes de entrar em um sinal de martelo. 40
HangingEntryThreshold Valor MFI mínimo exigido antes de entrar em um sinal de homem suspenso. 60
MfiUpperExitLevel Limite superior das IFM; cruzar acima dele fecha qualquer posição aberta. 70
MfiLowerExitLevel Limite inferior das IMFs; cruzar abaixo fecha posições longas, enquanto cruzar acima fecha posições curtas. 30

Notas

  • A estratégia avalia apenas velas finalizadas para evitar agir com base em informações incompletas.
  • A detecção do martelo e do homem enforcado é conservadora: são necessárias uma longa sombra inferior e um corpo localizado próximo à altura da vela.
  • A média móvel substitui o filtro MetaTrader 5 CloseAvg do consultor especialista original, garantindo que as entradas estejam alinhadas com a tendência mais ampla.
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;
	}
}