test for inf/nan returns (fixes #440)

This commit is contained in:
Robert Martin
2022-05-22 16:08:44 +01:00
parent cb2bb3eab7
commit b56b87cfac
2 changed files with 27 additions and 2 deletions

View File

@@ -25,6 +25,18 @@ import pandas as pd
import numpy as np
def _check_returns(returns):
# Check NaNs excluding leading NaNs
if np.any(np.isnan(returns.mask(returns.ffill().isnull(), 0))):
warnings.warn(
"Some returns are NaN. Please check your price data.", UserWarning
)
if np.any(np.isinf(returns)):
warnings.warn(
"Some returns are infinite. Please check your price data.", UserWarning
)
def returns_from_prices(prices, log_returns=False):
"""
Calculate the returns given prices.
@@ -38,9 +50,10 @@ def returns_from_prices(prices, log_returns=False):
:rtype: pd.DataFrame
"""
if log_returns:
return np.log(1 + prices.pct_change()).dropna(how="all")
returns = np.log(1 + prices.pct_change()).dropna(how="all")
else:
return prices.pct_change().dropna(how="all")
returns = prices.pct_change().dropna(how="all")
return returns
def prices_from_returns(returns, log_returns=False):
@@ -126,6 +139,8 @@ def mean_historical_return(
returns = prices
else:
returns = returns_from_prices(prices, log_returns)
_check_returns(returns)
if compounding:
return (1 + returns).prod() ** (frequency / returns.count()) - 1
else:
@@ -172,6 +187,7 @@ def ema_historical_return(
else:
returns = returns_from_prices(prices, log_returns)
_check_returns(returns)
if compounding:
return (1 + returns.ewm(span=span).mean().iloc[-1]) ** frequency - 1
else:
@@ -241,6 +257,8 @@ def capm_return(
market_returns.columns = ["mkt"]
returns = returns.join(market_returns, how="left")
_check_returns(returns)
# Compute covariance matrix for the new dataframe (including markets)
cov = returns.cov()
# The far-right column of the cov matrix is covariances to market

View File

@@ -50,6 +50,13 @@ def test_returns_from_prices():
pd.testing.assert_series_equal(returns_df.iloc[-1], df.pct_change().iloc[-1])
def test_returns_warning():
df = get_data()
df.iloc[3, :] = 0 # make some prices zero
with pytest.warns(UserWarning):
expected_returns.mean_historical_return(df)
def test_log_returns_from_prices():
df = get_data()
old_nan = df.isnull().sum(axis=1).sum()