Skip to content

Commit 7d37dc5

Browse files
eigenfootwiecki
authored andcommitted
MAINT: add NOT_PASSED_SENTINEL (#543)
* MAINT: add not passed sentinel * STY: pep8 * BUG: change benchmark_rets back to None after warning * BUG: added extra check to avoid invalid type comp * BUG: bufixes * MAINT: refactored vertical sections * BUG: fixed plotting order
1 parent 1ee6eab commit 7d37dc5

File tree

2 files changed

+62
-16
lines changed

2 files changed

+62
-16
lines changed

pyfolio/tears.py

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@
5454
'technology']
5555
}
5656

57+
BENCHMARK_RETS_WARNING = ('The latest version of pyfolio requires users to '
58+
'supply benchmark returns. Your current tearsheets '
59+
'will not include plots and analyses that require a '
60+
'benchmark. In the future, please pass '
61+
'benchmark_rets, or pass None to silence this '
62+
'warning.')
63+
5764

5865
def timer(msg_body, previous_time):
5966
current_time = time()
@@ -68,7 +75,7 @@ def create_full_tear_sheet(returns,
6875
positions=None,
6976
transactions=None,
7077
market_data=None,
71-
benchmark_rets=None,
78+
benchmark_rets=utils.NOT_PASSED_SENTINEL,
7279
slippage=None,
7380
live_start_date=None,
7481
sector_mappings=None,
@@ -188,6 +195,10 @@ def create_full_tear_sheet(returns,
188195
factor returns and risk exposures plots
189196
- See create_perf_attrib_tear_sheet().
190197
"""
198+
if (isinstance(benchmark_rets, str)
199+
and benchmark_rets == utils.NOT_PASSED_SENTINEL):
200+
warnings.warn(BENCHMARK_RETS_WARNING)
201+
benchmark_rets = None
191202

192203
if (unadjusted_returns is None) and (slippage is not None) and\
193204
(transactions is not None):
@@ -262,7 +273,7 @@ def create_full_tear_sheet(returns,
262273
def create_simple_tear_sheet(returns,
263274
positions=None,
264275
transactions=None,
265-
benchmark_rets=None,
276+
benchmark_rets=utils.NOT_PASSED_SENTINEL,
266277
slippage=None,
267278
estimate_intraday='infer',
268279
live_start_date=None,
@@ -335,6 +346,11 @@ def create_simple_tear_sheet(returns,
335346
positions = utils.check_intraday(estimate_intraday, returns,
336347
positions, transactions)
337348

349+
if (isinstance(benchmark_rets, str)
350+
and benchmark_rets == utils.NOT_PASSED_SENTINEL):
351+
warnings.warn(BENCHMARK_RETS_WARNING)
352+
benchmark_rets = None
353+
338354
if (slippage is not None) and (transactions is not None):
339355
returns = txn.adjust_returns_for_slippage(returns, positions,
340356
transactions, slippage)
@@ -443,7 +459,7 @@ def create_returns_tear_sheet(returns, positions=None,
443459
transactions=None,
444460
live_start_date=None,
445461
cone_std=(1.0, 1.5, 2.0),
446-
benchmark_rets=None,
462+
benchmark_rets=utils.NOT_PASSED_SENTINEL,
447463
bootstrap=False,
448464
turnover_denom='AGB',
449465
header_rows=None,
@@ -493,6 +509,11 @@ def create_returns_tear_sheet(returns, positions=None,
493509
If True, returns the figure that was plotted on.
494510
"""
495511

512+
if (isinstance(benchmark_rets, str)
513+
and benchmark_rets == utils.NOT_PASSED_SENTINEL):
514+
warnings.warn(BENCHMARK_RETS_WARNING)
515+
benchmark_rets = None
516+
496517
if benchmark_rets is not None:
497518
returns = utils.clip_returns_to_benchmark(returns, benchmark_rets)
498519

@@ -506,18 +527,21 @@ def create_returns_tear_sheet(returns, positions=None,
506527

507528
plotting.show_worst_drawdown_periods(returns)
508529

509-
vertical_sections = 11
530+
always_sections = 11
531+
live_start_date_sections = 1 if (live_start_date is not None) else 0
532+
benchmark_sections = 1 if (benchmark_rets is not None) else 0
533+
bootstrap_sections = 1 if bootstrap else 0
534+
535+
vertical_sections = sum([
536+
always_sections,
537+
live_start_date_sections,
538+
benchmark_sections,
539+
bootstrap_sections
540+
])
510541

511542
if live_start_date is not None:
512-
vertical_sections += 1
513543
live_start_date = ep.utils.get_utc_timestamp(live_start_date)
514544

515-
if benchmark_rets is not None:
516-
vertical_sections += 1
517-
518-
if bootstrap:
519-
vertical_sections += 1
520-
521545
fig = plt.figure(figsize=(14, vertical_sections * 6))
522546
gs = gridspec.GridSpec(vertical_sections, 3, wspace=0.5, hspace=0.5)
523547
ax_rolling_returns = plt.subplot(gs[:2, :])
@@ -531,10 +555,10 @@ def create_returns_tear_sheet(returns, positions=None,
531555
i += 1
532556
ax_returns = plt.subplot(gs[i, :],
533557
sharex=ax_rolling_returns)
534-
i += 1
535558
if benchmark_rets is not None:
536-
ax_rolling_beta = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
537559
i += 1
560+
ax_rolling_beta = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
561+
i += 1
538562
ax_rolling_volatility = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
539563
i += 1
540564
ax_rolling_sharpe = plt.subplot(gs[i, :], sharex=ax_rolling_returns)
@@ -614,7 +638,8 @@ def create_returns_tear_sheet(returns, positions=None,
614638
live_start_date=live_start_date,
615639
ax=ax_return_quantiles)
616640

617-
if bootstrap and benchmark_rets is not None:
641+
if ((bootstrap is not None)
642+
and (benchmark_rets is not None)):
618643
ax_bootstrap = plt.subplot(gs[i, :])
619644
plotting.plot_perf_stats(returns, benchmark_rets,
620645
ax=ax_bootstrap)
@@ -907,7 +932,10 @@ def create_round_trip_tear_sheet(returns, positions, transactions,
907932

908933
@plotting.customize
909934
def create_interesting_times_tear_sheet(
910-
returns, benchmark_rets=None, legend_loc='best', return_fig=False):
935+
returns,
936+
benchmark_rets=utils.NOT_PASSED_SENTINEL,
937+
legend_loc='best',
938+
return_fig=False):
911939
"""
912940
Generate a number of returns plots around interesting points in time,
913941
like the flash crash and 9/11.
@@ -934,6 +962,11 @@ def create_interesting_times_tear_sheet(
934962
If True, returns the figure that was plotted on.
935963
"""
936964

965+
if (isinstance(benchmark_rets, str)
966+
and benchmark_rets == utils.NOT_PASSED_SENTINEL):
967+
warnings.warn(BENCHMARK_RETS_WARNING)
968+
benchmark_rets = None
969+
937970
rets_interesting = timeseries.extract_interesting_date_ranges(returns)
938971

939972
if not rets_interesting:
@@ -1094,7 +1127,8 @@ def create_capacity_tear_sheet(returns, positions, transactions,
10941127

10951128

10961129
@plotting.customize
1097-
def create_bayesian_tear_sheet(returns, benchmark_rets=None,
1130+
def create_bayesian_tear_sheet(returns,
1131+
benchmark_rets=utils.NOT_PASSED_SENTINEL,
10981132
live_start_date=None, samples=2000,
10991133
return_fig=False, stoch_vol=False,
11001134
progressbar=True):
@@ -1126,6 +1160,10 @@ def create_bayesian_tear_sheet(returns, benchmark_rets=None,
11261160
progressbar : boolean, optional
11271161
If True, show a progress bar
11281162
"""
1163+
if (isinstance(benchmark_rets, str)
1164+
and benchmark_rets == utils.NOT_PASSED_SENTINEL):
1165+
warnings.warn(BENCHMARK_RETS_WARNING)
1166+
benchmark_rets = None
11291167

11301168
if not have_bayesian:
11311169
raise NotImplementedError(

pyfolio/utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
from . import pos
2929
from . import txn
30+
from .deprecate import deprecated
3031

3132
APPROX_BDAYS_PER_MONTH = 21
3233
APPROX_BDAYS_PER_YEAR = 252
@@ -53,6 +54,11 @@
5354
'#008080', '#e6beff', '#aa6e28', '#800000', '#aaffc3',
5455
'#808000', '#ffd8b1', '#000080', '#808080']
5556

57+
DEPRECATION_WARNING = ('register_return_func and get_symbol_rets are '
58+
'deprecated and will be removed in a future version.')
59+
60+
NOT_PASSED_SENTINEL = '__not_passed_by_user'
61+
5662

5763
def one_dec_places(x, pos):
5864
"""
@@ -436,6 +442,7 @@ def to_series(df):
436442
}
437443

438444

445+
@deprecated(msg=DEPRECATION_WARNING)
439446
def register_return_func(func):
440447
"""
441448
Registers the 'returns_func' that will be called for
@@ -459,6 +466,7 @@ def register_return_func(func):
459466
SETTINGS['returns_func'] = func
460467

461468

469+
@deprecated(msg=DEPRECATION_WARNING)
462470
def get_symbol_rets(symbol, start=None, end=None):
463471
"""
464472
Calls the currently registered 'returns_func'

0 commit comments

Comments
 (0)