Skip to content
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

MAINT: code refactoring to make it compatible with pandas 0.23.4 #328

Merged
merged 1 commit into from
Dec 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's inferred, why is it a required argument?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because plot_cumulative_returns doesn't receive factor_data in input, which has the inferred trading calendar.

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