AI For Trading: Factor Model of Asset Return (52)
Factor Model of Return
An asset's return can be modeled as the contribution from a set of factors, plus the specific return (the part that isn't explained by the factors).
Factor Model of Asset Return Exercise
Factor Model of Asset Return
import sys
!{sys.executable} -m pip install -r requirements.txt
Requirement already satisfied: numpy==1.14.5 in /opt/conda/lib/python3.6/site-packages (from -r requirements.txt (line 1))
Requirement already satisfied: pandas==0.18.1 in /opt/conda/lib/python3.6/site-packages (from -r requirements.txt (line 2))
Requirement already satisfied: plotly==2.2.3 in /opt/conda/lib/python3.6/site-packages (from -r requirements.txt (line 3))
Requirement already satisfied: scikit-learn==0.19.1 in /opt/conda/lib/python3.6/site-packages (from -r requirements.txt (line 4))
Requirement already satisfied: six==1.11.0 in /opt/conda/lib/python3.6/site-packages (from -r requirements.txt (line 5))
Requirement already satisfied: zipline===1.2.0 in /opt/conda/lib/python3.6/site-packages (from -r requirements.txt (line 6))
Requirement already satisfied: python-dateutil>=2 in /opt/conda/lib/python3.6/site-packages (from pandas==0.18.1->-r requirements.txt (line 2))
Requirement already satisfied: pytz>=2011k in /opt/conda/lib/python3.6/site-packages (from pandas==0.18.1->-r requirements.txt (line 2))
Requirement already satisfied: decorator>=4.0.6 in /opt/conda/lib/python3.6/site-packages (from plotly==2.2.3->-r requirements.txt (line 3))
Requirement already satisfied: requests in /opt/conda/lib/python3.6/site-packages (from plotly==2.2.3->-r requirements.txt (line 3))
Requirement already satisfied: nbformat>=4.2 in /opt/conda/lib/python3.6/site-packages (from plotly==2.2.3->-r requirements.txt (line 3))
Requirement already satisfied: intervaltree>=2.1.0 in /opt/conda/lib/python3.6/site-packages (from zipline===1.2.0->-r requirements.txt (line 6))
Requirement already satisfied: pandas-datareader<0.6,>=0.2.1 in /opt/conda/lib/python3.6/site-packages (from zipline===1.2.0->-r requirements.txt (line 6))
Requirement already satisfied: MarkupSafe>=0.23 in /opt/conda/lib/python3.6/site-packages (from zipline===1.2.0->-r requirements.txt (line 6))
Requirement already satisfied: contextlib2>=0.4.0 in /opt/conda/lib/python3.6/site-packages (from zipline===1.2.0->-r requirements.txt (line 6))
Requirement already satisfied: empyrical>=0.4.2 in /opt/conda/lib/python3.6/site-packages (from zipline===1.2.0->-r requirements.txt (line 6))
Requirement already satisfied: numexpr>=2.6.1 in /opt/conda/lib/python3.6/site-packages (from zipline===1.2.0->-r requirements.txt (line 6))
[33mYou are using pip version 9.0.1, however version 18.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.[0m
import numpy as np
import pandas as pd
import time
import os
import quiz_helper
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (14, 8)
data bundle
import os
import quiz_helper
from zipline.data import bundles
os.environ['ZIPLINE_ROOT'] = os.path.join(os.getcwd(), '..', '..','data','module_4_quizzes_eod')
ingest_func = bundles.csvdir.csvdir_equities(['daily'], quiz_helper.EOD_BUNDLE_NAME)
bundles.register(quiz_helper.EOD_BUNDLE_NAME, ingest_func)
print('Data Registered')
Data Registered
Build pipeline engine
from zipline.pipeline import Pipeline
from zipline.pipeline.factors import AverageDollarVolume
from zipline.utils.calendars import get_calendar
universe = AverageDollarVolume(window_length=120).top(500)
trading_calendar = get_calendar('NYSE')
bundle_data = bundles.load(quiz_helper.EOD_BUNDLE_NAME)
engine = quiz_helper.build_pipeline_engine(bundle_data, trading_calendar)
View Data露
With the pipeline engine built, let's get the stocks at the end of the period in the universe we're using. We'll use these tickers to generate the returns data for the our risk model.
universe_end_date = pd.Timestamp('2016-01-05', tz='UTC')
universe_tickers = engine\
.run_pipeline(
Pipeline(screen=universe),
universe_end_date,
universe_end_date)\
.index.get_level_values(1)\
.values.tolist()
universe_tickers
[Equity(0 [A]),
Equity(1 [AAL]),
Equity(2 [AAP]),
Equity(3 [AAPL]),
Equity(4 [ABBV]),
Equity(5 [ABC]),
Equity(6 [ABT]),
Equity(7 [ACN]),
Equity(8 [ADBE]),
Equity(9 [ADI]),
Equity(10 [ADM]),
Equity(11 [ADP]),
Equity(12 [ADS]),
Equity(13 [ADSK]),
Equity(14 [AEE]),
Equity(15 [AEP]),
Equity(16 [AES]),
Equity(17 [AET]),
Equity(18 [AFL]),
Equity(19 [AGN]),
Equity(20 [AIG]),
Equity(21 [AIV]),
Equity(22 [AIZ]),
Equity(23 [AJG]),
Equity(24 [AKAM]),
Equity(25 [ALB]),
Equity(26 [ALGN]),
Equity(27 [ALK]),
Equity(28 [ALL]),
Equity(29 [ALLE]),
Equity(30 [ALXN]),
Equity(31 [AMAT]),
Equity(32 [AMD]),
Equity(33 [AME]),
Equity(34 [AMG]),
Equity(35 [AMGN]),
Equity(36 [AMP]),
Equity(37 [AMT]),
Equity(38 [AMZN]),
Equity(39 [ANDV]),
Equity(40 [ANSS]),
Equity(41 [ANTM]),
Equity(42 [AON]),
Equity(43 [AOS]),
Equity(44 [APA]),
Equity(45 [APC]),
Equity(46 [APD]),
Equity(47 [APH]),
Equity(48 [ARE]),
Equity(49 [ARNC]),
Equity(50 [ATVI]),
Equity(51 [AVB]),
Equity(52 [AVGO]),
Equity(53 [AVY]),
Equity(54 [AWK]),
Equity(55 [AXP]),
Equity(56 [AYI]),
Equity(57 [AZO]),
Equity(58 [BA]),
Equity(59 [BAC]),
Equity(60 [BAX]),
Equity(61 [BBT]),
Equity(62 [BBY]),
Equity(63 [BCR]),
Equity(64 [BDX]),
Equity(65 [BEN]),
Equity(66 [BIIB]),
Equity(67 [BK]),
Equity(68 [BLK]),
Equity(69 [BLL]),
Equity(70 [BMY]),
Equity(71 [BSX]),
Equity(72 [BWA]),
Equity(73 [BXP]),
Equity(74 [C]),
Equity(75 [CA]),
Equity(76 [CAG]),
Equity(77 [CAH]),
Equity(78 [CAT]),
Equity(79 [CB]),
Equity(80 [CBG]),
Equity(81 [CBOE]),
Equity(82 [CBS]),
Equity(83 [CCI]),
Equity(84 [CCL]),
Equity(85 [CELG]),
Equity(86 [CERN]),
Equity(87 [CF]),
Equity(88 [CFG]),
Equity(89 [CHD]),
Equity(90 [CHK]),
Equity(91 [CHRW]),
Equity(92 [CHTR]),
Equity(93 [CI]),
Equity(94 [CINF]),
Equity(95 [CL]),
Equity(96 [CLX]),
Equity(97 [CMA]),
Equity(98 [CMCSA]),
Equity(99 [CME]),
Equity(100 [CMG]),
Equity(101 [CMI]),
Equity(102 [CMS]),
Equity(103 [CNC]),
Equity(104 [CNP]),
Equity(105 [COF]),
Equity(106 [COG]),
Equity(107 [COL]),
Equity(108 [COO]),
Equity(109 [COP]),
Equity(110 [COST]),
Equity(111 [COTY]),
Equity(112 [CPB]),
Equity(113 [CRM]),
Equity(114 [CSCO]),
Equity(115 [CSRA]),
Equity(116 [CSX]),
Equity(117 [CTAS]),
Equity(118 [CTL]),
Equity(119 [CTSH]),
Equity(120 [CTXS]),
Equity(121 [CVS]),
Equity(122 [CVX]),
Equity(123 [CXO]),
Equity(124 [D]),
Equity(125 [DAL]),
Equity(126 [DE]),
Equity(127 [DFS]),
Equity(128 [DG]),
Equity(129 [DGX]),
Equity(130 [DHI]),
Equity(131 [DHR]),
Equity(132 [DIS]),
Equity(133 [DISCA]),
Equity(134 [DISCK]),
Equity(135 [DISH]),
Equity(136 [DLR]),
Equity(137 [DLTR]),
Equity(138 [DOV]),
Equity(139 [DPS]),
Equity(140 [DRE]),
Equity(141 [DRI]),
Equity(142 [DTE]),
Equity(143 [DUK]),
Equity(144 [DVA]),
Equity(145 [DVN]),
Equity(146 [EA]),
Equity(147 [EBAY]),
Equity(148 [ECL]),
Equity(149 [ED]),
Equity(150 [EFX]),
Equity(151 [EIX]),
Equity(152 [EL]),
Equity(153 [EMN]),
Equity(154 [EMR]),
Equity(155 [EOG]),
Equity(156 [EQIX]),
Equity(157 [EQR]),
Equity(158 [EQT]),
Equity(159 [ES]),
Equity(160 [ESRX]),
Equity(161 [ESS]),
Equity(162 [ETFC]),
Equity(163 [ETN]),
Equity(164 [ETR]),
Equity(165 [EVHC]),
Equity(166 [EW]),
Equity(167 [EXC]),
Equity(168 [EXPD]),
Equity(169 [EXPE]),
Equity(170 [EXR]),
Equity(171 [F]),
Equity(172 [FAST]),
Equity(173 [FB]),
Equity(174 [FBHS]),
Equity(175 [FCX]),
Equity(176 [FDX]),
Equity(177 [FE]),
Equity(178 [FFIV]),
Equity(179 [FIS]),
Equity(180 [FISV]),
Equity(181 [FITB]),
Equity(182 [FL]),
Equity(183 [FLIR]),
Equity(184 [FLR]),
Equity(185 [FLS]),
Equity(186 [FMC]),
Equity(187 [FOX]),
Equity(188 [FOXA]),
Equity(189 [FRT]),
Equity(190 [FTI]),
Equity(191 [GD]),
Equity(192 [GE]),
Equity(193 [GGP]),
Equity(194 [GILD]),
Equity(195 [GIS]),
Equity(196 [GLW]),
Equity(197 [GM]),
Equity(198 [GOOG]),
Equity(199 [GOOGL]),
Equity(200 [GPC]),
...
Equity(488 [ZBH]),
Equity(489 [ZION]),
Equity(490 [ZTS])]
len(universe_tickers)
490
from zipline.data.data_portal import DataPortal
data_portal = DataPortal(
bundle_data.asset_finder,
trading_calendar=trading_calendar,
first_trading_day=bundle_data.equity_daily_bar_reader.first_trading_day,
equity_minute_reader=None,
equity_daily_reader=bundle_data.equity_daily_bar_reader,
adjustment_reader=bundle_data.adjustment_reader)
Get pricing data helper function
from quiz_helper import get_pricing
get pricing data into a dataframe
returns_df = \
get_pricing(
data_portal,
trading_calendar,
universe_tickers,
universe_end_date - pd.DateOffset(years=5),
universe_end_date)\
.pct_change()[1:].fillna(0) #convert prices into returns
returns_df
| Equity(0 [A]) | Equity(1 [AAL]) | Equity(2 [AAP]) | Equity(3 [AAPL]) | Equity(4 [ABBV]) | Equity(5 [ABC]) | Equity(6 [ABT]) | Equity(7 [ACN]) | Equity(8 [ADBE]) | Equity(9 [ADI]) | ... | Equity(481 [XL]) | Equity(482 [XLNX]) | Equity(483 [XOM]) | Equity(484 [XRAY]) | Equity(485 [XRX]) | Equity(486 [XYL]) | Equity(487 [YUM]) | Equity(488 [ZBH]) | Equity(489 [ZION]) | Equity(490 [ZTS]) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2011-01-07 00:00:00+00:00 | 0.008437 | 0.014230 | 0.026702 | 0.007146 | 0.000000 | 0.001994 | 0.004165 | 0.001648 | -0.007127 | -0.005818 | ... | -0.001838 | -0.005619 | 0.005461 | -0.004044 | -0.013953 | 0.000000 | 0.012457 | -0.000181 | -0.010458 | 0.000000 |
| 2011-01-10 00:00:00+00:00 | -0.004174 | 0.006195 | 0.007435 | 0.018852 | 0.000000 | -0.005714 | -0.008896 | -0.008854 | 0.028714 | 0.002926 | ... | 0.000947 | 0.007814 | -0.006081 | 0.010466 | 0.009733 | 0.000000 | 0.001440 | 0.007784 | -0.017945 | 0.000000 |
| 2011-01-11 00:00:00+00:00 | -0.001886 | -0.043644 | -0.005927 | -0.002367 | 0.000000 | 0.009783 | -0.002067 | 0.013717 | 0.000607 | 0.008753 | ... | 0.001314 | 0.010179 | 0.007442 | 0.007351 | 0.006116 | 0.000000 | -0.006470 | 0.035676 | 0.007467 | 0.000000 |
| 2016-01-05 00:00:00+00:00 | 0.004058 | -0.009541 | -0.006830 | -0.025054 | -0.004169 | 0.014629 | -0.000247 | 0.005207 | 0.004023 | -0.007347 | ... | 0.002098 | 0.014863 | 0.008511 | 0.020390 | -0.001957 | -0.000286 | -0.002495 | 0.020820 | -0.010853 | 0.015647 |
1256 rows 脳 490 columns
Let's look at one stock
Let's look at this for just one stock. We'll pick AAPL in this example.
aapl_col = returns_df.columns[3]
asset_return = returns_df[aapl_col]
asset_return = asset_return.rename('asset_return')
Factor returns
Let's make up a "factor" by taking an average of all stocks in our list. You can think of this as an equal weighted index of the 490 stocks, kind of like a measure of the "market". We'll also make another factor by calculating the median of all the stocks. These are mainly intended to help us generate some data to work with. We'll go into how some common risk factors are generated later in the lessons.
Also note that we're setting axis=1 so that we calculate a value for each time period (row) instead of one value for each column (assets).
factor_return_1 = returns_df.mean(axis=1)
factor_return_2 = returns_df.median(axis=1)
Factor exposures
Factor exposures refer to how "exposed" a stock is to each factor. We'll get into this more later. For now, just think of this as one number for each stock, for each of the factors.
from sklearn.linear_model import LinearRegression
"""
You can run these in separate cells to see each step in detail
But for now, just assume that we're calculating a number for each
stock, for each factor, which represents how "exposed" each stock is
to each factor.
We'll discuss how factor exposure is calculated later in the lessons.
"""
lr = LinearRegression()
X = np.array([factor_return_1.values,factor_return_2.values]).T
y = np.array(asset_return.values)
lr.fit(X,y)
factor_exposure_1 = lr.coef_[0]
factor_exposure_2 = lr.coef_[1]
Quiz 1 Contribution of Factors
The sum of the products of factor exposure times factor return is the contribution of the factors. It's also called the "common return." calculate the common return of AAPL, given the two factor exposures and the two factor returns.
Answer 1
# Calculate the contribution of the two factors to the return of this example asset
common_return = (factor_exposure_1 * factor_return_1) + (factor_exposure_2 * factor_return_2)
common_return = common_return.rename('common_return')
Quiz 2 Specific Return
The specific return is the part of the stock return that isn't explained by the factors. So it's the actual return minus the common return.
Calculate the specific return of the stock.
Answer 2
# TODO: calculate the specific return of this asset
specific_return = asset_return - common_return
specific_return = specific_return.rename('specific_return')
Visualize the common return and specific return
return_components = pd.concat([common_return,specific_return],axis=1)
return_components.head(2)
| common_return | specific_return | |
|---|---|---|
| 2011-01-07 00:00:00+00:00 | 0.000654 | 0.006492 |
| 2011-01-10 00:00:00+00:00 | 0.000506 | 0.018346 |
return_components.plot(title="asset return = common return + specific return");
pd.DataFrame(asset_return).plot(color='purple');


为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)