def test_add_closing_trades(self): dates = date_range(start="2015-01-01", periods=20) transactions = DataFrame( data=[[2, 10, "A"], [-5, 10, "A"], [-1, 10, "B"]], columns=["amount", "price", "symbol"], index=dates[:3], ) positions = DataFrame( data=[[20, 10, 0], [-30, 10, 30], [-60, 0, 30]], columns=["A", "B", "cash"], index=dates[:3], ) expected_ix = dates[:3].append( DatetimeIndex([dates[2] + Timedelta(seconds=1)])) expected = DataFrame( data=[ ["A", 2, 10], ["A", -5, 10], ["B", -1, 10.0], [ "A", 3, 20.0, ], ], columns=["symbol", "amount", "price"], index=expected_ix, ) transactions_closed = add_closing_transactions(positions, transactions) assert_frame_equal(transactions_closed, expected)
def test_txn_pnl_matches_round_trip_pnl(self): __location__ = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__))) test_txn = read_csv(gzip.open( __location__ + '/test_data/test_txn.csv.gz'), index_col=0, parse_dates=True) test_pos = read_csv(gzip.open( __location__ + '/test_data/test_pos.csv.gz'), index_col=0, parse_dates=True) transactions_closed = add_closing_transactions(test_pos, test_txn) transactions_closed['txn_dollars'] = transactions_closed.amount * \ -1. * transactions_closed.price round_trips = extract_round_trips(transactions_closed) self.assertAlmostEqual(round_trips.pnl.sum(), transactions_closed.txn_dollars.sum())
def test_add_closing_trades(self): dates = date_range(start='2015-01-01', periods=20) transactions = DataFrame(data=[[2, 10, 'A'], [-5, 10, 'A'], [-1, 10, 'B']], columns=['amount', 'price', 'symbol'], index=[dates[:3]]) positions = DataFrame(data=[[20, 10, 0], [-30, 10, 30], [-60, 0, 30]], columns=['A', 'B', 'cash'], index=[dates[:3]]) expected_ix = dates[:3].append( DatetimeIndex([dates[2] + Timedelta(seconds=1)])) expected = DataFrame(data=[[2, 10, 'A'], [-5, 10, 'A'], [-1, 10., 'B'], [3, 20., 'A']], columns=['amount', 'price', 'symbol'], index=expected_ix) transactions_closed = add_closing_transactions(positions, transactions) assert_frame_equal(transactions_closed, expected)
def test_add_closing_trades(self): dates = date_range(start='2015-01-01', periods=20) transactions = DataFrame(data=[[2, 10, 'A'], [-5, 10, 'A'], [-1, 10, 'B']], columns=['amount', 'price', 'symbol'], index=[dates[:3]]) positions = DataFrame(data=[[20, 10, 0], [-30, 10, 30], [-60, 0, 30]], columns=['A', 'B', 'cash'], index=[dates[:3]]) expected_ix = dates[:3].append(DatetimeIndex([dates[2] + Timedelta(seconds=1)])) expected = DataFrame(data=[[2, 10, 'A'], [-5, 10, 'A'], [-1, 10., 'B'], [3, 20., 'A']], columns=['amount', 'price', 'symbol'], index=expected_ix) transactions_closed = add_closing_transactions(positions, transactions) assert_frame_equal(transactions_closed, expected)
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)