else: f1 = plt.figure(1) pf.plot_rolling_returns(strat_ret, factor_returns=bm_ret) f1.show() f2 = plt.figure(2) pf.plot_rolling_volatility(strat_ret, factor_returns=bm_ret) f2.show() f3 = plt.figure(3) pf.plot_rolling_sharpe(strat_ret) f3.show() f4 = plt.figure(4) pf.plot_drawdown_periods(strat_ret) f4.show() f5 = plt.figure(5) pf.plot_monthly_returns_heatmap(strat_ret) f5.show() f6 = plt.figure(6) pf.plot_annual_returns(strat_ret) f6.show() f7 = plt.figure(7) pf.plot_monthly_returns_dist(strat_ret) plt.show() f8 = plt.figure(8) pf.create_position_tear_sheet(strat_ret, df_positions) plt.show() f9 = plt.figure(9) pf.create_txn_tear_sheet(strat_ret, df_positions, df_trades) plt.show() f10 = plt.figure(10) pf.create_round_trip_tear_sheet(strat_ret, df_positions, df_trades) plt.show()
def create_report(perf, filename, now, doc=None, duration=None, param=None, info=None, show_image=True): if not hasattr(perf, 'returns'): perf['returns'] = perf['pnl'] / (perf['portfolio_value'] - perf['pnl']) perf['returns'] = perf['returns'].replace([np.nan, np.inf, -np.inf], 0.0) tot_positions = sum([len(x) for x in perf.positions]) if tot_positions == 0: log.warn("No positions available") return rets, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline( perf) date_rows = OrderedDict() if len(rets.index) > 0: date_rows['Start date'] = rets.index[0].strftime('%Y-%m-%d') date_rows['End date'] = rets.index[-1].strftime('%Y-%m-%d') date_rows['Total months'] = int(len(rets) / 21) perf_stats_series = pf.timeseries.perf_stats(rets, positions=positions, transactions=transactions) benchmark_rets = returns(symbol('SPY'), rets.index[0], rets.index[-1]) benchmark_perf_stats = pf.timeseries.perf_stats(benchmark_rets) perf_stats_df = pd.DataFrame(perf_stats_series, columns=['Backtest']) perf_stats_df['Benchmark'] = benchmark_perf_stats perf_stats_df[ 'Spread'] = perf_stats_df['Backtest'] - perf_stats_df['Benchmark'] format_perf_stats(perf_stats_df) drawdown_df = pf.timeseries.gen_drawdown_table(rets, top=5) rets_interesting = pf.timeseries.extract_interesting_date_ranges(rets) positions = utils.check_intraday('infer', rets, positions, transactions) transactions_closed = rt.add_closing_transactions(positions, transactions) trades = rt.extract_round_trips( transactions_closed, portfolio_value=positions.sum(axis='columns') / (1 + rets)) if show_image: fig0 = None fig1 = None fig2 = None fig3 = None fig4 = None fig5 = None try: fig0 = create_log_returns_chart(rets, benchmark_rets) except Exception as e: log.warn(e) try: fig1 = pf.create_returns_tear_sheet(rets, positions, transactions, benchmark_rets=benchmark_rets, return_fig=True) except Exception as e: log.warn(e) try: fig2 = pf.create_position_tear_sheet(rets, positions, return_fig=True) except Exception as e: log.warn(e) try: fig3 = pf.create_txn_tear_sheet(rets, positions, transactions, return_fig=True) except Exception as e: log.warn(e) try: fig4 = pf.create_interesting_times_tear_sheet(rets, return_fig=True) except Exception as e: log.warn(e) try: fig5 = pf.create_round_trip_tear_sheet(rets, positions, transactions, return_fig=True) except Exception as e: log.warn(e) report_suffix = "_%s_%.2f_report.htm" % ( now.strftime(DATETIME_FMT), 100. * perf_stats_series['Annual return']) reportfile = change_extension(filename, report_suffix) with open(reportfile, 'w') as f: print("""<!DOCTYPE html> <html> <head> <title>Performance Report</title> <style > body { font-family: Arial, Helvetica, sans-serif; } table { border-collapse: collapse; } tbody tr:nth-child(odd) { background-color: lightgrey; } tbody tr:nth-child(even) { background-color: white; } tr th { border: none; text-align: right; padding: 2px 5px 2px; } tr td { border: none; text-align: right; padding: 2px 5px 2px; } </style> <script type="text/javascript"> function showElement() { element = document.getElementById('code'); element.style.visibility = 'visible'; } function hideElement() { element = document.getElementById('code'); element.style.visibility = 'hidden'; } </script> </head> <body>""", file=f) print("<h1>Performance report for " + os.path.basename(filename) + "</h1>", file=f) print("<p>Created on %s</p>" % (now), file=f) if duration is not None: print("<p>Backtest executed in %s</p>" % (time.strftime("%H:%M:%S", time.gmtime(duration))), file=f) if doc is not None: print('<h3>Description</h3>', file=f) print('<p style="white-space: pre">%s</p>' % doc.strip(), file=f) if param is not None and len(param) > 0: print('<h3>Parameters</h3>', file=f) print('<pre>%s</pre><br/>' % str(param), file=f) if info is not None and len(info) > 0: print('<h3>Info</h3>', file=f) print('<pre>%s</pre><br/>' % str(info), file=f) print(to_html_table(perf_stats_df, float_format='{0:.2f}'.format, header_rows=date_rows), file=f) print("<br/>", file=f) if show_image: if fig0 is not None: print("<h3>Log Returns</h3>", file=f) print(_to_img(fig0), file=f) print("<br/>", file=f) print(to_html_table( drawdown_df.sort_values('Net drawdown in %', ascending=False), name='Worst drawdown periods', float_format='{0:.2f}'.format, ), file=f) print("<br/>", file=f) print(to_html_table(pd.DataFrame(rets_interesting).describe(). transpose().loc[:, ['mean', 'min', 'max']] * 100, name='Stress Events', float_format='{0:.2f}%'.format), file=f) print("<br/>", file=f) if len(trades) >= 5: stats = rt.gen_round_trip_stats(trades) print(to_html_table(stats['summary'], float_format='{:.2f}'.format, name='Summary stats'), file=f) print("<br/>", file=f) print(to_html_table(stats['pnl'], float_format='${:.2f}'.format, name='PnL stats'), file=f) print("<br/>", file=f) print(to_html_table(stats['duration'], float_format='{:.2f}'.format, name='Duration stats'), file=f) print("<br/>", file=f) print(to_html_table(stats['returns'] * 100, float_format='{:.2f}%'.format, name='Return stats'), file=f) print("<br/>", file=f) stats['symbols'].columns = stats['symbols'].columns.map( format_asset) print(to_html_table(stats['symbols'] * 100, float_format='{:.2f}%'.format, name='Symbol stats'), file=f) if show_image: if fig1 is not None: print("<h3>Returns</h3>", file=f) print(_to_img(fig1), file=f) if fig2 is not None: print("<h3>Positions</h3>", file=f) print(_to_img(fig2), file=f) if fig3 is not None: print("<h3>Transactions</h3>", file=f) print(_to_img(fig3), file=f) if fig4 is not None: print("<h3>Interesting Times</h3>", file=f) print(_to_img(fig4), file=f) if fig5 is not None: print("<h3>Trades</h3>", file=f) print(_to_img(fig5), file=f) print('<br/>', file=f) print( '<button onclick="showElement()">Show Code</button> <button onclick="hideElement()">Hide Code</button>', file=f) print('<pre id="code" style="visibility: hidden">', file=f) print(open(filename, "r").read(), file=f) print('</pre>', file=f) print("</body>\n</html>", file=f)