Files
nt8-sdk/docs/architecture/routing_configuration_system.md
Billy Valentine 92f3732b3d
Some checks failed
Build and Test / build (push) Has been cancelled
Phase 0 completion: NT8 SDK core framework with risk management and position sizing
2025-09-09 17:06:37 -04:00

44 KiB

Routing Configuration System Design

Overview

This document details the implementation of the routing configuration system for the Order Management System (OMS), which allows users to configure and customize the smart order routing behavior through a flexible and extensible configuration system.

Configuration Architecture

The routing configuration system provides a hierarchical approach to configuration management:

  1. Global Configuration: System-wide default settings
  2. Venue-Specific Configuration: Settings that apply to specific execution venues
  3. Symbol-Specific Configuration: Settings that apply to specific trading symbols
  4. Strategy-Specific Configuration: Settings that apply to specific trading strategies
  5. Runtime Configuration: Dynamic configuration that can be updated during operation

Configuration Models

Base Configuration Interface

/// <summary>
/// Base interface for all configuration objects
/// </summary>
public interface IConfiguration
{
    /// <summary>
    /// Unique identifier for this configuration
    /// </summary>
    string Id { get; }
    
    /// <summary>
    /// Name of this configuration
    /// </summary>
    string Name { get; }
    
    /// <summary>
    /// Description of this configuration
    /// </summary>
    string Description { get; }
    
    /// <summary>
    /// Whether this configuration is active
    /// </summary>
    bool IsActive { get; set; }
    
    /// <summary>
    /// When this configuration was created
    /// </summary>
    DateTime CreatedAt { get; }
    
    /// <summary>
    /// When this configuration was last updated
    /// </summary>
    DateTime UpdatedAt { get; set; }
    
    /// <summary>
    /// Version of this configuration
    /// </summary>
    int Version { get; }
}

Routing Configuration Model

/// <summary>
/// Main routing configuration parameters
/// </summary>
public record RoutingConfig : IConfiguration
{
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public string Name { get; set; } = "Default Routing Configuration";
    public string Description { get; set; } = "Default routing configuration for the OMS";
    public bool IsActive { get; set; } = true;
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    public int Version { get; set; } = 1;
    
    // Core routing settings
    public bool SmartRoutingEnabled { get; set; } = true;
    public string DefaultVenue { get; set; } = "primary-broker";
    public Dictionary<string, double> VenuePreferences { get; set; } = new Dictionary<string, double>
    {
        ["primary-broker"] = 1.0,
        ["secondary-broker"] = 0.8,
        ["dark-pool"] = 0.6
    };
    
    // Routing criteria weights
    public double CostWeight { get; set; } = 0.4; // 40% weight to cost
    public double SpeedWeight { get; set; } = 0.3; // 30% weight to speed
    public double ReliabilityWeight { get; set; } = 0.3; // 30% weight to reliability
    
    // Risk controls
    public double MaxSlippagePercent { get; set; } = 0.5;
    public TimeSpan MaxRoutingTime { get; set; } = TimeSpan.FromSeconds(30);
    public bool EnableSlippageControl { get; set; } = true;
    public bool EnableTimeoutControl { get; set; } = true;
    
    // Advanced routing features
    public bool EnableTimeBasedRouting { get; set; } = true;
    public bool EnableLiquidityBasedRouting { get; set; } = true;
    public bool EnableSizeBasedRouting { get; set; } = true;
    
    // Performance thresholds
    public double MinFillRateThreshold { get; set; } = 0.95; // 95% minimum fill rate
    public double MaxLatencyThresholdMs { get; set; } = 500; // 500ms maximum latency
    public int MaxConsecutiveFailures { get; set; } = 5; // Max consecutive failures before deactivating venue
    
    // Algorithmic order routing
    public Dictionary<string, string> AlgorithmVenuePreferences { get; set; } = new Dictionary<string, string>
    {
        ["TWAP"] = "primary-broker",
        ["VWAP"] = "primary-broker",
        ["Iceberg"] = "dark-pool"
    };
    
    // Symbol-specific routing
    public Dictionary<string, string> SymbolVenuePreferences { get; set; } = new Dictionary<string, string>();
    
    // Time-based routing
    public Dictionary<TimeOfDayRange, string> TimeBasedVenuePreferences { get; set; } = new Dictionary<TimeOfDayRange, string>();
    
    public static RoutingConfig Default => new RoutingConfig();
}

Time of Day Range Model

/// <summary>
/// Represents a time range during the day
/// </summary>
public record TimeOfDayRange(
    TimeSpan StartTime,
    TimeSpan EndTime
)
{
    public bool Contains(DateTime time)
    {
        var timeOfDay = time.TimeOfDay;
        return timeOfDay >= StartTime && timeOfDay <= EndTime;
    }
    
    public bool Overlaps(TimeOfDayRange other)
    {
        return StartTime <= other.EndTime && EndTime >= other.StartTime;
    }
}

