Skip to content

Commit

Permalink
Merge pull request #328 from luca-s/new_pandas
Browse files Browse the repository at this point in the history
MAINT: code refactoring to make it compatible with pandas 0.23.4
  • Loading branch information
twiecki authored Dec 17, 2018
2 parents e67d2b5 + b499773 commit 957d5cc
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 19 deletions.
4 changes: 0 additions & 4 deletions alphalens/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,6 @@ def to_weights(group, _demeaned, _equal_weight):
if group_adjust:
weights = weights.groupby(level='date').apply(to_weights, False, False)

# preserve freq, which contains trading calendar information
weights.index.levels[0].freq = factor_data.index.levels[0].freq
return weights


Expand Down Expand Up @@ -253,8 +251,6 @@ def factor_returns(factor_data,
else:
returns = weighted_returns.groupby(level='date').sum()

# preserve freq, which contains trading calendar information
returns.index.freq = factor_data.index.levels[0].freq
return returns


Expand Down
17 changes: 14 additions & 3 deletions alphalens/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ def plot_monthly_ic_heatmap(mean_monthly_ic, ax=None):
return ax


def plot_cumulative_returns(factor_returns, period, title=None, ax=None):
def plot_cumulative_returns(factor_returns, period, freq, title=None, ax=None):
"""
Plots the cumulative returns of the returns series passed in.
Expand All @@ -724,6 +724,11 @@ def plot_cumulative_returns(factor_returns, period, title=None, ax=None):
Length of period for which the returns are computed (e.g. 1 day)
if 'period' is a string it must follow pandas.Timedelta constructor
format (e.g. '1 days', '1D', '30m', '3h', '1D1h', etc)
freq : pandas DateOffset
Used to specify a particular trading calendar e.g. BusinessDay or Day
Usually this is inferred from utils.infer_trading_calendar, which is
called by either get_clean_factor_and_forward_returns or
compute_forward_returns
title: string, optional
Custom title
ax : matplotlib.Axes, optional
Expand All @@ -737,7 +742,7 @@ def plot_cumulative_returns(factor_returns, period, title=None, ax=None):
if ax is None:
f, ax = plt.subplots(1, 1, figsize=(18, 6))

factor_returns = perf.cumulative_returns(factor_returns, period)
factor_returns = perf.cumulative_returns(factor_returns, period, freq)

factor_returns.plot(ax=ax, lw=3, color='forestgreen', alpha=0.6)
ax.set(ylabel='Cumulative Returns',
Expand All @@ -751,6 +756,7 @@ def plot_cumulative_returns(factor_returns, period, title=None, ax=None):

def plot_cumulative_returns_by_quantile(quantile_returns,
period,
freq,
ax=None):
"""
Plots the cumulative returns of various factor quantiles.
Expand All @@ -763,6 +769,11 @@ def plot_cumulative_returns_by_quantile(quantile_returns,
Length of period for which the returns are computed (e.g. 1 day)
if 'period' is a string it must follow pandas.Timedelta constructor
format (e.g. '1 days', '1D', '30m', '3h', '1D1h', etc)
freq : pandas DateOffset
Used to specify a particular trading calendar e.g. BusinessDay or Day
Usually this is inferred from utils.infer_trading_calendar, which is
called by either get_clean_factor_and_forward_returns or
compute_forward_returns
ax : matplotlib.Axes, optional
Axes upon which to plot.
Expand All @@ -776,7 +787,7 @@ def plot_cumulative_returns_by_quantile(quantile_returns,

ret_wide = quantile_returns.unstack('factor_quantile')

cum_ret = ret_wide.apply(perf.cumulative_returns, period=period)
cum_ret = ret_wide.apply(perf.cumulative_returns, period=period, freq=freq)
cum_ret = cum_ret.loc[:, ::-1] # we want negative quantiles as 'red'

cum_ret.plot(lw=2, ax=ax, cmap=cm.coolwarm)
Expand Down
46 changes: 36 additions & 10 deletions alphalens/tears.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import pandas as pd
import warnings

from . import plotting
from . import performance as perf
Expand Down Expand Up @@ -249,21 +250,35 @@ def create_returns_tear_sheet(factor_data,
ylim_percentiles=(1, 99),
ax=gf.next_row())

trading_calendar = factor_data.index.levels[0].freq
if trading_calendar is None:
trading_calendar = pd.tseries.offsets.BDay()
warnings.warn(
"'freq' not set in factor_data index: assuming business day",
UserWarning
)

for p in factor_returns:

title = ('Factor Weighted '
+ ('Group Neutral ' if group_neutral else '')
+ ('Long/Short ' if long_short else '')
+ "Portfolio Cumulative Return ({} Period)".format(p))

plotting.plot_cumulative_returns(factor_returns[p],
period=p,
title=title,
ax=gf.next_row())
plotting.plot_cumulative_returns(
factor_returns[p],
period=p,
freq=trading_calendar,
title=title,
ax=gf.next_row()
)

plotting.plot_cumulative_returns_by_quantile(mean_quant_ret_bydate[p],
period=p,
ax=gf.next_row())
plotting.plot_cumulative_returns_by_quantile(
mean_quant_ret_bydate[p],
period=p,
freq=trading_calendar,
ax=gf.next_row()
)

ax_mean_quantile_returns_spread_ts = [gf.next_row()
for x in range(fr_cols)]
Expand Down Expand Up @@ -665,11 +680,22 @@ def create_event_study_tear_sheet(factor_data,
ylim_percentiles=(1, 99),
ax=gf.next_row())

trading_calendar = factor_data.index.levels[0].freq
if trading_calendar is None:
trading_calendar = pd.tseries.offsets.BDay()
warnings.warn(
"'freq' not set in factor_data index: assuming business day",
UserWarning
)

for p in factor_returns:

plotting.plot_cumulative_returns(factor_returns[p],
period=p,
ax=gf.next_row())
plotting.plot_cumulative_returns(
factor_returns[p],
period=p,
freq=trading_calendar,
ax=gf.next_row()
)

plt.show()
gf.close()
3 changes: 1 addition & 2 deletions alphalens/tests/test_performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,9 +747,8 @@ def test_cumulative_returns(self, returns, ret_freq, period_len,
period_len = Timedelta(period_len)
index = date_range('1/1/1999', periods=len(returns), freq=ret_freq)
returns = Series(returns, index=index)
returns.index.freq = ret_freq_class

cum_ret = cumulative_returns(returns, period_len)
cum_ret = cumulative_returns(returns, period_len, ret_freq_class)

expected = Series(expected_vals, index=cum_ret.index)

Expand Down

0 comments on commit 957d5cc

Please sign in to comment.