using Microsoft.VisualStudio.TestTools.UnitTesting; using NT8.Adapters.Wrappers; using NT8.Core.Common.Interfaces; using NT8.Core.Common.Models; using NT8.Core.Logging; using System; using System.Collections.Generic; namespace NT8.Integration.Tests { /// /// Integration tests for NT8 strategy wrapper behavior. /// [TestClass] public class NT8WrapperTests { /// /// Verifies wrapper construction initializes expected defaults. /// [TestMethod] public void Constructor_Defaults_AreInitialized() { // Arrange / Act var wrapper = new SimpleORBNT8Wrapper(); // Assert Assert.AreEqual(10, wrapper.StopTicks); Assert.AreEqual(20, wrapper.TargetTicks); Assert.AreEqual(100.0, wrapper.RiskAmount); Assert.AreEqual(30, wrapper.OpeningRangeMinutes); Assert.AreEqual(1.0, wrapper.StdDevMultiplier); } /// /// Verifies processing a valid bar/context does not throw when strategy emits no intent. /// [TestMethod] public void ProcessBarUpdate_ValidData_NoIntent_DoesNotThrow() { // Arrange var wrapper = new SimpleORBNT8Wrapper(); var bar = CreateBar("ES"); var context = CreateContext("ES"); // Act wrapper.ProcessBarUpdate(bar, context); // Assert Assert.IsTrue(true); } /// /// Verifies null bar input is rejected. /// [TestMethod] public void ProcessBarUpdate_NullBar_ThrowsArgumentNullException() { // Arrange var wrapper = new SimpleORBNT8Wrapper(); var context = CreateContext("NQ"); // Act / Assert Assert.ThrowsException( () => wrapper.ProcessBarUpdate(null, context)); } /// /// Verifies null context input is rejected. /// [TestMethod] public void ProcessBarUpdate_NullContext_ThrowsArgumentNullException() { // Arrange var wrapper = new SimpleORBNT8Wrapper(); var bar = CreateBar("NQ"); // Act / Assert Assert.ThrowsException( () => wrapper.ProcessBarUpdate(bar, null)); } /// /// Verifies wrapper can process a generated intent flow from a derived test strategy. /// [TestMethod] public void ProcessBarUpdate_WithGeneratedIntent_CompletesWithoutException() { // Arrange var wrapper = new TestIntentWrapper(); var bar = CreateBar("MES"); var context = CreateContext("MES"); // Act wrapper.ProcessBarUpdate(bar, context); // Assert Assert.IsTrue(true); } /// /// Verifies Simple ORB strategy emits a long intent after opening range breakout. /// [TestMethod] public void ProcessBarUpdate_SimpleOrbBreakout_ProducesExecutionRecord() { // Arrange var wrapper = new SimpleORBNT8Wrapper(); var sessionStart = DateTime.Today.AddHours(9.5); var symbol = "ES"; var openingBar1 = new BarData(symbol, sessionStart.AddMinutes(5), 100, 101, 99, 100.5, 1000, TimeSpan.FromMinutes(5)); var openingBar2 = new BarData(symbol, sessionStart.AddMinutes(10), 100.5, 102, 100, 101.5, 1000, TimeSpan.FromMinutes(5)); var breakoutBar = new BarData(symbol, sessionStart.AddMinutes(35), 102, 104.5, 101.5, 104.2, 1200, TimeSpan.FromMinutes(5)); // Act wrapper.ProcessBarUpdate(openingBar1, CreateContext(symbol, openingBar1.Time, sessionStart)); wrapper.ProcessBarUpdate(openingBar2, CreateContext(symbol, openingBar2.Time, sessionStart)); wrapper.ProcessBarUpdate(breakoutBar, CreateContext(symbol, breakoutBar.Time, sessionStart)); // Assert var adapter = wrapper.GetAdapterForTesting(); var records = adapter.GetExecutionHistory(); Assert.AreEqual(1, records.Count); Assert.AreEqual(OrderSide.Buy, records[0].Side); Assert.AreEqual(symbol, records[0].Symbol); } private static BarData CreateBar(string symbol) { return new BarData( symbol, DateTime.UtcNow, 5000, 5010, 4995, 5005, 10000, TimeSpan.FromMinutes(5)); } private static StrategyContext CreateContext(string symbol) { return new StrategyContext( symbol, DateTime.UtcNow, new Position(symbol, 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 StrategyContext CreateContext(string symbol, DateTime currentTime, DateTime sessionStart) { return new StrategyContext( symbol, currentTime, new Position(symbol, 0, 0, 0, 0, currentTime), new AccountInfo(100000, 100000, 0, 0, currentTime), new MarketSession(sessionStart, sessionStart.AddHours(6.5), true, "RTH"), new Dictionary()); } /// /// Wrapper used to verify execution path when an intent is emitted. /// private class TestIntentWrapper : BaseNT8StrategyWrapper { protected override IStrategy CreateSdkStrategy() { return new TestIntentStrategy(); } } /// /// Minimal strategy that always returns a valid intent. /// private class TestIntentStrategy : IStrategy { public StrategyMetadata Metadata { get; private set; } public TestIntentStrategy() { Metadata = new StrategyMetadata( "TestIntentStrategy", "Test strategy that emits a deterministic intent", "1.0", "NT8 SDK Tests", new string[] { "MES" }, 1); } public void Initialize(StrategyConfig config, IMarketDataProvider dataProvider, ILogger logger) { // No-op for test strategy. } public StrategyIntent OnBar(BarData bar, StrategyContext context) { return new StrategyIntent( context.Symbol, OrderSide.Buy, OrderType.Market, null, 8, 16, 0.7, "Wrapper integration test intent", new Dictionary()); } public StrategyIntent OnTick(TickData tick, StrategyContext context) { return null; } public Dictionary GetParameters() { return new Dictionary(); } public void SetParameters(Dictionary parameters) { // No-op for test strategy. } } } }