Phase 0 completion: NT8 SDK core framework with risk management and position sizing
Some checks failed
Build and Test / build (push) Has been cancelled
Some checks failed
Build and Test / build (push) Has been cancelled
This commit is contained in:
708
docs/architecture/order_manager_implementation.md
Normal file
708
docs/architecture/order_manager_implementation.md
Normal file
@@ -0,0 +1,708 @@
|
||||
# OrderManager Class Implementation Design
|
||||
|
||||
## Overview
|
||||
|
||||
The OrderManager class is the primary implementation of the IOrderManager interface, providing core order management functionality, integration with risk management, and support for algorithmic execution strategies.
|
||||
|
||||
## Class Structure
|
||||
|
||||
```csharp
|
||||
using NT8.Core.Common.Models;
|
||||
using NT8.Core.Risk;
|
||||
using NT8.Core.Sizing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NT8.Core.Orders
|
||||
{
|
||||
/// <summary>
|
||||
/// Order manager implementation with smart routing and algorithmic execution
|
||||
/// </summary>
|
||||
public class OrderManager : IOrderManager
|
||||
{
|
||||
private readonly IRiskManager _riskManager;
|
||||
private readonly IPositionSizer _positionSizer;
|
||||
private readonly ILogger<OrderManager> _logger;
|
||||
private readonly object _lock = new object();
|
||||
|
||||
// Configuration
|
||||
private RoutingConfig _routingConfig;
|
||||
private AlgorithmParameters _algorithmParameters;
|
||||
|
||||
// State
|
||||
private readonly Dictionary<string, OrderStatus> _orders;
|
||||
private readonly Dictionary<string, ExecutionVenue> _venues;
|
||||
private readonly RoutingMetrics _routingMetrics;
|
||||
private readonly OmsMetrics _omsMetrics;
|
||||
|
||||
public OrderManager(
|
||||
IRiskManager riskManager,
|
||||
IPositionSizer positionSizer,
|
||||
ILogger<OrderManager> logger)
|
||||
{
|
||||
_riskManager = riskManager ?? throw new ArgumentNullException(nameof(riskManager));
|
||||
_positionSizer = positionSizer ?? throw new ArgumentNullException(nameof(positionSizer));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_orders = new Dictionary<string, OrderStatus>();
|
||||
_venues = new Dictionary<string, ExecutionVenue>();
|
||||
_routingMetrics = new RoutingMetrics(new Dictionary<string, VenueMetrics>(), 0, 0.0, DateTime.UtcNow);
|
||||
_omsMetrics = new OmsMetrics(0, 0, 0.0, 0.0, 0.0, 0, DateTime.UtcNow);
|
||||
|
||||
InitializeDefaultConfig();
|
||||
InitializeVenues();
|
||||
}
|
||||
|
||||
private void InitializeDefaultConfig()
|
||||
{
|
||||
_routingConfig = new RoutingConfig(
|
||||
SmartRoutingEnabled: true,
|
||||
DefaultVenue: "Primary",
|
||||
VenuePreferences: new Dictionary<string, double> { ["Primary"] = 1.0, ["Secondary"] = 0.8 },
|
||||
MaxSlippagePercent: 0.5,
|
||||
MaxRoutingTime: TimeSpan.FromSeconds(30),
|
||||
RouteByCost: true,
|
||||
RouteBySpeed: true,
|
||||
RouteByReliability: true
|
||||
);
|
||||
|
||||
_algorithmParameters = new AlgorithmParameters(
|
||||
new TwapConfig(TimeSpan.FromMinutes(15), 30, true),
|
||||
new VwapConfig(0.1, true),
|
||||
new IcebergConfig(0.1, true)
|
||||
);
|
||||
}
|
||||
|
||||
private void InitializeVenues()
|
||||
{
|
||||
_venues.Add("Primary", new ExecutionVenue(
|
||||
"Primary", "Primary execution venue", true, 1.0, 1.0, 0.99));
|
||||
|
||||
_venues.Add("Secondary", new ExecutionVenue(
|
||||
"Secondary", "Backup execution venue", true, 1.2, 0.9, 0.95));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Core Order Management Implementation
|
||||
|
||||
### Order Submission
|
||||
|
||||
```csharp
|
||||
public async Task<OrderResult> SubmitOrderAsync(OrderRequest request, StrategyContext context)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Submitting order for {Symbol} {Side} {Quantity}",
|
||||
request.Symbol, request.Side, request.Quantity);
|
||||
|
||||
// 1. Validate order through risk management
|
||||
var riskDecision = await ValidateOrderAsync(request, context);
|
||||
if (!riskDecision.Allow)
|
||||
{
|
||||
_logger.LogWarning("Order rejected by risk management: {Reason}", riskDecision.RejectReason);
|
||||
return new OrderResult(false, null, riskDecision.RejectReason, null);
|
||||
}
|
||||
|
||||
// 2. Route order based on smart routing logic
|
||||
var routingResult = await RouteOrderAsync(request, context);
|
||||
if (!routingResult.Success)
|
||||
{
|
||||
_logger.LogError("Order routing failed: {Message}", routingResult.Message);
|
||||
return new OrderResult(false, null, routingResult.Message, null);
|
||||
}
|
||||
|
||||
// 3. Submit to selected venue (simulated)
|
||||
var orderId = Guid.NewGuid().ToString();
|
||||
var orderStatus = new OrderStatus(
|
||||
orderId, request.Symbol, request.Side, request.Type, request.Quantity, 0,
|
||||
request.LimitPrice, request.StopPrice, OrderState.Submitted, DateTime.UtcNow, null,
|
||||
new List<OrderFill>());
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_orders[orderId] = orderStatus;
|
||||
UpdateOmsMetrics();
|
||||
}
|
||||
|
||||
_logger.LogInformation("Order {OrderId} submitted to {Venue}", orderId, routingResult.SelectedVenue.Name);
|
||||
|
||||
return new OrderResult(true, orderId, "Order submitted successfully", orderStatus);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error submitting order for {Symbol}", request.Symbol);
|
||||
return new OrderResult(false, null, $"Error submitting order: {ex.Message}", null);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Order Cancellation
|
||||
|
||||
```csharp
|
||||
public async Task<bool> CancelOrderAsync(string orderId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(orderId)) throw new ArgumentException("Order ID required", nameof(orderId));
|
||||
|
||||
try
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_orders.ContainsKey(orderId))
|
||||
{
|
||||
_logger.LogWarning("Cannot cancel order {OrderId} - not found", orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
var order = _orders[orderId];
|
||||
if (order.State == OrderState.Filled || order.State == OrderState.Cancelled)
|
||||
{
|
||||
_logger.LogWarning("Cannot cancel order {OrderId} - already {State}", orderId, order.State);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update order state to cancelled
|
||||
var updatedOrder = order with { State = OrderState.Cancelled, FilledTime = DateTime.UtcNow };
|
||||
_orders[orderId] = updatedOrder;
|
||||
|
||||
UpdateOmsMetrics();
|
||||
}
|
||||
|
||||
_logger.LogInformation("Order {OrderId} cancelled successfully", orderId);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error cancelling order {OrderId}", orderId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Risk Integration Implementation
|
||||
|
||||
```csharp
|
||||
public async Task<RiskDecision> ValidateOrderAsync(OrderRequest request, StrategyContext context)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
// Convert OrderRequest to StrategyIntent for risk validation
|
||||
var intent = new StrategyIntent(
|
||||
request.Symbol,
|
||||
request.Side,
|
||||
ConvertOrderType(request.Type),
|
||||
(double?)request.LimitPrice,
|
||||
GetStopTicks(request),
|
||||
null, // TargetTicks
|
||||
1.0, // Confidence
|
||||
"OMS Order Submission",
|
||||
new Dictionary<string, object>()
|
||||
);
|
||||
|
||||
// Create a mock risk config for validation
|
||||
var riskConfig = new RiskConfig(1000, 200, 10, true);
|
||||
|
||||
return _riskManager.ValidateOrder(intent, context, riskConfig);
|
||||
}
|
||||
|
||||
private OrderType ConvertOrderType(NT8.Core.Orders.OrderType orderType)
|
||||
{
|
||||
return orderType switch
|
||||
{
|
||||
NT8.Core.Orders.OrderType.Market => OrderType.Market,
|
||||
NT8.Core.Orders.OrderType.Limit => OrderType.Limit,
|
||||
NT8.Core.Orders.OrderType.StopMarket => OrderType.StopMarket,
|
||||
NT8.Core.Orders.OrderType.StopLimit => OrderType.StopLimit,
|
||||
_ => OrderType.Market
|
||||
};
|
||||
}
|
||||
|
||||
private int GetStopTicks(OrderRequest request)
|
||||
{
|
||||
// Simplified stop ticks calculation
|
||||
return 10;
|
||||
}
|
||||
```
|
||||
|
||||
## Smart Order Routing Implementation
|
||||
|
||||
```csharp
|
||||
public async Task<RoutingResult> RouteOrderAsync(OrderRequest request, StrategyContext context)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
if (!_routingConfig.SmartRoutingEnabled)
|
||||
{
|
||||
var defaultVenue = _venues[_routingConfig.DefaultVenue];
|
||||
return new RoutingResult(true, null, defaultVenue, "Routing disabled, using default venue",
|
||||
new Dictionary<string, object> { ["venue"] = defaultVenue.Name });
|
||||
}
|
||||
|
||||
// Select best venue based on configuration
|
||||
var selectedVenue = SelectBestVenue(request, context);
|
||||
|
||||
// Update routing metrics
|
||||
UpdateRoutingMetrics(selectedVenue);
|
||||
|
||||
return new RoutingResult(true, null, selectedVenue, "Order routed successfully",
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
["venue"] = selectedVenue.Name,
|
||||
["cost_factor"] = selectedVenue.CostFactor,
|
||||
["speed_factor"] = selectedVenue.SpeedFactor
|
||||
});
|
||||
}
|
||||
|
||||
private ExecutionVenue SelectBestVenue(OrderRequest request, StrategyContext context)
|
||||
{
|
||||
ExecutionVenue bestVenue = null;
|
||||
double bestScore = double.MinValue;
|
||||
|
||||
foreach (var venue in _venues.Values)
|
||||
{
|
||||
if (!venue.IsActive) continue;
|
||||
|
||||
double score = 0;
|
||||
|
||||
// Factor in venue preferences
|
||||
if (_routingConfig.VenuePreferences.ContainsKey(venue.Name))
|
||||
{
|
||||
score += _routingConfig.VenuePreferences[venue.Name] * 100;
|
||||
}
|
||||
|
||||
// Factor in cost if enabled
|
||||
if (_routingConfig.RouteByCost)
|
||||
{
|
||||
score -= venue.CostFactor * 50; // Lower cost is better
|
||||
}
|
||||
|
||||
// Factor in speed if enabled
|
||||
if (_routingConfig.RouteBySpeed)
|
||||
{
|
||||
score += venue.SpeedFactor * 30; // Higher speed is better
|
||||
}
|
||||
|
||||
// Factor in reliability
|
||||
if (_routingConfig.RouteByReliability)
|
||||
{
|
||||
score += venue.ReliabilityFactor * 20; // Higher reliability is better
|
||||
}
|
||||
|
||||
if (score > bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
bestVenue = venue;
|
||||
}
|
||||
|
||||
return bestVenue ?? _venues[_routingConfig.DefaultVenue];
|
||||
}
|
||||
|
||||
private void UpdateRoutingMetrics(ExecutionVenue venue)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var venueMetrics = _routingMetrics.VenuePerformance.ContainsKey(venue.Name) ?
|
||||
_routingMetrics.VenuePerformance[venue.Name] :
|
||||
new VenueMetrics(venue.Name, 0, 0.0, 0.0, 0.0, 0);
|
||||
|
||||
var updatedMetrics = venueMetrics with
|
||||
{
|
||||
OrdersRouted = venueMetrics.OrdersRouted + 1
|
||||
};
|
||||
|
||||
_routingMetrics.VenuePerformance[venue.Name] = updatedMetrics;
|
||||
_routingMetrics.TotalRoutedOrders++;
|
||||
_routingMetrics.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Algorithmic Execution Support
|
||||
|
||||
### TWAP Algorithm Integration
|
||||
|
||||
```csharp
|
||||
public async Task<OrderResult> ExecuteTwapAsync(TwapParameters parameters, StrategyContext context)
|
||||
{
|
||||
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
_logger.LogInformation("Executing TWAP order for {Symbol} {Side} {Quantity} over {Duration}",
|
||||
parameters.Symbol, parameters.Side, parameters.TotalQuantity, parameters.Duration);
|
||||
|
||||
// Create a parent order for tracking
|
||||
var parentOrderId = Guid.NewGuid().ToString();
|
||||
|
||||
// Calculate slice parameters
|
||||
var sliceCount = (int)(parameters.Duration.TotalSeconds / parameters.IntervalSeconds);
|
||||
var sliceQuantity = parameters.TotalQuantity / sliceCount;
|
||||
|
||||
// Execute slices
|
||||
for (int i = 0; i < sliceCount; i++)
|
||||
{
|
||||
// Create slice order
|
||||
var sliceRequest = new OrderRequest(
|
||||
parameters.Symbol,
|
||||
parameters.Side,
|
||||
OrderType.Market, // Simplified to market orders
|
||||
sliceQuantity,
|
||||
parameters.LimitPrice,
|
||||
null, // StopPrice
|
||||
TimeInForce.Day,
|
||||
null, // No algorithm for slices
|
||||
new Dictionary<string, object>()
|
||||
);
|
||||
|
||||
// Submit slice order
|
||||
var result = await SubmitOrderAsync(sliceRequest, context);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
_logger.LogWarning("TWAP slice {Slice}/{Total} failed: {Message}",
|
||||
i + 1, sliceCount, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("TWAP slice {Slice}/{Total} submitted: {OrderId}",
|
||||
i + 1, sliceCount, result.OrderId);
|
||||
}
|
||||
|
||||
// Wait for next interval (except for last slice)
|
||||
if (i < sliceCount - 1)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(parameters.IntervalSeconds));
|
||||
}
|
||||
}
|
||||
|
||||
return new OrderResult(true, parentOrderId, "TWAP execution completed", null);
|
||||
}
|
||||
```
|
||||
|
||||
### VWAP Algorithm Integration
|
||||
|
||||
```csharp
|
||||
public async Task<OrderResult> ExecuteVwapAsync(VwapParameters parameters, StrategyContext context)
|
||||
{
|
||||
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
_logger.LogInformation("Executing VWAP order for {Symbol} {Side} {Quantity} from {Start} to {End}",
|
||||
parameters.Symbol, parameters.Side, parameters.TotalQuantity, parameters.StartTime, parameters.EndTime);
|
||||
|
||||
// Create a parent order for tracking
|
||||
var parentOrderId = Guid.NewGuid().ToString();
|
||||
|
||||
// Simplified VWAP implementation - in a real system, this would:
|
||||
// 1. Monitor market volume throughout the execution period
|
||||
// 2. Calculate participation rate based on target participation
|
||||
// 3. Execute orders in proportion to volume
|
||||
|
||||
// For now, we'll execute the order as a single market order
|
||||
var request = new OrderRequest(
|
||||
parameters.Symbol,
|
||||
parameters.Side,
|
||||
OrderType.Market,
|
||||
parameters.TotalQuantity,
|
||||
parameters.LimitPrice,
|
||||
null, // StopPrice
|
||||
TimeInForce.Day,
|
||||
null, // No algorithm for this simplified version
|
||||
new Dictionary<string, object>()
|
||||
);
|
||||
|
||||
var result = await SubmitOrderAsync(request, context);
|
||||
|
||||
return new OrderResult(result.Success, parentOrderId,
|
||||
result.Success ? "VWAP execution completed" : $"VWAP execution failed: {result.Message}",
|
||||
result.Status);
|
||||
}
|
||||
```
|
||||
|
||||
### Iceberg Algorithm Integration
|
||||
|
||||
```csharp
|
||||
public async Task<OrderResult> ExecuteIcebergAsync(IcebergParameters parameters, StrategyContext context)
|
||||
{
|
||||
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
_logger.LogInformation("Executing Iceberg order for {Symbol} {Side} {TotalQuantity} (visible: {VisibleQuantity})",
|
||||
parameters.Symbol, parameters.Side, parameters.TotalQuantity, parameters.VisibleQuantity);
|
||||
|
||||
// Create a parent order for tracking
|
||||
var parentOrderId = Guid.NewGuid().ToString();
|
||||
|
||||
var remainingQuantity = parameters.TotalQuantity;
|
||||
|
||||
while (remainingQuantity > 0)
|
||||
{
|
||||
// Determine visible quantity for this slice
|
||||
var visibleQuantity = Math.Min(parameters.VisibleQuantity, remainingQuantity);
|
||||
|
||||
// Create slice order
|
||||
var sliceRequest = new OrderRequest(
|
||||
parameters.Symbol,
|
||||
parameters.Side,
|
||||
parameters.LimitPrice.HasValue ? OrderType.Limit : OrderType.Market,
|
||||
visibleQuantity,
|
||||
parameters.LimitPrice,
|
||||
null, // StopPrice
|
||||
TimeInForce.Day,
|
||||
null, // No algorithm for slices
|
||||
new Dictionary<string, object>()
|
||||
);
|
||||
|
||||
// Submit slice order
|
||||
var result = await SubmitOrderAsync(sliceRequest, context);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
_logger.LogWarning("Iceberg slice failed with {Remaining} qty remaining: {Message}",
|
||||
remainingQuantity, result.Message);
|
||||
break;
|
||||
}
|
||||
|
||||
// Update remaining quantity
|
||||
remainingQuantity -= visibleQuantity;
|
||||
|
||||
_logger.LogInformation("Iceberg slice submitted, {Remaining} qty remaining", remainingQuantity);
|
||||
|
||||
// In a real implementation, we would wait for the order to fill
|
||||
// before submitting the next slice. For this design, we'll add a delay.
|
||||
if (remainingQuantity > 0)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(5)); // Simulate time between slices
|
||||
}
|
||||
|
||||
return new OrderResult(true, parentOrderId, "Iceberg execution completed", null);
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Management
|
||||
|
||||
```csharp
|
||||
public void UpdateRoutingConfig(RoutingConfig config)
|
||||
{
|
||||
if (config == null) throw new ArgumentNullException(nameof(config));
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_routingConfig = config;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Routing configuration updated");
|
||||
}
|
||||
|
||||
public RoutingConfig GetRoutingConfig()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _routingConfig;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateAlgorithmParameters(AlgorithmParameters parameters)
|
||||
{
|
||||
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_algorithmParameters = parameters;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Algorithm parameters updated");
|
||||
}
|
||||
|
||||
public AlgorithmParameters GetAlgorithmParameters()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _algorithmParameters;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Metrics and Monitoring
|
||||
|
||||
```csharp
|
||||
private void UpdateOmsMetrics()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var activeOrders = 0;
|
||||
var filledOrders = 0;
|
||||
var failedOrders = 0;
|
||||
var totalQuantity = 0;
|
||||
|
||||
foreach (var order in _orders.Values)
|
||||
{
|
||||
switch (order.State)
|
||||
{
|
||||
case OrderState.Submitted:
|
||||
case OrderState.Accepted:
|
||||
case OrderState.PartiallyFilled:
|
||||
activeOrders++;
|
||||
break;
|
||||
case OrderState.Filled:
|
||||
filledOrders++;
|
||||
break;
|
||||
case OrderState.Rejected:
|
||||
case OrderState.Expired:
|
||||
case OrderState.Cancelled:
|
||||
failedOrders++;
|
||||
break;
|
||||
}
|
||||
|
||||
totalQuantity += order.Quantity;
|
||||
}
|
||||
|
||||
var totalOrders = _orders.Count;
|
||||
var fillRate = totalOrders > 0 ? (double)filledOrders / totalOrders : 0.0;
|
||||
|
||||
_omsMetrics = _omsMetrics with
|
||||
{
|
||||
TotalOrders = totalOrders,
|
||||
ActiveOrders = activeOrders,
|
||||
FailedOrders = failedOrders,
|
||||
FillRate = fillRate,
|
||||
TotalValueTraded = totalQuantity, // Simplified
|
||||
LastUpdated = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public OmsMetrics GetMetrics()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _omsMetrics;
|
||||
}
|
||||
}
|
||||
|
||||
public RoutingMetrics GetRoutingMetrics()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _routingMetrics;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHealthy()
|
||||
{
|
||||
// Simple health check - in a real implementation, this would check:
|
||||
// - Connection to execution venues
|
||||
// - Risk management system availability
|
||||
// - Position sizing system availability
|
||||
// - Internal state consistency
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
## Order Status Management
|
||||
|
||||
```csharp
|
||||
public async Task<OrderStatus> GetOrderStatusAsync(string orderId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(orderId)) throw new ArgumentException("Order ID required", nameof(orderId));
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
return _orders.ContainsKey(orderId) ? _orders[orderId] : null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<OrderStatus>> GetOrdersBySymbolAsync(string symbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(symbol)) throw new ArgumentException("Symbol required", nameof(symbol));
|
||||
|
||||
var result = new List<OrderStatus>();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var order in _orders.Values)
|
||||
{
|
||||
if (order.Symbol.Equals(symbol, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Add(order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<OrderStatus>> GetActiveOrdersAsync()
|
||||
{
|
||||
var result = new List<OrderStatus>();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var order in _orders.Values)
|
||||
{
|
||||
if (order.State == OrderState.Submitted ||
|
||||
order.State == OrderState.Accepted ||
|
||||
order.State == OrderState.PartiallyFilled)
|
||||
{
|
||||
result.Add(order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling and Validation
|
||||
|
||||
The OrderManager implements comprehensive error handling:
|
||||
|
||||
1. **Input Validation**: All public methods validate their parameters
|
||||
2. **Exception Handling**: Try-catch blocks around critical operations
|
||||
3. **Logging**: Detailed logging of all operations and errors
|
||||
4. **Graceful Degradation**: When possible, the system continues operating even when some components fail
|
||||
|
||||
## Thread Safety
|
||||
|
||||
The OrderManager uses a lock-based approach to ensure thread safety:
|
||||
|
||||
1. **State Protection**: All shared state is protected by a single lock
|
||||
2. **Atomic Operations**: Complex state updates are performed atomically
|
||||
3. **Immutable Data**: Where possible, immutable data structures are used
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Risk Management
|
||||
- All orders pass through the IRiskManager.ValidateOrder method
|
||||
- Risk decisions are respected before order submission
|
||||
|
||||
### Position Sizing
|
||||
- Future enhancement could integrate with IPositionSizer for dynamic quantity adjustments
|
||||
|
||||
### Execution Venues
|
||||
- Orders are routed to configured execution venues
|
||||
- Routing decisions are based on configurable criteria
|
||||
|
||||
## Testing Considerations
|
||||
|
||||
The OrderManager is designed to be testable:
|
||||
|
||||
1. **Dependency Injection**: All dependencies are injected through the constructor
|
||||
2. **Interface-Based**: Depends on interfaces rather than concrete implementations
|
||||
3. **State Access**: Provides methods to access internal state for verification
|
||||
4. **Configuration**: All behavior can be controlled through configuration
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
1. **Lock Contention**: The single lock could become a bottleneck under high load
|
||||
2. **Memory Usage**: Order state is maintained in memory
|
||||
3. **Latency**: Order routing adds minimal latency
|
||||
4. **Scalability**: Design supports horizontal scaling through instance isolation
|
||||
Reference in New Issue
Block a user