Ver no GitHub

Estratégia Nirvaman Imax

Visão geral

A estratégia Nirvaman Imax é uma conversão direta dos MetaTrader 4 consultores especialistas NirvamanImax.mq4 agrupados com os indicadores personalizados HA, Moving Averages2 e iMAX3alert. A implementação StockSharp mantém a ideia original de combinar velas Heikin-Ashi com um detector de tendência bifásico e um filtro de linha de base EMA enquanto adota o API de alto nível. A estratégia funciona em um único instrumento e período de tempo e fecha automaticamente as negociações após um período de manutenção configurável.

Indicadores e filtros

  • Heikin-Ashi velas – reproduz o indicador HA original e classifica as velas como de alta ou de baixa comparando os valores de abertura e fechamento do Heikin.
  • Crossover EMA rápido/lento – substitui a saída de fase dupla MT4 iMAX3alert1. Um sinal de alta aparece quando o EMA rápida cruza acima do EMA lenta; um sinal de baixa ocorre no cruzamento oposto.
  • EMA filtro de tendência – espelha o buffer Moving Averages2 EMA e atua como uma linha de base. Somente negociações longas acima do filtro e negociações curtas abaixo dele são permitidas.
  • Filtro de tempo – ignora qualquer vela cuja hora esteja dentro da janela proibida definida por NoTradeStartHour e NoTradeEndHour (a janela suporta meia-noite e uma mudança de fuso horário do corretor).
  • Saída temporizada – cada posição é fechada à força após CloseAfter decorrido, reproduzindo a lógica tiempoCierre da versão MQL.
  • Stops e metas – o stop loss e o take-profit são aplicados em etapas de preço derivadas do tamanho do tick do instrumento. Definir como 0 desativa a proteção correspondente.

Regras de negociação

  1. Aguarde até que Heikin-Ashi, EMA rápida, EMA lenta e filtro EMA sejam formados e um fechamento de vela anterior esteja disponível.
  2. Rejeite o sinal se o tempo da vela estiver dentro da janela de negociação restrita.
  3. Entrada longa:
    • O EMA rápido cruza acima do EMA lento na vela atual.
    • O fechamento de Heikin-Ashi está acima de sua abertura (corpo de alta).
    • O fechamento da vela anterior está acima do filtro EMA.
  4. Entrada curta:
    • O EMA rápido cruza abaixo do EMA lento na vela atual.
    • O fechamento de Heikin-Ashi está abaixo de sua abertura (corpo de baixa).
    • O fechamento da vela anterior está abaixo do filtro EMA.
  5. Regras de saída:
    • Os níveis de stop loss ou takeprofit são tocados pela faixa de velas.
    • O tempo de vida máximo da posição CloseAfter foi excedido.
    • A proteção manual acionada via StartProtection() fecha a posição quando o mecanismo a solicita.

Parâmetros

Nome Descrição Padrão
TradeVolume Volume base de ordens de mercado. 0.1
CandleType Período de vela usado para cada indicador e sinal. 30m período de tempo
FastTrendLength Comprimento do EMA rápida que emula a fase azul do iMAX. 10
SlowTrendLength Comprimento do EMA lenta que emula a fase vermelha do iMAX. 21
FilterLength Período EMA para o filtro de linha de base (equivalente a Médias Móveis2). 13
StopLoss Distância de parada protetora nas etapas de preço; 0 desativa a parada. 50
TakeProfit Distância alvo de lucro em etapas de preço; 0 desativa o alvo. 100
CloseAfter Tempo máximo de retenção antes que a posição seja fechada à força. 15000 s
NoTradeStartHour Hora (0–23) que marca o início da janela de não negociação. 22
NoTradeEndHour Hora (0–23) que marca o fim da janela de não negociação. 2
BrokerTimeOffset Deslocamento do fuso horário do corretor (horas) aplicado antes do filtro de horário. 0

Notas de conversão

  • O indicador MT4 iMAX3alert1 expõe dois buffers codificados por cores. Seu cruzamento é traduzido em um cruzamento rápido/EMA lenta, que preserva a lógica de entrada original orientada a eventos.
  • O indicador Moving Averages2 foi executado no modo EMA com um comprimento padrão de 13. A versão StockSharp reutiliza um ExponentialMovingAverage padrão com o mesmo padrão.
  • O gerenciamento do ciclo de vida da posição reflete o script MQL: a posição é fechada no tempo limite antes que novas entradas possam ser avaliadas e nenhuma lógica adicional de trailing stop foi adicionada.

Dicas de uso

  1. Anexe a estratégia a uma placa/segurança e defina o CandleType desejado antes de iniciá-la.
  2. Ajuste TradeVolume, StopLoss, TakeProfit e CloseAfter para corresponder à volatilidade do instrumento e à tolerância ao risco.
  3. Otimize os períodos EMA se precisar aproximar o comportamento do ajuste original do iMAX para um novo mercado.
  4. Combine com controles de risco de nível superior (proteção de portfólio, controle de sessão) ao executar múltiplas instâncias.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Nirvaman Imax: Dual EMA crossover with trend filter and timed exit.
/// Fast EMA crosses slow EMA for direction, filter EMA confirms trend.
/// </summary>
public class NirvamanImaxStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _filterLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public NirvamanImaxStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastLength = Param(nameof(FastLength), 10)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowLength = Param(nameof(SlowLength), 21)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

		_filterLength = Param(nameof(FilterLength), 50)
			.SetDisplay("Filter EMA", "Trend filter EMA period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period for stops.", "Indicators");
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	public int FilterLength
	{
		get => _filterLength.Value;
		set => _filterLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

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

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;

		var fast = new ExponentialMovingAverage { Length = FastLength };
		var slow = new ExponentialMovingAverage { Length = SlowLength };
		var filter = new ExponentialMovingAverage { Length = FilterLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, filter, atr, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal filterVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;

		// Exit management
		if (Position > 0)
		{
			if (close <= _entryPrice - atrVal * 2m || close >= _entryPrice + atrVal * 3m)
			{
				SellMarket();
				_entryPrice = 0;
			}
			else if (_prevFast >= _prevSlow && fastVal < slowVal)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close >= _entryPrice + atrVal * 2m || close <= _entryPrice - atrVal * 3m)
			{
				BuyMarket();
				_entryPrice = 0;
			}
			else if (_prevFast <= _prevSlow && fastVal > slowVal)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		// Entry: EMA crossover confirmed by filter EMA trend
		if (Position == 0)
		{
			if (_prevFast <= _prevSlow && fastVal > slowVal && close > filterVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (_prevFast >= _prevSlow && fastVal < slowVal && close < filterVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}