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 OrbConfluenceFactorTests { [TestMethod] public void NarrowRange_NR7_ScoresOne() { var calc = new NarrowRangeFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); intent.Metadata["daily_bars"] = CreateDailyContext(new double[] { 10, 10, 10, 10, 10, 10, 5 }); var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(1.0, result.Score, 0.000001); } [TestMethod] public void NarrowRange_NR4_Scores075() { var calc = new NarrowRangeFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); intent.Metadata["daily_bars"] = CreateDailyContext(new double[] { 5, 5, 5, 10, 9, 8, 7 }); var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(0.75, result.Score, 0.000001); } [TestMethod] public void NarrowRange_WideRange_ScoresLow() { var calc = new NarrowRangeFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); intent.Metadata["daily_bars"] = CreateDailyContext(new double[] { 5, 5, 5, 5, 5, 5, 12 }); var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.IsTrue(result.Score <= 0.3); } [TestMethod] public void NarrowRange_MissingContext_DefaultsTo03() { var calc = new NarrowRangeFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(0.3, result.Score, 0.000001); } [TestMethod] public void NarrowRange_InsufficientBars_DefaultsTo03() { var calc = new NarrowRangeFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); intent.Metadata["daily_bars"] = CreateDailyContext(new double[] { 8, 7, 6, 5 }); var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(0.3, result.Score, 0.000001); } [TestMethod] public void OrbRangeVsAtr_SmallRange_ScoresOne() { var calc = new OrbRangeVsAtrFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 10, 10, 10, 10, 10, 10, 10 }); intent.Metadata["daily_bars"] = daily; intent.Metadata["orb_range_ticks"] = 8.0; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(1.0, result.Score, 0.000001); } [TestMethod] public void OrbRangeVsAtr_LargeRange_ScoresVeryLow() { var calc = new OrbRangeVsAtrFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 10, 10, 10, 10, 10, 10, 10 }); intent.Metadata["daily_bars"] = daily; intent.Metadata["orb_range_ticks"] = 40.0; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.IsTrue(result.Score <= 0.15); } [TestMethod] public void OrbRangeVsAtr_MissingContext_DefaultsTo05() { var calc = new OrbRangeVsAtrFactorCalculator(new BasicLogger("test")); var intent = CreateIntent(); var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(0.5, result.Score, 0.000001); } [TestMethod] public void GapDirection_LargeAlignedGap_ScoresOne() { var calc = new GapDirectionAlignmentCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); daily.Closes[daily.Count - 2] = 100.0; daily.TodayOpen = 106.0; daily.TradeDirection = 1; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(1.0, result.Score, 0.000001); } [TestMethod] public void GapDirection_LargeOpposingGap_ScoresVeryLow() { var calc = new GapDirectionAlignmentCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); daily.Closes[daily.Count - 2] = 100.0; daily.TodayOpen = 106.0; daily.TradeDirection = -1; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.IsTrue(result.Score <= 0.15); } [TestMethod] public void GapDirection_FlatOpen_ScoresNeutral() { var calc = new GapDirectionAlignmentCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); daily.Closes[daily.Count - 2] = 100.0; daily.TodayOpen = 100.1; daily.TradeDirection = 1; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(0.55, result.Score, 0.000001); } [TestMethod] public void BreakoutVolume_ThreeX_ScoresOne() { var calc = new BreakoutVolumeStrengthCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); daily.BreakoutBarVolume = 3000.0; daily.AvgIntradayBarVolume = 1000.0; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(1.0, result.Score, 0.000001); } [TestMethod] public void BreakoutVolume_BelowAverage_ScoresLow() { var calc = new BreakoutVolumeStrengthCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); daily.BreakoutBarVolume = 800.0; daily.AvgIntradayBarVolume = 1200.0; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.IsTrue(result.Score <= 0.25); } [TestMethod] public void PriorCloseStrength_LongTopQuartile_ScoresOne() { var calc = new PriorDayCloseStrengthCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); int prev = daily.Count - 2; daily.Lows[prev] = 100.0; daily.Highs[prev] = 120.0; daily.Closes[prev] = 118.0; daily.TradeDirection = 1; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(1.0, result.Score, 0.000001); } [TestMethod] public void PriorCloseStrength_LongBottomQuartile_ScoresLow() { var calc = new PriorDayCloseStrengthCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); int prev = daily.Count - 2; daily.Lows[prev] = 100.0; daily.Highs[prev] = 120.0; daily.Closes[prev] = 101.0; daily.TradeDirection = 1; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.IsTrue(result.Score <= 0.20); } [TestMethod] public void PriorCloseStrength_ShortBottomQuartile_ScoresOne() { var calc = new PriorDayCloseStrengthCalculator(new BasicLogger("test")); var intent = CreateIntent(); var daily = CreateDailyContext(new double[] { 8, 8, 8, 8, 8, 8, 8 }); int prev = daily.Count - 2; daily.Lows[prev] = 100.0; daily.Highs[prev] = 120.0; daily.Closes[prev] = 101.0; daily.TradeDirection = -1; intent.Metadata["daily_bars"] = daily; var result = calc.Calculate(intent, CreateContext(), CreateBar()); Assert.AreEqual(1.0, result.Score, 0.000001); } private static StrategyIntent CreateIntent() { return new StrategyIntent( "ES", OrderSide.Buy, OrderType.Market, null, 8, 16, 0.8, "test", new Dictionary()); } private static StrategyContext CreateContext() { return new StrategyContext( "ES", DateTime.UtcNow, new Position("ES", 0, 0, 0, 0, DateTime.UtcNow), new AccountInfo(100000, 100000, 0, 0, DateTime.UtcNow), new MarketSession(DateTime.Today.AddHours(9.5), DateTime.Today.AddHours(16), true, "RTH"), new Dictionary()); } private static BarData CreateBar() { return new BarData("ES", DateTime.UtcNow, 5000, 5005, 4998, 5002, 1000, TimeSpan.FromMinutes(5)); } private static DailyBarContext CreateDailyContext(double[] ranges) { DailyBarContext context = new DailyBarContext(); context.Count = ranges.Length; context.Highs = new double[ranges.Length]; context.Lows = new double[ranges.Length]; context.Closes = new double[ranges.Length]; context.Opens = new double[ranges.Length]; context.Volumes = new long[ranges.Length]; for (int i = 0; i < ranges.Length; i++) { context.Lows[i] = 100.0; context.Highs[i] = 100.0 + ranges[i]; context.Opens[i] = 100.0 + (ranges[i] * 0.25); context.Closes[i] = 100.0 + (ranges[i] * 0.75); context.Volumes[i] = 100000; } context.TodayOpen = context.Closes[Math.Max(0, context.Count - 2)] + 1.0; context.BreakoutBarVolume = 1000.0; context.AvgIntradayBarVolume = 1000.0; context.TradeDirection = 1; return context; } } }