/// <summary> /// Calculate /// </summary> /// <returns></returns> public virtual SeriesResponse Calculate() { var count = Values.Count(); var seriesInverse = 0; var seriesItem = new SeriesData(); var seriesItems = new List <SeriesData>(); for (var i = 0; i < count; i++) { var current = Values.ElementAtOrDefault(i); var previous = Values.ElementAtOrDefault(i - 1); if (current != null && previous != null) { var direction = 0; var change = current.Value - previous.Value; var gain = Math.Abs(Math.Max(change, 0.0)); var loss = Math.Abs(Math.Min(change, 0.0)); direction = previous.Value < current.Value ? 1 : direction; direction = previous.Value > current.Value ? -1 : direction; seriesItem = UpdateSeries(seriesInverse, direction, seriesItem, seriesItems); seriesItem.Gain += gain; seriesItem.Loss += loss; seriesItem.WinCount += gain > 0 ? 1 : 0; seriesItem.LossCount += loss > 0 ? 1 : 0; seriesItem.Count++; seriesInverse = direction; } } var response = new SeriesResponse { Count = 0, MaxWinCount = 0, MaxLossCount = 0, MaxWin = 0.0, MaxLoss = 0.0 }; if (seriesItems.Any()) { response.Count = seriesItems.Count; response.MaxWin = seriesItems.Max(o => o.Gain); response.MaxLoss = seriesItems.Max(o => o.Loss); response.MaxWinCount = seriesItems.Max(o => o.WinCount); response.MaxLossCount = seriesItems.Max(o => o.LossCount); } return(response); }
/// <summary> /// Calculate /// </summary> /// <returns></returns> public virtual IDictionary <string, IEnumerable <ScoreData> > Calculate() { if (Values.Any() == false) { return(new Dictionary <string, IEnumerable <ScoreData> >()); } var balanceMax = 0.0; var balanceDrawdown = 0.0; var balanceDrawdownMax = 0.0; var count = Values.Count(); var longs = new DirectionData(); var shorts = new DirectionData(); var inputBalance = Values.ElementAtOrDefault(0); var outputBalance = Values.ElementAtOrDefault(count - 1); for (var i = 0; i < count; i++) { var current = Values.ElementAtOrDefault(i); var previous = Values.ElementAtOrDefault(i - 1); if (current != null && previous != null) { var item = current.Value - previous.Value; var itemGain = Math.Abs(Math.Max(item, 0.0)); var itemLoss = Math.Abs(Math.Min(item, 0.0)); balanceDrawdownMax = Math.Max(balanceMax - current.Min, balanceDrawdownMax); balanceDrawdown = Math.Max(balanceMax - current.Value, balanceDrawdown); balanceMax = Math.Max(balanceMax, current.Value); switch (current.Direction) { case 1: longs.Gains += itemGain; longs.Losses += itemLoss; longs.GainsMax = Math.Max(itemGain, longs.GainsMax); longs.LossesMax = Math.Max(itemLoss, longs.LossesMax); longs.GainsCount += item > 0.0 ? 1 : 0; longs.LossesCount += item < 0.0 ? 1 : 0; longs.Commissions += current.Commission; break; case -1: shorts.Gains += itemGain; shorts.Losses += itemLoss; shorts.GainsMax = Math.Max(itemGain, shorts.GainsMax); shorts.LossesMax = Math.Max(itemLoss, shorts.LossesMax); shorts.GainsCount += item > 0.0 ? 1 : 0; shorts.LossesCount += item < 0.0 ? 1 : 0; shorts.Commissions += current.Commission; break; } } } var stats = new List <ScoreData>(); stats.Add(new ScoreData { Group = "Balance", Name = "Initial balance $", Value = inputBalance.Value }); stats.Add(new ScoreData { Group = "Balance", Name = "Final balance $", Value = outputBalance.Value }); stats.Add(new ScoreData { Group = "Balance", Name = "Commissions $", Value = longs.Commissions + shorts.Commissions }); stats.Add(new ScoreData { Group = "Balance", Name = "Drawdown $", Value = -balanceDrawdown }); stats.Add(new ScoreData { Group = "Balance", Name = "Drawdown %", Value = -Validate(() => balanceDrawdown * 100.0 / balanceMax) }); stats.Add(new ScoreData { Group = "Balance", Name = "Equity drawdown $", Value = -balanceDrawdownMax }); stats.Add(new ScoreData { Group = "Balance", Name = "Equity drawdown %", Value = -Validate(() => balanceDrawdownMax * 100.0 / balanceMax) }); stats.Add(new ScoreData { Group = "Balance", Name = "Change $", Value = new Change { Values = Values }.Calculate(0) }); stats.Add(new ScoreData { Group = "Balance", Name = "Change %", Value = new Change { Values = Values }.Calculate(1) }); var gains = longs.Gains + shorts.Gains; var losses = longs.Losses + shorts.Losses; var gainsMax = Math.Max(longs.GainsMax, shorts.GainsMax); var lossesMax = Math.Max(longs.LossesMax, shorts.LossesMax); var gainsCount = longs.GainsCount + shorts.GainsCount; var lossesCount = longs.LossesCount + shorts.LossesCount; var gainsAverage = Validate(() => gains / gainsCount); var lossesAverage = Validate(() => losses / lossesCount); var dealsCount = gainsCount + lossesCount; stats.Add(new ScoreData { Group = "Wins", Name = "Total gain $", Value = gains }); stats.Add(new ScoreData { Group = "Wins", Name = "Max single gain $", Value = gainsMax }); stats.Add(new ScoreData { Group = "Wins", Name = "Average gain $", Value = gainsAverage }); stats.Add(new ScoreData { Group = "Wins", Name = "Number of wins", Value = gainsCount }); stats.Add(new ScoreData { Group = "Wins", Name = "Percentage of wins %", Value = Validate(() => gainsCount * 100.0 / dealsCount) }); stats.Add(new ScoreData { Group = "Losses", Name = "Total loss $", Value = -losses }); stats.Add(new ScoreData { Group = "Losses", Name = "Max single loss $", Value = -lossesMax }); stats.Add(new ScoreData { Group = "Losses", Name = "Average loss $", Value = -lossesAverage }); stats.Add(new ScoreData { Group = "Losses", Name = "Number of losses", Value = lossesCount }); stats.Add(new ScoreData { Group = "Losses", Name = "Percentage of losses %", Value = Validate(() => lossesCount * 100.0 / dealsCount) }); stats.Add(new ScoreData { Group = "Longs", Name = "Total gain $", Value = longs.Gains }); stats.Add(new ScoreData { Group = "Longs", Name = "Total loss $", Value = -longs.Losses }); stats.Add(new ScoreData { Group = "Longs", Name = "Max gain $", Value = longs.GainsMax }); stats.Add(new ScoreData { Group = "Longs", Name = "Max loss $", Value = -longs.LossesMax }); stats.Add(new ScoreData { Group = "Longs", Name = "Average gain $", Value = Validate(() => longs.Gains / longs.GainsCount) }); stats.Add(new ScoreData { Group = "Longs", Name = "Average loss $", Value = -Validate(() => longs.Losses / longs.LossesCount) }); stats.Add(new ScoreData { Group = "Longs", Name = "Number of longs", Value = longs.GainsCount + longs.LossesCount }); stats.Add(new ScoreData { Group = "Longs", Name = "Percentage of longs %", Value = Validate(() => (longs.GainsCount + longs.LossesCount) * 100.0 / dealsCount) }); stats.Add(new ScoreData { Group = "Shorts", Name = "Total gain $", Value = shorts.Gains }); stats.Add(new ScoreData { Group = "Shorts", Name = "Total loss $", Value = -shorts.Losses }); stats.Add(new ScoreData { Group = "Shorts", Name = "Max gain $", Value = shorts.GainsMax }); stats.Add(new ScoreData { Group = "Shorts", Name = "Max loss $", Value = -shorts.LossesMax }); stats.Add(new ScoreData { Group = "Shorts", Name = "Average gain $", Value = Validate(() => shorts.Gains / shorts.GainsCount) }); stats.Add(new ScoreData { Group = "Shorts", Name = "Average loss $", Value = -Validate(() => shorts.Losses / shorts.LossesCount) }); stats.Add(new ScoreData { Group = "Shorts", Name = "Number of shorts", Value = shorts.GainsCount + shorts.LossesCount }); stats.Add(new ScoreData { Group = "Shorts", Name = "Percentage of shorts %", Value = Validate(() => (shorts.GainsCount + shorts.LossesCount) * 100.0 / dealsCount) }); stats.Add(new ScoreData { Group = "Ratios", Name = "Profit Factor", Value = Validate(() => gains / losses) }); stats.Add(new ScoreData { Group = "Ratios", Name = "Mean", Value = Validate(() => (gains - losses) / dealsCount) }); stats.Add(new ScoreData { Group = "Ratios", Name = "CAGR", Value = new CAGR { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "Sharpe Ratio", Value = new SharpeRatio { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "MAE", Value = new MAE { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "MFE", Value = new MFE { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "MAR", Value = new MAR { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "AHPR", Value = new AHPR { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "GHPR", Value = new GHPR { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "Z-Score", Value = new StandardScore { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "E-Ratio", Value = new EdgeRatio { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "Martin Ratio", Value = new MartinRatio { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "Sortino Ratio", Value = new SortinoRatio { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "Sterling Ratio", Value = new SterlingRatio { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "Kestner Ratio", Value = new KestnerRatio { Values = Values }.Calculate() }); stats.Add(new ScoreData { Group = "Ratios", Name = "LR Correlation", Value = new RegressionCorrelation { Values = Values }.Calculate() }); StatsByFrames = new FrameMetrics { Values = Values }.Calculate(); StatsBySeries = new SeriesMetrics { Values = Values }.Calculate(); return(stats.GroupBy(o => o.Group).ToDictionary(o => o.Key, o => o.AsEnumerable())); }