using System; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using NT8.Core.Execution; using NT8.Core.MarketData; using NT8.Core.OMS; namespace NT8.Integration.Tests { [TestClass] public class Phase3IntegrationTests { [TestMethod] public void Flow_LiquidityToOrderValidationToExecutionTracking_Works() { var marketLogger = new IntegrationMockLogger(); var liquidityMonitor = new LiquidityMonitor(marketLogger); liquidityMonitor.UpdateSpread("ES", 5000.00, 5000.25, 1000); var acceptable = liquidityMonitor.IsLiquidityAcceptable("ES", LiquidityScore.Poor); Assert.IsTrue(acceptable); var orderValidator = new OrderTypeValidator(new IntegrationMockLogger()); var limit = new LimitOrderRequest("ES", OrderSide.Buy, 1, 5000m, TimeInForce.Day); var validation = orderValidator.ValidateLimitOrder(limit, 5001m); Assert.IsTrue(validation.IsValid); var tracker = new ExecutionQualityTracker(new IntegrationMockLogger()); var t0 = DateTime.UtcNow; tracker.RecordExecution("ES-INT-1", 5000m, 5000.25m, t0.AddMilliseconds(10), t0.AddMilliseconds(3), t0); var metrics = tracker.GetExecutionMetrics("ES-INT-1"); Assert.IsNotNull(metrics); } [TestMethod] public void Flow_DuplicateDetection_PreventsSecondOrder() { var detector = new DuplicateOrderDetector(new IntegrationMockLogger(), TimeSpan.FromSeconds(5)); var request = new OrderRequest { Symbol = "NQ", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 2, TimeInForce = TimeInForce.Day, ClientOrderId = "INT-DUP-1" }; detector.RecordOrderIntent(request); var duplicate = detector.IsDuplicateOrder(request); Assert.IsTrue(duplicate); } [TestMethod] public void Flow_CircuitBreaker_TripsOnFailures_ThenBlocksOrders() { var breaker = new ExecutionCircuitBreaker(new IntegrationMockLogger(), 3, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(5), 100, 3); breaker.OnFailure(); breaker.OnFailure(); breaker.OnFailure(); var state = breaker.GetState(); Assert.AreEqual(CircuitBreakerStatus.Open, state.Status); Assert.IsFalse(breaker.ShouldAllowOrder()); } [TestMethod] public void Flow_MultiTargets_WithTrailingManager_ProvidesActions() { var targetManager = new MultiLevelTargetManager(new IntegrationMockLogger()); var trailingManager = new TrailingStopManager(new IntegrationMockLogger()); targetManager.SetTargets("ORD-INTEG-1", new MultiLevelTargets(8, 2, 16, 2, 32, 1)); var targetResult = targetManager.OnTargetHit("ORD-INTEG-1", 1, 5002m); Assert.AreEqual(TargetAction.PartialClose, targetResult.Action); var position = new OrderStatus { OrderId = "ORD-INTEG-1", Symbol = "ES", Side = OrderSide.Buy, Quantity = 5, FilledQuantity = 5, AverageFillPrice = 5000m, State = OrderState.Working }; trailingManager.StartTrailing("ORD-INTEG-1", position, new NT8.Core.Execution.TrailingStopConfig(8)); var stop = trailingManager.GetCurrentStopPrice("ORD-INTEG-1"); Assert.IsTrue(stop.HasValue); } [TestMethod] public void Flow_RMultipleTargets_WithSlippageImpact_ComputesValues() { var rCalc = new RMultipleCalculator(new IntegrationMockLogger()); var slippageCalc = new SlippageCalculator(); var position = new NT8.Core.Common.Models.Position("ES", 2, 5000.0, 0, 0, DateTime.UtcNow); var rValue = rCalc.CalculateRValue(position, 4998.0, 50.0); Assert.IsTrue(rValue > 0.0); var targets = rCalc.CreateRBasedTargets(5000.0, 4998.0, new double[] { 1.0, 2.0, 3.0 }); Assert.IsTrue(targets.TP1Ticks > 0); var slippage = slippageCalc.CalculateSlippage(OrderType.Market, 5000m, 5000.25m); var impact = slippageCalc.SlippageImpact(slippage, 2, 12.5m, OrderSide.Buy); Assert.IsTrue(impact <= 0m || impact >= 0m); } [TestMethod] public void Flow_ContractRollHandler_ReturnsActiveContractAndRollPeriod() { var handler = new ContractRollHandler(new IntegrationMockLogger()); var symbol = "ES"; var date = new DateTime(DateTime.UtcNow.Year, 3, 10); var activeContract = handler.GetActiveContract(symbol, date); Assert.IsFalse(string.IsNullOrEmpty(activeContract)); var rollCheck = handler.IsRollPeriod(symbol, date); Assert.IsTrue(rollCheck || !rollCheck); } [TestMethod] public void Flow_SessionManager_WithLiquidityMonitor_ClassifiesSession() { var sessionManager = new SessionManager(new IntegrationMockLogger()); var liquidityMonitor = new LiquidityMonitor(new IntegrationMockLogger()); var now = DateTime.UtcNow; var session = sessionManager.GetCurrentSession("ES", now); Assert.IsFalse(string.IsNullOrEmpty(session.Symbol)); liquidityMonitor.UpdateSpread("ES", 5000.0, 5000.25, 1200); var score = liquidityMonitor.CalculateLiquidityScore("ES"); Assert.IsTrue(score == LiquidityScore.Poor || score == LiquidityScore.Fair || score == LiquidityScore.Good || score == LiquidityScore.Excellent); } [TestMethod] public void Flow_CircuitBreaker_RecoversThroughHalfOpenAndReset() { var breaker = new ExecutionCircuitBreaker(new IntegrationMockLogger(), 1, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(5), 100, 3); breaker.OnFailure(); Assert.AreEqual(CircuitBreakerStatus.Open, breaker.GetState().Status); System.Threading.Thread.Sleep(20); var allowed = breaker.ShouldAllowOrder(); Assert.IsTrue(allowed); breaker.OnSuccess(); Assert.AreEqual(CircuitBreakerStatus.Closed, breaker.GetState().Status); } [TestMethod] public void Flow_DuplicateDetector_ClearOldIntents_AllowsAfterWindow() { var detector = new DuplicateOrderDetector(new IntegrationMockLogger(), TimeSpan.FromMilliseconds(10)); var request = new OrderRequest { Symbol = "GC", Side = OrderSide.Sell, Type = OrderType.Market, Quantity = 1, TimeInForce = TimeInForce.Day, ClientOrderId = "INT-DUP-2" }; detector.RecordOrderIntent(request); Assert.IsTrue(detector.IsDuplicateOrder(request)); System.Threading.Thread.Sleep(20); detector.ClearOldIntents(TimeSpan.FromMilliseconds(10)); Assert.IsFalse(detector.IsDuplicateOrder(request)); } } internal class IntegrationMockLogger : ILogger { public IDisposable BeginScope(TState state) { return new IntegrationMockDisposable(); } public bool IsEnabled(LogLevel logLevel) { return true; } public void Log( LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { } } internal class IntegrationMockDisposable : IDisposable { public void Dispose() { } } }