Files
nt8-sdk/docs/architecture/unit_test_plan.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

90 KiB

Unit Test Plan for OMS Components

Overview

This document outlines a comprehensive plan for writing unit tests for all Order Management System (OMS) components, ensuring proper functionality, reliability, and maintainability of the system.

Test Strategy

Testing Principles

  1. Comprehensive Coverage: Aim for >90% code coverage for all critical components
  2. Isolation: Each test should be independent and not rely on external state
  3. Repeatability: Tests should produce consistent results across runs
  4. Speed: Tests should execute quickly to enable rapid development cycles
  5. Readability: Tests should be clear and self-documenting
  6. Maintainability: Tests should be easy to update when implementation changes

Testing Framework

  • Framework: xUnit.net
  • Mocking: Moq
  • Assertion Library: FluentAssertions
  • Test Runner: dotnet test

Test Categories

  1. Unit Tests: Test individual components in isolation
  2. Integration Tests: Test interactions between components
  3. Performance Tests: Test system performance under load
  4. Regression Tests: Ensure previously fixed bugs don't reappear

Component Test Plans

1. OrderManager Tests

Core Functionality Tests

/// <summary>
/// Tests for OrderManager core functionality
/// </summary>
public class OrderManagerTests
{
    private Mock<IRiskManager> _mockRiskManager;
    private Mock<IPositionSizer> _mockPositionSizer;
    private Mock<ILogger<OrderManager>> _mockLogger;
    private Mock<RoutingConfigurationManager> _mockConfigManager;
    private Mock<RoutingMetricsCollector> _mockMetricsCollector;
    private Mock<TwapExecutor> _mockTwapExecutor;
    private Mock<VwapExecutor> _mockVwapExecutor;
    private Mock<IcebergExecutor> _mockIcebergExecutor;
    private Mock<AlgorithmParameterProvider> _mockParameterProvider;
    private Mock<RateLimiter> _mockRateLimiter;
    private Mock<ValueLimiter> _mockValueLimiter;
    private Mock<CircuitBreaker> _mockCircuitBreaker;
    private OrderManager _orderManager;
    
    [Fact]
    public void Constructor_WithValidDependencies_ShouldInitializeSuccessfully()
    {
        // Arrange
        SetupMocks();
        
        // Act
        var orderManager = new OrderManager(
            _mockRiskManager.Object,
            _mockPositionSizer.Object,
            _mockLogger.Object,
            _mockConfigManager.Object,
            _mockMetricsCollector.Object,
            _mockTwapExecutor.Object,
            _mockVwapExecutor.Object,
            _mockIcebergExecutor.Object,
            _mockParameterProvider.Object,
            _mockRateLimiter.Object,
            _mockValueLimiter.Object,
            _mockCircuitBreaker.Object);
        
        // Assert
        orderManager.Should().NotBeNull();
    }
    
    [Fact]
    public async Task SubmitOrderAsync_WithValidMarketOrder_ShouldSubmitSuccessfully()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var request = new OrderRequest(
            Symbol: "ES",
            Side: OrderSide.Buy,
            Type: OrderType.Market,
            Quantity: 1,
            LimitPrice: null,
            StopPrice: null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var riskDecision = new RiskDecision(
            Allow: true,
            RejectReason: null,
            ModifiedIntent: null,
            RiskLevel: RiskLevel.Low,
            RiskMetrics: new Dictionary<string, object>()
        );
        
        _mockRiskManager.Setup(rm => rm.ValidateOrder(It.IsAny<StrategyIntent>(), It.IsAny<StrategyContext>(), It.IsAny<RiskConfig>()))
            .Returns(riskDecision);
        
        // Act
        var result = await _orderManager.SubmitOrderAsync(request, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Success.Should().BeTrue();
        result.OrderId.Should().NotBeNullOrEmpty();
        result.Message.Should().Contain("submitted successfully");
    }
    
    [Fact]
    public async Task SubmitOrderAsync_WithRiskRejection_ShouldRejectOrder()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var request = new OrderRequest(
            Symbol: "ES",
            Side: OrderSide.Buy,
            Type: OrderType.Market,
            Quantity: 1,
            LimitPrice: null,
            StopPrice: null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var riskDecision = new RiskDecision(
            Allow: false,
            RejectReason: "Daily loss limit exceeded",
            ModifiedIntent: null,
            RiskLevel: RiskLevel.Critical,
            RiskMetrics: new Dictionary<string, object>()
        );
        
        _mockRiskManager.Setup(rm => rm.ValidateOrder(It.IsAny<StrategyIntent>(), It.IsAny<StrategyContext>(), It.IsAny<RiskConfig>()))
            .Returns(riskDecision);
        
        // Act
        var result = await _orderManager.SubmitOrderAsync(request, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Success.Should().BeFalse();
        result.Message.Should().Contain("Risk validation failed");
        result.Message.Should().Contain("Daily loss limit exceeded");
    }
    
    [Fact]
    public async Task SubmitOrderAsync_WithInvalidParameters_ShouldReturnValidationError()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var request = new OrderRequest(
            Symbol: "", // Invalid - empty symbol
            Side: OrderSide.Buy,
            Type: OrderType.Market,
            Quantity: 0, // Invalid - zero quantity
            LimitPrice: null,
            StopPrice: null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act
        var result = await _orderManager.SubmitOrderAsync(request, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Success.Should().BeFalse();
        result.Message.Should().Contain("validation");
    }
    
    [Fact]
    public async Task CancelOrderAsync_WithValidOrderId_ShouldCancelSuccessfully()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var orderId = Guid.NewGuid().ToString();
        
        // Act
        var result = await _orderManager.CancelOrderAsync(orderId);
        
        // Assert
        result.Should().BeTrue();
        // Note: In a real implementation, we would verify the order was actually cancelled
        // This is a simplified test
    }
    
    [Fact]
    public async Task CancelOrderAsync_WithInvalidOrderId_ShouldReturnFalse()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        string orderId = null; // Invalid - null order ID
        
        // Act
        var result = await _orderManager.CancelOrderAsync(orderId);
        
        // Assert
        result.Should().BeFalse();
    }
    
    [Fact]
    public async Task GetOrderStatusAsync_WithValidOrderId_ShouldReturnStatus()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var orderId = Guid.NewGuid().ToString();
        
        // Act
        var status = await _orderManager.GetOrderStatusAsync(orderId);
        
        // Assert
        // In a real implementation, we would verify the status was retrieved correctly
        // This is a simplified test
    }
    
    [Fact]
    public async Task GetActiveOrdersAsync_ShouldReturnActiveOrders()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        // Act
        var orders = await _orderManager.GetActiveOrdersAsync();
        
        // Assert
        orders.Should().NotBeNull();
        // In a real implementation, we would verify the active orders were retrieved correctly
    }
    
    private void SetupMocks()
    {
        _mockRiskManager = new Mock<IRiskManager>();
        _mockPositionSizer = new Mock<IPositionSizer>();
        _mockLogger = new Mock<ILogger<OrderManager>>();
        _mockConfigManager = new Mock<RoutingConfigurationManager>();
        _mockMetricsCollector = new Mock<RoutingMetricsCollector>();
        _mockTwapExecutor = new Mock<TwapExecutor>();
        _mockVwapExecutor = new Mock<VwapExecutor>();
        _mockIcebergExecutor = new Mock<IcebergExecutor>();
        _mockParameterProvider = new Mock<AlgorithmParameterProvider>();
        _mockRateLimiter = new Mock<RateLimiter>();
        _mockValueLimiter = new Mock<ValueLimiter>();
        _mockCircuitBreaker = new Mock<CircuitBreaker>();
    }
    
    private OrderManager CreateOrderManager()
    {
        return new OrderManager(
            _mockRiskManager.Object,
            _mockPositionSizer.Object,
            _mockLogger.Object,
            _mockConfigManager.Object,
            _mockMetricsCollector.Object,
            _mockTwapExecutor.Object,
            _mockVwapExecutor.Object,
            _mockIcebergExecutor.Object,
            _mockParameterProvider.Object,
            _mockRateLimiter.Object,
            _mockValueLimiter.Object,
            _mockCircuitBreaker.Object);
    }
}

