using System; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using NT8.Core.Common.Models; using NT8.Core.Intelligence; using NT8.Core.Logging; namespace NT8.Core.Tests.Intelligence { [TestClass] public class RegimeDetectionTests { [TestMethod] public void VolatilityDetector_ClassifiesLow() { var detector = CreateVolDetector(); var regime = detector.DetectRegime("ES", 0.5, 1.0); Assert.AreEqual(VolatilityRegime.Low, regime); } [TestMethod] public void VolatilityDetector_ClassifiesBelowNormal() { var detector = CreateVolDetector(); var regime = detector.DetectRegime("ES", 0.7, 1.0); Assert.AreEqual(VolatilityRegime.BelowNormal, regime); } [TestMethod] public void VolatilityDetector_ClassifiesNormal() { var detector = CreateVolDetector(); var regime = detector.DetectRegime("ES", 1.0, 1.0); Assert.AreEqual(VolatilityRegime.Normal, regime); } [TestMethod] public void VolatilityDetector_ClassifiesElevated() { var detector = CreateVolDetector(); var regime = detector.DetectRegime("ES", 1.3, 1.0); Assert.AreEqual(VolatilityRegime.Elevated, regime); } [TestMethod] public void VolatilityDetector_ClassifiesHigh() { var detector = CreateVolDetector(); var regime = detector.DetectRegime("ES", 1.7, 1.0); Assert.AreEqual(VolatilityRegime.High, regime); } [TestMethod] public void VolatilityDetector_ClassifiesExtreme() { var detector = CreateVolDetector(); var regime = detector.DetectRegime("ES", 2.2, 1.0); Assert.AreEqual(VolatilityRegime.Extreme, regime); } [TestMethod] public void VolatilityDetector_CalculateScore_ReturnsRatio() { var detector = CreateVolDetector(); var score = detector.CalculateVolatilityScore(1.5, 1.0); Assert.AreEqual(1.5, score, 0.000001); } [TestMethod] public void VolatilityDetector_TransitionHistory_TracksChanges() { var detector = CreateVolDetector(); detector.DetectRegime("NQ", 1.0, 1.0); detector.DetectRegime("NQ", 2.3, 1.0); var transitions = detector.GetTransitions("NQ"); Assert.IsTrue(transitions.Count >= 1); Assert.AreEqual("NQ", transitions[0].Symbol); } [TestMethod] public void VolatilityDetector_GetCurrentRegime_Unknown_ReturnsNormal() { var detector = CreateVolDetector(); var regime = detector.GetCurrentRegime("GC"); Assert.AreEqual(VolatilityRegime.Normal, regime); } [TestMethod] public void TrendDetector_DetectsStrongUp() { var detector = CreateTrendDetector(); var bars = BuildUptrendBars(12, 5000.0, 2.0); var regime = detector.DetectTrend("ES", bars, 4995.0); Assert.IsTrue(regime == TrendRegime.StrongUp || regime == TrendRegime.WeakUp); } [TestMethod] public void TrendDetector_DetectsStrongDown() { var detector = CreateTrendDetector(); var bars = BuildDowntrendBars(12, 5000.0, 2.0); var regime = detector.DetectTrend("ES", bars, 5005.0); Assert.IsTrue(regime == TrendRegime.StrongDown || regime == TrendRegime.WeakDown); } [TestMethod] public void TrendDetector_CalculateStrength_UptrendPositive() { var detector = CreateTrendDetector(); var bars = BuildUptrendBars(10, 100.0, 1.0); var strength = detector.CalculateTrendStrength(bars, 95.0); Assert.IsTrue(strength > 0.0); } [TestMethod] public void TrendDetector_CalculateStrength_DowntrendNegative() { var detector = CreateTrendDetector(); var bars = BuildDowntrendBars(10, 100.0, 1.0); var strength = detector.CalculateTrendStrength(bars, 105.0); Assert.IsTrue(strength < 0.0); } [TestMethod] public void TrendDetector_IsRanging_FlatBars_True() { var detector = CreateTrendDetector(); var bars = BuildRangeBars(10, 100.0, 0.1); var ranging = detector.IsRanging(bars, 0.2); Assert.IsTrue(ranging); } [TestMethod] public void TrendDetector_AssessTrendQuality_GoodStructure_ReturnsNotPoor() { var detector = CreateTrendDetector(); var bars = BuildUptrendBars(12, 100.0, 0.8); var quality = detector.AssessTrendQuality(bars); Assert.IsTrue(quality == TrendQuality.Fair || quality == TrendQuality.Good || quality == TrendQuality.Excellent); } [TestMethod] public void RegimeManager_UpdateAndGetCurrentRegime_ReturnsState() { var manager = CreateRegimeManager(); var bar = CreateBar("ES", 5000, 5004, 4998, 5002, 1000); manager.UpdateRegime("ES", bar, 5000.0, 1.0, 1.0); var state = manager.GetCurrentRegime("ES"); Assert.IsNotNull(state); Assert.AreEqual("ES", state.Symbol); } [TestMethod] public void RegimeManager_ShouldAdjustStrategy_ExtremeVolatility_True() { var manager = CreateRegimeManager(); var bars = BuildUptrendBars(6, 5000.0, 1.0); for (var i = 0; i < bars.Count; i++) { manager.UpdateRegime("ES", bars[i], 5000.0, 2.5, 1.0); } var intent = CreateIntent(OrderSide.Buy); var shouldAdjust = manager.ShouldAdjustStrategy("ES", intent); Assert.IsTrue(shouldAdjust); } [TestMethod] public void RegimeManager_TransitionsRecorded_WhenRegimeChanges() { var manager = CreateRegimeManager(); var bars = BuildUptrendBars(6, 5000.0, 1.0); for (var i = 0; i < bars.Count; i++) { manager.UpdateRegime("NQ", bars[i], 5000.0, 1.0, 1.0); } manager.UpdateRegime("NQ", CreateBar("NQ", 5000, 5001, 4990, 4991, 1500), 5000.0, 2.3, 1.0); var transitions = manager.GetRecentTransitions("NQ", TimeSpan.FromHours(2)); Assert.IsTrue(transitions.Count >= 1); } private static VolatilityRegimeDetector CreateVolDetector() { return new VolatilityRegimeDetector(new BasicLogger("RegimeDetectionTests"), 50); } private static TrendRegimeDetector CreateTrendDetector() { return new TrendRegimeDetector(new BasicLogger("RegimeDetectionTests")); } private static RegimeManager CreateRegimeManager() { var logger = new BasicLogger("RegimeManagerTests"); var vol = new VolatilityRegimeDetector(logger, 50); var trend = new TrendRegimeDetector(logger); return new RegimeManager(logger, vol, trend, 200, 100); } private static List BuildUptrendBars(int count, double start, double step) { var result = new List(); var time = DateTime.UtcNow.AddMinutes(-count); for (var i = 0; i < count; i++) { var close = start + (i * step); result.Add(new BarData("ES", time.AddMinutes(i), close - 1.0, close + 1.0, close - 2.0, close, 1000 + i, TimeSpan.FromMinutes(1))); } return result; } private static List BuildDowntrendBars(int count, double start, double step) { var result = new List(); var time = DateTime.UtcNow.AddMinutes(-count); for (var i = 0; i < count; i++) { var close = start - (i * step); result.Add(new BarData("ES", time.AddMinutes(i), close + 1.0, close + 2.0, close - 1.0, close, 1000 + i, TimeSpan.FromMinutes(1))); } return result; } private static List BuildRangeBars(int count, double center, double amplitude) { var result = new List(); var time = DateTime.UtcNow.AddMinutes(-count); for (var i = 0; i < count; i++) { var close = center + ((i % 2 == 0) ? amplitude : -amplitude); result.Add(new BarData("ES", time.AddMinutes(i), close - 0.05, close + 0.10, close - 0.10, close, 800 + i, TimeSpan.FromMinutes(1))); } return result; } private static BarData CreateBar(string symbol, double open, double high, double low, double close, long volume) { return new BarData(symbol, DateTime.UtcNow, open, high, low, close, volume, TimeSpan.FromMinutes(1)); } private static StrategyIntent CreateIntent(OrderSide side) { return new StrategyIntent( "ES", side, OrderType.Market, null, 8, 16, 0.8, "Test", new Dictionary()); } } }