mirror of
https://github.com/robertmartin8/PyPortfolioOpt.git
synced 2022-11-27 18:02:41 +03:00
test for inf/nan returns (fixes #440)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user