Algorithmic Order Tests

/// <summary>
/// Tests for OrderManager algorithmic order functionality
/// </summary>
public class OrderManagerAlgorithmicTests
{
    private Mock<IRiskManager> _mockRiskManager;
    private Mock<IPositionSizer> _mockPositionSizer;
    private Mock<ILogger<OrderManager>> _mockLogger;
    private Mock<RoutingConfigurationManager> _mockConfigManager;
    private Mock<RoutingMetricsCollector> _mockMetricsCollector;
    private Mock<TwapExecutor> _mockTwapExecutor;
    private Mock<VwapExecutor> _mockVwapExecutor;
    private Mock<IcebergExecutor> _mockIcebergExecutor;
    private Mock<AlgorithmParameterProvider> _mockParameterProvider;
    private Mock<RateLimiter> _mockRateLimiter;
    private Mock<ValueLimiter> _mockValueLimiter;
    private Mock<CircuitBreaker> _mockCircuitBreaker;
    private OrderManager _orderManager;
    
    [Fact]
    public async Task ExecuteTwapAsync_WithValidParameters_ShouldExecuteSuccessfully()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var parameters = new TwapParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 10,
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            IntervalSeconds: 60,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinSliceSize: 1,
            MaxSliceSize: null,
            AdjustForRemainingTime: true,
            CancelAtEndTime: true,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var riskDecision = new RiskDecision(
            Allow: true,
            RejectReason: null,
            ModifiedIntent: null,
            RiskLevel: RiskLevel.Low,
            RiskMetrics: new Dictionary<string, object>()
        );
        
        _mockRiskManager.Setup(rm => rm.ValidateOrder(It.IsAny<StrategyIntent>(), It.IsAny<StrategyContext>(), It.IsAny<RiskConfig>()))
            .Returns(riskDecision);
        
        var executionState = new TwapExecutionState
        {
            ExecutionId = Guid.NewGuid().ToString(),
            Parameters = parameters,
            Status = TwapExecutionStatus.Completed,
            TotalQuantity = 10,
            ExecutedQuantity = 10,
            StartTime = DateTime.UtcNow,
            EndTime = DateTime.UtcNow.AddMinutes(30),
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };
        
        _mockTwapExecutor.Setup(te => te.ExecuteTwapAsync(It.IsAny<TwapParameters>(), It.IsAny<StrategyContext>()))
            .ReturnsAsync(executionState);
        
        // Act
        var result = await _orderManager.ExecuteTwapAsync(parameters, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Success.Should().BeTrue();
        result.OrderId.Should().NotBeNullOrEmpty();
        result.Message.Should().Contain("completed successfully");
    }
    
    [Fact]
    public async Task ExecuteVwapAsync_WithValidParameters_ShouldExecuteSuccessfully()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var parameters = new VwapParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 10,
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            ParticipationRate: 0.1,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinOrderSize: 1,
            MaxOrderSize: null,
            CheckIntervalSeconds: 30,
            CancelAtEndTime: true,
            Aggressiveness: 0.5,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var riskDecision = new RiskDecision(
            Allow: true,
            RejectReason: null,
            ModifiedIntent: null,
            RiskLevel: RiskLevel.Low,
            RiskMetrics: new Dictionary<string, object>()
        );
        
        _mockRiskManager.Setup(rm => rm.ValidateOrder(It.IsAny<StrategyIntent>(), It.IsAny<StrategyContext>(), It.IsAny<RiskConfig>()))
            .Returns(riskDecision);
        
        var executionState = new VwapExecutionState
        {
            ExecutionId = Guid.NewGuid().ToString(),
            Parameters = parameters,
            Status = VwapExecutionStatus.Completed,
            TotalQuantity = 10,
            ExecutedQuantity = 10,
            StartTime = DateTime.UtcNow,
            EndTime = DateTime.UtcNow.AddMinutes(30),
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };
        
        _mockVwapExecutor.Setup(ve => ve.ExecuteVwapAsync(It.IsAny<VwapParameters>(), It.IsAny<StrategyContext>()))
            .ReturnsAsync(executionState);
        
        // Act
        var result = await _orderManager.ExecuteVwapAsync(parameters, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Success.Should().BeTrue();
        result.OrderId.Should().NotBeNullOrEmpty();
        result.Message.Should().Contain("completed successfully");
    }
    
    [Fact]
    public async Task ExecuteIcebergAsync_WithValidParameters_ShouldExecuteSuccessfully()
    {
        // Arrange
        SetupMocks();
        _orderManager = CreateOrderManager();
        
        var parameters = new IcebergParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 100,
            VisibleQuantity: 10,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            AutoReplenish: true,
            MinVisibleQuantity: 1,
            MaxVisibleQuantity: null,
            PlacementDelayMs: 1000,
            CancelAtEnd: true,
            Aggressiveness: 0.5,
            AdaptiveVisibility: false,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var riskDecision = new RiskDecision(
            Allow: true,
            RejectReason: null,
            ModifiedIntent: null,
            RiskLevel: RiskLevel.Low,
            RiskMetrics: new Dictionary<string, object>()
        );
        
        _mockRiskManager.Setup(rm => rm.ValidateOrder(It.IsAny<StrategyIntent>(), It.IsAny<StrategyContext>(), It.IsAny<RiskConfig>()))
            .Returns(riskDecision);
        
        var executionState = new IcebergExecutionState
        {
            ExecutionId = Guid.NewGuid().ToString(),
            Parameters = parameters,
            Status = IcebergExecutionStatus.Completed,
            TotalQuantity = 100,
            ExecutedQuantity = 100,
            VisibleQuantity = 10,
            StartTime = DateTime.UtcNow,
            EndTime = DateTime.UtcNow.AddMinutes(30),
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };
        
        _mockIcebergExecutor.Setup(ie => ie.ExecuteIcebergAsync(It.IsAny<IcebergParameters>(), It.IsAny<StrategyContext>()))
            .ReturnsAsync(executionState);
        
        // Act
        var result = await _orderManager.ExecuteIcebergAsync(parameters, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Success.Should().BeTrue();
        result.OrderId.Should().NotBeNullOrEmpty();
        result.Message.Should().Contain("completed successfully");
    }
    
    private void SetupMocks()
    {
        _mockRiskManager = new Mock<IRiskManager>();
        _mockPositionSizer = new Mock<IPositionSizer>();
        _mockLogger = new Mock<ILogger<OrderManager>>();
        _mockConfigManager = new Mock<RoutingConfigurationManager>();
        _mockMetricsCollector = new Mock<RoutingMetricsCollector>();
        _mockTwapExecutor = new Mock<TwapExecutor>();
        _mockVwapExecutor = new Mock<VwapExecutor>();
        _mockIcebergExecutor = new Mock<IcebergExecutor>();
        _mockParameterProvider = new Mock<AlgorithmParameterProvider>();
        _mockRateLimiter = new Mock<RateLimiter>();
        _mockValueLimiter = new Mock<ValueLimiter>();
        _mockCircuitBreaker = new Mock<CircuitBreaker>();
    }
    
    private OrderManager CreateOrderManager()
    {
        return new OrderManager(
            _mockRiskManager.Object,
            _mockPositionSizer.Object,
            _mockLogger.Object,
            _mockConfigManager.Object,
            _mockMetricsCollector.Object,
            _mockTwapExecutor.Object,
            _mockVwapExecutor.Object,
            _mockIcebergExecutor.Object,
            _mockParameterProvider.Object,
            _mockRateLimiter.Object,
            _mockValueLimiter.Object,
            _mockCircuitBreaker.Object);
    }
}

2. RiskManager Tests

Core Risk Management Tests

/// <summary>
/// Tests for RiskManager core functionality
/// </summary>
public class RiskManagerTests
{
    private Mock<ILogger<BasicRiskManager>> _mockLogger;
    private BasicRiskManager _riskManager;
    
