diff --git a/Common/Statistics/PortfolioStatistics.cs b/Common/Statistics/PortfolioStatistics.cs index ef036c86688e..a0f326ec9a5d 100644 --- a/Common/Statistics/PortfolioStatistics.cs +++ b/Common/Statistics/PortfolioStatistics.cs @@ -299,7 +299,7 @@ public PortfolioStatistics( var benchmarkVariance = listBenchmark.Variance(); Beta = benchmarkVariance.IsNaNOrZero() ? 0 : (decimal)(listPerformance.Covariance(listBenchmark) / benchmarkVariance); - Alpha = Beta == 0 ? 0 : annualPerformance - (riskFreeRate + Beta * (benchmarkAnnualPerformance - riskFreeRate)); + Alpha = Beta == 0 ? 0 : Extensions.SafeDecimalCast((double)annualPerformance - ((double)riskFreeRate + (double)Beta * ((double)benchmarkAnnualPerformance - (double)riskFreeRate))); TrackingError = (decimal)Statistics.TrackingError(listPerformance, listBenchmark, (double)tradingDaysPerYear); diff --git a/Tests/Common/Statistics/PortfolioStatisticsTests.cs b/Tests/Common/Statistics/PortfolioStatisticsTests.cs index 628fb124fdea..cf136c78a9ad 100644 --- a/Tests/Common/Statistics/PortfolioStatisticsTests.cs +++ b/Tests/Common/Statistics/PortfolioStatisticsTests.cs @@ -186,6 +186,26 @@ public void PortfolioStatisticsDoesNotFailWhenAnnualPerformanceIsLarge() Assert.DoesNotThrow(() => new PortfolioStatistics(profitLoss, equity, portfolioTurnover, listPerformance, listBenchmark, startingCapital, riskFreeInterestRateModel, tradingDaysPerYear)); } + [Test] + public void PortfolioStatisticsDoesNotFailWhenAlphaExceedsDecimalRange() + { + var profitLoss = new SortedDictionary(); + var equity = new SortedDictionary(); + var portfolioTurnover = new SortedDictionary(); + // A deposit into a live account shows up as one huge daily return, which caps the annual performance at decimal.MaxValue + var listPerformance = new List() { 0.001, 0.004, 1.56, 0.002 }; + // The benchmark rises on the deposit day and falls overall, so beta is large and the benchmark term of alpha is negative + var listBenchmark = new List() { -0.004, -0.006, 0.005, -0.003 }; + var startingCapital = 100000; + var riskFreeInterestRateModel = new InterestRateProvider(); + var tradingDaysPerYear = 252; + + var statistics = default(PortfolioStatistics); + Assert.DoesNotThrow(() => statistics = new PortfolioStatistics(profitLoss, equity, portfolioTurnover, listPerformance, listBenchmark, startingCapital, riskFreeInterestRateModel, tradingDaysPerYear)); + + Assert.AreEqual(decimal.MaxValue, statistics.Alpha); + } + /// /// Initialize and return Portfolio Statistics depends on input data ///