Открыть на GitHub

Стратегия Auto Trading Publish

Обзор

Данная стратегия переносит утилиту MetaTrader 4 «Auto Trading Publish» на платформу StockSharp. Вместо отправки заявок она контролирует временные окна, когда торговля разрешена. Стратегия подписывается на поток свечей, чтобы отслеживать биржевое время, и переключает флаг AutoTradingActive при достижении заданных часов запуска и остановки, тем самым повторяя работу оригинального инструмента, который нажимал кнопку «AutoTrading» в MT4.

Логика работы

  • Подписка на «легкие» свечи (по умолчанию минутные), чтобы получать актуальное время даже без сделок.
  • Когда закрытая свеча попадает на час StartHour, флаг AutoTradingActive включается и событие фиксируется в журнале.
  • Когда закрытая свеча попадает на час StopHour, флаг AutoTradingActive выключается и запись попадает в журнал.
  • В пределах одного часа повторные переключения подавляются, чтобы журнал не заполнялся одинаковыми сообщениями.

Параметры

Параметр Описание
StartHour Час (0-23), с которого торговля разрешена.
StopHour Час (0-23), по достижении которого торговля запрещается.
CandleType Таймфрейм свечей для проверки времени; чем он меньше, тем быстрее реакция.

Рекомендации по использованию

  • Стратегия не отправляет ордера: используйте флаг AutoTradingActive в своих модулях или панелях управления, чтобы решать, когда разрешать сделки.
  • Если StartHour и StopHour совпадают, событие остановки выполняется сразу после запуска — итоговое состояние «торговля выключена», как и в оригинальном советнике.
  • Выбирайте таймфрейм свечи в зависимости от требуемой скорости реакции. Минутные свечи дают хороший компромисс между оперативностью и нагрузкой на систему.

Отличия от версии MetaTrader

  • В MT4 глобальная кнопка переключалась через Windows-сообщения. В StockSharp используется флаг на уровне стратегии, что упрощает интеграцию с комплексными системами.
  • Порт полностью реализован на высокоуровневом API, поэтому не требует работы с низкоуровневыми хукми и легко комбинируется с графиками или другими вспомогательными стратегиями.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Auto Trading Publish strategy: SMA crossover + RSI confirmation.
/// Buys when close crosses above SMA and RSI is below 40.
/// Sells when close crosses below SMA and RSI is above 60.
/// </summary>
public class AutoTradingPublishStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

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

	public int SmaPeriod
	{
		get => _smaPeriod.Value;
		set => _smaPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public AutoTradingPublishStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "SMA period", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

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

		var sma = new SimpleMovingAverage { Length = SmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		decimal? prevClose = null;
		decimal? prevSma = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, rsi, (candle, smaVal, rsiVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (prevClose.HasValue && prevSma.HasValue)
				{
					var crossUp = prevClose.Value <= prevSma.Value && close > smaVal;
					var crossDown = prevClose.Value >= prevSma.Value && close < smaVal;

					if (crossUp && rsiVal < 55m && Position <= 0)
						BuyMarket();
					else if (crossDown && rsiVal > 45m && Position >= 0)
						SellMarket();
				}

				prevClose = close;
				prevSma = smaVal;
			})
			.Start();

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