    [Fact]
    public void Constructor_WithValidLogger_ShouldInitializeSuccessfully()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        
        // Act
        var riskManager = new BasicRiskManager(_mockLogger.Object);
        
        // Assert
        riskManager.Should().NotBeNull();
    }
    
    [Fact]
    public void ValidateOrder_WithValidIntentAndWithinLimits_ShouldAllow()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 10,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var config = new RiskConfig(
            DailyLossLimit: 1000,
            MaxTradeRisk: 200,
            MaxOpenPositions: 5,
            EmergencyFlattenEnabled: true
        );
        
        // Act
        var decision = _riskManager.ValidateOrder(intent, context, config);
        
        // Assert
        decision.Should().NotBeNull();
        decision.Allow.Should().BeTrue();
        decision.RejectReason.Should().BeNull();
        decision.RiskLevel.Should().Be(RiskLevel.Low);
    }
    
    [Fact]
    public void ValidateOrder_WithNullIntent_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        StrategyIntent intent = null;
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var config = new RiskConfig(
            DailyLossLimit: 1000,
            MaxTradeRisk: 200,
            MaxOpenPositions: 5,
            EmergencyFlattenEnabled: true
        );
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _riskManager.ValidateOrder(intent, context, config));
    }
    
    [Fact]
    public void ValidateOrder_WithNullContext_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 10,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        StrategyContext context = null;
        
        var config = new RiskConfig(
            DailyLossLimit: 1000,
            MaxTradeRisk: 200,
            MaxOpenPositions: 5,
            EmergencyFlattenEnabled: true
        );
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _riskManager.ValidateOrder(intent, context, config));
    }
    
    [Fact]
    public void ValidateOrder_WithNullConfig_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 10,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        RiskConfig config = null;
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _riskManager.ValidateOrder(intent, context, config));
    }
    
    [Fact]
    public void ValidateOrder_WithDailyLossLimitExceeded_ShouldReject()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        // Simulate daily loss exceeding limit
        _riskManager.OnPnLUpdate(-1500, -1500); // $1500 loss, exceeds $1000 limit
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 10,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var config = new RiskConfig(
            DailyLossLimit: 1000,
            MaxTradeRisk: 200,
            MaxOpenPositions: 5,
            EmergencyFlattenEnabled: true
        );
        
        // Act
        var decision = _riskManager.ValidateOrder(intent, context, config);
        
        // Assert
        decision.Should().NotBeNull();
        decision.Allow.Should().BeFalse();
        decision.RejectReason.Should().Contain("Daily loss limit breached");
        decision.RiskLevel.Should().Be(RiskLevel.Critical);
    }
    
    [Fact]
    public void OnFill_WithValidFill_ShouldUpdateRiskState()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        var fill = new OrderFill(
            OrderId: Guid.NewGuid().ToString(),
            Symbol: "ES",
            Quantity: 2,
            FillPrice: 4200,
            FillTime: DateTime.UtcNow,
            Commission: 4.50m,
            ExecutionId: Guid.NewGuid().ToString()
        );
        
        // Act
        _riskManager.OnFill(fill);
        
        // Assert
        // In a real implementation, we would verify the risk state was updated correctly
        // This is a simplified test
    }
    
    [Fact]
    public void OnPnLUpdate_WithValidPnL_ShouldUpdateRiskState()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        var netPnL = -500.0;
        var dayPnL = -500.0;
        
        // Act
        _riskManager.OnPnLUpdate(netPnL, dayPnL);
        
        // Assert
        // In a real implementation, we would verify the risk state was updated correctly
        // This is a simplified test
    }
    
    [Fact]
    public async Task EmergencyFlattenAsync_WithValidReason_ShouldFlattenPositions()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        var reason = "Manual emergency flatten";
        
        // Act
        var result = await _riskManager.EmergencyFlatten(reason);
        
        // Assert
        result.Should().BeTrue();
        // In a real implementation, we would verify positions were actually flattened
    }
    
    [Fact]
    public void GetRiskStatus_ShouldReturnCurrentRiskStatus()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicRiskManager>>();
        _riskManager = new BasicRiskManager(_mockLogger.Object);
        
        // Act
        var status = _riskManager.GetRiskStatus();
        
        // Assert
        status.Should().NotBeNull();
        status.TradingEnabled.Should().BeTrue();
        status.DailyPnL.Should().Be(0);
        status.MaxDrawdown.Should().Be(0);
    }
}

3. PositionSizer Tests

Core Position Sizing Tests

/// <summary>
/// Tests for PositionSizer core functionality
/// </summary>
public class PositionSizerTests
{
    private Mock<ILogger<BasicPositionSizer>> _mockLogger;
    private BasicPositionSizer _positionSizer;
    
    [Fact]
    public void Constructor_WithValidLogger_ShouldInitializeSuccessfully()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicPositionSizer>>();
        
        // Act
        var positionSizer = new BasicPositionSizer(_mockLogger.Object);
        
