Skip to content

v1.1.0

Latest

Choose a tag to compare

@github-actions github-actions released this 17 Apr 19:59

Added

  • Boutquin.Trading.Recipes project: IBacktestDataset, BacktestDataset, BacktestDatasetBuilder, BacktestDatasetSpec, and FakeBacktestDataset — provides the bridge between the backtest engine and the Boutquin.MarketData IDataPipeline for production data workflows.
  • Nine new covariance estimators completing the four-tier lineup (13 total):
    • Linear shrinkage: LedoitWolfConstantCorrelationEstimator (average-correlation target — recommended default for equities), LedoitWolfSingleFactorEstimator (market factor target), OracleApproximatingShrinkageEstimator (OAS, Chen et al. 2010)
    • Nonlinear/denoising: QuadraticInverseShrinkageEstimator (per-eigenvalue shrinkage, gold standard for N ≥ 10), TracyWidomDenoisedCovarianceEstimator (sharper finite-sample threshold, preferred when T/N < 5)
    • Factor/sparse/nonparametric: PoetCovarianceEstimator (low-rank + sparse residual), NercomeCovarianceEstimator (nonparametric split-sample), DoublySparseEstimator (sparsifies eigenvectors + noise eigenvalues), DetonedCovarianceEstimator (PC1 market-factor shrinkage, Lopez de Prado 2020)

Changed

  • CorrelationAnalyzer.Analyze now delegates covariance computation to Boutquin.Numerics.Statistics.SampleCovarianceEstimator, removing the inline two-pass covariance loop (~25 lines). RollingCorrelation now delegates entirely to Boutquin.Numerics.Statistics.PearsonCorrelation.Rolling, removing ~30 lines of inline rolling-window arithmetic.
  • MonteCarloSimulator.Run now delegates to Boutquin.Numerics.MonteCarlo.BootstrapMonteCarloEngine, removing the inline bootstrap loop, per-simulation mean/std computation, and private Percentile helper (~30 lines).
  • SampleCovarianceEstimator, ExponentiallyWeightedCovarianceEstimator, LedoitWolfShrinkageEstimator, DenoisedCovarianceEstimator, and DetonedCovarianceEstimator now delegate to Boutquin.Numerics.Statistics, removing ~900 lines of duplicated math.
  • PrincipalPortfolioAnalyzer, EffectiveNumberOfBets, and PcaRegimeSignal now use Boutquin.Numerics.LinearAlgebra.JacobiEigenDecomposition, removing ~400 lines of inline Jacobi sweeps.
  • FactorRegressor now uses Boutquin.Numerics.Solvers.OrdinaryLeastSquares<decimal> (Householder QR, 28-digit accuracy) instead of hand-rolled Gaussian elimination in double.
  • DecimalArrayExtensions.ValueAtRisk now delegates to Boutquin.Numerics.Distributions.InverseNormal.Evaluate, removing the inline 52-line Abramowitz & Stegun rational approximation.
  • MinimumVarianceConstruction and MeanVarianceConstruction now use Boutquin.Numerics.Solvers.ActiveSetQpSolver (Cholesky active-set with correct KKT cross-covariance handling) instead of the hand-rolled CholeskyQpSolver, which had a bug: it ignored the Σ_FC * w_C cross-covariance adjustment when solving the free-variable sub-problem after fixing weights at bounds, causing constrained solutions to be suboptimal.
  • MaximumDiversificationConstruction likewise migrated to ActiveSetQpSolver.
  • DecimalArrayExtensions.Skewness and Kurtosis now delegate to Boutquin.Numerics.Statistics.SampleSkewness.Compute and SampleExcessKurtosis.Compute, removing ~40 lines of duplicated math.
  • RollingWindow<T> is now consumed from Boutquin.Numerics.Collections instead of the local Domain/Helpers copy.
  • Boutquin.Numerics version bumped to 1.1.0.

Fixed

  • Collinear factor inputs to FactorRegressor now correctly throw CalculationException instead of OverflowException. The fix is in Boutquin.Numerics.LinearAlgebra.Internal.HouseholderQr<T>.BuildXtXInverse, which now converts decimal arithmetic overflow to InvalidOperationException.
  • MinimumVarianceConstruction constrained QP now finds the true global minimum. The old CholeskyQpSolver ignored the KKT cross-covariance term Σ_FC * w_C when fixed-bound variables were present, causing the free-variable sub-problem to be solved against an incorrect RHS and producing a higher-variance portfolio than necessary. ActiveSetQpSolver accounts for the full KKT system and matches scipy SLSQP to float64 precision.

Removed

  • Asset value object removed from Boutquin.Trading.Domain.ValueObjects; replaced by Boutquin.MarketData.Abstractions.ReferenceData.Symbol. Both are readonly record struct with a Ticker property; Symbol is the canonical type at the data-access layer.
  • AssetClassCode, ContinentCode, CountryCode, CurrencyCode, DividendType, ExchangeCode, SecuritySymbolStandard, and TimeZoneCode enums removed from Boutquin.Trading.Domain.Enums. All eight are now consumed from Boutquin.MarketData.Abstractions.ReferenceData, which is the canonical source. Boutquin.Trading.Domain.Enums retains only backtest-specific enums (TradeAction, OrderType, SignalType, EconomicRegime, RebalancingFrequency, AccountType, HoldingPeriod, CanadianProvince, UsState).
  • FamaFrenchDataset enum removed; the IDataPipeline architecture uses Boutquin.MarketData.Abstractions.ReferenceData.FactorDatasetId (a string-typed record struct) for all factor dataset identification.
  • MarketDataNotFoundException, MarketDataProcessingException, MarketDataRetrievalException, MarketDataStorageException removed from Boutquin.Trading.Domain.Exceptions; canonical versions live in Boutquin.MarketData.Abstractions.Exceptions. Also removed dead-code exceptions SymbolReaderException, NegativeBusinessDaysPerYearException, and NegativeRiskFreeRateException (zero usages).
  • Domain.Data.MarketData and Domain.Data.FxRateData records removed; backtest infrastructure uses Boutquin.MarketData.Abstractions.Records.Bar and FxRate directly.
  • Boutquin.Trading.Domain.Helpers.CholeskyQpSolver removed; replaced by Boutquin.Numerics.Solvers.ActiveSetQpSolver.
  • Boutquin.Trading.Domain.Helpers.RollingWindow<T> removed; replaced by Boutquin.Numerics.Collections.RollingWindow<T>.