17 using System.Collections.Generic;
21 using MathNet.Numerics.Distributions;
22 using MathNet.Numerics.Statistics;
39 public static decimal
DrawdownPercent(SortedDictionary<DateTime, decimal> equityOverTime,
int rounding = 2)
44 var lPrices = equityOverTime.Values.ToList();
45 var lDrawdowns =
new List<decimal>();
46 var high = lPrices[0];
47 foreach (var price
in lPrices)
49 if (price >= high) high = price;
50 lDrawdowns.Add((price/high) - 1);
52 dd = Math.Round(Math.Abs(lDrawdowns.Min()), rounding);
70 if (years == 0 || startingCapital == 0)
74 var power = 1 / (double)years;
75 var baseNumber = (double)finalCapital / (
double)startingCapital;
76 var result = Math.Pow(baseNumber, power) - 1;
77 return result.IsNaNOrInfinity() ? 0 : result.SafeDecimalCast();
89 return Math.Pow((performance.Average() + 1), tradingDaysPerYear) - 1;
99 public static double AnnualVariance(List<double> performance,
double tradingDaysPerYear)
101 var variance = performance.Variance();
102 return variance.IsNaNOrZero() ? 0 : variance * tradingDaysPerYear;
117 return Math.Sqrt(
AnnualVariance(performance, tradingDaysPerYear));
128 public static double AnnualDownsideVariance(List<double> performance,
double tradingDaysPerYear,
double minimumAcceptableReturn = 0)
130 return AnnualVariance(performance.Where(ret => ret < minimumAcceptableReturn).ToList(), tradingDaysPerYear);
153 public static double TrackingError(List<double> algoPerformance, List<double> benchmarkPerformance,
double tradingDaysPerYear)
156 if (algoPerformance.Count != benchmarkPerformance.Count)
161 var performanceDifference =
new List<double>();
162 for (var i = 0; i < algoPerformance.Count; i++)
164 performanceDifference.Add(algoPerformance[i] - benchmarkPerformance[i]);
167 return Math.Sqrt(
AnnualVariance(performanceDifference, tradingDaysPerYear));
178 public static double SharpeRatio(
double averagePerformance,
double standardDeviation,
double riskFreeRate)
180 return standardDeviation == 0 ? 0 : (averagePerformance - riskFreeRate) / standardDeviation;
191 public static decimal
SharpeRatio(decimal averagePerformance, decimal standardDeviation, decimal riskFreeRate)
193 return SharpeRatio((
double)averagePerformance, (
double)standardDeviation, (
double)riskFreeRate).SafeDecimalCast();
204 public static double SharpeRatio(List<double> algoPerformance,
double riskFreeRate,
double tradingDaysPerYear)
218 public static double SortinoRatio(List<double> algoPerformance,
double riskFreeRate,
double tradingDaysPerYear,
double minimumAcceptableReturn = 0)
230 double benchmarkSharpeRatio)
234 var skewness = listPerformance.Skewness();
235 var kurtosis = listPerformance.Kurtosis();
237 var operandA = skewness * observedSharpeRatio;
238 var operandB = ((kurtosis - 1) / 4) * (Math.Pow(observedSharpeRatio, 2));
241 var estimateStandardDeviation = Math.Pow((1 - operandA + operandB) / (listPerformance.Count - 1), 0.5);
243 if (
double.IsNaN(estimateStandardDeviation))
249 var value = estimateStandardDeviation.IsNaNOrZero() ? 0 : (observedSharpeRatio - benchmarkSharpeRatio) / estimateStandardDeviation;
250 return (
new Normal()).CumulativeDistribution(value);
260 var performanceAverage = listPerformance.Average();
261 var standardDeviation = listPerformance.StandardDeviation();
263 return standardDeviation.IsNaNOrZero() ? 0 : performanceAverage / standardDeviation;
273 public static decimal
DrawdownPercent(decimal current, decimal high,
int roundingDecimals = 2)
277 throw new ArgumentException(
"High value must not be 0");
280 var drawdownPercentage = ((current / high) - 1) * 100;
281 return Math.Round(drawdownPercentage, roundingDecimals);