        // Assert
        positionSizer.Should().NotBeNull();
    }
    
    [Fact]
    public void CalculateSize_WithFixedContractsMethod_ShouldReturnCorrectSize()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicPositionSizer>>();
        _positionSizer = new BasicPositionSizer(_mockLogger.Object);
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 8,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var config = new SizingConfig(
            Method: SizingMethod.FixedContracts,
            MinContracts: 1,
            MaxContracts: 10,
            RiskPerTrade: 200,
            MethodParameters: new Dictionary<string, object> { ["contracts"] = 3 }
        );
        
        // Act
        var result = _positionSizer.CalculateSize(intent, context, config);
        
        // Assert
        result.Should().NotBeNull();
        result.Contracts.Should().Be(3);
        result.Method.Should().Be(SizingMethod.FixedContracts);
        result.RiskAmount.Should().Be(300.0); // 3 contracts * 8 ticks * $12.50
        result.Calculations.Should().ContainKey("target_contracts");
        result.Calculations.Should().ContainKey("clamped_contracts");
    }
    
    [Fact]
    public void CalculateSize_WithFixedDollarRiskMethod_ShouldReturnCorrectSize()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicPositionSizer>>();
        _positionSizer = new BasicPositionSizer(_mockLogger.Object);
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 10,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var config = new SizingConfig(
            Method: SizingMethod.FixedDollarRisk,
            MinContracts: 1,
            MaxContracts: 10,
            RiskPerTrade: 250.0, // Target $250 risk
            MethodParameters: new Dictionary<string, object>()
        );
        
        // Act
        var result = _positionSizer.CalculateSize(intent, context, config);
        
        // Assert
        result.Should().NotBeNull();
        result.Contracts.Should().Be(2); // $250 / (10 ticks * $12.50) = 2 contracts
        result.Method.Should().Be(SizingMethod.FixedDollarRisk);
        result.RiskAmount.Should().Be(250.0); // 2 * 10 * $12.50
        result.Calculations.Should().ContainKey("target_risk");
        result.Calculations.Should().ContainKey("optimal_contracts");
        result.Calculations.Should().ContainKey("actual_risk");
    }
    
    [Fact]
    public void CalculateSize_WithNullIntent_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicPositionSizer>>();
        _positionSizer = new BasicPositionSizer(_mockLogger.Object);
        
        StrategyIntent intent = null;
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var config = new SizingConfig(
            Method: SizingMethod.FixedContracts,
            MinContracts: 1,
            MaxContracts: 10,
            RiskPerTrade: 200,
            MethodParameters: new Dictionary<string, object> { ["contracts"] = 3 }
        );
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _positionSizer.CalculateSize(intent, context, config));
    }
    
    [Fact]
    public void CalculateSize_WithNullContext_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicPositionSizer>>();
        _positionSizer = new BasicPositionSizer(_mockLogger.Object);
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 8,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        StrategyContext context = null;
        
        var config = new SizingConfig(
            Method: SizingMethod.FixedContracts,
            MinContracts: 1,
            MaxContracts: 10,
            RiskPerTrade: 200,
            MethodParameters: new Dictionary<string, object> { ["contracts"] = 3 }
        );
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _positionSizer.CalculateSize(intent, context, config));
    }
    
    [Fact]
    public void CalculateSize_WithNullConfig_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicPositionSizer>>();
        _positionSizer = new BasicPositionSizer(_mockLogger.Object);
        
        var intent = new StrategyIntent(
            Symbol: "ES",
            Side: OrderSide.Buy,
            EntryType: OrderType.Market,
            LimitPrice: null,
            StopTicks: 8,
            TargetTicks: null,
            Confidence: 1.0,
            Reason: "Test order",
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        SizingConfig config = null;
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _positionSizer.CalculateSize(intent, context, config));
    }
    
    [Fact]
    public void GetMetadata_ShouldReturnCorrectMetadata()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<BasicPositionSizer>>();
        _positionSizer = new BasicPositionSizer(_mockLogger.Object);
        
        // Act
        var metadata = _positionSizer.GetMetadata();
        
        // Assert
        metadata.Should().NotBeNull();
        metadata.Name.Should().Be("Basic Position Sizer");
        metadata.Description.Should().Contain("Fixed contracts");
        metadata.Description.Should().Contain("fixed dollar risk");
        metadata.RequiredParameters.Should().Contain("method");
        metadata.RequiredParameters.Should().Contain("risk_per_trade");
    }
    
    [Fact]
    public void ValidateConfig_WithValidConfig_ShouldReturnTrue()
    {
        // Arrange
        var config = new SizingConfig(
            Method: SizingMethod.FixedContracts,
            MinContracts: 1,
            MaxContracts: 10,
            RiskPerTrade: 200,
            MethodParameters: new Dictionary<string, object> { ["contracts"] = 2 }
        );
        
        // Act
        var isValid = BasicPositionSizer.ValidateConfig(config, out var errors);
        
        // Assert
        isValid.Should().BeTrue();
        errors.Should().BeEmpty();
    }
    
    [Fact]
    public void ValidateConfig_WithInvalidConfig_ShouldReturnFalse()
    {
        // Arrange
        var config = new SizingConfig(
            Method: SizingMethod.FixedContracts,
            MinContracts: 5,
            MaxContracts: 2, // Invalid: min > max
            RiskPerTrade: -100, // Invalid: negative risk
            MethodParameters: new Dictionary<string, object>() // Missing required parameter
        );
        
        // Act
        var isValid = BasicPositionSizer.ValidateConfig(config, out var errors);
        
        // Assert
        isValid.Should().BeFalse();
        errors.Should().Contain("MinContracts must be <= MaxContracts");
        errors.Should().Contain("RiskPerTrade must be > 0");
        errors.Should().Contain("FixedContracts method requires 'contracts' parameter");
    }
}

4. TWAP Algorithm Tests

TWAP Execution Tests

/// <summary>
/// Tests for TWAP algorithm execution
/// </summary>
public class TwapExecutorTests
{
    private Mock<ILogger<TwapExecutor>> _mockLogger;
    private Mock<IOrderManager> _mockOrderManager;
    private Mock<IMarketDataProvider> _mockMarketDataProvider;
    private TwapExecutor _twapExecutor;
    
    [Fact]
    public void Constructor_WithValidDependencies_ShouldInitializeSuccessfully()
    {
        // Arrange
        SetupMocks();
        
        // Act
        var twapExecutor = new TwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        // Assert
        twapExecutor.Should().NotBeNull();
    }
    
    [Fact]
    public async Task ExecuteTwapAsync_WithValidParameters_ShouldExecuteSuccessfully()
    {
        // Arrange
        SetupMocks();
        _twapExecutor = new TwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new TwapParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 100,
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            IntervalSeconds: 60,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinSliceSize: 1,
            MaxSliceSize: null,
            AdjustForRemainingTime: true,
            CancelAtEndTime: true,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var orderResult = new OrderResult(
            Success: true,
            OrderId: Guid.NewGuid().ToString(),
            Message: "Order submitted successfully",
            Status: new OrderStatus(
                OrderId: Guid.NewGuid().ToString(),
                Symbol: "ES",
                Side: OrderSide.Buy,
                Type: OrderType.Market,
                Quantity: 10,
                FilledQuantity: 10,
                LimitPrice: null,
                StopPrice: null,
                State: OrderState.Filled,
                CreatedTime: DateTime.UtcNow,
                FilledTime: DateTime.UtcNow,
                Fills: new List<OrderFill>
                {
                    new OrderFill(
                        OrderId: Guid.NewGuid().ToString(),
                        Symbol: "ES",
                        Quantity: 10,
                        FillPrice: 4200,
                        FillTime: DateTime.UtcNow,
                        Commission: 4.50m,
                        ExecutionId: Guid.NewGuid().ToString()
                    )
                }
            )
        );
        
        _mockOrderManager.Setup(om => om.SubmitOrderAsync(It.IsAny<OrderRequest>(), It.IsAny<StrategyContext>()))
            .ReturnsAsync(orderResult);
        
        // Act
        var executionState = await _twapExecutor.ExecuteTwapAsync(parameters, context);
        
        // Assert
        executionState.Should().NotBeNull();
        executionState.Status.Should().Be(TwapExecutionStatus.Running); // Initially running
        executionState.TotalQuantity.Should().Be(100);
        executionState.ExecutedQuantity.Should().Be(0); // Initially 0
        executionState.Parameters.Should().BeEquivalentTo(parameters);
    }
    
    [Fact]
    public async Task ExecuteTwapAsync_WithInvalidParameters_ShouldThrowArgumentException()
    {
        // Arrange
        SetupMocks();
        _twapExecutor = new TwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new TwapParameters(
            Symbol: "", // Invalid - empty symbol
            Side: OrderSide.Buy,
            TotalQuantity: 0, // Invalid - zero quantity
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            IntervalSeconds: 60,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinSliceSize: 1,
            MaxSliceSize: null,
            AdjustForRemainingTime: true,
            CancelAtEndTime: true,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() => _twapExecutor.ExecuteTwapAsync(parameters, context));
    }
    
    [Fact]
    public async Task ExecuteTwapAsync_WithNullParameters_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _twapExecutor = new TwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        TwapParameters parameters = null;
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _twapExecutor.ExecuteTwapAsync(parameters, context));
    }
    
    [Fact]
    public async Task ExecuteTwapAsync_WithNullContext_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _twapExecutor = new TwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new TwapParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 100,
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            IntervalSeconds: 60,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinSliceSize: 1,
            MaxSliceSize: null,
            AdjustForRemainingTime: true,
            CancelAtEndTime: true,
            Metadata: new Dictionary<string, object>()
        );
        
        StrategyContext context = null;
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _twapExecutor.ExecuteTwapAsync(parameters, context));
    }
    
    [Fact]
    public async Task CancelExecutionAsync_WithValidExecutionId_ShouldCancelSuccessfully()
    {
        // Arrange
        SetupMocks();
        _twapExecutor = new TwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var executionId = Guid.NewGuid().ToString();
        
        // Act
        var result = await _twapExecutor.CancelExecutionAsync(executionId);
        
        // Assert
        result.Should().BeFalse(); // False because execution doesn't exist
        // In a real implementation, we would test cancelling an actual execution
    }
    
    [Fact]
    public async Task CancelExecutionAsync_WithInvalidExecutionId_ShouldReturnFalse()
    {
        // Arrange
        SetupMocks();
        _twapExecutor = new TwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        string executionId = null; // Invalid - null execution ID
        
        // Act
        var result = await _twapExecutor.CancelExecutionAsync(executionId);
        
        // Assert
        result.Should().BeFalse(); // False because execution ID is invalid
    }
    
    private void SetupMocks()
    {
        _mockLogger = new Mock<ILogger<TwapExecutor>>();
        _mockOrderManager = new Mock<IOrderManager>();
        _mockMarketDataProvider = new Mock<IMarketDataProvider>();
    }
}

