/// <summary> /// Returns a summary of the algorithm performance as a dictionary /// </summary> private static Dictionary <string, string> GetSummary(AlgorithmPerformance totalPerformance, decimal totalFees, int totalTransactions) { return(new Dictionary <string, string> { { "Total Trades", totalTransactions.ToStringInvariant() }, { "Average Win", Math.Round(totalPerformance.PortfolioStatistics.AverageWinRate.SafeMultiply100(), 2).ToStringInvariant() + "%" }, { "Average Loss", Math.Round(totalPerformance.PortfolioStatistics.AverageLossRate.SafeMultiply100(), 2).ToStringInvariant() + "%" }, { "Compounding Annual Return", Math.Round(totalPerformance.PortfolioStatistics.CompoundingAnnualReturn.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { "Drawdown", Math.Round(totalPerformance.PortfolioStatistics.Drawdown.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { "Expectancy", Math.Round(totalPerformance.PortfolioStatistics.Expectancy, 3).ToStringInvariant() }, { "Net Profit", Math.Round(totalPerformance.PortfolioStatistics.TotalNetProfit.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { "Sharpe Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.SharpeRatio, 3).ToStringInvariant() }, { "Probabilistic Sharpe Ratio", Math.Round(totalPerformance.PortfolioStatistics.ProbabilisticSharpeRatio.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { "Loss Rate", Math.Round(totalPerformance.PortfolioStatistics.LossRate.SafeMultiply100()).ToStringInvariant() + "%" }, { "Win Rate", Math.Round(totalPerformance.PortfolioStatistics.WinRate.SafeMultiply100()).ToStringInvariant() + "%" }, { "Profit-Loss Ratio", Math.Round(totalPerformance.PortfolioStatistics.ProfitLossRatio, 2).ToStringInvariant() }, { "Alpha", Math.Round((double)totalPerformance.PortfolioStatistics.Alpha, 3).ToStringInvariant() }, { "Beta", Math.Round((double)totalPerformance.PortfolioStatistics.Beta, 3).ToStringInvariant() }, { "Annual Standard Deviation", Math.Round((double)totalPerformance.PortfolioStatistics.AnnualStandardDeviation, 3).ToStringInvariant() }, { "Annual Variance", Math.Round((double)totalPerformance.PortfolioStatistics.AnnualVariance, 3).ToStringInvariant() }, { "Information Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.InformationRatio, 3).ToStringInvariant() }, { "Tracking Error", Math.Round((double)totalPerformance.PortfolioStatistics.TrackingError, 3).ToStringInvariant() }, { "Treynor Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.TreynorRatio, 3).ToStringInvariant() }, { "Total Fees", "$" + totalFees.ToStringInvariant("0.00") } }); }
/// <summary> /// Returns a summary of the algorithm performance as a dictionary /// </summary> private static Dictionary <string, string> GetSummary(AlgorithmPerformance totalPerformance, CapacityEstimate estimatedStrategyCapacity, decimal totalFees, int totalTransactions, string accountCurrencySymbol) { var capacity = 0m; var lowestCapacitySymbol = Symbol.Empty; if (estimatedStrategyCapacity != null) { capacity = estimatedStrategyCapacity.Capacity; lowestCapacitySymbol = estimatedStrategyCapacity.LowestCapacityAsset ?? Symbol.Empty; } return(new Dictionary <string, string> { { PerformanceMetrics.TotalTrades, totalTransactions.ToStringInvariant() }, { PerformanceMetrics.AverageWin, Math.Round(totalPerformance.PortfolioStatistics.AverageWinRate.SafeMultiply100(), 2).ToStringInvariant() + "%" }, { PerformanceMetrics.AverageLoss, Math.Round(totalPerformance.PortfolioStatistics.AverageLossRate.SafeMultiply100(), 2).ToStringInvariant() + "%" }, { PerformanceMetrics.CompoundingAnnualReturn, Math.Round(totalPerformance.PortfolioStatistics.CompoundingAnnualReturn.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { PerformanceMetrics.Drawdown, Math.Round(totalPerformance.PortfolioStatistics.Drawdown.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { PerformanceMetrics.Expectancy, Math.Round(totalPerformance.PortfolioStatistics.Expectancy, 3).ToStringInvariant() }, { PerformanceMetrics.NetProfit, Math.Round(totalPerformance.PortfolioStatistics.TotalNetProfit.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { PerformanceMetrics.SharpeRatio, Math.Round((double)totalPerformance.PortfolioStatistics.SharpeRatio, 3).ToStringInvariant() }, { PerformanceMetrics.ProbabilisticSharpeRatio, Math.Round(totalPerformance.PortfolioStatistics.ProbabilisticSharpeRatio.SafeMultiply100(), 3).ToStringInvariant() + "%" }, { PerformanceMetrics.LossRate, Math.Round(totalPerformance.PortfolioStatistics.LossRate.SafeMultiply100()).ToStringInvariant() + "%" }, { PerformanceMetrics.WinRate, Math.Round(totalPerformance.PortfolioStatistics.WinRate.SafeMultiply100()).ToStringInvariant() + "%" }, { PerformanceMetrics.ProfitLossRatio, Math.Round(totalPerformance.PortfolioStatistics.ProfitLossRatio, 2).ToStringInvariant() }, { PerformanceMetrics.Alpha, Math.Round((double)totalPerformance.PortfolioStatistics.Alpha, 3).ToStringInvariant() }, { PerformanceMetrics.Beta, Math.Round((double)totalPerformance.PortfolioStatistics.Beta, 3).ToStringInvariant() }, { PerformanceMetrics.AnnualStandardDeviation, Math.Round((double)totalPerformance.PortfolioStatistics.AnnualStandardDeviation, 3).ToStringInvariant() }, { PerformanceMetrics.AnnualVariance, Math.Round((double)totalPerformance.PortfolioStatistics.AnnualVariance, 3).ToStringInvariant() }, { PerformanceMetrics.InformationRatio, Math.Round((double)totalPerformance.PortfolioStatistics.InformationRatio, 3).ToStringInvariant() }, { PerformanceMetrics.TrackingError, Math.Round((double)totalPerformance.PortfolioStatistics.TrackingError, 3).ToStringInvariant() }, { PerformanceMetrics.TreynorRatio, Math.Round((double)totalPerformance.PortfolioStatistics.TreynorRatio, 3).ToStringInvariant() }, { PerformanceMetrics.TotalFees, accountCurrencySymbol + totalFees.ToStringInvariant("0.00") }, { PerformanceMetrics.EstimatedStrategyCapacity, accountCurrencySymbol + capacity.RoundToSignificantDigits(2).ToStringInvariant() }, { PerformanceMetrics.LowestCapacityAsset, lowestCapacitySymbol != Symbol.Empty ? lowestCapacitySymbol.ID.ToString() : "" }, }); }
/// <summary> /// Initializes a new instance of the <see cref="StatisticsResults"/> class /// </summary> public StatisticsResults() { TotalPerformance = new AlgorithmPerformance(); RollingPerformances = new Dictionary <string, AlgorithmPerformance>(); Summary = new Dictionary <string, string>(); }
/// <summary> /// Initializes a new instance of the <see cref="StatisticsResults"/> class /// </summary> /// <param name="totalPerformance">The algorithm total performance</param> /// <param name="rollingPerformances">The algorithm rolling performances</param> /// <param name="summary">The summary performance dictionary</param> public StatisticsResults(AlgorithmPerformance totalPerformance, Dictionary <string, AlgorithmPerformance> rollingPerformances, Dictionary <string, string> summary) { TotalPerformance = totalPerformance; RollingPerformances = rollingPerformances; Summary = summary; }
/// <summary> /// Returns a summary of the algorithm performance as a dictionary /// </summary> private static Dictionary<string, string> GetSummary(AlgorithmPerformance totalPerformance, decimal totalFees, int totalTransactions) { return new Dictionary<string, string> { { "Total Trades", totalTransactions.ToString(CultureInfo.InvariantCulture) }, { "Average Win", Math.Round(totalPerformance.PortfolioStatistics.AverageWinRate * 100, 2) + "%" }, { "Average Loss", Math.Round(totalPerformance.PortfolioStatistics.AverageLossRate * 100, 2) + "%" }, { "Compounding Annual Return", Math.Round(totalPerformance.PortfolioStatistics.CompoundingAnnualReturn * 100, 3) + "%" }, { "Drawdown", (Math.Round(totalPerformance.PortfolioStatistics.Drawdown * 100, 3)) + "%" }, { "Expectancy", Math.Round(totalPerformance.PortfolioStatistics.Expectancy, 3).ToString(CultureInfo.InvariantCulture) }, { "Net Profit", Math.Round(totalPerformance.PortfolioStatistics.TotalNetProfit * 100, 3) + "%"}, { "Sharpe Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.SharpeRatio, 3).ToString(CultureInfo.InvariantCulture) }, { "Loss Rate", Math.Round(totalPerformance.PortfolioStatistics.LossRate * 100) + "%" }, { "Win Rate", Math.Round(totalPerformance.PortfolioStatistics.WinRate * 100) + "%" }, { "Profit-Loss Ratio", Math.Round(totalPerformance.PortfolioStatistics.ProfitLossRatio, 2).ToString(CultureInfo.InvariantCulture) }, { "Alpha", Math.Round((double)totalPerformance.PortfolioStatistics.Alpha, 3).ToString(CultureInfo.InvariantCulture) }, { "Beta", Math.Round((double)totalPerformance.PortfolioStatistics.Beta, 3).ToString(CultureInfo.InvariantCulture) }, { "Annual Standard Deviation", Math.Round((double)totalPerformance.PortfolioStatistics.AnnualStandardDeviation, 3).ToString(CultureInfo.InvariantCulture) }, { "Annual Variance", Math.Round((double)totalPerformance.PortfolioStatistics.AnnualVariance, 3).ToString(CultureInfo.InvariantCulture) }, { "Information Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.InformationRatio, 3).ToString(CultureInfo.InvariantCulture) }, { "Tracking Error", Math.Round((double)totalPerformance.PortfolioStatistics.TrackingError, 3).ToString(CultureInfo.InvariantCulture) }, { "Treynor Ratio", Math.Round((double)totalPerformance.PortfolioStatistics.TreynorRatio, 3).ToString(CultureInfo.InvariantCulture) }, { "Total Fees", "$" + totalFees.ToString("0.00") } }; }
/// <summary> /// Constructor for the result class using dictionary objects. /// </summary> public BacktestResult(IDictionary<string, Chart> charts, IDictionary<int, Order> orders, IDictionary<DateTime, decimal> profitLoss, IDictionary<string, string> statistics, IDictionary<string, string> runtimeStatistics, Dictionary<string, AlgorithmPerformance> rollingWindow, AlgorithmPerformance totalPerformance = null) { Charts = charts; Orders = orders; ProfitLoss = profitLoss; Statistics = statistics; RuntimeStatistics = runtimeStatistics; RollingWindow = rollingWindow; TotalPerformance = totalPerformance; }
/// <summary> /// Initializes a new instance of the <see cref="StatisticsResults"/> class /// </summary> public StatisticsResults() { TotalPerformance = new AlgorithmPerformance(); RollingPerformances = new Dictionary<string, AlgorithmPerformance>(); Summary = new Dictionary<string, string>(); }
/// <summary> /// Initializes a new instance of the <see cref="StatisticsResults"/> class /// </summary> /// <param name="totalPerformance">The algorithm total performance</param> /// <param name="rollingPerformances">The algorithm rolling performances</param> /// <param name="summary">The summary performance dictionary</param> public StatisticsResults(AlgorithmPerformance totalPerformance, Dictionary<string, AlgorithmPerformance> rollingPerformances, Dictionary<string, string> summary) { TotalPerformance = totalPerformance; RollingPerformances = rollingPerformances; Summary = summary; }
/// <summary> /// Returns the QPAS statistics for a QuantConnect Algorithm (uses Equity Curve) /// </summary> /// <param name="fromDate"></param> /// <param name="toDate"></param> /// <param name="trades"></param> /// <param name="totalPerformance"></param> /// <param name="rollingPerformances"></param> /// <param name="summary"></param> /// <param name="startingCapital"></param> /// <returns>QPAS Performance Statistics (JSON)</returns> public static string GetPerformanceQPAS( DateTime fromDate, DateTime toDate, List<Trade> trades, AlgorithmPerformance totalPerformance, Dictionary<string, AlgorithmPerformance> rollingPerformances, Dictionary<string, string> summary, decimal startingCapital) { if (trades.Count <= 0) return ""; // Equity Curve Statistics var qpasEC = new QPAS.EquityCurve((double)startingCapital, totalPerformance.TradeStatistics.StartDateTime); foreach (var trade in trades) qpasEC.AddChange((double)trade.ProfitLoss, trade.ExitTime); var equityCurveStatsQPAS = QPAS.PerformanceMeasurement.EquityCurveStats(qpasEC, (int)(toDate - fromDate).TotalDays); // Trade Statistics var instrument = new EntityModel.Instrument { ID = 1, Multiplier = 1, AssetCategory = EntityModel.AssetClass.Cash }; instrument.Symbol = trades[0].Symbol.Value; var qpasTrades = new List<EntityModel.Trade>(); foreach (var trade in trades) { var qpasTrade = new EntityModel.Trade(); qpasTrade.Orders = new List<EntityModel.Order> { // Open Order new EntityModel.Order { Instrument = instrument, Quantity = trade.Quantity, Price = trade.EntryPrice, BuySell = trade.BuyOrSell, TradeDate = trade.EntryTime, AssetCategory = EntityModel.AssetClass.Cash }, // Close Order new EntityModel.Order { Instrument = instrument, Quantity = trade.Quantity, Price = trade.ExitPrice, BuySell = trade.BuyOrSellClose, TradeDate = trade.ExitTime, AssetCategory = EntityModel.AssetClass.Cash } }; qpasTrade.ResultDollars = trade.ProfitLoss; qpasTrade.Commissions = trade.TotalFees; qpasTrades.Add(qpasTrade); } var capitalInPeriod = new List<decimal>(); var capital = startingCapital; capitalInPeriod.Add(capital); foreach (var trade in trades) { capital += trade.ProfitLoss; capitalInPeriod.Add(capital); } var tradeStatsQPAS = QPAS.PerformanceMeasurement.TradeStats(qpasTrades, fromDate, toDate, capitalInPeriod); // Merge Results into a Sorted Dictionary var statsQPAS = new SortedDictionary<string, string>(); foreach (KeyValuePair<string, string> entry in equityCurveStatsQPAS) statsQPAS.Add(entry.Key + " (Equity)", entry.Value); foreach (KeyValuePair<string, string> entry in tradeStatsQPAS) statsQPAS.Add(entry.Key + " (Trade)", entry.Value); // Return result as JSON return JsonConvert.SerializeObject(statsQPAS, Formatting.Indented); }