Venue Configuration Model

/// <summary>
/// Configuration for a specific execution venue
/// </summary>
public record VenueConfig : IConfiguration
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public bool IsActive { get; set; } = true;
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    public int Version { get; set; } = 1;
    
    // Venue-specific routing settings
    public double CostFactor { get; set; } = 1.0;
    public double SpeedFactor { get; set; } = 1.0;
    public double ReliabilityFactor { get; set; } = 1.0;
    
    // Venue capabilities
    public List<VenueOrderType> SupportedOrderTypes { get; set; } = new List<VenueOrderType>
    {
        VenueOrderType.Market,
        VenueOrderType.Limit,
        VenueOrderType.StopMarket,
        VenueOrderType.StopLimit
    };
    
    public List<string> SupportedSymbols { get; set; } = new List<string>();
    public Dictionary<string, decimal> MinimumOrderSizes { get; set; } = new Dictionary<string, decimal>();
    public Dictionary<string, decimal> MaximumOrderSizes { get; set; } = new Dictionary<string, decimal>();
    
    // Connection settings
    public string ApiKey { get; set; }
    public string ApiSecret { get; set; }
    public string BaseUrl { get; set; }
    public int RateLimit { get; set; } = 100; // Requests per minute
    
    // Performance settings
    public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
    public int MaxRetries { get; set; } = 3;
    public TimeSpan RetryDelay { get; set; } = TimeSpan.FromSeconds(1);
    
    // Market data settings
    public bool EnableMarketData { get; set; } = true;
    public int MarketDataDepth { get; set; } = 10; // Levels of market depth
    public TimeSpan MarketDataRefreshInterval { get; set; } = TimeSpan.FromMilliseconds(100);
}

Symbol Configuration Model

/// <summary>
/// Configuration for routing specific symbols
/// </summary>
public record SymbolRoutingConfig : IConfiguration
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public bool IsActive { get; set; } = true;
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    public int Version { get; set; } = 1;
    
    // Symbol-specific routing settings
    public string Symbol { get; set; }
    public string PreferredVenue { get; set; }
    public List<string> BackupVenues { get; set; } = new List<string>();
    
    // Symbol characteristics
    public LiquidityLevel Liquidity { get; set; } = LiquidityLevel.Medium;
    public VolatilityLevel Volatility { get; set; } = VolatilityLevel.Medium;
    public string AssetClass { get; set; } = "Equity";
    
    // Order size thresholds
    public int LargeOrderThreshold { get; set; } = 100;
    public int BlockOrderThreshold { get; set; } = 1000;
    
    // Pricing settings
    public int TickSize { get; set; } = 1; // In cents or appropriate units
    public decimal MinPriceIncrement { get; set; } = 0.01m;
    
    // Venue preferences for this symbol
    public Dictionary<string, double> VenuePreferences { get; set; } = new Dictionary<string, double>();
}

Configuration Management System

Configuration Manager

/// <summary>
/// Manages routing configuration for the OMS
/// </summary>
public class RoutingConfigurationManager
{
    private readonly ILogger<RoutingConfigurationManager> _logger;
    private readonly IConfigurationRepository _configRepository;
    private readonly Dictionary<string, IConfiguration> _configurations;
    private readonly object _lock = new object();
    
    public RoutingConfigurationManager(
        ILogger<RoutingConfigurationManager> logger,
        IConfigurationRepository configRepository)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _configRepository = configRepository ?? throw new ArgumentNullException(nameof(configRepository));
        _configurations = new Dictionary<string, IConfiguration>();
        