5. VWAP Algorithm Tests

VWAP Execution Tests

/// <summary>
/// Tests for VWAP algorithm execution
/// </summary>
public class VwapExecutorTests
{
    private Mock<ILogger<VwapExecutor>> _mockLogger;
    private Mock<IOrderManager> _mockOrderManager;
    private Mock<IMarketDataProvider> _mockMarketDataProvider;
    private VwapExecutor _vwapExecutor;
    
    [Fact]
    public void Constructor_WithValidDependencies_ShouldInitializeSuccessfully()
    {
        // Arrange
        SetupMocks();
        
        // Act
        var vwapExecutor = new VwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        // Assert
        vwapExecutor.Should().NotBeNull();
    }
    
    [Fact]
    public async Task ExecuteVwapAsync_WithValidParameters_ShouldExecuteSuccessfully()
    {
        // Arrange
        SetupMocks();
        _vwapExecutor = new VwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new VwapParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 100,
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            ParticipationRate: 0.1,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinOrderSize: 1,
            MaxOrderSize: null,
            CheckIntervalSeconds: 30,
            CancelAtEndTime: true,
            Aggressiveness: 0.5,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var orderResult = new OrderResult(
            Success: true,
            OrderId: Guid.NewGuid().ToString(),
            Message: "Order submitted successfully",
            Status: new OrderStatus(
                OrderId: Guid.NewGuid().ToString(),
                Symbol: "ES",
                Side: OrderSide.Buy,
                Type: OrderType.Market,
                Quantity: 10,
                FilledQuantity: 10,
                LimitPrice: null,
                StopPrice: null,
                State: OrderState.Filled,
                CreatedTime: DateTime.UtcNow,
                FilledTime: DateTime.UtcNow,
                Fills: new List<OrderFill>
                {
                    new OrderFill(
                        OrderId: Guid.NewGuid().ToString(),
                        Symbol: "ES",
                        Quantity: 10,
                        FillPrice: 4200,
                        FillTime: DateTime.UtcNow,
                        Commission: 4.50m,
                        ExecutionId: Guid.NewGuid().ToString()
                    )
                }
            )
        );
        
        _mockOrderManager.Setup(om => om.SubmitOrderAsync(It.IsAny<OrderRequest>(), It.IsAny<StrategyContext>()))
            .ReturnsAsync(orderResult);
        
        // Act
        var executionState = await _vwapExecutor.ExecuteVwapAsync(parameters, context);
        
        // Assert
        executionState.Should().NotBeNull();
        executionState.Status.Should().Be(VwapExecutionStatus.Running); // Initially running
        executionState.TotalQuantity.Should().Be(100);
        executionState.ExecutedQuantity.Should().Be(0); // Initially 0
        executionState.Parameters.Should().BeEquivalentTo(parameters);
    }
    
    [Fact]
    public async Task ExecuteVwapAsync_WithInvalidParameters_ShouldThrowArgumentException()
    {
        // Arrange
        SetupMocks();
        _vwapExecutor = new VwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new VwapParameters(
            Symbol: "", // Invalid - empty symbol
            Side: OrderSide.Buy,
            TotalQuantity: 0, // Invalid - zero quantity
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            ParticipationRate: 0.1,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinOrderSize: 1,
            MaxOrderSize: null,
            CheckIntervalSeconds: 30,
            CancelAtEndTime: true,
            Aggressiveness: 0.5,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() => _vwapExecutor.ExecuteVwapAsync(parameters, context));
    }
    
    [Fact]
    public async Task ExecuteVwapAsync_WithNullParameters_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _vwapExecutor = new VwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        VwapParameters parameters = null;
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _vwapExecutor.ExecuteVwapAsync(parameters, context));
    }
    
    [Fact]
    public async Task ExecuteVwapAsync_WithNullContext_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _vwapExecutor = new VwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new VwapParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 100,
            StartTime: DateTime.UtcNow,
            EndTime: DateTime.UtcNow.AddMinutes(30),
            ParticipationRate: 0.1,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            MinOrderSize: 1,
            MaxOrderSize: null,
            CheckIntervalSeconds: 30,
            CancelAtEndTime: true,
            Aggressiveness: 0.5,
            Metadata: new Dictionary<string, object>()
        );
        
        StrategyContext context = null;
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _vwapExecutor.ExecuteVwapAsync(parameters, context));
    }
    
    [Fact]
    public async Task CancelExecutionAsync_WithValidExecutionId_ShouldCancelSuccessfully()
    {
        // Arrange
        SetupMocks();
        _vwapExecutor = new VwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var executionId = Guid.NewGuid().ToString();
        
        // Act
        var result = await _vwapExecutor.CancelExecutionAsync(executionId);
        
        // Assert
        result.Should().BeFalse(); // False because execution doesn't exist
        // In a real implementation, we would test cancelling an actual execution
    }
    
    [Fact]
    public async Task CancelExecutionAsync_WithInvalidExecutionId_ShouldReturnFalse()
    {
        // Arrange
        SetupMocks();
        _vwapExecutor = new VwapExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        string executionId = null; // Invalid - null execution ID
        
        // Act
        var result = await _vwapExecutor.CancelExecutionAsync(executionId);
        
        // Assert
        result.Should().BeFalse(); // False because execution ID is invalid
    }
    
    private void SetupMocks()
    {
        _mockLogger = new Mock<ILogger<VwapExecutor>>();
        _mockOrderManager = new Mock<IOrderManager>();
        _mockMarketDataProvider = new Mock<IMarketDataProvider>();
    }
}

6. Iceberg Algorithm Tests

Iceberg Execution Tests

/// <summary>
/// Tests for Iceberg algorithm execution
/// </summary>
public class IcebergExecutorTests
{
    private Mock<ILogger<IcebergExecutor>> _mockLogger;
    private Mock<IOrderManager> _mockOrderManager;
    private Mock<IMarketDataProvider> _mockMarketDataProvider;
    private IcebergExecutor _icebergExecutor;
    
    [Fact]
    public void Constructor_WithValidDependencies_ShouldInitializeSuccessfully()
    {
        // Arrange
        SetupMocks();
        
        // Act
        var icebergExecutor = new IcebergExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        // Assert
        icebergExecutor.Should().NotBeNull();
    }
    
    [Fact]
    public async Task ExecuteIcebergAsync_WithValidParameters_ShouldExecuteSuccessfully()
    {
        // Arrange
        SetupMocks();
        _icebergExecutor = new IcebergExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new IcebergParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 100,
            VisibleQuantity: 10,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            AutoReplenish: true,
            MinVisibleQuantity: 1,
            MaxVisibleQuantity: null,
            PlacementDelayMs: 1000,
            CancelAtEnd: true,
            Aggressiveness: 0.5,
            AdaptiveVisibility: false,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        var orderResult = new OrderResult(
            Success: true,
            OrderId: Guid.NewGuid().ToString(),
            Message: "Order submitted successfully",
            Status: new OrderStatus(
                OrderId: Guid.NewGuid().ToString(),
                Symbol: "ES",
                Side: OrderSide.Buy,
                Type: OrderType.Market,
                Quantity: 10,
                FilledQuantity: 10,
                LimitPrice: null,
                StopPrice: null,
                State: OrderState.Filled,
                CreatedTime: DateTime.UtcNow,
                FilledTime: DateTime.UtcNow,
                Fills: new List<OrderFill>
                {
                    new OrderFill(
                        OrderId: Guid.NewGuid().ToString(),
                        Symbol: "ES",
                        Quantity: 10,
                        FillPrice: 4200,
                        FillTime: DateTime.UtcNow,
                        Commission: 4.50m,
                        ExecutionId: Guid.NewGuid().ToString()
                    )
                }
            )
        );
        
        _mockOrderManager.Setup(om => om.SubmitOrderAsync(It.IsAny<OrderRequest>(), It.IsAny<StrategyContext>()))
            .ReturnsAsync(orderResult);
        
        // Act
        var executionState = await _icebergExecutor.ExecuteIcebergAsync(parameters, context);
        
        // Assert
        executionState.Should().NotBeNull();
        executionState.Status.Should().Be(IcebergExecutionStatus.Running); // Initially running
        executionState.TotalQuantity.Should().Be(100);
        executionState.ExecutedQuantity.Should().Be(0); // Initially 0
        executionState.VisibleQuantity.Should().Be(10);
        executionState.Parameters.Should().BeEquivalentTo(parameters);
    }
    
