Ver no GitHub

Estratégia de filtro de faixa de investidores Up3x1

Visão geral

Esta estratégia é uma porta direta do consultor especialista MetaTrader 4 up3x1_Investor. Ele negocia um único instrumento usando velas concluídas em um período configurável (H1 por padrão). A porta replica a lógica original com StockSharp APIs de alto nível e adiciona parâmetros claros de gerenciamento de risco.

Lógica de negociação

  • A estratégia avalia a última vela totalmente fechada e verifica se:
    • A faixa da vela (máxima menos mínima) excede 0.0060 unidades de preço.
    • O corpo da vela (diferença absoluta entre abertura e fechamento) excede 0.0050 unidades de preço.
  • Se a vela fechar em alta e as condições acima forem atendidas, a estratégia abre uma posição de mercado longa.
  • Se a vela fechar em baixa e as condições forem atendidas, a estratégia abre uma posição de mercado curta.
  • A negociação é completamente desativada às segundas-feiras (para espelhar a proteção DayOfWeek()==1 do código MQL).

Gerenciamento de posição

  • Após a entrada, a estratégia define metas internas usando as distâncias configuradas baseadas em etapas:
    • TakeProfitPoints → distância até a meta de lucro.
    • StopLossPoints → distância de parada protetora.
    • TrailingStopPoints → distância usada para rastrear o stop quando o preço se move a favor.
  • Stops e alvos são avaliados em cada vela finalizada:
    • Se o preço atingir o alvo, a posição será fechada ao preço alvo.
    • Se o preço atingir o stop, a posição será fechada para limitar a perda.
    • Uma vez que o preço avança além da distância de fuga, o stop é movido para mais perto do preço de mercado para garantir o lucro.
  • Além disso, se as médias móveis simples de 24 e 60 períodos calculadas nas mesmas velas se tornarem iguais (dentro de uma etapa de preço), a posição será fechada imediatamente. Isso imita a lógica MQL em que o pedido é fechado quando ambas as médias correspondem exatamente.

Gestão de Volume e Risco

  • BaseVolume define o tamanho do lote substituto quando nenhum ajuste baseado em conta pode ser calculado.
  • MaximumRisk replica a fórmula AccountFreeMargin()*MaximumRisk/1000 original. Se o valor do portfólio estiver disponível, a estratégia dimensiona a posição como value * MaximumRisk / 1000, arredondada para uma casa decimal.
  • DecreaseFactor imita a redução da sequência de perdas: após mais de uma perda consecutiva, o volume diminui proporcionalmente para losses / DecreaseFactor.
  • MinimumVolume garante que o volume nunca caia abaixo do menor tamanho negociável usado no script MQL (0,1 lote).

Parâmetros

Nome Padrão Descrição
BaseVolume 0.1 Tamanho base da posição em lotes quando nenhum ajuste de risco é aplicado.
MaximumRisk 0.2 Fator de risco usado para derivar o volume do patrimônio da conta (igual ao EA original).
DecreaseFactor 3 Reduz o tamanho da posição após perdas consecutivas.
MinimumVolume 0.1 Menor volume permitido.
TakeProfitPoints 20 Distância da meta de lucro medida em etapas de preço.
StopLossPoints 50 Distância de stop-loss medida em etapas de preço.
TrailingStopPoints 10 Distância do trailing stop medida em etapas de preço.
SkipMondays true Desative todas as atividades de negociação às segundas-feiras.
CandleType 1 hour Prazo para assinatura da vela.

Notas

  • A estratégia mantém apenas uma posição aberta por vez, correspondendo à guarda CalculateCurrentOrders original.
  • O rastreamento de perdas consecutivas é puramente interno porque os corretores StockSharp não expõem o histórico de pedidos de MetaTrader.
  • Nenhuma ordem pendente é usada; todas as negociações são enviadas como ordens de mercado via BuyMarket e SellMarket.
using System;







using StockSharp.Algo.Indicators;



using StockSharp.Algo.Strategies;



using StockSharp.BusinessEntities;



using StockSharp.Messages;







namespace StockSharp.Samples.Strategies;







public class Up3x1InvestorRangeFilterStrategy : Strategy



{



	private readonly StrategyParam<int> _emaPeriod;



	private readonly StrategyParam<int> _atrPeriod;



	private readonly StrategyParam<DataType> _candleType;







	private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;



	private int _cooldown;







	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }



	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }



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







	public Up3x1InvestorRangeFilterStrategy()



	{



		_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA lookback", "Indicators");



		_atrPeriod = Param(nameof(AtrPeriod), 14).SetDisplay("ATR Period", "ATR lookback", "Indicators");



		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");



	}







	/// <inheritdoc />



	protected override void OnReseted()



	{



		base.OnReseted();



		_prevClose = default;



		_prevEma = default;



		_hasPrev = default;



		_cooldown = default;



	}







	/// <inheritdoc />



	/// <inheritdoc />

	protected override void OnStarted2(DateTime time)



	{



		base.OnStarted2(time);



		_hasPrev = false;



		var ema = new ExponentialMovingAverage { Length = EmaPeriod };



		var subscription = SubscribeCandles(CandleType);



		subscription.Bind(ema, ProcessCandle).Start();



	}







	private void ProcessCandle(ICandleMessage candle, decimal ema)



	{



		if (candle.State != CandleStates.Finished) return;



		if (!IsFormedAndOnlineAndAllowTrading()) return;



		var close = candle.ClosePrice;



		if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }



		if (_cooldown > 0)



		{



			_cooldown--;



			_prevClose = close; _prevEma = ema;



			return;



		}







		if (_prevClose <= _prevEma && close > ema && Position <= 0)



		{



			var volume = Volume + Math.Abs(Position);



			BuyMarket(volume);



			_cooldown = 6;



		}



		else if (_prevClose >= _prevEma && close < ema && Position >= 0)



		{



			var volume = Volume + Math.Abs(Position);



			SellMarket(volume);



			_cooldown = 6;



		}



		_prevClose = close; _prevEma = ema;



	}



}