# 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 { /// /// Order manager implementation with smart routing and algorithmic execution /// public class OrderManager : IOrderManager { private readonly IRiskManager _riskManager; private readonly IPositionSizer _positionSizer; private readonly ILogger _logger; private readonly object _lock = new object(); // Configuration private RoutingConfig _routingConfig; private AlgorithmParameters _algorithmParameters; // State private readonly Dictionary _orders; private readonly Dictionary _venues; private readonly RoutingMetrics _routingMetrics; private readonly OmsMetrics _omsMetrics; public OrderManager( IRiskManager riskManager, IPositionSizer positionSizer, ILogger 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(); _venues = new Dictionary(); _routingMetrics = new RoutingMetrics(new Dictionary(), 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 { ["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 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()); 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 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 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() ); // 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 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 { ["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 { ["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 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() ); // 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 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() ); 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 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() ); // 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 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> GetOrdersBySymbolAsync(string symbol) { if (string.IsNullOrEmpty(symbol)) throw new ArgumentException("Symbol required", nameof(symbol)); var result = new List(); lock (_lock) { foreach (var order in _orders.Values) { if (order.Symbol.Equals(symbol, StringComparison.OrdinalIgnoreCase)) { result.Add(order); } } } return result; } public async Task> GetActiveOrdersAsync() { var result = new List(); 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