    [Fact]
    public async Task ExecuteIcebergAsync_WithInvalidParameters_ShouldThrowArgumentException()
    {
        // Arrange
        SetupMocks();
        _icebergExecutor = new IcebergExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new IcebergParameters(
            Symbol: "", // Invalid - empty symbol
            Side: OrderSide.Buy,
            TotalQuantity: 0, // Invalid - zero quantity
            VisibleQuantity: 0, // Invalid - zero visible quantity
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            AutoReplenish: true,
            MinVisibleQuantity: 1,
            MaxVisibleQuantity: null,
            PlacementDelayMs: 1000,
            CancelAtEnd: true,
            Aggressiveness: 0.5,
            AdaptiveVisibility: false,
            Metadata: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(() => _icebergExecutor.ExecuteIcebergAsync(parameters, context));
    }
    
    [Fact]
    public async Task ExecuteIcebergAsync_WithNullParameters_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _icebergExecutor = new IcebergExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        IcebergParameters parameters = null;
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _icebergExecutor.ExecuteIcebergAsync(parameters, context));
    }
    
    [Fact]
    public async Task ExecuteIcebergAsync_WithNullContext_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _icebergExecutor = new IcebergExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var parameters = new IcebergParameters(
            Symbol: "ES",
            Side: OrderSide.Buy,
            TotalQuantity: 100,
            VisibleQuantity: 10,
            LimitPrice: null,
            TimeInForce: TimeInForce.Day,
            AutoReplenish: true,
            MinVisibleQuantity: 1,
            MaxVisibleQuantity: null,
            PlacementDelayMs: 1000,
            CancelAtEnd: true,
            Aggressiveness: 0.5,
            AdaptiveVisibility: false,
            Metadata: new Dictionary<string, object>()
        );
        
        StrategyContext context = null;
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _icebergExecutor.ExecuteIcebergAsync(parameters, context));
    }
    
    [Fact]
    public async Task CancelExecutionAsync_WithValidExecutionId_ShouldCancelSuccessfully()
    {
        // Arrange
        SetupMocks();
        _icebergExecutor = new IcebergExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        var executionId = Guid.NewGuid().ToString();
        
        // Act
        var result = await _icebergExecutor.CancelExecutionAsync(executionId);
        
        // Assert
        result.Should().BeFalse(); // False because execution doesn't exist
        // In a real implementation, we would test cancelling an actual execution
    }
    
    [Fact]
    public async Task CancelExecutionAsync_WithInvalidExecutionId_ShouldReturnFalse()
    {
        // Arrange
        SetupMocks();
        _icebergExecutor = new IcebergExecutor(
            _mockLogger.Object,
            _mockOrderManager.Object,
            _mockMarketDataProvider.Object);
        
        string executionId = null; // Invalid - null execution ID
        
        // Act
        var result = await _icebergExecutor.CancelExecutionAsync(executionId);
        
        // Assert
        result.Should().BeFalse(); // False because execution ID is invalid
    }
    
    private void SetupMocks()
    {
        _mockLogger = new Mock<ILogger<IcebergExecutor>>();
        _mockOrderManager = new Mock<IOrderManager>();
        _mockMarketDataProvider = new Mock<IMarketDataProvider>();
    }
}

7. Rate Limiter Tests

Rate Limiting Tests

/// <summary>
/// Tests for RateLimiter functionality
/// </summary>
public class RateLimiterTests
{
    private Mock<ILogger<RateLimiter>> _mockLogger;
    private RateLimiter _rateLimiter;
    
    [Fact]
    public void Constructor_WithValidLogger_ShouldInitializeSuccessfully()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        
        // Act
        var rateLimiter = new RateLimiter(_mockLogger.Object);
        
        // Assert
        rateLimiter.Should().NotBeNull();
    }
    
    [Fact]
    public void CheckRateLimit_WithValidOrderAndWithinLimits_ShouldAllow()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        _rateLimiter = new RateLimiter(_mockLogger.Object);
        
        var order = new OrderRequest(
            Symbol: "ES",
            Side: OrderSide.Buy,
            Type: OrderType.Market,
            Quantity: 1,
            LimitPrice: null,
            StopPrice: null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act
        var result = _rateLimiter.CheckRateLimit(order, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Action.Should().Be(RateLimitAction.Allow);
        result.Violations.Should().BeEmpty();
    }
    
    [Fact]
    public void CheckRateLimit_WithNullOrder_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        _rateLimiter = new RateLimiter(_mockLogger.Object);
        
        OrderRequest order = null;
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _rateLimiter.CheckRateLimit(order, context));
    }
    
    [Fact]
    public void CheckRateLimit_WithNullContext_ShouldThrowArgumentNullException()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        _rateLimiter = new RateLimiter(_mockLogger.Object);
        
        var order = new OrderRequest(
            Symbol: "ES",
            Side: OrderSide.Buy,
            Type: OrderType.Market,
            Quantity: 1,
            LimitPrice: null,
            StopPrice: null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
        
        StrategyContext context = null;
        
        // Act & Assert
        Assert.Throws<ArgumentNullException>(() => _rateLimiter.CheckRateLimit(order, context));
    }
    
    [Fact]
    public void GetMetrics_ShouldReturnCurrentMetrics()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        _rateLimiter = new RateLimiter(_mockLogger.Object);
        
        // Act
        var metrics = _rateLimiter.GetMetrics();
        
        // Assert
        metrics.Should().NotBeNull();
        metrics.GlobalPerSecondRate.Should().BeGreaterOrEqualTo(0);
        metrics.GlobalPerMinuteRate.Should().BeGreaterOrEqualTo(0);
        metrics.GlobalPerHourRate.Should().BeGreaterOrEqualTo(0);
    }
    
    [Fact]
    public void ResetUserState_WithValidUserId_ShouldResetUserState()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        _rateLimiter = new RateLimiter(_mockLogger.Object);
        
        var userId = "test-user";
        
        // Act
        _rateLimiter.ResetUserState(userId);
        
        // Assert
        // In a real implementation, we would verify the user state was reset
        // This is a simplified test
    }
    
    [Fact]
    public void ResetSymbolState_WithValidSymbol_ShouldResetSymbolState()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        _rateLimiter = new RateLimiter(_mockLogger.Object);
        
        var symbol = "ES";
        
        // Act
        _rateLimiter.ResetSymbolState(symbol);
        
        // Assert
        // In a real implementation, we would verify the symbol state was reset
        // This is a simplified test
    }
    
    [Fact]
    public void ResetAllState_ShouldResetAllState()
    {
        // Arrange
        _mockLogger = new Mock<ILogger<RateLimiter>>();
        _rateLimiter = new RateLimiter(_mockLogger.Object);
        
        // Act
        _rateLimiter.ResetAllState();
        
        // Assert
        // In a real implementation, we would verify all state was reset
        // This is a simplified test
    }
}

