diff --git a/alphalens/plotting.py b/alphalens/plotting.py index 96cf7a04..a69d0054 100644 --- a/alphalens/plotting.py +++ b/alphalens/plotting.py @@ -35,6 +35,7 @@ def customize(func): """ Decorator to set plotting context and axes style during function call. """ + @wraps(func) def call_w_context(*args, **kwargs): set_context = kwargs.pop('set_context', True) @@ -45,6 +46,7 @@ def call_w_context(*args, **kwargs): return func(*args, **kwargs) else: return func(*args, **kwargs) + return call_w_context @@ -133,7 +135,8 @@ def axes_style(style='darkgrid', rc=None): def plot_returns_table(alpha_beta, mean_ret_quantile, - mean_ret_spread_quantile): + mean_ret_spread_quantile, + return_table=False): returns_table = pd.DataFrame() returns_table = returns_table.append(alpha_beta) returns_table.loc["Mean Period Wise Return Top Quantile (bps)"] = \ @@ -145,9 +148,12 @@ def plot_returns_table(alpha_beta, print("Returns Analysis") utils.print_table(returns_table.apply(lambda x: x.round(3))) + if return_table: + return returns_table -def plot_turnover_table(autocorrelation_data, quantile_turnover): +def plot_turnover_table(autocorrelation_data, quantile_turnover, + return_table=False): turnover_table = pd.DataFrame() for period in sorted(quantile_turnover.keys()): for quantile, p_data in quantile_turnover[period].iteritems(): @@ -161,9 +167,12 @@ def plot_turnover_table(autocorrelation_data, quantile_turnover): print("Turnover Analysis") utils.print_table(turnover_table.apply(lambda x: x.round(3))) utils.print_table(auto_corr.apply(lambda x: x.round(3))) + if return_table: + return [turnover_table, auto_corr] -def plot_information_table(ic_data): +def plot_information_table(ic_data, + return_table=False): ic_summary_table = pd.DataFrame() ic_summary_table["IC Mean"] = ic_data.mean() ic_summary_table["IC Std."] = ic_data.std() @@ -177,19 +186,25 @@ def plot_information_table(ic_data): print("Information Analysis") utils.print_table(ic_summary_table.apply(lambda x: x.round(3)).T) + if return_table: + return ic_summary_table -def plot_quantile_statistics_table(factor_data): +def plot_quantile_statistics_table(factor_data, + return_table=False): quantile_stats = factor_data.groupby('factor_quantile') \ .agg(['min', 'max', 'mean', 'std', 'count'])['factor'] - quantile_stats['count %'] = quantile_stats['count'] \ - / quantile_stats['count'].sum() * 100. + quantile_stats['count %'] = \ + quantile_stats['count'] / quantile_stats['count'].sum() * 100. print("Quantiles Statistics") utils.print_table(quantile_stats) + if return_table: + return quantile_stats -def plot_ic_ts(ic, ax=None): +def plot_ic_ts(ic, ax=None, + return_fig=False): """ Plots Spearman Rank Information Coefficient and IC moving average for a given factor. @@ -209,6 +224,7 @@ def plot_ic_ts(ic, ax=None): ic = ic.copy() num_plots = len(ic.columns) + f = None if ax is None: f, ax = plt.subplots(num_plots, 1, figsize=(18, num_plots * 7)) ax = np.asarray([ax]).flatten() @@ -241,11 +257,14 @@ def plot_ic_ts(ic, ax=None): for a in ax: a.set_ylim([ymin, ymax]) - - return ax + if return_fig: + return f, ax + else: + return ax -def plot_ic_hist(ic, ax=None): +def plot_ic_hist(ic, ax=None, + return_fig=False): """ Plots Spearman Rank Information Coefficient histogram for a given factor. @@ -267,7 +286,7 @@ def plot_ic_hist(ic, ax=None): num_plots = len(ic.columns) v_spaces = ((num_plots - 1) // 3) + 1 - + f = None if ax is None: f, ax = plt.subplots(v_spaces, 3, figsize=(18, v_spaces * 6)) ax = ax.flatten() @@ -286,10 +305,14 @@ def plot_ic_hist(ic, ax=None): if num_plots < len(ax): ax[-1].set_visible(False) - return ax + if return_fig: + return f, ax + else: + return ax -def plot_ic_qq(ic, theoretical_dist=stats.norm, ax=None): +def plot_ic_qq(ic, theoretical_dist=stats.norm, ax=None, + return_fig=False): """ Plots Spearman Rank Information Coefficient "Q-Q" plot relative to a theoretical distribution. @@ -315,7 +338,7 @@ def plot_ic_qq(ic, theoretical_dist=stats.norm, ax=None): num_plots = len(ic.columns) v_spaces = ((num_plots - 1) // 3) + 1 - + f = None if ax is None: f, ax = plt.subplots(v_spaces, 3, figsize=(18, v_spaces * 6)) ax = ax.flatten() @@ -331,17 +354,21 @@ def plot_ic_qq(ic, theoretical_dist=stats.norm, ax=None): sm.qqplot(ic.replace(np.nan, 0.).values, theoretical_dist, fit=True, line='45', ax=a) a.set(title="{} Period IC {} Dist. Q-Q".format( - period_num, dist_name), - ylabel='Observed Quantile', - xlabel='{} Distribution Quantile'.format(dist_name)) + period_num, dist_name), + ylabel='Observed Quantile', + xlabel='{} Distribution Quantile'.format(dist_name)) - return ax + if return_fig: + return f, ax + else: + return ax def plot_quantile_returns_bar(mean_ret_by_q, by_group=False, ylim_percentiles=None, - ax=None): + ax=None, + return_fig=False): """ Plots mean period wise returns for factor quantiles. @@ -361,7 +388,9 @@ def plot_quantile_returns_bar(mean_ret_by_q, ax : matplotlib.Axes The axes that were plotted on. """ - + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return mean_ret_by_q = mean_ret_by_q.copy() if ylim_percentiles is not None: @@ -372,11 +401,10 @@ def plot_quantile_returns_bar(mean_ret_by_q, else: ymin = None ymax = None - + f = None if by_group: num_group = len( mean_ret_by_q.index.get_level_values('group').unique()) - if ax is None: v_spaces = ((num_group - 1) // 2) + 1 f, ax = plt.subplots(v_spaces, 2, sharex=False, @@ -385,8 +413,8 @@ def plot_quantile_returns_bar(mean_ret_by_q, for a, (sc, cor) in zip(ax, mean_ret_by_q.groupby(level='group')): (cor.xs(sc, level='group') - .multiply(DECIMAL_TO_BPS) - .plot(kind='bar', title=sc, ax=a)) + .multiply(DECIMAL_TO_BPS) + .plot(kind='bar', title=sc, ax=a)) a.set(xlabel='', ylabel='Mean Return (bps)', ylim=(ymin, ymax)) @@ -394,24 +422,31 @@ def plot_quantile_returns_bar(mean_ret_by_q, if num_group < len(ax): ax[-1].set_visible(False) - return ax + if return_fig: + return f, ax + else: + return ax else: if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) (mean_ret_by_q.multiply(DECIMAL_TO_BPS) - .plot(kind='bar', - title="Mean Period Wise Return By Factor Quantile", ax=ax)) + .plot(kind='bar', + title="Mean Period Wise Return By Factor Quantile", ax=ax)) ax.set(xlabel='', ylabel='Mean Return (bps)', ylim=(ymin, ymax)) - return ax + if return_fig: + return f, ax + else: + return ax def plot_quantile_returns_violin(return_by_q, ylim_percentiles=None, - ax=None): + ax=None, + return_fig=False): """ Plots a violin box plot of period wise returns for factor quantiles. @@ -430,7 +465,9 @@ def plot_quantile_returns_violin(return_by_q, ax : matplotlib.Axes The axes that were plotted on. """ - + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return return_by_q = return_by_q.copy() if ylim_percentiles is not None: @@ -441,7 +478,7 @@ def plot_quantile_returns_violin(return_by_q, else: ymin = None ymax = None - + f = None if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) @@ -466,13 +503,17 @@ def plot_quantile_returns_violin(return_by_q, ax.axhline(0.0, linestyle='-', color='black', lw=0.7, alpha=0.6) - return ax + if return_fig: + return f, ax + else: + return ax def plot_mean_quantile_returns_spread_time_series(mean_returns_spread, std_err=None, bandwidth=1, - ax=None): + ax=None, + return_fig=False): """ Plots mean period wise returns for factor quantiles. @@ -493,7 +534,10 @@ def plot_mean_quantile_returns_spread_time_series(mean_returns_spread, ax : matplotlib.Axes The axes that were plotted on. """ - + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return + f = None if isinstance(mean_returns_spread, pd.DataFrame): if ax is None: ax = [None for a in mean_returns_spread.columns] @@ -552,10 +596,14 @@ def plot_mean_quantile_returns_spread_time_series(mean_returns_spread, ylim=(-ylim, ylim)) ax.axhline(0.0, linestyle='-', color='black', lw=1, alpha=0.8) - return ax + if return_fig: + return f, ax + else: + return ax -def plot_ic_by_group(ic_group, ax=None): +def plot_ic_by_group(ic_group, ax=None, + return_fig=False): """ Plots Spearman Rank Information Coefficient for a given factor over provided forward returns. Separates by group. @@ -572,6 +620,10 @@ def plot_ic_by_group(ic_group, ax=None): ax : matplotlib.Axes The axes that were plotted on. """ + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return + f = None if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) ic_group.plot(kind='bar', ax=ax) @@ -579,12 +631,16 @@ def plot_ic_by_group(ic_group, ax=None): ax.set(title="Information Coefficient By Group", xlabel="") ax.set_xticklabels(ic_group.index, rotation=45) - return ax + if return_fig: + return f, ax + else: + return ax def plot_factor_rank_auto_correlation(factor_autocorrelation, period=1, - ax=None): + ax=None, + return_fig=False): """ Plots factor rank autocorrelation over time. See factor_rank_autocorrelation for more details. @@ -604,6 +660,10 @@ def plot_factor_rank_auto_correlation(factor_autocorrelation, ax : matplotlib.Axes The axes that were plotted on. """ + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return + f = None if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) @@ -617,10 +677,14 @@ def plot_factor_rank_auto_correlation(factor_autocorrelation, transform=ax.transAxes, verticalalignment='top') - return ax + if return_fig: + return f, ax + else: + return ax -def plot_top_bottom_quantile_turnover(quantile_turnover, period=1, ax=None): +def plot_top_bottom_quantile_turnover(quantile_turnover, period=1, ax=None, + return_fig=False): """ Plots period wise top and bottom quantile factor turnover. @@ -638,6 +702,10 @@ def plot_top_bottom_quantile_turnover(quantile_turnover, period=1, ax=None): ax : matplotlib.Axes The axes that were plotted on. """ + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return + f = None if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) @@ -650,10 +718,14 @@ def plot_top_bottom_quantile_turnover(quantile_turnover, period=1, ax=None): .format(period), ax=ax, alpha=0.6, lw=0.8) ax.set(ylabel='Proportion Of Names New To Quantile', xlabel="") - return ax + if return_fig: + return f, ax + else: + return ax -def plot_monthly_ic_heatmap(mean_monthly_ic, ax=None): +def plot_monthly_ic_heatmap(mean_monthly_ic, ax=None, + return_fig=False): """ Plots a heatmap of the information coefficient or returns by month. @@ -667,13 +739,15 @@ def plot_monthly_ic_heatmap(mean_monthly_ic, ax=None): ax : matplotlib.Axes The axes that were plotted on. """ - + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return mean_monthly_ic = mean_monthly_ic.copy() num_plots = len(mean_monthly_ic.columns) v_spaces = ((num_plots - 1) // 3) + 1 - + f = None if ax is None: f, ax = plt.subplots(v_spaces, 3, figsize=(18, v_spaces * 6)) ax = ax.flatten() @@ -689,7 +763,6 @@ def plot_monthly_ic_heatmap(mean_monthly_ic, ax=None): names=["year", "month"]) for a, (periods_num, ic) in zip(ax, mean_monthly_ic.iteritems()): - sns.heatmap( ic.unstack(), annot=True, @@ -708,10 +781,14 @@ def plot_monthly_ic_heatmap(mean_monthly_ic, ax=None): if num_plots < len(ax): ax[-1].set_visible(False) - return ax + if return_fig: + return f, ax + else: + return ax -def plot_cumulative_returns(factor_returns, period, freq, title=None, ax=None): +def plot_cumulative_returns(factor_returns, period, freq, title=None, ax=None, + return_fig=False): """ Plots the cumulative returns of the returns series passed in. @@ -739,6 +816,10 @@ def plot_cumulative_returns(factor_returns, period, freq, title=None, ax=None): ax : matplotlib.Axes The axes that were plotted on. """ + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return + f = None if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) @@ -751,13 +832,17 @@ def plot_cumulative_returns(factor_returns, period, freq, title=None, ax=None): xlabel='') ax.axhline(1.0, linestyle='-', color='black', lw=1) - return ax + if return_fig: + return f, ax + else: + return ax def plot_cumulative_returns_by_quantile(quantile_returns, period, freq, - ax=None): + ax=None, + return_fig=False): """ Plots the cumulative returns of various factor quantiles. @@ -781,7 +866,10 @@ def plot_cumulative_returns_by_quantile(quantile_returns, ------- ax : matplotlib.Axes """ - + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return + f = None if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) @@ -804,14 +892,18 @@ def plot_cumulative_returns_by_quantile(quantile_returns, ax.yaxis.set_major_formatter(ScalarFormatter()) ax.axhline(1.0, linestyle='-', color='black', lw=1) - return ax + if return_fig: + return f, ax + else: + return ax def plot_quantile_average_cumulative_return(avg_cumulative_returns, by_quantile=False, std_bar=False, title=None, - ax=None): + ax=None, + return_fig=False): """ Plots sector-wise mean daily returns for factor quantiles across provided forward price movement columns. @@ -834,12 +926,14 @@ def plot_quantile_average_cumulative_return(avg_cumulative_returns, ------- ax : matplotlib.Axes """ - + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return avg_cumulative_returns = avg_cumulative_returns.multiply(DECIMAL_TO_BPS) quantiles = len(avg_cumulative_returns.index.levels[0].unique()) palette = [cm.coolwarm(i) for i in np.linspace(0, 1, quantiles)] palette = palette[::-1] # we want negative quantiles as 'red' - + f = None if by_quantile: if ax is None: @@ -848,10 +942,9 @@ def plot_quantile_average_cumulative_return(avg_cumulative_returns, sharey=False, figsize=(18, 6 * v_spaces)) ax = ax.flatten() - for i, (quantile, q_ret) in enumerate(avg_cumulative_returns - .groupby(level='factor_quantile') - ): - + for i, (quantile, q_ret) in \ + enumerate(avg_cumulative_returns + .groupby(level='factor_quantile')): mean = q_ret.loc[(quantile, 'mean')] mean.name = 'Quantile ' + str(quantile) mean.plot(ax=ax[i], color=palette[i]) @@ -871,10 +964,9 @@ def plot_quantile_average_cumulative_return(avg_cumulative_returns, if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) - for i, (quantile, q_ret) in enumerate(avg_cumulative_returns - .groupby(level='factor_quantile') - ): - + for i, (quantile, q_ret) in \ + enumerate(avg_cumulative_returns + .groupby(level='factor_quantile')): mean = q_ret.loc[(quantile, 'mean')] mean.name = 'Quantile ' + str(quantile) mean.plot(ax=ax, color=palette[i]) @@ -892,10 +984,14 @@ def plot_quantile_average_cumulative_return(avg_cumulative_returns, if title is None else title), xlabel='Periods') - return ax + if return_fig: + return f, ax + else: + return ax -def plot_events_distribution(events, num_bars=50, ax=None): +def plot_events_distribution(events, num_bars=50, ax=None, + return_fig=False): """ Plots the distribution of events in time. @@ -912,7 +1008,10 @@ def plot_events_distribution(events, num_bars=50, ax=None): ------- ax : matplotlib.Axes """ - + if ax is not None and return_fig: + print("Error argument combination: ax should be None if return_fig") + return + f = None if ax is None: f, ax = plt.subplots(1, 1, figsize=(18, 6)) @@ -925,4 +1024,7 @@ def plot_events_distribution(events, num_bars=50, ax=None): title='Distribution of events in time', xlabel='Date') - return ax + if return_fig: + return f, ax + else: + return ax diff --git a/alphalens/tears.py b/alphalens/tears.py index a193b37c..dcd0265c 100644 --- a/alphalens/tears.py +++ b/alphalens/tears.py @@ -62,7 +62,9 @@ def close(self): @plotting.customize def create_summary_tear_sheet(factor_data, long_short=True, - group_neutral=False): + group_neutral=False, + return_tf=False, + show=True): """ Creates a small summary tear sheet with returns, information, and turnover analysis. @@ -128,11 +130,19 @@ def create_summary_tear_sheet(factor_data, vertical_sections = 2 + fr_cols * 3 gf = GridFigure(rows=vertical_sections, cols=1) - plotting.plot_quantile_statistics_table(factor_data) - - plotting.plot_returns_table(alpha_beta, - mean_quant_rateret, - mean_ret_spread_quant) + result_tables = {} + result_figs = [] + quantile_statistics_table = \ + plotting.plot_quantile_statistics_table(factor_data, + return_table=return_tf) + if quantile_statistics_table is not None: + result_tables["quantile_statistics_table"] = quantile_statistics_table + returns_table = plotting.plot_returns_table(alpha_beta, + mean_quant_rateret, + mean_ret_spread_quant, + return_table=return_tf) + if returns_table is not None: + result_tables["returns_table"] = returns_table plotting.plot_quantile_returns_bar(mean_quant_rateret, by_group=False, @@ -141,8 +151,10 @@ def create_summary_tear_sheet(factor_data, # Information Analysis ic = perf.factor_information_coefficient(factor_data) - plotting.plot_information_table(ic) - + ic_summary_table =\ + plotting.plot_information_table(ic, return_table=return_tf) + if ic_summary_table is not None: + result_tables["summary_ic_summary_table"] = ic_summary_table # Turnover Analysis quantile_factor = factor_data['factor_quantile'] @@ -150,23 +162,36 @@ def create_summary_tear_sheet(factor_data, {p: pd.concat([perf.quantile_turnover(quantile_factor, q, p) for q in range(1, int(quantile_factor.max()) + 1)], axis=1) - for p in periods} + for p in periods} autocorrelation = pd.concat( [perf.factor_rank_autocorrelation(factor_data, period) for period in periods], axis=1) - plotting.plot_turnover_table(autocorrelation, quantile_turnover) - - plt.show() + turnover_table_results =\ + plotting.plot_turnover_table(autocorrelation, + quantile_turnover, + return_table=return_tf) + if turnover_table_results is not None: + result_tables["summary_turnover_table"] = turnover_table_results[0] + result_tables["summary_auto_corr"] = turnover_table_results[1] + if show: + plt.show() + if return_tf: + fig = gf.fig + result_figs.append(fig) gf.close() + if return_tf: + return result_tables, result_figs @plotting.customize def create_returns_tear_sheet(factor_data, long_short=True, group_neutral=False, - by_group=False): + by_group=False, + return_tf=False, + show=True): """ Creates a tear sheet for returns analysis of a factor. @@ -237,9 +262,14 @@ def create_returns_tear_sheet(factor_data, vertical_sections = 2 + fr_cols * 3 gf = GridFigure(rows=vertical_sections, cols=1) - plotting.plot_returns_table(alpha_beta, - mean_quant_rateret, - mean_ret_spread_quant) + result_tables = {} + result_figs = [] + returns_table = plotting.plot_returns_table(alpha_beta, + mean_quant_rateret, + mean_ret_spread_quant, + return_table=return_tf) + if returns_table is not None: + result_tables["returns_table"] = returns_table plotting.plot_quantile_returns_bar(mean_quant_rateret, by_group=False, @@ -259,7 +289,6 @@ def create_returns_tear_sheet(factor_data, ) for p in factor_returns: - title = ('Factor Weighted ' + ('Group Neutral ' if group_neutral else '') + ('Long/Short ' if long_short else '') @@ -288,8 +317,11 @@ def create_returns_tear_sheet(factor_data, bandwidth=0.5, ax=ax_mean_quantile_returns_spread_ts ) - - plt.show() + if show: + plt.show() + if return_tf: + res_fig = gf.fig + result_figs.append(res_fig) gf.close() if by_group: @@ -318,13 +350,20 @@ def create_returns_tear_sheet(factor_data, ylim_percentiles=(5, 95), ax=ax_quantile_returns_bar_by_group) plt.show() + if return_tf: + res_group_fig = gf.fig + result_figs.append(res_group_fig) gf.close() + if return_tf: + return result_tables, result_figs @plotting.customize def create_information_tear_sheet(factor_data, group_neutral=False, - by_group=False): + by_group=False, + return_tf=False, + show=True): """ Creates a tear sheet for information analysis of a factor. @@ -341,10 +380,14 @@ def create_information_tear_sheet(factor_data, by_group : bool If True, display graphs separately for each group. """ - + result_tables = {} + result_figs = [] ic = perf.factor_information_coefficient(factor_data, group_neutral) - plotting.plot_information_table(ic) + ic_summary_table = \ + plotting.plot_information_table(ic, return_table=return_tf) + if ic_summary_table is not None: + result_tables["information_ic_summary_table"] = ic_summary_table columns_wide = 2 fr_cols = len(ic.columns) @@ -360,7 +403,6 @@ def create_information_tear_sheet(factor_data, plotting.plot_ic_qq(ic, ax=ax_ic_hqq[1::2]) if not by_group: - mean_monthly_ic = \ perf.mean_information_coefficient(factor_data, group_adjust=group_neutral, @@ -377,13 +419,19 @@ def create_information_tear_sheet(factor_data, by_group=True) plotting.plot_ic_by_group(mean_group_ic, ax=gf.next_row()) - - plt.show() + if show: + plt.show() + if return_tf: + fig = gf.fig + result_figs.append(fig) gf.close() + if return_tf: + return result_tables, result_figs @plotting.customize -def create_turnover_tear_sheet(factor_data, turnover_periods=None): +def create_turnover_tear_sheet(factor_data, turnover_periods=None, + return_tf=False, show=True): """ Creates a tear sheet for analyzing the turnover properties of a factor. @@ -403,7 +451,8 @@ def create_turnover_tear_sheet(factor_data, turnover_periods=None): are 2h and 4h and the factor is computed daily and so values like ['1D', '2D'] could be used instead """ - + result_tables = {} + result_figs = [] if turnover_periods is None: turnover_periods = utils.get_forward_returns_columns( factor_data.columns) @@ -414,13 +463,19 @@ def create_turnover_tear_sheet(factor_data, turnover_periods=None): {p: pd.concat([perf.quantile_turnover(quantile_factor, q, p) for q in range(1, int(quantile_factor.max()) + 1)], axis=1) - for p in turnover_periods} + for p in turnover_periods} autocorrelation = pd.concat( [perf.factor_rank_autocorrelation(factor_data, period) for period in turnover_periods], axis=1) - plotting.plot_turnover_table(autocorrelation, quantile_turnover) + turnover_tables =\ + plotting.plot_turnover_table(autocorrelation, + quantile_turnover, + return_table=return_tf) + if turnover_tables is not None: + result_tables["turnover_turnover_table"] = turnover_tables[0] + result_tables["turnover_auto_corr"] = turnover_tables[1] fr_cols = len(turnover_periods) columns_wide = 1 @@ -441,9 +496,14 @@ def create_turnover_tear_sheet(factor_data, turnover_periods=None): plotting.plot_factor_rank_auto_correlation(autocorrelation[period], period=period, ax=gf.next_row()) - - plt.show() + if show: + plt.show() + if return_tf: + fig = gf.fig + result_figs.append(fig) gf.close() + if return_tf: + return result_tables, result_figs @plotting.customize @@ -476,7 +536,6 @@ def create_full_tear_sheet(factor_data, by_group : bool If True, display graphs separately for each group. """ - plotting.plot_quantile_statistics_table(factor_data) create_returns_tear_sheet(factor_data, long_short, @@ -497,7 +556,9 @@ def create_event_returns_tear_sheet(factor_data, long_short=True, group_neutral=False, std_bar=True, - by_group=False): + by_group=False, + return_tf=False, + show=True): """ Creates a tear sheet to view the average cumulative returns for a factor within a window (pre and post event). @@ -527,7 +588,8 @@ def create_event_returns_tear_sheet(factor_data, by_group : bool If True, display graphs separately for each group. """ - + result_tables = {} + result_figs = [] before, after = avgretplot avg_cumulative_returns = \ @@ -558,8 +620,11 @@ def create_event_returns_tear_sheet(factor_data, by_quantile=True, std_bar=True, ax=ax_avg_cumulative_returns_by_q) - - plt.show() + if show: + plt.show() + if return_tf: + fig1 = gf.fig + result_figs.append(fig1) gf.close() if by_group: @@ -586,9 +651,14 @@ def create_event_returns_tear_sheet(factor_data, std_bar=False, title=group, ax=gf.next_cell()) - - plt.show() + if show: + plt.show() + if return_tf: + fig2 = gf.fig + result_figs.append(fig2) gf.close() + if return_tf: + return result_tables, result_figs @plotting.customize @@ -596,7 +666,9 @@ def create_event_study_tear_sheet(factor_data, prices=None, avgretplot=(5, 15), rate_of_ret=True, - n_bars=50): + n_bars=50, + return_tf=False, + show=True): """ Creates an event study tear sheet for analysis of a specific event. @@ -621,7 +693,8 @@ def create_event_study_tear_sheet(factor_data, n_bars : int, optional Number of bars in event distribution plot """ - + result_tables = {} + result_figs = [] long_short = False plotting.plot_quantile_statistics_table(factor_data) @@ -630,11 +703,14 @@ def create_event_study_tear_sheet(factor_data, plotting.plot_events_distribution(events=factor_data['factor'], num_bars=n_bars, ax=gf.next_row()) - plt.show() + if show: + plt.show() + if return_tf: + fig = gf.fig + result_figs.append(fig) gf.close() if prices is not None and avgretplot is not None: - create_event_returns_tear_sheet(factor_data=factor_data, prices=prices, avgretplot=avgretplot, @@ -689,13 +765,17 @@ def create_event_study_tear_sheet(factor_data, ) for p in factor_returns: - plotting.plot_cumulative_returns( factor_returns[p], period=p, freq=trading_calendar, ax=gf.next_row() ) - - plt.show() + if show: + plt.show() + if return_tf: + fig = gf.fig + result_figs.append(fig) gf.close() + if return_tf: + return result_tables, result_figs