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

ENH: Use ddof=0 and nanstd, remove skipped test #36

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions empyrical/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ def annual_volatility(returns, period=DAILY, alpha=2.0,

ann_factor = annualization_factor(period, annualization)

volatility = nanstd(returns, ddof=1) * (ann_factor ** (1.0 / alpha))
volatility = nanstd(returns) * (ann_factor ** (1.0 / alpha))

return volatility

Expand Down Expand Up @@ -558,10 +558,10 @@ def sharpe_ratio(returns, risk_free=0, period=DAILY, annualization=None):
returns_risk_adj = np.asanyarray(_adjust_returns(returns, risk_free))
returns_risk_adj = returns_risk_adj[~np.isnan(returns_risk_adj)]

if np.std(returns_risk_adj, ddof=1) == 0:
if nanstd(returns_risk_adj) == 0:
return np.nan

return np.mean(returns_risk_adj) / np.std(returns_risk_adj, ddof=1) * \
return np.mean(returns_risk_adj) / nanstd(returns_risk_adj) * \
np.sqrt(ann_factor)


Expand Down Expand Up @@ -695,7 +695,7 @@ def information_ratio(returns, factor_returns):
return np.nan

active_return = _adjust_returns(returns, factor_returns)
tracking_error = nanstd(active_return, ddof=1)
tracking_error = nanstd(active_return)
if np.isnan(tracking_error):
return 0.0
if tracking_error == 0:
Expand Down
40 changes: 10 additions & 30 deletions empyrical/tests/test_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import random
from copy import copy
from operator import attrgetter
from unittest import TestCase, skip, SkipTest
from unittest import TestCase, SkipTest

from nose_parameterized import parameterized
import numpy as np
Expand Down Expand Up @@ -210,26 +210,6 @@ def test_max_drawdown(self, returns, expected):
expected,
DECIMAL_PLACES)

# Multiplying returns by a positive constant larger than 1 will increase
# the maximum drawdown by a factor greater than or equal to the constant.
# Similarly, a positive constant smaller than 1 will decrease maximum
# drawdown by at least the constant.
@parameterized.expand([
(noise_uniform, 1.1),
(noise, 2),
(noise_uniform, 10),
(noise_uniform, 0.99),
(noise, 0.5)
])
@skip("Randomly fails")
def test_max_drawdown_transformation(self, returns, constant):
max_dd = self.empyrical.max_drawdown(returns)
transformed_dd = self.empyrical.max_drawdown(constant*returns)
if constant >= 1:
assert constant*max_dd <= transformed_dd
else:
assert constant*max_dd >= transformed_dd

# Maximum drawdown is always less than or equal to zero. Translating
# returns by a positive constant should increase the maximum
# drawdown to a maximum of zero. Translating by a negative constant
Expand Down Expand Up @@ -265,9 +245,9 @@ def test_annual_ret(self, returns, period, expected):

@parameterized.expand([
(flat_line_1_tz, empyrical.DAILY, 0.0),
(mixed_returns, empyrical.DAILY, 0.9136465399704637),
(weekly_returns, empyrical.WEEKLY, 0.38851569394870583),
(monthly_returns, empyrical.MONTHLY, 0.18663690238892558)
(mixed_returns, empyrical.DAILY, 0.8546380812952347),
(weekly_returns, empyrical.WEEKLY, 0.36629610905136956),
(monthly_returns, empyrical.MONTHLY, 0.17596295906514803)
])
def test_annual_volatility(self, returns, period, expected):
assert_almost_equal(
Expand Down Expand Up @@ -333,10 +313,10 @@ def test_omega_returns(self, returns, required_return_less,
(empty_returns, 0.0, np.nan),
(one_return, 0.0, np.nan),
(mixed_returns, mixed_returns, np.nan),
(mixed_returns, 0.0, 1.7238613961706866),
(mixed_returns, simple_benchmark, 0.34111411441060574),
(positive_returns, 0.0, 52.915026221291804),
(negative_returns, 0.0, -24.406808633910085)
(mixed_returns, 0.0, 1.842885350501853),
(mixed_returns, simple_benchmark, 0.36466632740494126),
(positive_returns, 0.0, 56.124860801609117),
(negative_returns, 0.0, -25.887329838240298)
])
def test_sharpe_ratio(self, returns, risk_free, expected):
assert_almost_equal(
Expand Down Expand Up @@ -638,8 +618,8 @@ def test_sortino_translation_diff(self, returns, required_return,
(empty_returns, 0.0, np.nan),
(one_return, 0.0, np.nan),
(pos_line, pos_line, np.nan),
(mixed_returns, 0.0, 0.10859306069076737),
(mixed_returns, flat_line_1, -0.06515583641446039),
(mixed_returns, 0.0, 0.11609086505314305),
(mixed_returns, flat_line_1, -0.0696545190318858),
])
def test_information_ratio(self, returns, factor_returns, expected):
assert_almost_equal(
Expand Down