Ver no GitHub

Robô comercial AIS1 (conversão MQL/8700)

Visão geral

O AIS1 Trading Robot é uma conversão direta em C# do MetaTrader 4 consultor especialista de MQL/8700/AIS1.MQ4. O sistema original é adaptado para rompimentos diários do EURUSD e usa intervalos de vários intervalos de tempo para cálculos de stop, target e trailing. Esta implementação StockSharp preserva a estrutura do robô legado enquanto expõe cada elemento configurável como parâmetros de estratégia.

Lógica de negociação

  • Prazos
    • Velas primárias: barras de 1 dia para condições de entrada, stop loss e distâncias de take-profit.
    • Velas secundárias: barras de 4 horas para cálculos dinâmicos de trailing stop.
  • Condições de entrada
    • Longo rompimento: o fechamento diário de ontem está acima do ponto médio da barra e a oferta atual perfura a máxima diária anterior.
    • Breakout curto: o fechamento diário de ontem está abaixo do ponto médio e o lance atual cai abaixo do mínimo diário anterior.
    • Apenas uma posição poderá ser aberta por vez; sinais opostos são ignorados até que a negociação atual seja fechada.
  • Risco e recompensa inicial
    • Stop loss = máxima/mínima diária anterior ± StopFactor × daily range.
    • Take Profit = preço de entrada ± TakeFactor × daily range.
    • Ambos os níveis são validados em relação ao StopBufferTicks opcional para respeitar as restrições de distância de parada do corretor.
  • Parada final
    • Usa o intervalo da última vela de 4 horas multiplicado por TrailFactor.
    • As atualizações finais exigem que o preço se mova pelo menos TrailStepMultiplier × spread além do stop existente e fique longe da meta pelo buffer configurado.
    • A proteção contra saque desativa as atualizações finais quando o patrimônio cai abaixo do limite de reserva.
  • Gerenciamento de Riscos
    • O tamanho do lote é derivado de OrderReserve × equity dividido pelo risco monetário entre entrada e stop.
    • Os volumes são limitados aos limites de troca (MinVolume, MaxVolume, VolumeStep).
    • O monitoramento do patrimônio rastreia o máximo em execução e bloqueia novas entradas quando o patrimônio cai abaixo de AccountReserve - OrderReserve desse pico.
  • Proteção de tempo
    • As ações (entradas ou atualizações finais) são separadas por uma pausa obrigatória de cinco segundos, replicando o acelerador EA original.

Parâmetros

Parâmetro Padrão Descrição
AccountReserve 0,20 Fração do patrimônio que deve permanecer intocada. Usado para calcular o rebaixamento permitido.
OrderReserve 0,04 Fração do patrimônio alocado para cada negociação e base para dimensionamento da posição.
PrimaryCandleType Diariamente Tipo de vela usado para lógica de breakout e alvos estáticos.
SecondaryCandleType 4 horas Tipo de vela usado para derivar distâncias finais.
TakeFactor 0,8 Multiplicador da faixa diária aplicada para obter lucro.
StopFactor 1,0 Multiplicador da faixa diária aplicado ao stop loss.
TrailFactor 5,0 Multiplicador do intervalo de 4 horas aplicado aos trailing stops.
TrailStepMultiplier 1,0 Multiplicador de spread que controla quanto o preço deve avançar antes que um novo trailing stop seja definido.
StopBufferTicks 0 Etapas de preço adicionais adicionadas como margens de segurança em torno de stops e metas.

Notas de uso

  1. Atribua o título desejado (EURUSD por padrão) e o portfólio antes de iniciar a estratégia.
  2. Certifique-se de que as fontes de velas diárias e de 4 horas estejam disponíveis; caso contrário, os módulos breakout e trailing não poderão ser ativados.
  3. A estratégia assina a carteira de pedidos para obter os preços atuais de compra/venda. Em mercados sem feed de profundidade, o último preço negociado é usado como alternativa.
  4. As saídas de posição são realizadas por meio de ordens de mercado quando as condições de parada ou meta são atendidas, correspondendo ao comportamento do MetaTrader EA que modificou as ordens de proteção no lado do servidor.
  5. O limitador de rebaixamento, o temporizador de pausa e a lógica de dimensionamento de risco podem ser ajustados por meio dos parâmetros expostos para adaptar o robô a diferentes corretores ou especificações de contrato.

Diferenças vs. Original MQL

  • As paradas e metas de proteção são emuladas por fechamentos manuais de posição quando os preços cruzam os níveis armazenados (o MT4 tratou disso por meio da modificação da ordem).
  • A conversão de risco depende de PriceStep e StepPrice do objeto Security. Quando esses metadados estão faltando, o código volta para uma conversão monetária 1:1, portanto os usuários devem verificar novamente as especificações do contrato.
  • Comentários extensos e descrições de parâmetros foram adicionados para maior clareza e melhor integração com as ferramentas de otimização do StockSharp.

Requisitos

  • StockSharp API de alto nível com acesso a assinaturas de velas e dados do livro de pedidos.
  • Conexão comercial configurada corretamente para colocação de pedidos e avaliação de portfólio.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// AIS1 breakout strategy with ATR-based stops and trailing.
/// Trades breakouts above/below EMA with ATR-based risk management.
/// </summary>
public class Ais1TradingRobotStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _takeFactor;
	private readonly StrategyParam<decimal> _stopFactor;

	private decimal _entryPrice;

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

		_emaLength = Param(nameof(EmaLength), 50)
			.SetDisplay("EMA Length", "Period for trend EMA.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 20)
			.SetDisplay("ATR Length", "Period for ATR.", "Indicators");

		_takeFactor = Param(nameof(TakeFactor), 3.0m)
			.SetDisplay("Take Factor", "ATR multiplier for take profit.", "Risk");

		_stopFactor = Param(nameof(StopFactor), 1.5m)
			.SetDisplay("Stop Factor", "ATR multiplier for stop loss.", "Risk");
	}

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

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

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

	public decimal TakeFactor
	{
		get => _takeFactor.Value;
		set => _takeFactor.Value = value;
	}

	public decimal StopFactor
	{
		get => _stopFactor.Value;
		set => _stopFactor.Value = value;
	}

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

		_entryPrice = 0;
	}

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

		_entryPrice = 0;

		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, atr, ProcessCandle)
			.Start();

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

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

		if (atrValue <= 0)
			return;

		var close = candle.ClosePrice;
		var takeDistance = atrValue * TakeFactor;
		var stopDistance = atrValue * StopFactor;

		// Position management with ATR-based stops
		if (Position > 0)
		{
			if (_entryPrice > 0)
			{
				if (close >= _entryPrice + takeDistance || close <= _entryPrice - stopDistance)
				{
					SellMarket();
				}
			}
		}
		else if (Position < 0)
		{
			if (_entryPrice > 0)
			{
				if (close <= _entryPrice - takeDistance || close >= _entryPrice + stopDistance)
				{
					BuyMarket();
				}
			}
		}

		// Entry: breakout above/below EMA
		if (Position == 0)
		{
			if (close > emaValue + atrValue * 1.5m)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (close < emaValue - atrValue * 1.5m)
			{
				_entryPrice = close;
				SellMarket();
			}
		}
	}
}