def rebalance(context, data): algo.record(aapl_price=data.current(symbol('AAPL'), "price")) # calculate intraday returns for our winners current_prices = data.current(context.winners, "price") prior_closes = data.history(context.winners, "close", 2, "1d").iloc[0] intraday_returns = (current_prices - prior_closes) / prior_closes positions = context.portfolio.positions # Exit positions we no longer want to hold for asset, position in positions.items(): if asset not in context.winners: algo.order_target_value(asset, 0, style=MarketOrder()) # Enter long positions for asset in context.winners: # if already long, nothing to do if asset in positions: continue # if the stock is up for the day, don't enter if intraday_returns[asset] > 0: continue # otherwise, buy a fixed $100K position per asset algo.order_target_value(asset, 100e3, style=MarketOrder())
class InterestRate(CustomFactor): inputs = [Closes()[symbol('TR1Y')]] window_safe = True window_length = 1 def compute(self, today, assets, out, int_rate): out[:] = int_rate[-self.window_length]
class Beta(CustomFactor): outputs = ['beta', 'residual_var'] inputs = [DailyReturns(), DailyReturns()[symbol('SPY')]] window_length = 252 params = ('standardize',) def compute(self, today, assets, out, assets_returns, market_returns, standardize): allowed_missing_percentage = 0.25 allowed_missing_count = int(allowed_missing_percentage * self.window_length) (out.beta, out.residual_var) = beta_residual(assets_returns, market_returns, allowed_missing_count, standardize)
class TBillBeta(CustomFactor): inputs = [USEquityPricing.close, Closes()[symbol('TR3M')]] window_safe = True window_length = 252 def compute(self, today, assets, out, close, rate): # monthly log returns monthly_r = np.diff(np.log(close[0::21, :]), axis=0) r = 12. * monthly_r # Treasury Bonds rates means every 21 daily t_r = np.log1p(rate) t_r = np.mean(t_r.reshape(-1, 21), axis=1)[1:].reshape(11, 1) beta = beta_residual(r, t_r, standardize=True)[0] out[:] = beta
start = pd.to_datetime('2021-03-08', utc=True) end = pd.to_datetime('2021-03-12', utc=True) assets = symbols(['IBM', 'F', 'AAPL']) p = prices(assets, start, end) print(p) assert p.shape == (5, 3) assert type(p) == pd.DataFrame assets = symbols(['SPY']) p = prices(assets, start, end) assert p.shape == (5, ) assert type(p) == pd.Series assets = [symbol('SPY')] p = prices(assets, start, end) print(p) assert p.shape == (5, ) assert type(p) == pd.Series assets = symbols(['IBM', 'F', 'AAPL']) p = returns(assets, start, end) print(p) assert p.shape == (5, 3) assert type(p) == pd.DataFrame assets = symbols(['SPY']) p = returns(assets, start, end) print(p) assert p.shape == (5, )
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)
import pandas as pd from sharadar.pipeline.engine import symbol, returns import matplotlib.pylab as plt import numpy as np def create_log_rets(rets, benchmark_rets): cum_log_returns = np.log1p(rets).cumsum() cum_log_benchmark_rets = np.log1p(benchmark_rets).cumsum() fig, ax = plt.subplots() cum_log_returns.plot(ax=ax, figsize=(20, 10)) cum_log_benchmark_rets.plot(ax=ax) ax.grid(True) ax.axhline(y=0, linestyle='--', color='black') ax.legend(['Backtest', 'Benchmark']) plt.title("Log returns") return plt if __name__ == "__main__": results = pd.read_pickle( '../algo/haugen20/haugen20_202006300552_perf.dump') rets, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline( results) benchmark_rets = returns(symbol('SPY'), rets.index[0], rets.index[0]) plt = create_log_rets(rets, benchmark_rets) plt.show()
import pandas as pd from zipline.pipeline import Pipeline from zipline.pipeline.data import USEquityPricing from sharadar.pipeline.engine import symbol, symbols, make_pipeline_engine from zipline.pipeline.filters import StaticAssets tickers = symbols(['TR1M', 'TR1Y', 'RATEINF']) print(tickers) pipe = Pipeline(columns={ 'Close': USEquityPricing.close.latest, }, screen=StaticAssets(tickers)) engine = make_pipeline_engine() pipe_start = pd.to_datetime('2020-02-03', utc=True) pipe_end = pd.to_datetime('2020-02-07', utc=True) stocks = engine.run_pipeline(pipe, pipe_start, pipe_end) print("stocks.shape [close]", stocks) print(symbol('TR1M').to_dict())
from sharadar.pipeline.engine import load_sharadar_bundle, symbol, symbols, prices, returns, trading_date import pandas as pd df_rets = returns( assets=symbol('AAPL'), start='2013-01-01', end='2014-01-01' ) assets = symbols(['IBM', 'F', 'AAPL']) start = pd.to_datetime('2020-02-03', utc=True) end = pd.to_datetime('2020-02-07', utc=True) print(prices(assets, start, end)) print(prices(assets, '2020-02-03', '2020-02-05')) print(returns(assets, start, end))
import pyfolio as pf import pandas as pd import numpy as np from sharadar.pipeline.engine import symbol, returns import empyrical as ep results = pd.read_pickle('../../../algo/haugen20/haugen20_perf.dump') rets, pos, trax = pf.utils.extract_rets_pos_txn_from_zipline(results) start_date = rets.index[0] end_date = rets.index[-1] print(start_date, end_date) benchmark_rets = returns(symbol('SPY'), start_date, end_date) cum_rets = ep.cum_returns(rets, 1.0) cum_benchmark_rets = ep.cum_returns(benchmark_rets, 1.0) cum_log_returns = np.log1p(rets).cumsum() cum_log_benchmark_rets = np.log1p(benchmark_rets).cumsum() fig1 = pf.create_returns_tear_sheet(rets, pos, trax, benchmark_rets=benchmark_rets, return_fig=True)