        // Load initial configurations
        LoadConfigurationsAsync().Wait();
    }
    
    /// <summary>
    /// Get the current routing configuration
    /// </summary>
    public async Task<RoutingConfig> GetRoutingConfigAsync()
    {
        var config = await GetConfigurationAsync<RoutingConfig>("routing-config");
        return config ?? RoutingConfig.Default;
    }
    
    /// <summary>
    /// Update the routing configuration
    /// </summary>
    public async Task UpdateRoutingConfigAsync(RoutingConfig config)
    {
        if (config == null) throw new ArgumentNullException(nameof(config));
        
        await UpdateConfigurationAsync(config);
        _logger.LogInformation("Routing configuration updated");
    }
    
    /// <summary>
    /// Get configuration for a specific venue
    /// </summary>
    public async Task<VenueConfig> GetVenueConfigAsync(string venueId)
    {
        if (string.IsNullOrEmpty(venueId)) throw new ArgumentException("Venue ID required", nameof(venueId));
        
        var config = await GetConfigurationAsync<VenueConfig>($"venue-{venueId}");
        return config;
    }
    
    /// <summary>
    /// Update configuration for a specific venue
    /// </summary>
    public async Task UpdateVenueConfigAsync(VenueConfig config)
    {
        if (config == null) throw new ArgumentNullException(nameof(config));
        if (string.IsNullOrEmpty(config.Id)) throw new ArgumentException("Venue config ID required", nameof(config));
        
        await UpdateConfigurationAsync(config);
        _logger.LogInformation("Venue configuration updated for {VenueId}", config.Id);
    }
    
    /// <summary>
    /// Get routing configuration for a specific symbol
    /// </summary>
    public async Task<SymbolRoutingConfig> GetSymbolRoutingConfigAsync(string symbol)
    {
        if (string.IsNullOrEmpty(symbol)) throw new ArgumentException("Symbol required", nameof(symbol));
        
        var config = await GetConfigurationAsync<SymbolRoutingConfig>($"symbol-{symbol}");
        return config;
    }
    
    /// <summary>
    /// Update routing configuration for a specific symbol
    /// </summary>
    public async Task UpdateSymbolRoutingConfigAsync(SymbolRoutingConfig config)
    {
        if (config == null) throw new ArgumentNullException(nameof(config));
        if (string.IsNullOrEmpty(config.Symbol)) throw new ArgumentException("Symbol required", nameof(config));
        
        var configId = $"symbol-{config.Symbol}";
        config.Id = configId;
        config.Name = $"Routing config for {config.Symbol}";
        config.Description = $"Routing configuration for symbol {config.Symbol}";
        
        await UpdateConfigurationAsync(config);
        _logger.LogInformation("Symbol routing configuration updated for {Symbol}", config.Symbol);
    }
    
    /// <summary>
    /// Get configuration by ID
    /// </summary>
    public async Task<T> GetConfigurationAsync<T>(string configId) where T : class, IConfiguration
    {
        if (string.IsNullOrEmpty(configId)) throw new ArgumentException("Config ID required", nameof(configId));
        
        lock (_lock)
        {
            if (_configurations.ContainsKey(configId))
            {
                return _configurations[configId] as T;
            }
        }
        
        // Load from repository if not in memory
        var config = await _configRepository.GetConfigurationAsync<T>(configId);
        if (config != null)
        {
            lock (_lock)
            {
                _configurations[configId] = config;
            }
        }
        
        return config;
    }
    
    /// <summary>
    /// Update a configuration
    /// </summary>
    public async Task UpdateConfigurationAsync<T>(T config) where T : class, IConfiguration
    {
        if (config == null) throw new ArgumentNullException(nameof(config));
        if (string.IsNullOrEmpty(config.Id)) throw new ArgumentException("Config ID required", nameof(config));
        
        // Validate configuration
        if (!ValidateConfiguration(config))
        {
            throw new ArgumentException("Invalid configuration", nameof(config));
        }
        
        // Increment version
        var versionProperty = typeof(T).GetProperty("Version");
        if (versionProperty != null && versionProperty.CanWrite)
        {
            var currentVersion = (int)versionProperty.GetValue(config);
            versionProperty.SetValue(config, currentVersion + 1);
        }
        
        // Update timestamp
        var updatedAtProperty = typeof(T).GetProperty("UpdatedAt");
        if (updatedAtProperty != null && updatedAtProperty.CanWrite)
        {
            updatedAtProperty.SetValue(config, DateTime.UtcNow);
        }
        
        // Save to repository
        await _configRepository.SaveConfigurationAsync(config);
        
        // Update in memory cache
        lock (_lock)
        {
            _configurations[config.Id] = config;
        }
    }
    
    /// <summary>
    /// Validate a configuration
    /// </summary>
    public bool ValidateConfiguration<T>(T config) where T : class, IConfiguration
    {
        if (config == null) return false;
        
        // Basic validation
        if (string.IsNullOrEmpty(config.Id)) return false;
        if (string.IsNullOrEmpty(config.Name)) return false;
        if (config.CreatedAt > DateTime.UtcNow) return false;
        if (config.UpdatedAt < config.CreatedAt) return false;
        if (config.Version < 1) return false;
        
        // Type-specific validation
        switch (config)
        {
            case RoutingConfig routingConfig:
                return ValidateRoutingConfig(routingConfig);
            case VenueConfig venueConfig:
                return ValidateVenueConfig(venueConfig);
            case SymbolRoutingConfig symbolConfig:
                return ValidateSymbolRoutingConfig(symbolConfig);
            default:
                return true; // Unknown config type, assume valid
        }
    }
    
    private bool ValidateRoutingConfig(RoutingConfig config)
    {
        // Validate weights sum to 1.0 (approximately)
        var totalWeight = config.CostWeight + config.SpeedWeight + config.ReliabilityWeight;
        if (Math.Abs(totalWeight - 1.0) > 0.01) return false;
        
        // Validate thresholds
        if (config.MaxSlippagePercent < 0 || config.MaxSlippagePercent > 100) return false;
        if (config.MaxRoutingTime.TotalMilliseconds <= 0) return false;
        if (config.MinFillRateThreshold < 0 || config.MinFillRateThreshold > 1) return false;
        if (config.MaxLatencyThresholdMs <= 0) return false;
        if (config.MaxConsecutiveFailures <= 0) return false;
        
        return true;
    }
    
    private bool ValidateVenueConfig(VenueConfig config)
    {
        // Validate factors are positive
        if (config.CostFactor <= 0) return false;
        if (config.SpeedFactor <= 0) return false;
        if (config.ReliabilityFactor <= 0) return false;
        
        // Validate connection settings
        if (string.IsNullOrEmpty(config.BaseUrl)) return false;
        if (config.RateLimit <= 0) return false;
        if (config.Timeout.TotalMilliseconds <= 0) return false;
        if (config.MaxRetries < 0) return false;
        
        return true;
    }
    
    private bool ValidateSymbolRoutingConfig(SymbolRoutingConfig config)
    {
        // Validate symbol
        if (string.IsNullOrEmpty(config.Symbol)) return false;
        
        // Validate thresholds
        if (config.LargeOrderThreshold <= 0) return false;
        if (config.BlockOrderThreshold <= 0) return false;
        if (config.LargeOrderThreshold > config.BlockOrderThreshold) return false;
        
        // Validate pricing settings
        if (config.TickSize <= 0) return false;
        if (config.MinPriceIncrement <= 0) return false;
        
        return true;
    }
    
    /// <summary>
    /// Load all configurations from repository
    /// </summary>
    private async Task LoadConfigurationsAsync()
    {
        try
        {
            var configs = await _configRepository.GetAllConfigurationsAsync();
            lock (_lock)
            {
                _configurations.Clear();
                foreach (var config in configs)
                {
                    _configurations[config.Id] = config;
                }
            }
            
            _logger.LogInformation("Loaded {Count} configurations", configs.Count);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error loading configurations");
            throw;
        }
    }
    
    /// <summary>
    /// Reload configurations from repository
    /// </summary>
    public async Task ReloadConfigurationsAsync()
    {
        await LoadConfigurationsAsync();
        _logger.LogInformation("Configurations reloaded");
    }
}

