ml-finance-python
python scripts for finance machine learning
git clone https://9o.is/git/ml-finance-python.git
alpha_factor_zipline_with_trades.py
(4244B)
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 __author__ = 'Stefan Jansen'
4
5 import sys
6 from pathlib import Path
7 import pandas as pd
8 from pytz import UTC
9 from zipline import run_algorithm
10 from zipline.api import (attach_pipeline, date_rules, time_rules, order_target_percent,
11 pipeline_output, record, schedule_function, get_open_orders, calendars,
12 set_commission, set_slippage)
13 from zipline.finance import commission, slippage
14 from zipline.pipeline import Pipeline, CustomFactor
15 from zipline.pipeline.factors import Returns, AverageDollarVolume
16 import logbook
17
18 from pyfolio.utils import extract_rets_pos_txn_from_zipline
19
20 # setup stdout logging
21 zipline_logging = logbook.NestedSetup([
22 logbook.NullHandler(level=logbook.DEBUG),
23 logbook.StreamHandler(sys.stdout, level=logbook.INFO),
24 logbook.StreamHandler(sys.stderr, level=logbook.ERROR),
25 ])
26 zipline_logging.push_application()
27
28 # Settings
29 MONTH = 21
30 YEAR = 12 * MONTH
31 N_LONGS = 200
32 N_SHORTS = 0
33 VOL_SCREEN = 1000
34
35 start = pd.Timestamp('2010-01-01', tz=UTC)
36 end = pd.Timestamp('2018-01-01', tz=UTC)
37 capital_base = 1e7
38
39
40 class MeanReversion(CustomFactor):
41 """Compute ratio of latest monthly return to 12m average,
42 normalized by std dev of monthly returns"""
43 inputs = [Returns(window_length=MONTH)]
44 window_length = YEAR
45
46 def compute(self, today, assets, out, monthly_returns):
47 df = pd.DataFrame(monthly_returns)
48 out[:] = df.iloc[-1].sub(df.mean()).div(df.std())
49
50
51 def compute_factors():
52 """Create factor pipeline incl. mean reversion,
53 filtered by 30d Dollar Volume; capture factor ranks"""
54 mean_reversion = MeanReversion()
55 dollar_volume = AverageDollarVolume(window_length=30)
56 return Pipeline(columns={'longs' : mean_reversion.bottom(N_LONGS),
57 'shorts' : mean_reversion.top(N_SHORTS),
58 'ranking': mean_reversion.rank(ascending=False)},
59 screen=dollar_volume.top(VOL_SCREEN))
60
61
62 def exec_trades(data, assets, target_percent):
63 """Place orders for assets using target portfolio percentage"""
64 for asset in assets:
65 if data.can_trade(asset) and not get_open_orders(asset):
66 order_target_percent(asset, target_percent)
67
68
69 def rebalance(context, data):
70 """Compute long, short and obsolete holdings; place trade orders"""
71 factor_data = context.factor_data
72 assets = factor_data.index
73
74 longs = assets[factor_data.longs]
75 shorts = assets[factor_data.shorts]
76 divest = context.portfolio.positions.keys() - longs.union(shorts)
77
78 exec_trades(data, assets=divest, target_percent=0)
79 exec_trades(data, assets=longs, target_percent=1 / N_LONGS if N_LONGS else 0)
80 exec_trades(data, assets=shorts, target_percent=-1 / N_SHORTS if N_SHORTS else 0)
81
82
83 def initialize(context):
84 """Setup: register pipeline, schedule rebalancing,
85 and set trading params"""
86 attach_pipeline(compute_factors(), 'factor_pipeline')
87 schedule_function(rebalance,
88 date_rules.week_start(),
89 time_rules.market_open(),
90 calendar=calendars.US_EQUITIES)
91
92 set_commission(us_equities=commission.PerShare(cost=0.00075, min_trade_cost=.01))
93 set_slippage(us_equities=slippage.VolumeShareSlippage(volume_limit=0.0025, price_impact=0.01))
94
95
96 def before_trading_start(context, data):
97 """Run factor pipeline"""
98 context.factor_data = pipeline_output('factor_pipeline')
99 record(factor_data=context.factor_data.ranking)
100 assets = context.factor_data.index
101 record(prices=data.current(assets, 'price'))
102
103
104 backtest = run_algorithm(start=start,
105 end=end,
106 initialize=initialize,
107 before_trading_start=before_trading_start,
108 capital_base=capital_base)
109
110 # depending on the pyfolio version, gross_leverage may also be returned
111 returns, positions, transactions = extract_rets_pos_txn_from_zipline(backtest)
112
113
114 print(returns.head())
115 print(returns.info())
116
117 # print(gross_lev.info())
118 # print(gross_lev.head())
119
120 print(positions.info())
121 print(positions.head())
122
123 print(transactions.info())
124 print(transactions.head())