using Microsoft.VisualStudio.TestTools.UnitTesting; using NT8.Core.Common.Models; using NT8.Core.Logging; using NT8.Core.Sizing; using System; using System.Collections.Generic; namespace NT8.Core.Tests.Sizing { [TestClass] public class BasicPositionSizerTests { private BasicPositionSizer _sizer; [TestInitialize] public void TestInitialize() { _sizer = new BasicPositionSizer(new BasicLogger("BasicPositionSizerTests")); } [TestMethod] public void CalculateSize_FixedContracts_ReturnsConfiguredContractsWithinBounds() { var intent = CreateIntent(stopTicks: 8); var context = CreateContext(); var parameters = new Dictionary(); parameters.Add("contracts", 3); var config = new SizingConfig( method: SizingMethod.FixedContracts, minContracts: 1, maxContracts: 10, riskPerTrade: 500, methodParameters: parameters); var result = _sizer.CalculateSize(intent, context, config); Assert.AreEqual(3, result.Contracts); Assert.AreEqual(SizingMethod.FixedContracts, result.Method); Assert.IsTrue(result.RiskAmount > 0); } [TestMethod] public void CalculateSize_FixedDollarRisk_ReturnsContractsWithinBounds() { var intent = CreateIntent(stopTicks: 8); var context = CreateContext(); var config = new SizingConfig( method: SizingMethod.FixedDollarRisk, minContracts: 1, maxContracts: 10, riskPerTrade: 500, methodParameters: new Dictionary()); var result = _sizer.CalculateSize(intent, context, config); Assert.IsTrue(result.Contracts >= 1); Assert.IsTrue(result.Contracts <= 10); Assert.AreEqual(SizingMethod.FixedDollarRisk, result.Method); Assert.IsTrue(result.RiskAmount > 0); } [TestMethod] public void CalculateSize_InvalidStopTicks_ReturnsZeroContractsForFixedRisk() { var intent = CreateIntent(stopTicks: 0); var context = CreateContext(); var config = new SizingConfig( method: SizingMethod.FixedDollarRisk, minContracts: 1, maxContracts: 10, riskPerTrade: 500, methodParameters: new Dictionary()); var result = _sizer.CalculateSize(intent, context, config); Assert.AreEqual(0, result.Contracts); Assert.AreEqual(0.0, result.RiskAmount); Assert.IsTrue(result.Calculations.ContainsKey("error")); } [TestMethod] public void ValidateConfig_FixedContractsWithoutContractsParam_ReturnsFalse() { var config = new SizingConfig( method: SizingMethod.FixedContracts, minContracts: 1, maxContracts: 10, riskPerTrade: 500, methodParameters: new Dictionary()); List errors; var valid = BasicPositionSizer.ValidateConfig(config, out errors); Assert.IsFalse(valid); Assert.IsTrue(errors.Count > 0); } [TestMethod] public void GetMetadata_ReturnsBasicSizerName() { var metadata = _sizer.GetMetadata(); Assert.IsNotNull(metadata); Assert.AreEqual("Basic Position Sizer", metadata.Name); } private static StrategyIntent CreateIntent(int stopTicks) { return new StrategyIntent( symbol: "ES", side: OrderSide.Buy, entryType: OrderType.Market, limitPrice: null, stopTicks: stopTicks, targetTicks: 16, confidence: 0.8, reason: "test", metadata: new Dictionary()); } private static StrategyContext CreateContext() { return new StrategyContext( symbol: "ES", currentTime: DateTime.UtcNow, currentPosition: new Position("ES", 0, 0, 0, 0, DateTime.UtcNow), account: new AccountInfo(50000, 50000, 0, 0, DateTime.UtcNow), session: new MarketSession(DateTime.Today.AddHours(9.5), DateTime.Today.AddHours(16), true, "RTH"), customData: new Dictionary()); } } }