Notebook

Import all of the needed classes into code

In [28]:
from quantopian.research import run_pipeline, returns
from quantopian.research.experimental import get_factor_loadings, get_factor_returns
from quantopian.pipeline import Pipeline
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.factors import ExponentialWeightedMovingAverage
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.classifiers.fundamentals import Sector
import alphalens as al
import numpy as np
import matplotlib as plt
import pyfolio as pf
import math

Set the stock universe we are wishing to work with

In [29]:
universe = QTradableStocksUS()

Create Factor

In [30]:
factor1 = ExponentialWeightedMovingAverage(inputs=[USEquityPricing.close], window_length=5, decay_rate=0.5)

Create the pipeline of dynamic stocks

In [31]:
pipe = Pipeline(
    columns = {
        'factor': factor1,
        'sector': Sector(mask=universe),
    },
    screen = universe
)

Run the pipeline to get results

In [32]:
factors = run_pipeline(pipe, '2005-01-01', '2010-12-31')

Drop all factors that doesn't return a value

In [33]:
factors = factors.dropna()

Get the assets returned

In [34]:
assets = factors.index.levels[1]
my_returns = returns(assets, '2005-01-01', '2010-12-31')

Get prices for stocks

In [35]:
prices = get_pricing(assets, start_date='2004-12-01', end_date='2010-01-31', fields='close_price')

Set Sectors, Get Returns, and handle potential bad data

In [36]:
sector_labels = dict(Sector.SECTOR_NAMES)
sector_labels[-1] = "Unknown"

Create Alphalens Analysis

In [37]:
factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=factors["factor"],
    prices=prices,
    groupby=factors["sector"],
    quantiles=5,
    periods = (1, 5, 10)
)
Dropped 15.2% entries from factor data: 15.2% in forward returns computation and 0.0% in binning phase (set max_loss=0 to see potentially suppressed Exceptions).
max_loss is 35.0%, not exceeded: OK!

Create Pyfolio Analysis

In [38]:
factor_returns, factor_positions, factor_benchmark = al.performance.create_pyfolio_input(
    factor_data,
    period = '1D',
    capital = 100000000,
    long_short = True,
    group_neutral = False,
    equal_weight = True,
    quantiles = [1, 5],
    groups = None,
    benchmark_period = '1D'
)

Plot the returns

In [39]:
factor_data.plot()
Out[39]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f37c4efd410>

Check correalation

In [40]:
np.corrcoef(factor_returns)
Out[40]:
1.0

Check risk factor of Quantopian risk model to our factor in pyfolio

In [41]:
start_date = factor_data.index.levels[0].min()
end_date = factor_data.index.levels[0].max()

factor_loadings = get_factor_loadings(assets, start_date, end_date)
factor_returns = get_factor_returns(start_date, end_date)
In [44]:
pf.tears.create_perf_attrib_tear_sheet(
    returns = assets,
    positions = factor_positions,
    factor_returns = factor_returns,
    factor_loadings = factor_loadings,
    pos_in_dollars = False,
)

ValueErrorTraceback (most recent call last)
<ipython-input-44-61f5e380293e> in <module>()
      4     factor_returns = factor_returns,
      5     factor_loadings = factor_loadings,
----> 6     pos_in_dollars = False,
      7 )

/usr/local/lib/python2.7/dist-packages/pyfolio/plotting.pyc in call_w_context(*args, **kwargs)
     50         if set_context:
     51             with plotting_context(), axes_style():
---> 52                 return func(*args, **kwargs)
     53         else:
     54             return func(*args, **kwargs)

/usr/local/lib/python2.7/dist-packages/pyfolio/tears.pyc in create_perf_attrib_tear_sheet(returns, positions, factor_returns, factor_loadings, transactions, pos_in_dollars, return_fig, factor_partitions)
   1531     portfolio_exposures, perf_attrib_data = perf_attrib.perf_attrib(
   1532         returns, positions, factor_returns, factor_loadings, transactions,
-> 1533         pos_in_dollars=pos_in_dollars
   1534     )
   1535 

