mirror of
https://github.com/robertmartin8/PyPortfolioOpt.git
synced 2022-11-27 18:02:41 +03:00
fixes #82 – pass None as expected returns
This commit is contained in:
@@ -374,6 +374,7 @@ def portfolio_performance(
|
||||
else:
|
||||
tickers = list(range(len(expected_returns)))
|
||||
new_weights = np.zeros(len(tickers))
|
||||
|
||||
for i, k in enumerate(tickers):
|
||||
if k in weights:
|
||||
new_weights[i] = weights[k]
|
||||
@@ -385,25 +386,25 @@ def portfolio_performance(
|
||||
raise ValueError("Weights is None")
|
||||
|
||||
sigma = np.sqrt(objective_functions.portfolio_variance(new_weights, cov_matrix))
|
||||
mu = objective_functions.portfolio_return(
|
||||
new_weights, expected_returns, negative=False
|
||||
)
|
||||
# new_weights.dot(expected_returns)
|
||||
|
||||
# sharpe = -objective_functions.negative_sharpe(
|
||||
# new_weights, expected_returns, cov_matrix, risk_free_rate=risk_free_rate
|
||||
# )
|
||||
if expected_returns is not None:
|
||||
mu = objective_functions.portfolio_return(
|
||||
new_weights, expected_returns, negative=False
|
||||
)
|
||||
|
||||
sharpe = objective_functions.sharpe_ratio(
|
||||
new_weights,
|
||||
expected_returns,
|
||||
cov_matrix,
|
||||
risk_free_rate=risk_free_rate,
|
||||
negative=False,
|
||||
)
|
||||
|
||||
if verbose:
|
||||
print("Expected annual return: {:.1f}%".format(100 * mu))
|
||||
print("Annual volatility: {:.1f}%".format(100 * sigma))
|
||||
print("Sharpe Ratio: {:.2f}".format(sharpe))
|
||||
return mu, sigma, sharpe
|
||||
sharpe = objective_functions.sharpe_ratio(
|
||||
new_weights,
|
||||
expected_returns,
|
||||
cov_matrix,
|
||||
risk_free_rate=risk_free_rate,
|
||||
negative=False,
|
||||
)
|
||||
if verbose:
|
||||
print("Expected annual return: {:.1f}%".format(100 * mu))
|
||||
print("Annual volatility: {:.1f}%".format(100 * sigma))
|
||||
print("Sharpe Ratio: {:.2f}".format(sharpe))
|
||||
return mu, sigma, sharpe
|
||||
else:
|
||||
if verbose:
|
||||
print("Annual volatility: {:.1f}%".format(100 * sigma))
|
||||
return None, sigma, None
|
||||
|
||||
@@ -84,15 +84,19 @@ class EfficientFrontier(base_optimizer.BaseConvexOptimizer):
|
||||
else: # use integer labels
|
||||
tickers = list(range(len(expected_returns)))
|
||||
|
||||
if cov_matrix.shape != (len(expected_returns), len(expected_returns)):
|
||||
raise ValueError("Covariance matrix does not match expected returns")
|
||||
if expected_returns is not None:
|
||||
if cov_matrix.shape != (len(expected_returns), len(expected_returns)):
|
||||
raise ValueError("Covariance matrix does not match expected returns")
|
||||
|
||||
super().__init__(len(tickers), tickers, weight_bounds)
|
||||
|
||||
@staticmethod
|
||||
def _validate_expected_returns(expected_returns):
|
||||
if expected_returns is None:
|
||||
raise ValueError("expected_returns must be provided")
|
||||
warnings.warn(
|
||||
"No expected returns provided. You may only use ef.min_volatility()"
|
||||
)
|
||||
return None
|
||||
elif isinstance(expected_returns, pd.Series):
|
||||
return expected_returns.values
|
||||
elif isinstance(expected_returns, list):
|
||||
|
||||
@@ -65,6 +65,19 @@ def test_min_volatility():
|
||||
)
|
||||
|
||||
|
||||
def test_min_volatility_no_rets():
|
||||
# Should work with no rets, see issue #82
|
||||
df = get_data()
|
||||
S = risk_models.sample_cov(df)
|
||||
ef = EfficientFrontier(None, S)
|
||||
w = ef.min_volatility()
|
||||
assert isinstance(w, dict)
|
||||
assert set(w.keys()) == set(ef.tickers)
|
||||
np.testing.assert_almost_equal(ef.weights.sum(), 1)
|
||||
assert all([i >= 0 for i in w.values()])
|
||||
np.testing.assert_almost_equal(ef.portfolio_performance()[1], 0.15915084514118694)
|
||||
|
||||
|
||||
def test_min_volatility_tx_costs():
|
||||
# Baseline
|
||||
ef = setup_efficient_frontier()
|
||||
|
||||
Reference in New Issue
Block a user