Configuration Repository Interface

/// <summary>
/// Repository for configuration storage and retrieval
/// </summary>
public interface IConfigurationRepository
{
    /// <summary>
    /// Get a configuration by ID
    /// </summary>
    Task<T> GetConfigurationAsync<T>(string configId) where T : class, IConfiguration;
    
    /// <summary>
    /// Save a configuration
    /// </summary>
    Task SaveConfigurationAsync<T>(T config) where T : class, IConfiguration;
    
    /// <summary>
    /// Delete a configuration
    /// </summary>
    Task DeleteConfigurationAsync(string configId);
    
    /// <summary>
    /// Get all configurations
    /// </summary>
    Task<List<IConfiguration>> GetAllConfigurationsAsync();
    
    /// <summary>
    /// Get configurations by type
    /// </summary>
    Task<List<T>> GetConfigurationsByTypeAsync<T>() where T : class, IConfiguration;
}

File-Based Configuration Repository

/// <summary>
/// File-based implementation of configuration repository
/// </summary>
public class FileConfigurationRepository : IConfigurationRepository
{
    private readonly string _configDirectory;
    private readonly ILogger<FileConfigurationRepository> _logger;
    private readonly JsonSerializerOptions _jsonOptions;
    
    public FileConfigurationRepository(
        string configDirectory,
        ILogger<FileConfigurationRepository> logger)
    {
        _configDirectory = configDirectory ?? throw new ArgumentNullException(nameof(configDirectory));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        
        // Ensure directory exists
        if (!Directory.Exists(_configDirectory))
        {
            Directory.CreateDirectory(_configDirectory);
        }
        
        _jsonOptions = new JsonSerializerOptions
        {
            WriteIndented = true,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };
    }
    
    public async Task<T> GetConfigurationAsync<T>(string configId) where T : class, IConfiguration
    {
        if (string.IsNullOrEmpty(configId)) throw new ArgumentException("Config ID required", nameof(configId));
        
        var filePath = Path.Combine(_configDirectory, $"{configId}.json");
        if (!File.Exists(filePath))
        {
            return null;
        }
        
        try
        {
            var json = await File.ReadAllTextAsync(filePath);
            return JsonSerializer.Deserialize<T>(json, _jsonOptions);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error reading configuration from {FilePath}", filePath);
            throw;
        }
    }
    
    public async Task SaveConfigurationAsync<T>(T config) where T : class, IConfiguration
    {
        if (config == null) throw new ArgumentNullException(nameof(config));
        if (string.IsNullOrEmpty(config.Id)) throw new ArgumentException("Config ID required", nameof(config));
        
        var filePath = Path.Combine(_configDirectory, $"{config.Id}.json");
        
        try
        {
            var json = JsonSerializer.Serialize(config, _jsonOptions);
            await File.WriteAllTextAsync(filePath, json);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error saving configuration to {FilePath}", filePath);
            throw;
        }
    }
    
