17 using System.Collections.Generic;
21 using Newtonsoft.Json;
27 using System.Text.RegularExpressions;
36 private string _template;
37 private readonly List<IReportElement> _elements;
55 public Report(
string name,
string description,
string version,
BacktestResult backtest,
LiveResult live,
string pointInTimePortfolioDestination =
null,
string cssOverride =
null,
string htmlCustom =
null)
57 _template = htmlCustom ??
File.ReadAllText(
"template.html");
58 var crisisHtmlContent =
GetRegexInInput(
@"<!--crisis(\r|\n)*((\r|\n|.)*?)crisis-->", _template);
59 var parametersHtmlContent =
GetRegexInInput(
@"<!--parameters(\r|\n)*((\r|\n|.)*?)parameters-->", _template);
64 var backtestOrders = backtest?.
Orders?.Values.ToList() ??
new List<Order>();
65 var liveOrders = live?.
Orders?.Values.ToList() ??
new List<Order>();
74 Log.
Trace($
"QuantConnect.Report.Report(): Processing backtesting orders");
76 Log.
Trace($
"QuantConnect.Report.Report(): Processing live orders");
77 var livePortfolioInTime =
PortfolioLooper.
FromOrders(liveCurve, liveOrders, liveConfiguration, liveSeries:
true).ToList();
79 var destination = pointInTimePortfolioDestination ??
Config.
Get(
"report-destination");
80 if (!
string.IsNullOrWhiteSpace(destination))
82 if (backtestPortfolioInTime.Count != 0)
84 var dailyBacktestPortfolioInTime = backtestPortfolioInTime
86 .GroupBy(x => x.Time.Date)
87 .Select(kvp => kvp.Last())
91 var outputFile = destination.Replace(
".html",
string.Empty) +
"-backtesting-portfolio.json";
92 Log.
Trace($
"Report.Report(): Writing backtest point-in-time portfolios to JSON file: {outputFile}");
93 var backtestPortfolioOutput = JsonConvert.SerializeObject(dailyBacktestPortfolioInTime);
94 File.WriteAllText(outputFile, backtestPortfolioOutput);
96 if (livePortfolioInTime.Count != 0)
98 var dailyLivePortfolioInTime = livePortfolioInTime
100 .GroupBy(x => x.Time.Date)
101 .Select(kvp => kvp.Last())
102 .OrderBy(x => x.Time)
105 var outputFile = destination.Replace(
".html",
string.Empty) +
"-live-portfolio.json";
106 Log.
Trace($
"Report.Report(): Writing live point-in-time portfolios to JSON file: {outputFile}");
107 var livePortfolioOutput = JsonConvert.SerializeObject(dailyLivePortfolioInTime);
108 File.WriteAllText(outputFile, livePortfolioOutput);
112 _elements =
new List<IReportElement>
115 new TextReportElement(
"strategy name", ReportKey.StrategyName, name),
116 new TextReportElement(
"description", ReportKey.StrategyDescription, description),
117 new TextReportElement(
"version", ReportKey.StrategyVersion, version),
118 new TextReportElement(
"stylesheet", ReportKey.Stylesheet,
File.ReadAllText(
"css/report.css") + (cssOverride)),
119 new TextReportElement(
"live marker key", ReportKey.LiveMarker, live ==
null ?
string.Empty :
"Live "),
122 new RuntimeDaysReportElement(
"runtime days kpi", ReportKey.BacktestDays, backtest, live),
123 new CAGRReportElement(
"cagr kpi", ReportKey.CAGR, backtest, live),
124 new TurnoverReportElement(
"turnover kpi", ReportKey.Turnover, backtest, live),
125 new MaxDrawdownReportElement(
"max drawdown kpi", ReportKey.MaxDrawdown, backtest, live),
127 new SortinoRatioReportElement(
"sortino kpi", ReportKey.SortinoRatio, backtest, live, tradingDayPerYear),
128 new PSRReportElement(
"psr kpi", ReportKey.PSR, backtest, live, tradingDayPerYear),
129 new InformationRatioReportElement(
"ir kpi", ReportKey.InformationRatio, backtest, live),
130 new MarketsReportElement(
"markets kpi", ReportKey.Markets, backtest, live),
131 new TradesPerDayReportElement(
"trades per day kpi", ReportKey.TradesPerDay, backtest, live),
135 new MonthlyReturnsReportElement(
"monthly return plot", ReportKey.MonthlyReturns, backtest, live),
136 new CumulativeReturnsReportElement(
"cumulative returns", ReportKey.CumulativeReturns, backtest, live),
137 new AnnualReturnsReportElement(
"annual returns", ReportKey.AnnualReturns, backtest, live),
138 new ReturnsPerTradeReportElement(
"returns per trade", ReportKey.ReturnsPerTrade, backtest, live),
139 new AssetAllocationReportElement(
"asset allocation over time pie chart", ReportKey.AssetAllocation, backtest, live, backtestPortfolioInTime, livePortfolioInTime),
140 new DrawdownReportElement(
"drawdown plot", ReportKey.Drawdown, backtest, live),
141 new DailyReturnsReportElement(
"daily returns plot", ReportKey.DailyReturns, backtest, live),
142 new RollingPortfolioBetaReportElement(
"rolling beta to equities plot", ReportKey.RollingBeta, backtest, live, tradingDayPerYear),
143 new RollingSharpeReportElement(
"rolling sharpe ratio plot", ReportKey.RollingSharpe, backtest, live, tradingDayPerYear),
144 new LeverageUtilizationReportElement(
"leverage plot", ReportKey.LeverageUtilization, backtest, live, backtestPortfolioInTime, livePortfolioInTime),
145 new ExposureReportElement(
"exposure plot", ReportKey.Exposure, backtest, live, backtestPortfolioInTime, livePortfolioInTime)
149 if (parametersHtmlContent !=
null)
151 _elements.Add(
new ParametersReportElement(
"parameters page", ReportKey.ParametersPageStyle, backtestConfiguration, liveConfiguration, parametersHtmlContent));
152 _elements.Add(
new ParametersReportElement(
"parameters", ReportKey.Parameters, backtestConfiguration, liveConfiguration, parametersHtmlContent));
156 if (crisisHtmlContent !=
null)
158 _elements.Add(
new CrisisReportElement(
"crisis page", ReportKey.CrisisPageStyle, backtest, live, crisisHtmlContent));
159 _elements.Add(
new CrisisReportElement(
"crisis plots", ReportKey.CrisisPlots, backtest, live, crisisHtmlContent));
168 public void Compile(out
string html, out
string reportStatistics)
171 var statistics =
new Dictionary<string, object>();
174 foreach (var element
in _elements)
176 Log.
Trace($
"QuantConnect.Report.Compile(): Rendering {element.Name}...");
177 html = html.Replace(element.Key, element.Render());
185 statistics[reportElement.JsonKey] = reportElement.
Result;
188 reportStatistics = JsonConvert.SerializeObject(statistics, Formatting.None);
199 var regex =
new Regex(pattern);
200 var match = regex.Match(input);
201 var regexWithinInput = match.Success ? match.Groups[2].Value :
null;
202 return regexWithinInput;