fix(returns): use non-excess kurtosis and omit NaNs in deflated Sharpe ratio - #872
Merged
Merged
Conversation
…e ratio The Deflated Sharpe Ratio standard error of Bailey and López de Prado, sqrt((1 - g3 * SR + (g4 - 1) / 4 * SR^2) / (T - 1)), takes g4 as the non-excess kurtosis (3 for Gaussian returns, which recovers the Lo (2002) standard error sqrt((1 + SR^2 / 2) / (T - 1))). scipy.stats.kurtosis returns the excess kurtosis by default, so the term was off by 3 / 4 * SR^2 and could turn the variance negative, yielding NaN. Missing returns were also replaced by zero-return periods before computing the moments and the horizon, diluting skewness and kurtosis and inflating the horizon, while sharpe_ratio ignores them. They are now omitted from the moments and the per-column horizon. Tests use the reference formula directly rather than only stored values.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ReturnsAccessor.deflated_sharpe_ratiodeviates from the formula it implements in two ways.1. Excess kurtosis where the formula needs non-excess kurtosis. The DSR of Bailey & López de Prado uses the Sharpe ratio standard error
where γ4 is the non-excess kurtosis: for Gaussian returns γ4 = 3 and the expression reduces to the classic Lo (2002) standard error
sqrt((1 + SR²/2) / (T - 1)). The accessor passesscipy.stats.kurtosis(returns), which returns the excess kurtosis by default (0 for Gaussian returns), so the term is off by3/4 · SR². For Gaussian returns the variance becomes1 - SR²/4instead of1 + SR²/2, and for a large per-period SR the argument of the square root can go negative, which is exactly why the existing test expectedNaNfor two of the three columns of the fixture.2. Missing returns counted as zero-return periods. Before computing skewness and kurtosis, NaNs were replaced by
0.0, andbacktest_horizonused the full number of rows.sharpe_ratioignores NaNs, so the DSR mixed a NaN-aware Sharpe ratio with moments and a horizon computed on a padded series. On a series with 50 missing days out of 300, the result differs from the same series with the missing days removed, which it should not.Changes
kurtosis(..., fisher=False)so the non-excess kurtosis enters the formula.nan_policy="omit"for skewness and kurtosis, and a per-columnbacktest_horizon = number of observed returns, consistent withsharpe_ratio.metrics.deflated_sharpe_ratioalready broadcasts, so it now accepts a per-column horizon (type hint and docstring updated, with the reference).NaNs) and two tests are added. One checks the accessor against the reference formula computed independently, and that Gaussian returns recover Lo's standard error; the other checks that a missing return is treated as absent rather than as a zero return.Reproduction on the current master, Gaussian returns with skew ≈ 0 and kurtosis ≈ 3 (per-period SR ≈ 0.05):
The gap is small at daily frequency because SR² is tiny per day; it grows with the per-period Sharpe ratio (monthly data) and with kurtosis, and the NaN handling can move the result by more than the kurtosis term (see the new test).
References