using Microsoft.VisualStudio.TestTools.UnitTesting; using NT8.Adapters.NinjaTrader; using NT8.Core.Common.Models; using NT8.Core.Risk; using NT8.Core.Sizing; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace NT8.Integration.Tests { /// /// Integration tests for NT8OrderAdapter behavior. /// [TestClass] public class NT8OrderAdapterIntegrationTests { private class FakeBridge : INT8ExecutionBridge { public void EnterLongManaged(int q, string n, int s, int t, double ts) { } public void EnterShortManaged(int q, string n, int s, int t, double ts) { } public void ExitLongManaged(string n) { } public void ExitShortManaged(string n) { } public void FlattenAll() { } } [TestMethod] public void Initialize_NullRiskManager_ThrowsArgumentNullException() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); var sizer = new TestPositionSizer(1); // Act / Assert Assert.ThrowsException( () => adapter.Initialize(null, sizer)); } [TestMethod] public void Initialize_NullPositionSizer_ThrowsArgumentNullException() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); var risk = new TestRiskManager(true); // Act / Assert Assert.ThrowsException( () => adapter.Initialize(risk, null)); } [TestMethod] public void ExecuteIntent_NotInitialized_ThrowsInvalidOperationException() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); // Act / Assert Assert.ThrowsException( () => adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig())); } [TestMethod] public void ExecuteIntent_RiskRejected_DoesNotRecordExecution() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); var risk = new TestRiskManager(false); var sizer = new TestPositionSizer(3); adapter.Initialize(risk, sizer); // Act adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig()); var history = adapter.GetExecutionHistory(); // Assert Assert.AreEqual(0, history.Count); } [TestMethod] public void ExecuteIntent_AllowedAndSized_RecordsExecution() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); var risk = new TestRiskManager(true); var sizer = new TestPositionSizer(4); adapter.Initialize(risk, sizer); // Act adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig()); var history = adapter.GetExecutionHistory(); // Assert Assert.AreEqual(1, history.Count); Assert.AreEqual("ES", history[0].Symbol); Assert.AreEqual(OrderSide.Buy, history[0].Side); Assert.AreEqual(OrderType.Market, history[0].EntryType); Assert.AreEqual(4, history[0].Contracts); Assert.AreEqual(8, history[0].StopTicks); Assert.AreEqual(16, history[0].TargetTicks); } [TestMethod] public void GetExecutionHistory_ReturnsCopy_NotMutableInternalReference() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); var risk = new TestRiskManager(true); var sizer = new TestPositionSizer(2); adapter.Initialize(risk, sizer); adapter.ExecuteIntent(CreateIntent(), CreateContext(), CreateConfig()); // Act var history = adapter.GetExecutionHistory(); history.Clear(); var historyAfterClear = adapter.GetExecutionHistory(); // Assert Assert.AreEqual(1, historyAfterClear.Count); } [TestMethod] public void OnOrderUpdate_EmptyOrderId_ThrowsArgumentException() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); // Act / Assert Assert.ThrowsException( () => adapter.OnOrderUpdate("", 0, 0, 1, 0, 0, "Working", DateTime.UtcNow, "", "")); } [TestMethod] public void OnExecutionUpdate_EmptyExecutionId_ThrowsArgumentException() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); // Act / Assert Assert.ThrowsException( () => adapter.OnExecutionUpdate("", "O1", 100, 1, "Long", DateTime.UtcNow)); } [TestMethod] public void OnExecutionUpdate_EmptyOrderId_ThrowsArgumentException() { // Arrange var adapter = new NT8OrderAdapter(new FakeBridge()); // Act / Assert Assert.ThrowsException( () => adapter.OnExecutionUpdate("E1", "", 100, 1, "Long", DateTime.UtcNow)); } private static StrategyIntent CreateIntent() { return new StrategyIntent( "ES", OrderSide.Buy, OrderType.Market, null, 8, 16, 0.8, "Order adapter integration 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 StrategyConfig CreateConfig() { return new StrategyConfig( "Test", "ES", new Dictionary(), new RiskConfig(1000, 500, 5, true), new SizingConfig(SizingMethod.FixedContracts, 1, 10, 500, new Dictionary())); } /// /// Test risk manager implementation for adapter tests. /// private class TestRiskManager : IRiskManager { private readonly bool _allow; public TestRiskManager(bool allow) { _allow = allow; } public RiskDecision ValidateOrder(StrategyIntent intent, StrategyContext context, RiskConfig config) { return new RiskDecision( _allow, _allow ? null : "Rejected by test risk manager", intent, RiskLevel.Low, new Dictionary()); } public void OnFill(OrderFill fill) { } public void OnPnLUpdate(double netPnL, double dayPnL) { } public Task EmergencyFlatten(string reason) { return Task.FromResult(true); } public RiskStatus GetRiskStatus() { return new RiskStatus(true, 0, 1000, 0, 0, DateTime.UtcNow, new List()); } } /// /// Test position sizer implementation for adapter tests. /// private class TestPositionSizer : IPositionSizer { private readonly int _contracts; public TestPositionSizer(int contracts) { _contracts = contracts; } public SizingResult CalculateSize(StrategyIntent intent, StrategyContext context, SizingConfig config) { return new SizingResult(_contracts, 100, SizingMethod.FixedContracts, new Dictionary()); } public SizingMetadata GetMetadata() { return new SizingMetadata("TestSizer", "Test sizer", new List()); } } } }