8. Value Limiter Tests

Value Limiting Tests

/// <summary>
/// Tests for ValueLimiter functionality
/// </summary>
public class ValueLimiterTests
{
    private Mock<ILogger<ValueLimiter>> _mockLogger;
    private Mock<ICurrencyConverter> _mockCurrencyConverter;
    private ValueLimiter _valueLimiter;
    
    [Fact]
    public void Constructor_WithValidDependencies_ShouldInitializeSuccessfully()
    {
        // Arrange
        SetupMocks();
        
        // Act
        var valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        // Assert
        valueLimiter.Should().NotBeNull();
    }
    
    [Fact]
    public async Task CheckValueLimitAsync_WithValidOrderAndWithinLimits_ShouldAllow()
    {
        // Arrange
        SetupMocks();
        _valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        var order = new OrderRequest(
            Symbol: "ES",
            Side: OrderSide.Buy,
            Type: OrderType.Market,
            Quantity: 1,
            LimitPrice: null,
            StopPrice: null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
        
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act
        var result = await _valueLimiter.CheckValueLimitAsync(order, context);
        
        // Assert
        result.Should().NotBeNull();
        result.Action.Should().Be(ValueLimitAction.Allow);
        result.Violations.Should().BeEmpty();
    }
    
    [Fact]
    public async Task CheckValueLimitAsync_WithNullOrder_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        OrderRequest order = null;
        var context = new StrategyContext(
            Symbol: "ES",
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _valueLimiter.CheckValueLimitAsync(order, context));
    }
    
    [Fact]
    public async Task CheckValueLimitAsync_WithNullContext_ShouldThrowArgumentNullException()
    {
        // Arrange
        SetupMocks();
        _valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        var order = new OrderRequest(
            Symbol: "ES",
            Side: OrderSide.Buy,
            Type: OrderType.Market,
            Quantity: 1,
            LimitPrice: null,
            StopPrice: null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
        
        StrategyContext context = null;
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentNullException>(() => _valueLimiter.CheckValueLimitAsync(order, context));
    }
    
    [Fact]
    public void GetMetrics_ShouldReturnCurrentMetrics()
    {
        // Arrange
        SetupMocks();
        _valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        // Act
        var metrics = _valueLimiter.GetMetrics();
        
        // Assert
        metrics.Should().NotBeNull();
        metrics.GlobalTotalValueToday.Should().BeGreaterOrEqualTo(0);
        metrics.GlobalAverageOrderValue.Should().BeGreaterOrEqualTo(0);
        metrics.GlobalMaxOrderValue.Should().BeGreaterOrEqualTo(0);
    }
    
    [Fact]
    public void ResetUserState_WithValidUserId_ShouldResetUserState()
    {
        // Arrange
        SetupMocks();
        _valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        var userId = "test-user";
        
        // Act
        _valueLimiter.ResetUserState(userId);
        
        // Assert
        // In a real implementation, we would verify the user state was reset
        // This is a simplified test
    }
    
    [Fact]
    public void ResetSymbolState_WithValidSymbol_ShouldResetSymbolState()
    {
        // Arrange
        SetupMocks();
        _valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        var symbol = "ES";
        
        // Act
        _valueLimiter.ResetSymbolState(symbol);
        
        // Assert
        // In a real implementation, we would verify the symbol state was reset
        // This is a simplified test
    }
    
    [Fact]
    public void ResetAllState_ShouldResetAllState()
    {
        // Arrange
        SetupMocks();
        _valueLimiter = new ValueLimiter(
            _mockLogger.Object,
            _mockCurrencyConverter.Object);
        
        // Act
        _valueLimiter.ResetAllState();
        
        // Assert
        // In a real implementation, we would verify all state was reset
        // This is a simplified test
    }
    
    private void SetupMocks()
    {
        _mockLogger = new Mock<ILogger<ValueLimiter>>();
        _mockCurrencyConverter = new Mock<ICurrencyConverter>();
    }
}

9. Circuit Breaker Tests

Circuit Breaking Tests

/// <summary>
/// Tests for CircuitBreaker functionality
/// </summary>
public class CircuitBreakerTests
{
    private Mock<ILogger<CircuitBreaker>> _mockLogger;
    private Mock<IHealthChecker> _mockHealthChecker;
    private CircuitBreaker _circuitBreaker;
    
    [Fact]
    public void Constructor_WithValidDependencies_ShouldInitializeSuccessfully()
    {
        // Arrange
        SetupMocks();
        
        // Act
        var circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object);
        
        // Assert
        circuitBreaker.Should().NotBeNull();
    }
    
    [Fact]
    public void CheckCircuit_WhenClosed_ShouldAllow()
    {
        // Arrange
        SetupMocks();
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object);
        
        // Act
        var result = _circuitBreaker.CheckCircuit();
        
        // Assert
        result.Should().NotBeNull();
        result.Action.Should().Be(CircuitBreakerAction.Allow);
        result.State.Should().Be(CircuitBreakerState.Closed);
    }
    
    [Fact]
    public void CheckCircuit_WhenOpen_ShouldReject()
    {
        // Arrange
        SetupMocks();
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object);
        
        // Manually open circuit
        _circuitBreaker.OpenCircuit("Test open");
        
        // Act
        var result = _circuitBreaker.CheckCircuit();
        
        // Assert
        result.Should().NotBeNull();
        result.Action.Should().Be(CircuitBreakerAction.Reject);
        result.State.Should().Be(CircuitBreakerState.Open);
    }
    
    [Fact]
    public void RecordFailure_WhenThresholdExceeded_ShouldOpenCircuit()
    {
        // Arrange
        SetupMocks();
        var config = new CircuitBreakerConfig
        {
            FailureThreshold = 2,
            TimeoutSeconds = 60,
            WindowSizeSeconds = 300
        };
        
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object,
            config);
        
        var failure1 = new FailureRecord
        {
            Timestamp = DateTime.UtcNow,
            Type = FailureType.OrderRejection,
            Message = "Test failure 1"
        };
        
        var failure2 = new FailureRecord
        {
            Timestamp = DateTime.UtcNow,
            Type = FailureType.OrderRejection,
            Message = "Test failure 2"
        };
        
        // Act
        _circuitBreaker.RecordFailure(failure1);
        _circuitBreaker.RecordFailure(failure2);
        
        // Assert
        _circuitBreaker.GetState().Should().Be(CircuitBreakerState.Open);
    }
    
    [Fact]
    public void RecordSuccess_WhenInHalfOpenAndThresholdExceeded_ShouldCloseCircuit()
    {
        // Arrange
        SetupMocks();
        var config = new CircuitBreakerConfig
        {
            FailureThreshold = 1,
            SuccessThreshold = 2,
            TimeoutSeconds = 1,
            WindowSizeSeconds = 300,
            EnableHalfOpenState = true,
            EnableAutomaticReset = true
        };
        
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object,
            config);
        
        // Open circuit
        var failure = new FailureRecord
        {
            Timestamp = DateTime.UtcNow,
            Type = FailureType.OrderRejection,
            Message = "Test failure"
        };
        
        _circuitBreaker.RecordFailure(failure);
        
        // Wait for timeout to transition to half-open
        Thread.Sleep(TimeSpan.FromSeconds(2));
        
        // Act
        _circuitBreaker.RecordSuccess(DateTime.UtcNow);
        _circuitBreaker.RecordSuccess(DateTime.UtcNow);
        
        // Assert
        _circuitBreaker.GetState().Should().Be(CircuitBreakerState.Closed);
    }
    
    [Fact]
    public void OpenCircuit_WithValidReason_ShouldOpenCircuit()
    {
        // Arrange
        SetupMocks();
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object);
        
        var reason = "Manual open";
        
        // Act
        _circuitBreaker.OpenCircuit(reason);
        
        // Assert
        _circuitBreaker.GetState().Should().Be(CircuitBreakerState.Open);
    }
    
    [Fact]
    public void CloseCircuit_WithValidReason_ShouldCloseCircuit()
    {
        // Arrange
        SetupMocks();
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object);
        
        // Open circuit first
        _circuitBreaker.OpenCircuit("Test open");
        
        var reason = "Manual close";
        
        // Act
        _circuitBreaker.CloseCircuit(reason);
        
        // Assert
        _circuitBreaker.GetState().Should().Be(CircuitBreakerState.Closed);
    }
    
    [Fact]
    public void GetMetrics_ShouldReturnCurrentMetrics()
    {
        // Arrange
        SetupMocks();
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object);
        
        // Act
        var metrics = _circuitBreaker.GetMetrics();
        
        // Assert
        metrics.Should().NotBeNull();
        metrics.State.Should().Be(CircuitBreakerState.Closed);
        metrics.FailureCount.Should().Be(0);
        metrics.SuccessCount.Should().Be(0);
    }
    
    [Fact]
    public void Reset_ShouldResetCircuitState()
    {
        // Arrange
        SetupMocks();
        _circuitBreaker = new CircuitBreaker(
            _mockLogger.Object,
            _mockHealthChecker.Object);
        
        // Open circuit
        _circuitBreaker.OpenCircuit("Test open");
        
        // Act
        _circuitBreaker.Reset();
        
        // Assert
        _circuitBreaker.GetState().Should().Be(CircuitBreakerState.Closed);
    }
    
    private void SetupMocks()
    {
        _mockLogger = new Mock<ILogger<CircuitBreaker>>();
        _mockHealthChecker = new Mock<IHealthChecker>();
    }
}

