Стратегия котирования по спреду

Обзор

MqSpreadStrategy - это стратегия, которая создает спред на рынке путем одновременного выставления котировок на покупку и продажу. Она использует два процессора котирования для управления заявками на обеих сторонах рынка.

Основные компоненты

public class MqSpreadStrategy : Strategy
{
	private readonly StrategyParam<MarketPriceTypes> _priceType;
	private readonly StrategyParam<Unit> _priceOffset;
	private readonly StrategyParam<Unit> _bestPriceOffset;

	private QuotingProcessor _buyProcessor;
	private QuotingProcessor _sellProcessor;
}

Параметры стратегии

Стратегия позволяет настраивать следующие параметры:

  • PriceType - тип рыночной цены для котирования (по умолчанию Following)
  • PriceOffset - смещение цены от рыночной цены
  • BestPriceOffset - минимальное отклонение для обновления котировки (по умолчанию 0.1%)

Инициализация стратегии

В методе OnStarted2 стратегия подписывается на изменения рыночного времени:

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

	// Подписка на изменения рыночного времени для обновления котировок
	Connector.CurrentTimeChanged += Connector_CurrentTimeChanged;
	Connector_CurrentTimeChanged(new TimeSpan());
}

Управление процессорами котирования

Метод Connector_CurrentTimeChanged вызывается при изменении рыночного времени и управляет созданием и обновлением процессоров котирования:

private void Connector_CurrentTimeChanged(TimeSpan obj)
{
	// Создаем новые процессоры только при нулевой позиции и если текущие остановлены
	if (Position != 0)
		return;

	if (_buyProcessor != null && _buyProcessor.LeftVolume > 0)
		return;

	if (_sellProcessor != null && _sellProcessor.LeftVolume > 0)
		return;

	// Освобождаем ресурсы существующих процессоров
	_buyProcessor?.Dispose();
	_buyProcessor = null;

	_sellProcessor?.Dispose();
	_sellProcessor = null;

	// Создаем поведения для рыночного котирования
	var buyBehavior = new MarketQuotingBehavior(
		PriceOffset,
		BestPriceOffset,
		PriceType
	);

	var sellBehavior = new MarketQuotingBehavior(
		PriceOffset,
		BestPriceOffset,
		PriceType
	);

	// Создаем процессор для покупки
	_buyProcessor = new QuotingProcessor(
		buyBehavior,
		Security,
		Portfolio,
		Sides.Buy,
		Volume,
		Volume, // Максимальный объем заявки
		TimeSpan.Zero, // Без таймаута
		this, // Стратегия реализует ISubscriptionProvider
		this, // Стратегия реализует IMarketRuleContainer
		this, // Стратегия реализует ITransactionProvider
		this, // Стратегия реализует ITimeProvider
		this, // Стратегия реализует IMarketDataProvider
		IsFormedAndOnlineAndAllowTrading, // Проверка разрешения торговли
		true, // Использовать цены стакана
		true  // Использовать цену последней сделки, если стакан пуст
	)
	{
		Parent = this
	};

	// Создаем процессор для продажи
	_sellProcessor = new QuotingProcessor(
		sellBehavior,
		Security,
		Portfolio,
		Sides.Sell,
		Volume,
		Volume, // Максимальный объем заявки
		TimeSpan.Zero, // Без таймаута
		this, // Стратегия реализует ISubscriptionProvider
		this, // Стратегия реализует IMarketRuleContainer
		this, // Стратегия реализует ITransactionProvider
		this, // Стратегия реализует ITimeProvider
		this, // Стратегия реализует IMarketDataProvider
		IsFormedAndOnlineAndAllowTrading, // Проверка разрешения торговли
		true, // Использовать цены стакана
		true  // Использовать цену последней сделки, если стакан пуст
	)
	{
		Parent = this
	};

	// Логируем создание новых процессоров котирования
	this.AddInfoLog($"Created buy/sell spread at {CurrentTime}");

	// Подписываемся на события процессора покупки для логирования
	_buyProcessor.OrderRegistered += order =>
		this.AddInfoLog($"Buy order {order.TransactionId} registered at price {order.Price}");

	_buyProcessor.OrderFailed += fail =>
		this.AddInfoLog($"Buy order failed: {fail.Error.Message}");

	_buyProcessor.OwnTrade += trade =>
		this.AddInfoLog($"Buy trade executed: {trade.Trade.Volume} at {trade.Trade.Price}");

	_buyProcessor.Finished += isOk => {
		this.AddInfoLog($"Buy quoting finished with success: {isOk}");
		_buyProcessor?.Dispose();
		_buyProcessor = null;
	};

	// Подписываемся на события процессора продажи для логирования
	_sellProcessor.OrderRegistered += order =>
		this.AddInfoLog($"Sell order {order.TransactionId} registered at price {order.Price}");

	_sellProcessor.OrderFailed += fail =>
		this.AddInfoLog($"Sell order failed: {fail.Error.Message}");

	_sellProcessor.OwnTrade += trade =>
		this.AddInfoLog($"Sell trade executed: {trade.Trade.Volume} at {trade.Trade.Price}");

	_sellProcessor.Finished += isOk => {
		this.AddInfoLog($"Sell quoting finished with success: {isOk}");
		_sellProcessor?.Dispose();
		_sellProcessor = null;
	};

	// Запускаем оба процессора
	_buyProcessor.Start();
	_sellProcessor.Start();
}

Освобождение ресурсов

В методе OnStopped стратегия освобождает ресурсы:

protected override void OnStopped()
{
	// Отписываемся для предотвращения утечек памяти
	Connector.CurrentTimeChanged -= Connector_CurrentTimeChanged;

	// Освобождаем ресурсы процессоров
	_buyProcessor?.Dispose();
	_buyProcessor = null;

	_sellProcessor?.Dispose();
	_sellProcessor = null;

	base.OnStopped();
}

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

  • Стратегия реагирует на изменения рыночного времени
  • При нулевой позиции и остановленных процессорах создаются два новых процессора:
    • Процессор для покупки (Buy)
    • Процессор для продажи (Sell)
  • Оба процессора настроены на одинаковый объем и используют одинаковые настройки котирования
  • Процессоры создают спред на рынке, выставляя одновременно заявки на покупку и продажу

Особенности

  • Использует современный процессор котирования QuotingProcessor с поведением MarketQuotingBehavior
  • Создает спред на рынке, выставляя одновременно заявки на покупку и продажу
  • Работает только при нулевой позиции, предотвращая накопление нежелательного риска
  • Поддерживает настройку различных параметров котирования (тип цены, смещение, минимальное отклонение)
  • Включает подробное логирование событий процессоров котирования
  • Корректно управляет ресурсами при остановке стратегии и создании новых процессоров
  • Поддерживает работу с различными типами рыночных цен (Following, Best, Opposite и др.)