Открыть на GitHub

Торговый робот AIS1 (конверсия MQL/8700)

Общее описание

AIS1 Trading Robot — это перенос экспертной системы из файла MQL/8700/AIS1.MQ4 на платформу StockSharp. Первоначально робот рассчитан на торговлю пробоями по EURUSD на дневных барах и использует несколько таймфреймов для вычисления стопов и трейлинг-стопа. Перевод на C# сохраняет оригинальную логику, но предоставляет гибкие параметры для дальнейшей оптимизации и интеграции с инфраструктурой StockSharp.

Логика торговли

  • Таймфреймы
    • Основные свечи: дневные бары, на их основе формируются условия входа, исходный стоп и тейк.
    • Дополнительные свечи: 4-часовые бары, их диапазон задаёт шаг трейлинг-стопа.
  • Сигналы входа
    • Лонг: закрытие предыдущего дня выше середины бара, а текущий ask пробивает максимум этого бара.
    • Шорт: закрытие предыдущего дня ниже середины, а текущий bid пробивает минимум.
    • Открывается только одна позиция; повторные сигналы игнорируются до полного выхода из сделки.
  • Начальные уровни риска
    • Стоп-лосс = максимум/минимум предыдущего дня ± StopFactor × дневной диапазон.
    • Тейк-профит = цена входа ± TakeFactor × дневной диапазон.
    • Параметр StopBufferTicks задаёт дополнительный отступ, если брокер требует минимальную дистанцию до стопов.
  • Трейлинг-стоп
    • Используется диапазон последней 4-часовой свечи, умноженный на TrailFactor.
    • Обновление выполняется только если цена продвинулась как минимум на TrailStepMultiplier × спред и остаётся достаточно далеко от целевого уровня.
    • При падении капитала ниже допустимого уровня трейлинг временно отключается.
  • Управление капиталом
    • Размер позиции = OrderReserve × Equity / денежный риск между входом и стопом.
    • Объём приводится к ограничениям инструмента (MinVolume, MaxVolume, VolumeStep).
    • Ведётся учёт максимальной equity: если текущая стоимость портфеля опускается ниже доли AccountReserve - OrderReserve, новые сделки не открываются.
  • Контроль частоты действий
    • После любого открытия или обновления трейлинг-стопа запускается пауза 5 секунд, как и в оригинальной версии на MQL.

Параметры

Параметр Значение по умолчанию Назначение
AccountReserve 0.20 Доля капитала, которую нельзя задействовать. Определяет допустимый уровень просадки.
OrderReserve 0.04 Доля капитала для одной сделки и база для расчёта объёма.
PrimaryCandleType День Таймфрейм для сигналов и статических целей.
SecondaryCandleType 4 часа Таймфрейм для расчёта трейлинг-стопа.
TakeFactor 0.8 Множитель дневного диапазона для тейк-профита.
StopFactor 1.0 Множитель дневного диапазона для стоп-лосса.
TrailFactor 5.0 Множитель 4-часового диапазона для трейлинга.
TrailStepMultiplier 1.0 Множитель спреда, определяющий минимальный шаг для обновления трейлинга.
StopBufferTicks 0 Дополнительное количество ценовых шагов, удерживающее стопы на безопасном расстоянии.

Практические рекомендации

  1. Перед запуском укажите нужный инструмент (по умолчанию EURUSD) и портфель, чтобы стратегия могла оценивать текущий капитал.
  2. Для корректной работы требуются и дневные, и 4-часовые свечи. При отсутствии данных модуль входа/трейлинга не активируется.
  3. Стратегия подписывается на стакан заявок и использует лучшую цену bid/ask. При отсутствии стакана в качестве приближения используется цена закрытия свечи.
  4. Выход из позиции осуществляется рыночными заявками по факту достижения стопа или тейка, что эквивалентно серверному изменению ордеров в MetaTrader.
  5. Настройки AccountReserve, задержки и риск-менеджмента можно подбирать под требования конкретного брокера.

Отличия от исходного MQL

  • Вместо модификации ордеров стоп и тейк реализованы через принудительное закрытие позиции, что повторяет логику оригинального советника.
  • Пересчёт риска использует Security.PriceStep и Security.StepPrice. Если данные отсутствуют, применяется упрощённое соотношение 1:1 — необходимо проверить спецификацию контракта.
  • Добавлены подробные комментарии и описания параметров для удобства оптимизации в рамках StockSharp.

Требования

  • Доступ к API StockSharp с поддержкой подписки на свечи и стакан.
  • Рабочее торговое подключение для выставления заявок и мониторинга портфеля.
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();
			}
		}
	}
}