Skip to content

Fama-French multivariate regression #406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Aug 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
56715f9
DOC updated docstring to indicate separate lin regressions
eigenfoo Jul 31, 2017
f16783c
ENH first pass at rolling multivar ff
eigenfoo Jul 31, 2017
e48d5b1
DOC used Mom instead of UMD
eigenfoo Jul 31, 2017
50c15f0
DOC UMD is a better name than Mom
eigenfoo Jul 31, 2017
85ded16
DOC described multivar lin reg in docstring
eigenfoo Jul 31, 2017
1302f93
MAINT refactored code, reduced clutter
eigenfoo Jul 31, 2017
3dbbfb3
DOC added comment to explain initial nan padding
eigenfoo Jul 31, 2017
503b8c1
BUG do not force intercept = 0
eigenfoo Aug 1, 2017
85cb552
BLD added statsmodels to requirements
eigenfoo Aug 1, 2017
053d10c
BLD added statsmodels requirement to .travis.yml and setup.py
eigenfoo Aug 1, 2017
c8f9c73
BUG made statsmodels version >= 0.6.1
eigenfoo Aug 1, 2017
04ccd27
DOC docstring style
eigenfoo Aug 1, 2017
0919334
BUG ols returns np ndarray, not pd Series
eigenfoo Aug 1, 2017
98957d6
TST using travis_wait to fix build timeouts
eigenfoo Aug 1, 2017
27b6d66
TST allow travis_wait 60 mins to finish build
eigenfoo Aug 1, 2017
0fc763e
TST allow 90 mins to finish tests...
eigenfoo Aug 1, 2017
a8ae484
REV remove travis_wait, pending discussion
eigenfoo Aug 1, 2017
f0c4121
ENH use sklearn instead of statsmodels
eigenfoo Aug 2, 2017
13a8b5f
REV revert to previous commit
eigenfoo Aug 2, 2017
5afed69
ENH use sklearn instead of statsmodels
eigenfoo Aug 2, 2017
8746053
ENH added sklearn to requirements
eigenfoo Aug 2, 2017
51603b6
END added sklearn, removed statsmodels
eigenfoo Aug 2, 2017
19a0545
BUG scikit-learn, not sklearn
eigenfoo Aug 2, 2017
cfe4600
BUG scikit-learn, not sklearn
eigenfoo Aug 2, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ before_install:
- cp pyfolio/tests/matplotlibrc .

install:
- conda create -q -n testenv --yes python=$TRAVIS_PYTHON_VERSION ipython pyzmq numpy scipy nose matplotlib pandas Cython patsy flake8 seaborn runipy pytables networkx pandas-datareader matplotlib-tests joblib
- conda create -q -n testenv --yes python=$TRAVIS_PYTHON_VERSION ipython pyzmq numpy scipy nose matplotlib pandas Cython patsy flake8 seaborn scikit-learn runipy pytables networkx pandas-datareader matplotlib-tests joblib
- source activate testenv
- pip install nose_parameterized
#- pip install --no-deps git+https://github.com/quantopian/zipline
Expand Down
37 changes: 28 additions & 9 deletions pyfolio/timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import numpy as np
import scipy as sp
import scipy.stats as stats
from sklearn import linear_model

from . import utils
from .utils import APPROX_BDAYS_PER_MONTH, APPROX_BDAYS_PER_YEAR
Expand Down Expand Up @@ -551,27 +552,27 @@ def rolling_beta(returns, factor_returns,
def rolling_fama_french(returns, factor_returns=None,
rolling_window=APPROX_BDAYS_PER_MONTH * 6):
"""
Computes rolling Fama-French single factor betas.
Computes rolling Fama-French single factor betas using a multivariate
linear regression (separate linear regressions is problematic because
the Fama-French factors are confounded).

Specifically, returns SMB, HML, and UMD.
Specifically, returns rolling betas to SMB, HML, and UMD.

Parameters
----------
returns : pd.Series
Daily returns of the strategy, noncumulative.
- See full explanation in tears.create_full_tear_sheet.
factor_returns : pd.DataFrame, optional
data set containing the Fama-French risk factors. See
Data set containing the Fama-French risk factors. See
utils.load_portfolio_risk_factors.
rolling_window : int, optional
The days window over which to compute the beta.
Default is 6 months.
The days window over which to compute the beta. Defaults to 6 months.

Returns
-------
pandas.DataFrame
DataFrame containing rolling beta coefficients for SMB, HML
and UMD
DataFrame containing rolling beta coefficients to SMB, HML and UMD
"""

if factor_returns is None:
Expand All @@ -580,8 +581,26 @@ def rolling_fama_french(returns, factor_returns=None,
factor_returns = factor_returns.drop(['Mkt-RF', 'RF'],
axis='columns')

return rolling_beta(returns, factor_returns,
rolling_window=rolling_window)
# add constant to regression
factor_returns['const'] = 1

# have NaNs when there is insufficient data to do a regression
regression_coeffs = np.empty((rolling_window,
len(factor_returns.columns)))
regression_coeffs.fill(np.nan)

for beg, end in zip(factor_returns.index[:-rolling_window],
factor_returns.index[rolling_window:]):
coeffs = linear_model.LinearRegression().fit(factor_returns[beg:end],
returns[beg:end]).coef_
regression_coeffs = np.append(regression_coeffs, [coeffs], axis=0)

rolling_fama_french = pd.DataFrame(data=regression_coeffs[:, :3],
columns=['SMB', 'HML', 'UMD'],
index=factor_returns.index)
rolling_fama_french.index.name = None

return rolling_fama_french


def gross_lev(positions):
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
'pandas>=0.19.0',
'pytz>=2014.10',
'scipy>=0.14.0',
'scikit-learn>=0.18.2'
'seaborn>=0.7.1',
'pandas-datareader>=0.2',
'empyrical>=0.3.0'
Expand Down