    public async Task DeleteConfigurationAsync(string configId)
    {
        if (string.IsNullOrEmpty(configId)) throw new ArgumentException("Config ID required", nameof(configId));
        
        var filePath = Path.Combine(_configDirectory, $"{configId}.json");
        if (File.Exists(filePath))
        {
            try
            {
                File.Delete(filePath);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting configuration file {FilePath}", filePath);
                throw;
            }
        }
    }
    
    public async Task<List<IConfiguration>> GetAllConfigurationsAsync()
    {
        var configs = new List<IConfiguration>();
        
        try
        {
            var files = Directory.GetFiles(_configDirectory, "*.json");
            foreach (var file in files)
            {
                try
                {
                    var json = await File.ReadAllTextAsync(file);
                    
                    // Try to deserialize as different config types
                    // In a real implementation, you might store type information in the file
                    var config = TryDeserializeConfig(json);
                    if (config != null)
                    {
                        configs.Add(config);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Error reading configuration file {FilePath}", file);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error reading configuration directory {ConfigDirectory}", _configDirectory);
            throw;
        }
        
        return configs;
    }
    
    public async Task<List<T>> GetConfigurationsByTypeAsync<T>() where T : class, IConfiguration
    {
        var configs = new List<T>();
        
        try
        {
            var files = Directory.GetFiles(_configDirectory, "*.json");
            foreach (var file in files)
            {
                try
                {
                    var json = await File.ReadAllTextAsync(file);
                    var config = JsonSerializer.Deserialize<T>(json, _jsonOptions);
                    if (config != null)
                    {
                        configs.Add(config);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Error reading configuration file {FilePath}", file);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error reading configuration directory {ConfigDirectory}", _configDirectory);
            throw;
        }
        
        return configs;
    }
    
    private IConfiguration TryDeserializeConfig(string json)
    {
        try
        {
            // Try different configuration types
            var doc = JsonDocument.Parse(json);
            var root = doc.RootElement;
            
            if (root.TryGetProperty("costWeight", out _))
            {
                return JsonSerializer.Deserialize<RoutingConfig>(json, _jsonOptions);
            }
            else if (root.TryGetProperty("costFactor", out _))
            {
                return JsonSerializer.Deserialize<VenueConfig>(json, _jsonOptions);
            }
            else if (root.TryGetProperty("symbol", out _))
            {
                return JsonSerializer.Deserialize<SymbolRoutingConfig>(json, _jsonOptions);
            }
            
            return null;
        }
        catch
        {
            return null;
        }
    }
}

Integration with OrderManager

Configuration Integration in OrderManager

public partial class OrderManager : IOrderManager
{
    private readonly RoutingConfigurationManager _configManager;
    
    // Enhanced constructor with configuration manager
    public OrderManager(
        IRiskManager riskManager,
        IPositionSizer positionSizer,
        ILogger<OrderManager> logger,
        RoutingConfigurationManager configManager) : base(riskManager, positionSizer, logger)
    {
        _configManager = configManager ?? throw new ArgumentNullException(nameof(configManager));
        _venueManager = new VenueManager(logger);
        _omsToVenueOrderIdMap = new Dictionary<string, string>();
        _venueToOmsOrderIdMap = new Dictionary<string, string>();
        
        // Initialize with configurations
        InitializeWithConfigurationsAsync().Wait();
    }
    
    private async Task InitializeWithConfigurationsAsync()
    {
        try
        {
            // Get routing configuration
            var routingConfig = await _configManager.GetRoutingConfigAsync();
            
            // Initialize venues based on configuration
            await InitializeVenuesFromConfigAsync(routingConfig);
            
            _logger.LogInformation("OrderManager initialized with configurations");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error initializing OrderManager with configurations");
            throw;
        }
    }
    
    private async Task InitializeVenuesFromConfigAsync(RoutingConfig routingConfig)
    {
        // Get all venue configurations
        var venueConfigs = await _configManager.GetConfigurationsByTypeAsync<VenueConfig>();
        
        foreach (var venueConfig in venueConfigs)
        {
            if (!venueConfig.IsActive) continue;
            
            try
            {
                // Create venue based on configuration
                var venue = CreateVenueFromConfig(venueConfig);
                if (venue != null)
                {
                    _venueManager.AddVenue(venue);
                    _logger.LogInformation("Venue {VenueId} initialized from configuration", venueConfig.Id);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error initializing venue {VenueId} from configuration", venueConfig.Id);
            }
        }
    }
    
    private IExecutionVenue CreateVenueFromConfig(VenueConfig config)
    {
        // Create venue based on type and configuration
        // This is a simplified implementation - in reality, you would have
        // specific venue implementations for different broker/exchange APIs
        
        return new BrokerExecutionVenue(
            id: config.Id,
            name: config.Name,
            description: config.Description,
            type: VenueType.Broker,
            config: config,
            brokerApi: CreateBrokerApiFromConfig(config),
            logger: _logger
        );
    }
    
    private IBrokerApi CreateBrokerApiFromConfig(VenueConfig config)
    {
        // Create broker API client based on configuration
        // This would be specific to each broker's API
        
        return new GenericBrokerApi(
            apiKey: config.ApiKey,
            apiSecret: config.ApiSecret,
            baseUrl: config.BaseUrl,
            rateLimit: config.RateLimit,
            timeout: config.Timeout,
            maxRetries: config.MaxRetries,
            retryDelay: config.RetryDelay
        );
    }
    
    // Enhanced routing with configuration
    public async Task<RoutingResult> RouteOrderAsync(OrderRequest request, StrategyContext context)
    {
        try
        {
            // Get current routing configuration
            var routingConfig = await _configManager.GetRoutingConfigAsync();
            
            // Check if smart routing is enabled
            if (!routingConfig.SmartRoutingEnabled)
            {
                var defaultVenue = _venueManager.GetVenue(routingConfig.DefaultVenue);
                if (defaultVenue == null)
                {
                    return new RoutingResult(false, null, null, "Default venue not found", 
                        new Dictionary<string, object> { ["error"] = "Default venue not found" });
                }
                
                _logger.LogInformation("Smart routing disabled, using default venue: {Venue}", defaultVenue.Name);
                return new RoutingResult(true, null, defaultVenue, "Routing disabled, using default venue", 
                    new Dictionary<string, object> { ["venue"] = defaultVenue.Name });
            }
            
            // Get symbol-specific configuration if available
            SymbolRoutingConfig symbolConfig = null;
            if (!string.IsNullOrEmpty(request.Symbol))
            {
                symbolConfig = await _configManager.GetSymbolRoutingConfigAsync(request.Symbol);
            }
            
            // Select best venue based on configuration
            var selectedVenue = await SelectBestVenueAsync(request, context, routingConfig, symbolConfig);
            
            if (selectedVenue == null)
            {
                return new RoutingResult(false, null, null, "No suitable venue found", 
                    new Dictionary<string, object> { ["error"] = "No suitable venue found" });
            }
            
            // Validate venue is active
            if (!selectedVenue.IsActive)
            {
                return new RoutingResult(false, null, null, $"Venue {selectedVenue.Name} is not active", 
                    new Dictionary<string, object> { ["error"] = "Venue inactive" });
            }
            
            // Update routing metrics
            UpdateRoutingMetrics(selectedVenue);
            
            _logger.LogInformation("Order routed to venue: {Venue} (Cost: {Cost}, Speed: {Speed}, Reliability: {Reliability})", 
                selectedVenue.Name, selectedVenue.CostFactor, selectedVenue.SpeedFactor, selectedVenue.ReliabilityFactor);
            
            return new RoutingResult(true, null, selectedVenue, "Order routed successfully",
                new Dictionary<string, object> 
                { 
                    ["venue"] = selectedVenue.Name, 
                    ["cost_factor"] = selectedVenue.CostFactor,
                    ["speed_factor"] = selectedVenue.SpeedFactor,
                    ["reliability_factor"] = selectedVenue.ReliabilityFactor
                });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error routing order for {Symbol}", request.Symbol);
            return new RoutingResult(false, null, null, $"Error routing order: {ex.Message}", 
                new Dictionary<string, object> { ["error"] = ex.Message });
        }
    }
    
    private async Task<IExecutionVenue> SelectBestVenueAsync(
        OrderRequest request, 
        StrategyContext context, 
        RoutingConfig routingConfig, 
        SymbolRoutingConfig symbolConfig)
    {
        // Get all active venues
        var venues = _venueManager.GetActiveVenues();
        
        if (venues.Count == 0)
        {
            return null;
        }
        
        if (venues.Count == 1)
        {
            return venues[0];
        }
        
        // Apply symbol-specific venue preference if available
        if (symbolConfig != null && !string.IsNullOrEmpty(symbolConfig.PreferredVenue))
        {
            var preferredVenue = venues.FirstOrDefault(v => v.Id == symbolConfig.PreferredVenue);
            if (preferredVenue != null)
            {
                _logger.LogInformation("Using symbol-preferred venue: {Venue}", preferredVenue.Name);
                return preferredVenue;
            }
        }
        
        // Apply algorithm-specific venue preference if available
        if (!string.IsNullOrEmpty(request.Algorithm))
        {
            if (routingConfig.AlgorithmVenuePreferences.ContainsKey(request.Algorithm))
            {
                var algorithmVenue = routingConfig.AlgorithmVenuePreferences[request.Algorithm];
                var preferredVenue = venues.FirstOrDefault(v => v.Id == algorithmVenue);
                if (preferredVenue != null)
                {
                    _logger.LogInformation("Using algorithm-preferred venue: {Venue} for {Algorithm}", 
                        preferredVenue.Name, request.Algorithm);
                    return preferredVenue;
                }
            }
        }
        
        // Apply time-based routing if enabled
        if (routingConfig.EnableTimeBasedRouting)
        {
            var timeBasedVenue = SelectVenueBasedOnTime(venues, routingConfig);
            if (timeBasedVenue != null)
            {
                _logger.LogInformation("Using time-based venue: {Venue}", timeBasedVenue.Name);
                return timeBasedVenue;
            }
        }
        
        // Calculate scores for all venues
        var venueScores = new Dictionary<IExecutionVenue, double>();
        
        foreach (var venue in venues)
        {
            double score = 0;
            
            // Get venue-specific configuration
            var venueConfig = await _configManager.GetVenueConfigAsync(venue.Id);
            
            // Factor in venue preferences from routing config
            if (routingConfig.VenuePreferences.ContainsKey(venue.Id))
            {
                score += routingConfig.VenuePreferences[venue.Id] * 100;
            }
            
            // Factor in cost
            var costFactor = venueConfig?.CostFactor ?? venue.CostFactor;
            score -= costFactor * (routingConfig.CostWeight * 100);
            
            // Factor in speed
            var speedFactor = venueConfig?.SpeedFactor ?? venue.SpeedFactor;
            score += speedFactor * (routingConfig.SpeedWeight * 100);
            
            // Factor in reliability
            var reliabilityFactor = venueConfig?.ReliabilityFactor ?? venue.ReliabilityFactor;
            score += reliabilityFactor * (routingConfig.ReliabilityWeight * 100);
            
            // Adjust for order characteristics
            score = AdjustScoreForOrderCharacteristics(score, venue, request, context, routingConfig, symbolConfig);
            
            venueScores[venue] = score;
        }
        
        // Select venue with highest score
        return venueScores.OrderByDescending(kvp => kvp.Value).First().Key;
    }
    
    private double AdjustScoreForOrderCharacteristics(
        double score, 
        IExecutionVenue venue, 
        OrderRequest request, 
        StrategyContext context, 
        RoutingConfig routingConfig, 
        SymbolRoutingConfig symbolConfig)
    {
        // Adjust for order size
        if (request.Quantity > (symbolConfig?.LargeOrderThreshold ?? 100))
        {
            // Prefer venues that handle large orders well
            if (venue.Type == VenueType.DarkPool)
            {
                score += 20; // Bonus for dark pool handling of large orders
            }
            else
            {
                score -= 10; // Penalty for regular venues handling large orders
            }
        }
        
        // Adjust for algorithmic orders
        if (!string.IsNullOrEmpty(request.Algorithm))
        {
            // Some venues may be better optimized for algorithmic orders
            if (venue.Id == routingConfig.DefaultVenue)
            {
                score += 5; // Small bonus for default venue handling algorithms
            }
        }
        
        // Adjust for symbol-specific venue preferences
        if (symbolConfig?.VenuePreferences?.ContainsKey(venue.Id) == true)
        {
            score += symbolConfig.VenuePreferences[venue.Id] * 10;
        }
        
        return score;
    }
    
    private IExecutionVenue SelectVenueBasedOnTime(List<IExecutionVenue> venues, RoutingConfig routingConfig)
    {
        var currentTime = DateTime.UtcNow.TimeOfDay;
        
        // Check time-based venue preferences
        foreach (var kvp in routingConfig.TimeBasedVenuePreferences)
        {
            if (kvp.Key.Contains(DateTime.UtcNow))
            {
                var venue = venues.FirstOrDefault(v => v.Id == kvp.Value);
                if (venue != null)
                {
                    return venue;
                }
            }
        }
        
        return null;
    }
}

Configuration Validation and Monitoring

Configuration Validation

/// <summary>
/// Validates routing configurations
/// </summary>
public class RoutingConfigurationValidator
{
    private readonly ILogger<RoutingConfigurationValidator> _logger;
    
    public RoutingConfigurationValidator(ILogger<RoutingConfigurationValidator> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }
    
    public async Task<ConfigurationValidationResult> ValidateConfigurationAsync(RoutingConfig config)
    {
        var result = new ConfigurationValidationResult
        {
            IsValid = true,
            Errors = new List<string>(),
            Warnings = new List<string>()
        };
        
        if (config == null)
        {
            result.IsValid = false;
            result.Errors.Add("Configuration is null");
            return result;
        }
        
        // Validate weights
        var totalWeight = config.CostWeight + config.SpeedWeight + config.ReliabilityWeight;
        if (Math.Abs(totalWeight - 1.0) > 0.01)
        {
            result.Warnings.Add($"Routing weights do not sum to 1.0 (current sum: {totalWeight:F2})");
        }
        
        // Validate venue preferences
        foreach (var venueId in config.VenuePreferences.Keys)
        {
            if (config.VenuePreferences[venueId] < 0 || config.VenuePreferences[venueId] > 1)
            {
                result.Errors.Add($"Invalid venue preference for {venueId}: {config.VenuePreferences[venueId]} (must be between 0 and 1)");
            }
        }
        
        // Validate algorithm venue preferences
        foreach (var algorithm in config.AlgorithmVenuePreferences.Keys)
        {
            var venueId = config.AlgorithmVenuePreferences[algorithm];
            if (!config.VenuePreferences.ContainsKey(venueId))
            {
                result.Warnings.Add($"Algorithm {algorithm} prefers venue {venueId} which is not in venue preferences");
            }
        }
        
        // Validate thresholds
        if (config.MaxSlippagePercent < 0.01)
        {
            result.Warnings.Add("Max slippage percent is very low, may reject valid orders");
        }
        
        if (config.MaxRoutingTime.TotalMilliseconds < 100)
        {
            result.Warnings.Add("Max routing time is very short, may cause timeouts");
        }
        
        result.IsValid = result.Errors.Count == 0;
        return result;
    }
}

/// <summary>
/// Result of configuration validation
/// </summary>
public record ConfigurationValidationResult
{
    public bool IsValid { get; set; }
    public List<string> Errors { get; set; } = new List<string>();
    public List<string> Warnings { get; set; } = new List<string>();
}

Testing Considerations

Unit Tests for Configuration System

  1. Configuration Validation: Test validation of different configuration types
  2. Configuration Loading/Saving: Test persistence of configurations
  3. Configuration Updates: Test updating configurations with versioning
  4. Venue Selection: Test venue selection based on different configurations
  5. Symbol-Specific Routing: Test routing based on symbol configurations

Integration Tests

  1. Configuration Repository: Test file-based configuration storage
  2. Dynamic Configuration Updates: Test updating configurations at runtime
  3. Performance Impact: Test performance with large configurations
  4. Error Handling: Test error handling for invalid configurations

Performance Considerations

Configuration Caching

/// <summary>
/// Caching layer for configurations
/// </summary>
public class ConfigurationCache
{
    private readonly MemoryCache _cache;
    private readonly ILogger<ConfigurationCache> _logger;
    
    public ConfigurationCache(ILogger<ConfigurationCache> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        
        var options = new MemoryCacheOptions
        {
            SizeLimit = 1000, // Maximum number of entries
            ExpirationScanFrequency = TimeSpan.FromMinutes(5)
        };
        
        _cache = new MemoryCache(options);
    }
    
    public T Get<T>(string key) where T : class
    {
        return _cache.Get<T>(key);
    }
    
    public void Set<T>(string key, T value, TimeSpan expiration) where T : class
    {
        var cacheEntryOptions = new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = expiration,
            Size = 1
        };
        
        _cache.Set(key, value, cacheEntryOptions);
    }
    
    public void Remove(string key)
    {
        _cache.Remove(key);
    }
    
    public void Clear()
    {
        _cache.Clear();
    }
}

Monitoring and Alerting

Configuration Change Tracking

/// <summary>
/// Tracks configuration changes for monitoring and auditing
/// </summary>
public class ConfigurationChangeTracker
{
    private readonly ILogger<ConfigurationChangeTracker> _logger;
    
    public ConfigurationChangeTracker(ILogger<ConfigurationChangeTracker> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }
    
    public void TrackConfigurationChange<T>(T oldConfig, T newConfig, string userId) where T : class, IConfiguration
    {
        if (oldConfig == null || newConfig == null) return;
        
        var changes = CompareConfigurations(oldConfig, newConfig);
        if (changes.Any())
        {
            _logger.LogInformation("Configuration {ConfigId} changed by {UserId}: {Changes}", 
                newConfig.Id, userId, string.Join(", ", changes));
        }
    }
    
    private List<string> CompareConfigurations<T>(T oldConfig, T newConfig) where T : class, IConfiguration
    {
        var changes = new List<string>();
        
        // Use reflection to compare properties
        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.CanRead);
            
        foreach (var property in properties)
        {
            var oldValue = property.GetValue(oldConfig);
            var newValue = property.GetValue(newConfig);
            
            if (!Equals(oldValue, newValue))
            {
                changes.Add($"{property.Name}: {oldValue} -> {newValue}");
            }
        }
        
        return changes;
    }
}

Future Enhancements

  1. Database Configuration Storage: Store configurations in a database for enterprise deployments
  2. Configuration Versioning: Full version history and rollback capabilities
  3. Configuration Templates: Predefined configuration templates for different trading scenarios
  4. A/B Testing: Test different configurations with subsets of orders
  5. Machine Learning: Use ML to optimize configuration parameters based on performance
  6. Real-time Configuration Updates: Push configuration updates to running instances
  7. Configuration Auditing: Full audit trail of all configuration changes
  8. Multi-tenancy: Support for multiple tenants with separate configurations