Открыть на GitHub

Стратегия последовательных покупок по таймеру

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

Стратегия последовательных покупок по таймеру повторяет работу советника MetaTrader buy_order.mq4, который отправляет рыночные заявки на покупку каждую секунду. Перенос на StockSharp сохраняет ту же синхронизацию: ордера выставляются в тот момент, когда таймер совпадает с ожидаемой секундой текущей минуты, а после отправки заданного количества сделок стратегия останавливается автоматически.

Реализация основана на высокоуровневом сервисе Timer из StockSharp, поэтому дополнительные индикаторы и подписки на свечи не требуются — логика полностью детерминирована таймером.

Основной алгоритм

  1. При старте стратегия включает защитный модуль StartProtection() и запускает таймер с указанным интервалом (по умолчанию 1 секунда).
  2. Каждое срабатывание таймера проверяет, доступна ли торговля, и совпадает ли текущая секунда с ожидаемой последовательностью.
  3. Если условия выполнены, отправляется рыночный ордер на покупку с заданным объемом.
  4. Процесс повторяется, пока не будет достигнуто требуемое количество ордеров, после чего стратегия завершает работу.

Сравнение секунд позволяет полностью воспроизвести поведение оригинального советника: первая заявка уходит только когда значение секунд равно нулю, дальнейшие заявки следуют за каждой следующей секундой.

Параметры

Название Тип Значение по умолчанию Описание
OrderVolume decimal 0.01 Объем каждой рыночной покупки. При неположительном значении стратегия выводит предупреждение и завершает работу.
OrdersToPlace int 60 Количество заявок, которое нужно отправить перед остановкой стратегии.
Interval TimeSpan 1s Интервал между срабатываниями таймера. Значение в 1 секунду полностью повторяет логику из MQL, но при необходимости может быть изменено.

Все параметры задаются через StrategyParam<T>, что упрощает оптимизацию и конфигурирование через пользовательский интерфейс.

Ход выполнения

  • Инициализация — метод OnReseted() сбрасывает счетчики перед повторным запуском или оптимизацией.
  • Запуск — в OnStarted() стратегия обнуляет счетчики, активирует защиту и запускает таймер.
  • Срабатывание таймера — метод OnTimer() синхронизирует секунды, отправляет ордера и ведет журналирование. После последней заявки стратегия останавливается.
  • Завершение — вспомогательный метод CompleteStrategy() предотвращает повторные вызовы Stop().

Особенности портирования

  • Вызов EventSetTimer(1) заменен на Timer.Start(TimeSpan.FromSeconds(1), OnTimer).
  • Комментарии к ордерам и «магическое» число из MetaTrader не используются; для отслеживания прогресса применяются сообщения в журнал.
  • Для сохранения 60 заявок в минуту используется сравнение номера секунды, а не только счетчик срабатываний таймера.

Рекомендации по применению

  1. Укажите нужный инструмент и портфель перед запуском.
  2. Отрегулируйте OrderVolume в соответствии с минимальным лотом и требованиями брокера.
  3. Уменьшите OrdersToPlace, если нужно меньше сделок; для отключения привязки к секундам потребуется модифицировать код (продвинутый сценарий).
  4. Следите за журналом сообщений, чтобы контролировать синхронизацию таймера и фактические отправки ордеров.

Ограничения

  • Стратегия выполняет только покупки; для выхода из позиции требуется ручное вмешательство или внешний риск-менеджмент.
  • Точность отправки ордеров зависит от таймера операционной системы и подключения; большие задержки могут нарушить равномерность последовательности.

Содержимое папки

  • CS/TimedBuyOrderStrategy.cs — реализация на C#.
  • README.md — документация на английском языке.
  • README_zh.md — документация на китайском языке.

Согласно требованиям проекта, Python-версия и соответствующая папка не создавались.

namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// Strategy that submits a sequence of market buy orders on each candle close.
/// After a configurable number of orders have been placed, it stops.
/// </summary>
public class TimedBuyOrderStrategy : Strategy
{
	private readonly StrategyParam<int> _ordersToPlace;
	private readonly StrategyParam<DataType> _candleType;

	private int _ordersPlaced;

	/// <summary>
	/// Initializes a new instance of the <see cref="TimedBuyOrderStrategy"/> class.
	/// </summary>
	public TimedBuyOrderStrategy()
	{
		_ordersToPlace = Param(nameof(OrdersToPlace), 60)
			.SetGreaterThanZero()
			.SetDisplay("Orders To Place", "Number of sequential buy orders before stopping", "Trading");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle type", "Candle type for strategy calculation.", "General");
	}

	/// <summary>
	/// Total number of buy orders to submit before the strategy stops.
	/// </summary>
	public int OrdersToPlace
	{
		get => _ordersToPlace.Value;
		set => _ordersToPlace.Value = value;
	}

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_ordersPlaced = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_ordersPlaced = 0;

		var sma = new SMA { Length = 5 };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, OnProcess)
			.Start();
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (_ordersPlaced >= OrdersToPlace)
			return;

		BuyMarket();

		_ordersPlaced++;
	}
}