feat(wbs): WBS M4/M5 C# domain engines & Vue 3 PrimeVue AG-Grid migration [WBS-10]
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Failing after 12s
Validators (Pushes and Pull Requests) / validate-core (push) Failing after 20s

This commit is contained in:
2026-07-24 11:31:36 +09:00
parent 2fe4cb288f
commit 757f2439af
81 changed files with 3739 additions and 2515 deletions
@@ -0,0 +1,30 @@
using System.Collections.Generic;
using Xunit;
using QuantEngine.Core.Domain;
namespace QuantEngine.Core.Tests;
public class BacktesterTests
{
[Fact]
public void RunBacktest_WithValidData_ReturnsCorrectMetrics()
{
// Arrange
var backtester = new Backtester();
var dailyValues = new List<decimal> { 100m, 102m, 101m, 105m, 108m, 110m };
var trades = new List<BacktestTrade>
{
new BacktestTrade("005930", System.DateTime.UtcNow.AddDays(-5), System.DateTime.UtcNow, 100m, 110m, 10, 0.10m, 1.5m)
};
// Act
var result = backtester.RunBacktest("test_run_01", dailyValues, trades, 1000m);
// Assert
Assert.Equal("test_run_01", result.RunId);
Assert.Equal("PASS", result.GateStatus);
Assert.True(result.SharpeRatio > 0);
Assert.True(result.MaxDrawdown >= 0 && result.MaxDrawdown <= 1);
Assert.True(result.TurnoverRate > 0);
}
}
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using Xunit;
using QuantEngine.Core.Domain;
namespace QuantEngine.Core.Tests;
public class FactorWeightCalibratorTests
{
[Fact]
public void CalibrateWeights_WithValidInputs_SatisfiesBoundsAndShrinkage()
{
// Arrange
var calibrator = new FactorWeightCalibrator();
var baseWeights = new Dictionary<string, decimal>
{
{ "F01_MOMENTUM", 0.30m },
{ "F02_VOLATILITY", 0.20m }
};
var rawWeights = new Dictionary<string, decimal>
{
{ "F01_MOMENTUM", 0.60m }, // Out of bounds raw
{ "F02_VOLATILITY", 0.10m }
};
// Act
var result = calibrator.CalibrateWeights("SS001_v1", baseWeights, rawWeights);
// Assert
Assert.Equal("SS001_v1", result.FormulaId);
Assert.Equal("PASS", result.GateStatus);
Assert.True(result.WeightsWithinBounds);
Assert.True(result.OosComparisonReported);
Assert.Equal(0.45m, result.Weights[0].CalibratedWeight); // Clamped to 0.30 * 1.5 = 0.45
}
}
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using Xunit;
using QuantEngine.Core.Domain;
namespace QuantEngine.Core.Tests;
public class MarketRegimeDetectorTests
{
[Fact]
public void DetectRegime_WithBullTrend_ReturnsBullLowVol()
{
// Arrange
var detector = new MarketRegimeDetector();
var prices = new List<decimal>();
for (int i = 1; i <= 200; i++)
{
prices.Add(100m + i * 0.1m); // Steady uptrend
}
// Act
var result = detector.DetectRegime("2026-07-24", prices);
// Assert
Assert.Equal("2026-07-24", result.AsOfDate);
Assert.Equal(MarketRegimeType.BULL_LOW_VOL, result.Regime);
Assert.True(result.CurrentIndexPrice > result.Sma200);
}
}
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using Xunit;
using QuantEngine.Core.Domain;
namespace QuantEngine.Core.Tests;
public class PortfolioSizerTests
{
[Fact]
public void CalculateTargetAllocations_WithValidScores_EnforcesCapsCorrectly()
{
// Arrange
var sizer = new PortfolioSizer();
var scores = new Dictionary<string, decimal>
{
{ "005930", 80m },
{ "000660", 20m }
};
var prices = new Dictionary<string, decimal>
{
{ "005930", 70000m },
{ "000660", 120000m }
};
var vols = new Dictionary<string, decimal>();
// Act
var packet = sizer.CalculateTargetAllocations("2026-07-24", 100000000m, 0.10m, scores, prices, vols);
// Assert
Assert.Equal("2026-07-24", packet.AsOfDate);
Assert.True(packet.AllCapsSatisfied);
Assert.Equal(10000000m, packet.ReservedCashKrw);
Assert.Equal(2, packet.Allocations.Count);
Assert.True(packet.Allocations[0].TargetWeightRatio <= 0.25m); // Cap enforced
}
}
@@ -0,0 +1,29 @@
using System.Collections.Generic;
using Xunit;
using QuantEngine.Core.Domain;
namespace QuantEngine.Core.Tests;
public class WalkForwardEngineTests
{
[Fact]
public void RunWalkForward_WithValidData_ReturnsMinimumFourWindowsAndPassesGate()
{
// Arrange
var engine = new WalkForwardEngine();
var dailyValues = new List<decimal>();
for (int i = 0; i < 252 * 3; i++)
{
dailyValues.Add(100m + (i * 0.1m));
}
// Act
var result = engine.RunWalkForward("formula_ss001_v1", dailyValues, 4);
// Assert
Assert.Equal("formula_ss001_v1", result.FormulaId);
Assert.Equal("PASS", result.GateStatus);
Assert.True(result.TotalWindows >= 4);
Assert.True(result.AverageOosSharpe > 0);
}
}