S2-B3/S3-05: PortfolioRiskManager, connection loss recovery, long-only lock
Some checks failed
Build and Test / build (push) Has been cancelled

This commit is contained in:
2026-03-19 16:17:02 -04:00
parent 3282254572
commit 2f623dc2f8
4 changed files with 452 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NT8.Core.Common.Models;
using NT8.Core.Risk;
namespace NT8.Core.Tests.Risk
{
[TestClass]
public class PortfolioRiskManagerTests
{
private PortfolioRiskManager _manager;
[TestInitialize]
public void TestInitialize()
{
_manager = PortfolioRiskManager.Instance;
}
[TestCleanup]
public void TestCleanup()
{
_manager.UnregisterStrategy("strat1");
_manager.UnregisterStrategy("strat2");
_manager.UnregisterStrategy("strat3");
_manager.UnregisterStrategy("strat4");
_manager.UnregisterStrategy("strat5");
_manager.PortfolioKillSwitch = false;
_manager.PortfolioDailyLossLimit = 2000.0;
_manager.MaxTotalOpenContracts = 6;
_manager.ResetDaily();
}
[TestMethod]
public void PortfolioDailyLossLimit_WhenBreached_BlocksNewOrder()
{
// Arrange
_manager.RegisterStrategy("strat1", TestDataBuilder.CreateTestRiskConfig());
_manager.PortfolioDailyLossLimit = 500;
_manager.ReportPnL("strat1", -501);
var intent = TestDataBuilder.CreateValidIntent();
// Act
var decision = _manager.ValidatePortfolioRisk("strat1", intent);
// Assert
Assert.IsFalse(decision.Allow);
}
[TestMethod]
public void MaxTotalOpenContracts_WhenAtCap_BlocksNewOrder()
{
// Arrange
_manager.RegisterStrategy("strat1", TestDataBuilder.CreateTestRiskConfig());
_manager.MaxTotalOpenContracts = 2;
var fill1 = new OrderFill("ord1", "ES", 1, 5000.0, System.DateTime.UtcNow, 0.0, "exec1");
var fill2 = new OrderFill("ord2", "ES", 1, 5001.0, System.DateTime.UtcNow, 0.0, "exec2");
_manager.ReportFill("strat1", fill1);
_manager.ReportFill("strat1", fill2);
var intent = TestDataBuilder.CreateValidIntent();
// Act
var decision = _manager.ValidatePortfolioRisk("strat1", intent);
// Assert
Assert.IsFalse(decision.Allow);
}
[TestMethod]
public void PortfolioKillSwitch_WhenTrue_BlocksAllOrders()
{
// Arrange
_manager.RegisterStrategy("strat1", TestDataBuilder.CreateTestRiskConfig());
_manager.PortfolioKillSwitch = true;
var intent = TestDataBuilder.CreateValidIntent();
// Act
var decision = _manager.ValidatePortfolioRisk("strat1", intent);
// Assert
Assert.IsFalse(decision.Allow);
Assert.IsTrue(decision.RejectReason.ToLowerInvariant().Contains("kill switch"));
}
[TestMethod]
public void ValidatePortfolioRisk_WhenWithinLimits_Passes()
{
// Arrange
_manager.RegisterStrategy("strat1", TestDataBuilder.CreateTestRiskConfig());
var intent = TestDataBuilder.CreateValidIntent();
// Act
var decision = _manager.ValidatePortfolioRisk("strat1", intent);
// Assert
Assert.IsTrue(decision.Allow);
}
[TestMethod]
public void ResetDaily_ClearsPnL_UnblocksTrading()
{
// Arrange
_manager.RegisterStrategy("strat1", TestDataBuilder.CreateTestRiskConfig());
_manager.PortfolioDailyLossLimit = 500;
_manager.ReportPnL("strat1", -600);
var intent = TestDataBuilder.CreateValidIntent();
// Act
var blocked = _manager.ValidatePortfolioRisk("strat1", intent);
_manager.ResetDaily();
var unblocked = _manager.ValidatePortfolioRisk("strat1", intent);
// Assert
Assert.IsFalse(blocked.Allow);
Assert.IsTrue(unblocked.Allow);
}
}
}