Ver en GitHub

Robot comercial AIS2 20005 (puerto StockSharp)

Descripción general

AIS2 Trading Robot 20005 es un asesor experto en ruptura intradiaria escrito originalmente para MetaTrader 4. El puerto recrea su lógica de marcos de tiempo múltiples además de la estrategia de alto nivel de StockSharp API. La estrategia espera rupturas de impulso por encima o por debajo del punto medio de la vela de marco temporal superior anterior, aplica distancias dinámicas de toma de ganancias y stop-loss derivadas del rango de esa vela y administra posiciones con un marco temporal secundario más rápido que impulsa un stop dinámico.

La conversión se centra en la transparencia y el control manual: las posiciones se abren con órdenes de mercado, los niveles de protección se aplican dentro de la propia estrategia y una pausa comercial configurable evita reingresos rápidos. El tamaño de las posiciones basado en acciones refleja la lógica de "reserva" original, permitiendo a los usuarios asignar una fracción del valor de la cartera a cada operación manteniendo intacto un colchón de capital.

Lógica principal

  1. Análisis del marco de tiempo principal – En cada vela finalizada del marco de tiempo principal (predeterminado 15 minutos), la estrategia calcula:
    • Punto medio de la vela (High + Low) / 2.
    • Distancias de obtención de beneficios y stop-loss basadas en rangos (range * TakeFactor y range * StopFactor).
    • Aproximación del diferencial actual, buffers de parada/congelación y un paso de seguimiento mínimo.
  2. Condiciones de ruptura: las entradas largas requieren tanto un cierre por encima del punto medio como que el precio de venta actual rompa el máximo anterior más el diferencial. Los pantalones cortos reflejan la condición de los mínimos. Las órdenes se bloquean si las distancias de parada/objetivo calculadas no cumplen con las restricciones a nivel de corredor.
  3. Gestión de riesgos: el tamaño de la posición se deriva del capital de la cartera: OrderReserve define la fracción negociable, mientras que AccountReserve mantiene una parte intacta. Si el capital disponible o los límites del corredor no permiten la operación, se omite la configuración.
  4. Gestión comercial: el período de tiempo más rápido (predeterminado 1 minuto) actualiza continuamente la distancia de seguimiento. A medida que el precio avanza, el stop migra a favor de la operación una vez que el rango secundario lo justifica. Alcanzar el objetivo o el stop da como resultado una salida inmediata del mercado.
  5. Barreras operativas: un temporizador de enfriamiento (TradingPauseSeconds) replica la pausa comercial MQL original. La estrategia también se suscribe al libro de órdenes para capturar valores de oferta/demanda en vivo; cuando no está disponible, vuelve a cerrar la vela.

Parámetros

Parámetro Descripción Predeterminado
PrimaryCandleType Se utiliza un marco de tiempo más alto para generar señales de entrada. velas de 15 minutos
SecondaryCandleType Plazo más bajo para los cálculos del trailing stop. velas de 1 minuto
TakeFactor Multiplicador aplicado al rango de velas principal para construir una distancia de toma de ganancias. 1.7
StopFactor Multiplicador aplicado al rango de vela principal para construir una distancia de stop-loss. 1.7
TrailFactor Multiplicador aplicado al rango de velas secundarias para actualizaciones finales. 0,5
AccountReserve Fracción del capital mantenido en reserva (no utilizado para negociar). 0,20
OrderReserve Fracción del capital total asignado por operación antes de los colchones. 0,04
BaseVolume Volumen de operaciones de respaldo cuando no se puede calcular el tamaño del riesgo. 1 lote
StopBufferTicks Se agregaron ticks adicionales a las verificaciones de cumplimiento a nivel de parada del corredor. 0
FreezeBufferTicks Marcas adicionales que evitan que las actualizaciones frecuentes se detengan cerca de los niveles de congelación. 0
TrailStepMultiplier Multiplicador aplicado al diferencial al validar los pasos finales. 1
TradingPauseSeconds Enfriamiento entre operaciones consecutivas. 5 segundos

Todos los parámetros numéricos exponen SetCanOptimize() (cuando sea significativo) para que puedan participar en StockSharp escenarios de optimización.

