/// <summary> /// Algorithm "beta" statistic - the covariance between the algorithm and benchmark performance, divided by benchmark's variance /// </summary> /// <param name="algoPerformance">Collection of double values for algorithm daily performance.</param> /// <param name="benchmarkPerformance">Collection of double benchmark daily performance values.</param> /// <remarks>Invokes the variance and covariance extensions in the MathNet Statistics class</remarks> /// <returns>Value for beta</returns> public static double Beta(List<double> algoPerformance, List<double> benchmarkPerformance) { return algoPerformance.Covariance(benchmarkPerformance) / benchmarkPerformance.Variance(); }
/// <summary> /// Initializes a new instance of the <see cref="PortfolioStatistics"/> class /// </summary> /// <param name="profitLoss">Trade record of profits and losses</param> /// <param name="equity">The list of daily equity values</param> /// <param name="listPerformance">The list of algorithm performance values</param> /// <param name="listBenchmark">The list of benchmark values</param> /// <param name="startingCapital">The algorithm starting capital</param> /// <param name="tradingDaysPerYear">The number of trading days per year</param> public PortfolioStatistics( SortedDictionary<DateTime, decimal> profitLoss, SortedDictionary<DateTime, decimal> equity, List<double> listPerformance, List<double> listBenchmark, decimal startingCapital, int tradingDaysPerYear = 252) { if (startingCapital == 0) return; var runningCapital = startingCapital; var totalProfit = 0m; var totalLoss = 0m; var totalWins = 0; var totalLosses = 0; foreach (var pair in profitLoss) { var tradeProfitLoss = pair.Value; if (tradeProfitLoss > 0) { totalProfit += tradeProfitLoss / runningCapital; totalWins++; } else { totalLoss += tradeProfitLoss / runningCapital; totalLosses++; } runningCapital += tradeProfitLoss; } AverageWinRate = totalWins == 0 ? 0 : totalProfit / totalWins; AverageLossRate = totalLosses == 0 ? 0 : totalLoss / totalLosses; ProfitLossRatio = AverageLossRate == 0 ? 0 : AverageWinRate / Math.Abs(AverageLossRate); WinRate = profitLoss.Count == 0 ? 0 : (decimal)totalWins / profitLoss.Count; LossRate = profitLoss.Count == 0 ? 0 : (decimal)totalLosses / profitLoss.Count; Expectancy = WinRate * ProfitLossRatio - LossRate; if (profitLoss.Count > 0) { TotalNetProfit = (equity.Values.LastOrDefault() / startingCapital) - 1; } var fractionOfYears = (decimal)(equity.Keys.LastOrDefault() - equity.Keys.FirstOrDefault()).TotalDays / 365; CompoundingAnnualReturn = CompoundingAnnualPerformance(startingCapital, equity.Values.LastOrDefault(), fractionOfYears); Drawdown = DrawdownPercent(equity, 3); AnnualVariance = GetAnnualVariance(listPerformance, tradingDaysPerYear); AnnualStandardDeviation = (decimal)Math.Sqrt((double)AnnualVariance); var annualPerformance = GetAnnualPerformance(listPerformance, tradingDaysPerYear); SharpeRatio = AnnualStandardDeviation == 0 ? 0 : (annualPerformance - RiskFreeRate) / AnnualStandardDeviation; var benchmarkVariance = listBenchmark.Variance(); Beta = benchmarkVariance.IsNaNOrZero() ? 0 : (decimal)(listPerformance.Covariance(listBenchmark) / benchmarkVariance); Alpha = Beta == 0 ? 0 : annualPerformance - (RiskFreeRate + Beta * (GetAnnualPerformance(listBenchmark, tradingDaysPerYear) - RiskFreeRate)); var correlation = Correlation.Pearson(listPerformance, listBenchmark); var benchmarkAnnualVariance = benchmarkVariance * tradingDaysPerYear; TrackingError = correlation.IsNaNOrZero() || benchmarkAnnualVariance.IsNaNOrZero() ? 0 : (decimal)Math.Sqrt((double)AnnualVariance - 2 * correlation * (double)AnnualStandardDeviation * Math.Sqrt(benchmarkAnnualVariance) + benchmarkAnnualVariance); InformationRatio = TrackingError == 0 ? 0 : (annualPerformance - GetAnnualPerformance(listBenchmark, tradingDaysPerYear)) / TrackingError; TreynorRatio = Beta == 0 ? 0 : (annualPerformance - RiskFreeRate) / Beta; }