Skip to content

Commit

Permalink
Merge pull request #294 from quantopian/tweaks
Browse files Browse the repository at this point in the history
Add log-scaling version of cumulative returns and raw returns plot to returns tear-sheet
  • Loading branch information
twiecki committed Apr 20, 2016
2 parents 37ef1d6 + ffdee90 commit a550a3c
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 32 deletions.
94 changes: 79 additions & 15 deletions pyfolio/examples/single_stock_example.ipynb

Large diffs are not rendered by default.

56 changes: 53 additions & 3 deletions pyfolio/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,57 @@ def show_perf_stats(returns, factor_returns, live_start_date=None,
fmt='{0:.2f}')


def plot_returns(returns,
live_start_date=None,
ax=None):
"""
Plots raw returns over time.
Backtest returns are in green, and out-of-sample (live trading)
returns are in red.
Parameters
----------
returns : pd.Series
Daily returns of the strategy, noncumulative.
- See full explanation in tears.create_full_tear_sheet.
live_start_date : datetime, optional
The date when the strategy began live trading, after
its backtest period. This date should be normalized.
ax : matplotlib.Axes, optional
Axes upon which to plot.
**kwargs, optional
Passed to plotting function.
Returns
-------
ax : matplotlib.Axes
The axes that were plotted on.
"""

if ax is None:
ax = plt.gca()

ax.set(xlabel='', ylabel='Returns')

if live_start_date is not None:
live_start_date = utils.get_utc_timestamp(live_start_date)
is_returns = returns.loc[returns.index < live_start_date]
oos_returns = returns.loc[returns.index >= live_start_date]
is_returns.plot(ax=ax, color='g')
oos_returns.plot(ax=ax, color='r')

else:
returns.plot(ax=ax, color='g')

return ax


def plot_rolling_returns(returns,
factor_returns=None,
live_start_date=None,
logy=False,
cone_std=None,
legend_loc='best',
volatility_match=False,
Expand All @@ -596,6 +644,8 @@ def plot_rolling_returns(returns,
live_start_date : datetime, optional
The date when the strategy began live trading, after
its backtest period. This date should be normalized.
logy : bool, optional
Whether to log-scale the y-axis.
cone_std : float, or tuple, optional
If float, The standard deviation to use for the cone plots.
If tuple, Tuple of standard deviation values to use for the cone plots
Expand Down Expand Up @@ -624,12 +674,12 @@ def cone(in_sample_returns (pd.Series),
ax : matplotlib.Axes
The axes that were plotted on.
"""
"""
if ax is None:
ax = plt.gca()

ax.set_ylabel('Cumulative returns')
ax.set_xlabel('')
ax.set(xlabel='', ylabel='Cumulative returns',
yscale='log' if logy else 'linear')

if volatility_match and factor_returns is None:
raise ValueError('volatility_match requires passing of'
Expand Down
62 changes: 48 additions & 14 deletions pyfolio/tears.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,29 +264,45 @@ def create_returns_tear_sheet(returns, live_start_date=None,
bootstrap=bootstrap,
live_start_date=live_start_date)

vertical_sections = 12

if live_start_date is not None:
vertical_sections = 11
vertical_sections += 1
live_start_date = utils.get_utc_timestamp(live_start_date)
else:
vertical_sections = 10

if bootstrap:
vertical_sections += 1

fig = plt.figure(figsize=(14, vertical_sections * 6))
gs = gridspec.GridSpec(vertical_sections, 3, wspace=0.5, hspace=0.5)
ax_rolling_returns = plt.subplot(gs[:2, :])
ax_rolling_returns_vol_match = plt.subplot(gs[2, :],

i = 2
ax_rolling_returns_vol_match = plt.subplot(gs[i, :],
sharex=ax_rolling_returns)
ax_rolling_beta = plt.subplot(gs[3, :], sharex=ax_rolling_returns)
ax_rolling_sharpe = plt.subplot(gs[4, :], sharex=ax_rolling_returns)
ax_rolling_risk = plt.subplot(gs[5, :], sharex=ax_rolling_returns)
ax_drawdown = plt.subplot(gs[6, :], sharex=ax_rolling_returns)
ax_underwater = plt.subplot(gs[7, :], sharex=ax_rolling_returns)
ax_monthly_heatmap = plt.subplot(gs[8, 0])
ax_annual_returns = plt.subplot(gs[8, 1])
ax_monthly_dist = plt.subplot(gs[8, 2])
ax_return_quantiles = plt.subplot(gs[9, :])
i += 1
ax_rolling_returns_log = plt.subplot(gs[i, :],
sharex=ax_rolling_returns)
i += 1
ax_returns = plt.subplot(gs[i, :],
sharex=ax_rolling_returns)
i += 1
ax_rolling_beta = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
i += 1
ax_rolling_sharpe = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
i += 1
ax_rolling_risk = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
i += 1
ax_drawdown = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
i += 1
ax_underwater = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
i += 1
ax_monthly_heatmap = plt.subplot(gs[i, 0])
ax_annual_returns = plt.subplot(gs[i, 1])
ax_monthly_dist = plt.subplot(gs[i, 2])
i += 1
ax_return_quantiles = plt.subplot(gs[i, :])
i += 1

plotting.plot_rolling_returns(
returns,
Expand All @@ -308,6 +324,24 @@ def create_returns_tear_sheet(returns, live_start_date=None,
ax_rolling_returns_vol_match.set_title(
'Cumulative returns volatility matched to benchmark.')

plotting.plot_rolling_returns(
returns,
factor_returns=benchmark_rets,
logy=True,
live_start_date=live_start_date,
cone_std=cone_std,
ax=ax_rolling_returns_log)
ax_rolling_returns_log.set_title(
'Cumulative Returns on logarithmic scale')

plotting.plot_returns(
returns,
live_start_date=live_start_date,
ax=ax_returns,
)
ax_returns.set_title(
'Returns')

plotting.plot_rolling_beta(
returns, benchmark_rets, ax=ax_rolling_beta)

Expand Down Expand Up @@ -343,7 +377,7 @@ def create_returns_tear_sheet(returns, live_start_date=None,
ax=ax_return_quantiles)

if bootstrap:
ax_bootstrap = plt.subplot(gs[10, :])
ax_bootstrap = plt.subplot(gs[i, :])
plotting.plot_perf_stats(returns, benchmark_rets,
ax=ax_bootstrap)

Expand Down

0 comments on commit a550a3c

Please sign in to comment.