/// <summary> /// Generate the rolling portfolio beta to equities plot using the python libraries. /// </summary> public override string Render() { var backtestPoints = ResultsUtil.EquityPoints(_backtest); var backtestBenchmarkPoints = ResultsUtil.BenchmarkPoints(_backtest); var livePoints = ResultsUtil.EquityPoints(_live); var liveBenchmarkPoints = ResultsUtil.BenchmarkPoints(_live); var backtestSeries = new Series <DateTime, double>(backtestPoints); var backtestBenchmarkSeries = new Series <DateTime, double>(backtestBenchmarkPoints); var liveSeries = new Series <DateTime, double>(livePoints); var liveBenchmarkSeries = new Series <DateTime, double>(liveBenchmarkPoints); var base64 = ""; using (Py.GIL()) { var backtestList = new PyList(); var liveList = new PyList(); var backtestRollingBetaSixMonths = Rolling.Beta(backtestSeries, backtestBenchmarkSeries, windowSize: 22 * 6); var backtestRollingBetaTwelveMonths = Rolling.Beta(backtestSeries, backtestBenchmarkSeries, windowSize: 252); backtestList.Append(backtestRollingBetaSixMonths.Keys.ToList().ToPython()); backtestList.Append(backtestRollingBetaSixMonths.Values.ToList().ToPython()); backtestList.Append(backtestRollingBetaTwelveMonths.Keys.ToList().ToPython()); backtestList.Append(backtestRollingBetaTwelveMonths.Values.ToList().ToPython()); var liveRollingBetaSixMonths = Rolling.Beta(liveSeries, liveBenchmarkSeries, windowSize: 22 * 6); var liveRollingBetaTwelveMonths = Rolling.Beta(liveSeries, liveBenchmarkSeries, windowSize: 252); liveList.Append(liveRollingBetaSixMonths.Keys.ToList().ToPython()); liveList.Append(liveRollingBetaSixMonths.Values.ToList().ToPython()); liveList.Append(liveRollingBetaTwelveMonths.Keys.ToList().ToPython()); liveList.Append(liveRollingBetaTwelveMonths.Values.ToList().ToPython()); base64 = Charting.GetRollingBeta(backtestList, liveList); } return(base64); }
/// <summary> /// The generated output string to be injected /// </summary> public override string Render() { var backtestPoints = ResultsUtil.EquityPoints(_backtest); var backtestBenchmarkPoints = ResultsUtil.BenchmarkPoints(_backtest); var backtestSeries = new Series <DateTime, double>(backtestPoints.Keys, backtestPoints.Values); var backtestBenchmarkSeries = new Series <DateTime, double>(backtestBenchmarkPoints.Keys, backtestBenchmarkPoints.Values); var html = new List <string>(); foreach (var crisisEvent in Crisis.Events) { using (Py.GIL()) { var crisis = crisisEvent.Value; var data = new PyList(); var frame = Frame.CreateEmpty <DateTime, string>(); // The two following operations are equivalent to Pandas' `df.resample("D").sum()` frame["Backtest"] = backtestSeries.ResampleEquivalence(date => date.Date, s => s.LastValue()); frame["Benchmark"] = backtestBenchmarkSeries.ResampleEquivalence(date => date.Date, s => s.LastValue()); var crisisFrame = frame.Where(kvp => kvp.Key >= crisis.Start && kvp.Key <= crisis.End); crisisFrame = crisisFrame.Join("BacktestPercent", crisisFrame["Backtest"].CumulativeReturns()); crisisFrame = crisisFrame.Join("BenchmarkPercent", crisisFrame["Benchmark"].CumulativeReturns()); // Pad out all missing values to start from 0 for nice plots crisisFrame = crisisFrame.FillMissing(Direction.Forward).FillMissing(0.0); data.Append(crisisFrame.RowKeys.ToList().ToPython()); data.Append(crisisFrame["BacktestPercent"].Values.ToList().ToPython()); data.Append(crisisFrame["BenchmarkPercent"].Values.ToList().ToPython()); var base64 = (string)Charting.GetCrisisEventsPlots(data, crisis.Name.Replace("/", "").Replace(".", "").Replace(" ", "")); if (base64 == _emptyChart) { continue; } if (!crisisFrame.IsEmpty) { var contents = _template.Replace(ReportKey.CrisisTitle, crisis.ToString(crisisFrame.GetRowKeyAt(0), crisisFrame.GetRowKeyAt(crisisFrame.RowCount - 1))); contents = contents.Replace(ReportKey.CrisisContents, base64); html.Add(contents); } } } if (Key == ReportKey.CrisisPageStyle) { if (html.Count == 0) { return("display: none;"); } return(string.Empty); } return(string.Join("\n", html)); }
/// <summary> /// Generate the cumulative return of the backtest, benchmark, and live /// strategy using the ReportCharts.py python library /// </summary> public override string Render() { var backtestReturns = ResultsUtil.EquityPoints(_backtest); var benchmark = ResultsUtil.BenchmarkPoints(_backtest); var liveReturns = ResultsUtil.EquityPoints(_live); var liveBenchmark = ResultsUtil.BenchmarkPoints(_live); var backtestTime = backtestReturns.Keys.ToList(); var backtestStrategy = backtestReturns.Values.ToList(); var benchmarkTime = benchmark.Keys.ToList(); var benchmarkPoints = benchmark.Values.ToList(); var liveTime = liveReturns.Keys.ToList(); var liveStrategy = liveReturns.Values.ToList(); var liveBenchmarkTime = liveBenchmark.Keys.ToList(); var liveBenchmarkStrategy = liveBenchmark.Values.ToList(); var base64 = ""; using (Py.GIL()) { var backtestList = new PyList(); var liveList = new PyList(); var backtestSeries = new Series <DateTime, double>(backtestTime, backtestStrategy); var liveSeries = new Series <DateTime, double>(liveTime, liveStrategy); var backtestBenchmarkSeries = new Series <DateTime, double>(benchmarkTime, benchmarkPoints); var liveBenchmarkSeries = new Series <DateTime, double>(liveBenchmarkTime, liveBenchmarkStrategy); // Equivalent in python using pandas for the following operations is: // -------------------------------------------------- // >>> # note: [...] denotes the data we're passing in // >>> df = pd.Series([...], index=time) // >>> df_live = pd.Series([...], index=live_time) // >>> df_live = df_live.mul(df.iloc[-1] / df_live.iloc[0]).fillna(method='ffill').dropna() // >>> df_final = pd.concat([df, df_live], axis=0) // >>> df_cumulative_returns = ((df_final.pct_change().dropna() + 1).cumprod() - 1) // -------------------------------------------------- // // We multiply the final value of the backtest and benchmark to have a continuous graph showing the performance out of sample // as a continuation of the cumulative returns graph. Otherwise, we start plotting from 0% and not the last value of the backtest data var backtestLastValue = backtestSeries.ValueCount == 0 ? 0 : backtestSeries.LastValue(); var backtestBenchmarkLastValue = backtestBenchmarkSeries.ValueCount == 0 ? 0 : backtestBenchmarkSeries.LastValue(); var liveContinuousEquity = liveSeries; var liveBenchContinuousEquity = liveBenchmarkSeries; if (liveSeries.ValueCount != 0) { liveContinuousEquity = (liveSeries * (backtestLastValue / liveSeries.FirstValue())) .FillMissing(Direction.Forward) .DropMissing(); } if (liveBenchmarkSeries.ValueCount != 0) { liveBenchContinuousEquity = (liveBenchmarkSeries * (backtestBenchmarkLastValue / liveBenchmarkSeries.FirstValue())) .FillMissing(Direction.Forward) .DropMissing(); } var liveStart = liveContinuousEquity.ValueCount == 0 ? DateTime.MaxValue : liveContinuousEquity.DropMissing().FirstKey(); var liveBenchStart = liveBenchContinuousEquity.ValueCount == 0 ? DateTime.MaxValue : liveBenchContinuousEquity.DropMissing().FirstKey(); var finalEquity = backtestSeries.Where(kvp => kvp.Key < liveStart).Observations.ToList(); var finalBenchEquity = backtestBenchmarkSeries.Where(kvp => kvp.Key < liveBenchStart).Observations.ToList(); finalEquity.AddRange(liveContinuousEquity.Observations); finalBenchEquity.AddRange(liveBenchContinuousEquity.Observations); var finalSeries = (new Series <DateTime, double>(finalEquity).CumulativeReturns() * 100) .FillMissing(Direction.Forward) .DropMissing(); var finalBenchSeries = (new Series <DateTime, double>(finalBenchEquity).CumulativeReturns() * 100) .FillMissing(Direction.Forward) .DropMissing(); var backtestCumulativePercent = finalSeries.Where(kvp => kvp.Key < liveStart); var backtestBenchmarkCumulativePercent = finalBenchSeries.Where(kvp => kvp.Key < liveBenchStart); var liveCumulativePercent = finalSeries.Where(kvp => kvp.Key >= liveStart); var liveBenchmarkCumulativePercent = finalBenchSeries.Where(kvp => kvp.Key >= liveBenchStart); backtestList.Append(backtestCumulativePercent.Keys.ToList().ToPython()); backtestList.Append(backtestCumulativePercent.Values.ToList().ToPython()); backtestList.Append(backtestBenchmarkCumulativePercent.Keys.ToList().ToPython()); backtestList.Append(backtestBenchmarkCumulativePercent.Values.ToList().ToPython()); liveList.Append(liveCumulativePercent.Keys.ToList().ToPython()); liveList.Append(liveCumulativePercent.Values.ToList().ToPython()); liveList.Append(liveBenchmarkCumulativePercent.Keys.ToList().ToPython()); liveList.Append(liveBenchmarkCumulativePercent.Values.ToList().ToPython()); base64 = Charting.GetCumulativeReturns(backtestList, liveList); } return(base64); }
/// <summary> /// Generate the cumulative return of the backtest, benchmark, and live /// strategy using the ReportCharts.py python library /// </summary> public override string Render() { var backtestReturns = ResultsUtil.EquityPoints(_backtest); var benchmark = ResultsUtil.BenchmarkPoints(_backtest); var liveReturns = ResultsUtil.EquityPoints(_live); var liveBenchmark = ResultsUtil.BenchmarkPoints(_live); var backtestTime = backtestReturns.Keys.ToList(); var backtestStrategy = backtestReturns.Values.ToList(); var benchmarkTime = benchmark.Keys.ToList(); var benchmarkPoints = benchmark.Values.ToList(); var liveTime = liveReturns.Keys.ToList(); var liveStrategy = liveReturns.Values.ToList(); var liveBenchmarkTime = liveBenchmark.Keys.ToList(); var liveBenchmarkStrategy = liveBenchmark.Values.ToList(); var base64 = ""; using (Py.GIL()) { var backtestList = new PyList(); var liveList = new PyList(); var backtestSeries = new Series <DateTime, double>(backtestTime, backtestStrategy); var liveSeries = new Series <DateTime, double>(liveTime, liveStrategy); var backtestBenchmarkSeries = new Series <DateTime, double>(benchmarkTime, benchmarkPoints); var liveBenchmarkSeries = new Series <DateTime, double>(liveBenchmarkTime, liveBenchmarkStrategy); // Equivalent in python using pandas for the following operations is: // // df.pct_change().cumsum().mul(100) var backtestCumulativePercent = (backtestSeries.CumulativeReturns() * 100).FillMissing(Direction.Forward).DropMissing(); var backtestBenchmarkCumulativePercent = (backtestBenchmarkSeries.CumulativeReturns() * 100).FillMissing(Direction.Forward).DropMissing(); // Equivalent in python using pandas for the following operations is: // -------------------------------------------------- // # note: [...] denotes the data we're passing in // bt = pd.Series([...], index=time) // df.pct_change().replace([np.inf, -np.inf], np.nan).dropna().cumsum().mul(100).add(bt.iloc[-1]) // -------------------------------------------------- // // We add the final value of the backtest and benchmark to have a continuous graph showing the performance out of sample // as a continuation of the cumulative returns graph. Otherwise, we start plotting from 0% and not the last value of the backtest data var backtestLastValue = backtestCumulativePercent.IsEmpty ? 0 : backtestCumulativePercent.LastValue(); var backtestBenchmarkLastValue = backtestBenchmarkCumulativePercent.IsEmpty ? 0 : backtestBenchmarkCumulativePercent.LastValue(); var liveCumulativePercent = (liveSeries.CumulativeReturns() * 100).FillMissing(Direction.Forward).DropMissing() + backtestLastValue; var liveBenchmarkCumulativePercent = (liveBenchmarkSeries.CumulativeReturns() * 100).FillMissing(Direction.Forward).DropMissing() + backtestBenchmarkLastValue; backtestList.Append(backtestCumulativePercent.Keys.ToList().ToPython()); backtestList.Append(backtestCumulativePercent.Values.ToList().ToPython()); backtestList.Append(backtestBenchmarkCumulativePercent.Keys.ToList().ToPython()); backtestList.Append(backtestBenchmarkCumulativePercent.Values.ToList().ToPython()); liveList.Append(liveCumulativePercent.Keys.ToList().ToPython()); liveList.Append(liveCumulativePercent.Values.ToList().ToPython()); liveList.Append(liveBenchmarkCumulativePercent.Keys.ToList().ToPython()); liveList.Append(liveBenchmarkCumulativePercent.Values.ToList().ToPython()); base64 = Charting.GetCumulativeReturns(backtestList, liveList); } return(base64); }