Test Coverage Goals

Component Coverage Targets

Component Coverage Target Notes
OrderManager 95% Critical component, extensive testing required
RiskManager 95% Core risk management, must be thoroughly tested
PositionSizer 90% Important for position sizing accuracy
TWAP Executor 90% Algorithmic execution, complex logic
VWAP Executor 90% Algorithmic execution, complex logic
Iceberg Executor 90% Algorithmic execution, complex logic
Rate Limiter 85% Important for system stability
Value Limiter 85% Important for risk management
Circuit Breaker 90% Critical for system resilience

Edge Case Testing

  1. Boundary Conditions: Test at the limits of all numeric parameters
  2. Race Conditions: Test concurrent access to shared resources
  3. Network Failures: Test handling of network interruptions
  4. System Overload: Test behavior under high load conditions
  5. Invalid Input: Test handling of malformed or malicious input
  6. Time Zone Issues: Test behavior across different time zones
  7. Memory Pressure: Test behavior under memory constraints
  8. Disk Space: Test behavior when disk space is low

Test Data Management

Test Data Generation

/// <summary>
/// Helper class for generating test data
/// </summary>
public static class TestDataGenerator
{
    /// <summary>
    /// Generate a valid order request for testing
    /// </summary>
    public static OrderRequest GenerateValidOrderRequest(
        string symbol = "ES",
        OrderSide side = OrderSide.Buy,
        OrderType type = OrderType.Market,
        int quantity = 1)
    {
        return new OrderRequest(
            Symbol: symbol,
            Side: side,
            Type: type,
            Quantity: quantity,
            LimitPrice: type == OrderType.Limit || type == OrderType.StopLimit ? 4200m : (decimal?)null,
            StopPrice: type == OrderType.StopMarket || type == OrderType.StopLimit ? 4190m : (decimal?)null,
            TimeInForce: TimeInForce.Day,
            Algorithm: null,
            AlgorithmParameters: new Dictionary<string, object>()
        );
    }
    
    /// <summary>
    /// Generate a valid strategy context for testing
    /// </summary>
    public static StrategyContext GenerateValidStrategyContext(string symbol = "ES")
    {
        return new StrategyContext(
            Symbol: symbol,
            CurrentTime: DateTime.UtcNow,
            CurrentPosition: new Position(symbol, 0, 0, 0, 0, DateTime.UtcNow),
            Account: new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow),
            Session: new MarketSession(DateTime.UtcNow.Date, DateTime.UtcNow.Date.AddDays(1), true, "RTH"),
            CustomData: new Dictionary<string, object>()
        );
    }
    
    /// <summary>
    /// Generate a valid risk config for testing
    /// </summary>
    public static RiskConfig GenerateValidRiskConfig()
    {
        return new RiskConfig(
            DailyLossLimit: 1000,
            MaxTradeRisk: 200,
            MaxOpenPositions: 5,
            EmergencyFlattenEnabled: true
        );
    }
    
    /// <summary>
    /// Generate a valid sizing config for testing
    /// </summary>
    public static SizingConfig GenerateValidSizingConfig()
    {
        return new SizingConfig(
            Method: SizingMethod.FixedContracts,
            MinContracts: 1,
            MaxContracts: 10,
            RiskPerTrade: 200,
            MethodParameters: new Dictionary<string, object> { ["contracts"] = 2 }
        );
    }
    
    /// <summary>
    /// Generate a valid order result for testing
    /// </summary>
    public static OrderResult GenerateValidOrderResult(string orderId = null)
    {
        return new OrderResult(
            Success: true,
            OrderId: orderId ?? Guid.NewGuid().ToString(),
            Message: "Order submitted successfully",
            Status: new OrderStatus(
                OrderId: orderId ?? Guid.NewGuid().ToString(),
                Symbol: "ES",
                Side: OrderSide.Buy,
                Type: OrderType.Market,
                Quantity: 1,
                FilledQuantity: 1,
                LimitPrice: null,
                StopPrice: null,
                State: OrderState.Filled,
                CreatedTime: DateTime.UtcNow,
                FilledTime: DateTime.UtcNow,
                Fills: new List<OrderFill>
                {
                    new OrderFill(
                        OrderId: orderId ?? Guid.NewGuid().ToString(),
                        Symbol: "ES",
                        Quantity: 1,
                        FillPrice: 4200,
                        FillTime: DateTime.UtcNow,
                        Commission: 4.50m,
                        ExecutionId: Guid.NewGuid().ToString()
                    )
                }
            )
        );
    }
}

Test Execution Strategy

Continuous Integration Testing

  1. Build Verification: Run critical tests on every commit
  2. Nightly Builds: Run full test suite nightly
  3. Release Testing: Run extended test suite before releases
  4. Performance Testing: Run performance tests weekly

Test Parallelization

  1. Component Isolation: Run component tests in parallel
  2. Database Isolation: Use separate test databases for each test
  3. Resource Management: Ensure tests don't interfere with each other

Test Reporting

  1. Real-time Feedback: Provide immediate feedback on test results
  2. Historical Trends: Track test results over time
  3. Coverage Reports: Generate code coverage reports
  4. Performance Metrics: Track test execution performance

Test Maintenance

Test Refactoring

  1. Regular Reviews: Review and refactor tests quarterly
  2. Dead Code Removal: Remove obsolete tests
  3. Duplication Elimination: Consolidate duplicate test logic
  4. Performance Optimization: Optimize slow tests

Test Documentation

  1. Inline Comments: Document complex test logic
  2. Test Descriptions: Provide clear test descriptions
  3. Failure Analysis: Document common test failures and resolutions
  4. Best Practices: Maintain test best practices documentation

Conclusion

This comprehensive unit test plan ensures that all OMS components are thoroughly tested with >90% code coverage. The plan covers all critical functionality, edge cases, and integration points, providing confidence in the reliability and correctness of the system.

The test suite will be implemented incrementally, with priority given to the most critical components (OrderManager, RiskManager, PositionSizer) followed by algorithmic execution components (TWAP, VWAP, Iceberg) and finally auxiliary components (Rate Limiter, Value Limiter, Circuit Breaker).

Regular test reviews and maintenance will ensure the test suite remains effective as the system evolves.