Spread Quoting Strategy
Overview
MqSpreadStrategy
is a strategy that creates a spread in the market by simultaneously placing quotes for buying and selling. It uses two quoting processors to manage orders on both sides of the market.
Main Components
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;
}
Strategy Parameters
The strategy allows customizing the following parameters:
- PriceType - market price type for quoting (default Following)
- PriceOffset - price offset from the market price
- BestPriceOffset - minimum deviation for quote update (default 0.1%)
Strategy Initialization
In the OnStarted method, the strategy subscribes to market time changes:
protected override void OnStarted(DateTimeOffset time)
{
base.OnStarted(time);
// Subscribe to market time changes for quote updates
Connector.CurrentTimeChanged += Connector_CurrentTimeChanged;
Connector_CurrentTimeChanged(new TimeSpan());
}
Managing Quoting Processors
The Connector_CurrentTimeChanged
method is called when the market time changes and manages the creation and update of quoting processors:
private void Connector_CurrentTimeChanged(TimeSpan obj)
{
// Create new processors only with zero position and if current ones are stopped
if (Position != 0)
return;
if (_buyProcessor != null && _buyProcessor.LeftVolume > 0)
return;
if (_sellProcessor != null && _sellProcessor.LeftVolume > 0)
return;
// Release resources of existing processors
_buyProcessor?.Dispose();
_buyProcessor = null;
_sellProcessor?.Dispose();
_sellProcessor = null;
// Create behaviors for market quoting
var buyBehavior = new MarketQuotingBehavior(
PriceOffset,
BestPriceOffset,
PriceType
);
var sellBehavior = new MarketQuotingBehavior(
PriceOffset,
BestPriceOffset,
PriceType
);
// Create processor for buying
_buyProcessor = new QuotingProcessor(
buyBehavior,
Security,
Portfolio,
Sides.Buy,
Volume,
Volume, // Maximum order volume
TimeSpan.Zero, // No timeout
this, // Strategy implements ISubscriptionProvider
this, // Strategy implements IMarketRuleContainer
this, // Strategy implements ITransactionProvider
this, // Strategy implements ITimeProvider
this, // Strategy implements IMarketDataProvider
IsFormedAndOnlineAndAllowTrading, // Check trading permission
true, // Use order book prices
true // Use last trade price if the order book is empty
)
{
Parent = this
};
// Create processor for selling
_sellProcessor = new QuotingProcessor(
sellBehavior,
Security,
Portfolio,
Sides.Sell,
Volume,
Volume, // Maximum order volume
TimeSpan.Zero, // No timeout
this, // Strategy implements ISubscriptionProvider
this, // Strategy implements IMarketRuleContainer
this, // Strategy implements ITransactionProvider
this, // Strategy implements ITimeProvider
this, // Strategy implements IMarketDataProvider
IsFormedAndOnlineAndAllowTrading, // Check trading permission
true, // Use order book prices
true // Use last trade price if the order book is empty
)
{
Parent = this
};
// Log creation of new quoting processors
this.AddInfoLog($"Created buy/sell spread at {CurrentTime}");
// Subscribe to buy processor events for logging
_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;
};
// Subscribe to sell processor events for logging
_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;
};
// Start both processors
_buyProcessor.Start();
_sellProcessor.Start();
}
Resource Release
In the OnStopped method, the strategy releases resources:
protected override void OnStopped()
{
// Unsubscribe to prevent memory leaks
Connector.CurrentTimeChanged -= Connector_CurrentTimeChanged;
// Release processor resources
_buyProcessor?.Dispose();
_buyProcessor = null;
_sellProcessor?.Dispose();
_sellProcessor = null;
base.OnStopped();
}
Trading Logic
- The strategy responds to market time changes
- With zero position and stopped processors, two new processors are created:
- Buy processor (Buy)
- Sell processor (Sell)
- Both processors are configured with the same volume and use the same quoting settings
- Processors create a spread in the market by simultaneously placing buy and sell orders
Features
- Uses modern quoting processor QuotingProcessor with MarketQuotingBehavior
- Creates a spread in the market by simultaneously placing buy and sell orders
- Works only with zero position, preventing accumulation of unwanted risk
- Supports configuration of various quoting parameters (price type, offset, minimum deviation)
- Includes detailed logging of quoting processor events
- Properly manages resources when stopping the strategy and creating new processors
- Supports working with different types of market prices (Following, Best, Opposite, etc.)