/usr/local/lib/python2.7/dist-packages/pyfolio/perf_attrib.pyc in perf_attrib(returns, positions, factor_returns, factor_loadings, transactions, pos_in_dollars)
    137     risk_exposures_portfolio = compute_exposures(positions,
    138                                                  factor_loadings,
--> 139                                                  stack_positions=False)
    140 
    141     perf_attrib_by_factor = risk_exposures_portfolio.multiply(factor_returns)

/usr/local/lib/python2.7/dist-packages/pyfolio/perf_attrib.pyc in compute_exposures(positions, factor_loadings, stack_positions, pos_in_dollars)
    215 
    216     risk_exposures = factor_loadings.multiply(positions,
--> 217                                               axis='rows')
    218 
    219     return risk_exposures.groupby(level='dt').sum()

/usr/local/lib/python2.7/dist-packages/pandas/core/ops.pyc in f(self, other, axis, level, fill_value)
   1060             return self._combine_frame(other, na_op, fill_value, level)
   1061         elif isinstance(other, ABCSeries):
-> 1062             return self._combine_series(other, na_op, fill_value, axis, level)
   1063         elif isinstance(other, (list, tuple)):
   1064             if axis is not None and self._get_axis_name(axis) == 'index':

/usr/local/lib/python2.7/dist-packages/pandas/core/frame.pyc in _combine_series(self, other, func, fill_value, axis, level)
   3508             if axis == 'index':
   3509                 return self._combine_match_index(other, func, level=level,
-> 3510                                                  fill_value=fill_value)
   3511             else:
   3512                 return self._combine_match_columns(other, func, level=level,

/usr/local/lib/python2.7/dist-packages/pandas/core/frame.pyc in _combine_match_index(self, other, func, level, fill_value)
   3529     def _combine_match_index(self, other, func, level=None, fill_value=None):
   3530         left, right = self.align(other, join='outer', axis=0, level=level,
-> 3531                                  copy=False)
   3532         if fill_value is not None:
   3533             raise NotImplementedError("fill_value %r not supported." %

/usr/local/lib/python2.7/dist-packages/pandas/core/frame.pyc in align(self, other, join, axis, level, copy, fill_value, method, limit, fill_axis, broadcast_axis)
   2734                                             method=method, limit=limit,
   2735                                             fill_axis=fill_axis,
-> 2736                                             broadcast_axis=broadcast_axis)
   2737 
   2738     @Appender(_shared_docs['reindex'] % _shared_doc_kwargs)

/usr/local/lib/python2.7/dist-packages/pandas/core/generic.pyc in align(self, other, join, axis, level, copy, fill_value, method, limit, fill_axis, broadcast_axis)
   4181                                       copy=copy, fill_value=fill_value,
   4182                                       method=method, limit=limit,
-> 4183                                       fill_axis=fill_axis)
   4184         else:  # pragma: no cover
   4185             raise TypeError('unsupported type: %s' % type(other))

/usr/local/lib/python2.7/dist-packages/pandas/core/generic.pyc in _align_series(self, other, join, axis, level, copy, fill_value, method, limit, fill_axis)
   4254                     join_index, lidx, ridx = self.index.join(
   4255                         other.index, how=join, level=level,
-> 4256                         return_indexers=True)
   4257 
   4258                 if lidx is not None:

/usr/local/lib/python2.7/dist-packages/pandas/indexes/base.pyc in join(self, other, how, level, return_indexers)
   2443             else:
   2444                 return self._join_multi(other, how=how,
-> 2445                                         return_indexers=return_indexers)
   2446 
   2447         # join on the level

/usr/local/lib/python2.7/dist-packages/pandas/indexes/base.pyc in _join_multi(self, other, how, return_indexers)
   2535         # need at least 1 in common, but not more than 1
   2536         if not len(overlap):
-> 2537             raise ValueError("cannot join with no level specified and no "
   2538                              "overlapping names")
   2539         if len(overlap) > 1:

ValueError: cannot join with no level specified and no overlapping names