Notas de uso

  • Adjunte la estrategia a un valor y asegúrese de que los datos del libro de pedidos/Nivel 1 estén disponibles para una detección precisa del diferencial. Sin cotizaciones activas, la lógica aún se ejecuta mediante cierres de velas, pero las validaciones de parada se vuelven conservadoras.
  • Establece PrimaryCandleType/SecondaryCandleType en los períodos de tiempo que existen en tu feed de datos. El puerto utiliza SubscribeCandles y vincula los controladores a través del nivel alto de StockSharp API.
  • El trailing stop es virtual (gestionado internamente); no se envían órdenes de parada al corredor. Si necesita paradas del lado del servidor, extienda el código para registrar órdenes de protección después de las entradas.
  • StartProtection() se llama al arrancar para que el motor liquide posiciones inesperadas si es necesario.

Diferencias con el original EA

  • La versión MetaTrader manipuló variables globales en todo el terminal; este puerto mantiene los parámetros dentro de la estrategia y los expone a través de contenedores StrategyParam.
  • Las modificaciones de órdenes fueron reemplazadas por salidas directas del mercado porque StockSharp maneja la lógica de parada/objetivo dentro del propio algoritmo.
  • Los cálculos de riesgo operan sobre el capital de la cartera proporcionado por StockSharp en lugar de consultas de saldo de cuenta desde MT4.

Archivos

  • CS/Ais2TradingRobot20005Strategy.cs – Implementación de estrategia utilizando API de alto nivel de StockSharp.
  • README.md – Descripción en inglés (este archivo).
  • README_zh.md – Traducción al chino.
  • README_ru.md – traducción al ruso.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// AIS2 Trading Robot: range breakout strategy.
/// Enters on close above/below previous candle range midpoint,
/// uses ATR for trailing stop management.
/// </summary>
public class Ais2TradingRobot20005Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _takeFactor;
	private readonly StrategyParam<decimal> _stopFactor;

	private decimal _prevHigh;
	private decimal _prevLow;
	private decimal _prevMid;
	private decimal _entryPrice;
	private decimal _stopPrice;

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

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

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

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

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.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();

		_prevHigh = 0;
		_prevLow = 0;
		_prevMid = 0;
		_entryPrice = 0;
		_stopPrice = 0;
	}

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

		_prevHigh = 0;
		_prevLow = 0;
		_prevMid = 0;
		_entryPrice = 0;
		_stopPrice = 0;

		var atr = new AverageTrueRange { Length = AtrLength };

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

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

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

		if (_prevHigh == 0 || atrVal <= 0)
		{
			_prevHigh = candle.HighPrice;
			_prevLow = candle.LowPrice;
			_prevMid = (candle.HighPrice + candle.LowPrice) / 2m;
			return;
		}

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

		// Manage open position
		if (Position > 0)
		{
			// Take profit
			if (close - _entryPrice >= takeDistance)
			{
				SellMarket();
				_entryPrice = 0;
				_stopPrice = 0;
			}
			// Stop loss
			else if (_stopPrice > 0 && close <= _stopPrice)
			{
				SellMarket();
				_entryPrice = 0;
				_stopPrice = 0;
			}
			// Trail stop
			else
			{
				var newStop = close - stopDistance;
				if (newStop > _stopPrice)
					_stopPrice = newStop;
			}
		}
		else if (Position < 0)
		{
			if (_entryPrice - close >= takeDistance)
			{
				BuyMarket();
				_entryPrice = 0;
				_stopPrice = 0;
			}
			else if (_stopPrice > 0 && close >= _stopPrice)
			{
				BuyMarket();
				_entryPrice = 0;
				_stopPrice = 0;
			}
			else
			{
				var newStop = close + stopDistance;
				if (newStop < _stopPrice || _stopPrice == 0)
					_stopPrice = newStop;
			}
		}

		// New entry: breakout above previous high with close above midpoint
		if (Position == 0)
		{
			if (close > _prevHigh && close > _prevMid)
			{
				_entryPrice = close;
				_stopPrice = close - stopDistance;
				BuyMarket();
			}
			else if (close < _prevLow && close < _prevMid)
			{
				_entryPrice = close;
				_stopPrice = close + stopDistance;
				SellMarket();
			}
		}

		_prevHigh = candle.HighPrice;
		_prevLow = candle.LowPrice;
		_prevMid = (candle.HighPrice + candle.LowPrice) / 2m;
	}
}