Untitled
unknown
plain_text
a year ago
3.6 kB
6
Indexable
from scipy.optimize import minimize # Function to Optimize def minimize_return_variance_joint(weights, covariance_matrix, expected_returns, gamma=0.2): return -np.sum(expected_returns * weights) + gamma * weights.T.dot(covariance_matrix).dot(weights) def minimize_neg_returns(weights, covariance_matrix, expected_returns): return -np.sum(expected_returns * weights) def negative_sharpe_ratio(weights, covariance_matrix, expected_returns): portfolio_return = np.dot(weights, expected_returns) portfolio_variance = np.dot(weights.T, np.dot(covariance_matrix, weights)) sharpe_ratio = (portfolio_return) / np.sqrt(portfolio_variance) return -sharpe_ratio def compute_optimal_weights(covariance_matrix, expected_returns, optimization_fn=minimize_neg_returns): """ Compute the optimal weights for a given covariance matrix and expected returns. :param covariance_matrix: The covariance matrix of the assets. :param expected_returns: The expected returns of the assets. :return: The mean-variance optimal weights subject to constraints on the sum of weights and individual weights. """ num_assets = len(expected_returns) objective_fn = lambda weights: optimization_fn(weights, covariance_matrix, expected_returns) # Constraints # -1 <= w_i <= 1 for all i # sum(w_i) = 1 weight_sum_constraint = {'type': 'eq', 'fun': lambda weights: np.sum(weights) - 1.0} bounds = tuple((-1, 1) for _ in range(num_assets)) initial_weights = np.ones(num_assets) / num_assets # Sequential Least SQuares Programming (SLSQP). # https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html # https://docs.scipy.org/doc/scipy/reference/optimize.minimize-slsqp.html results = minimize(objective_fn, initial_weights, method='SLSQP', bounds=bounds, constraints=[weight_sum_constraint], options={'disp': False}) return results def compute_returns_info(allocation_mat_df, holdout_df, N): predicted_indicies = [r.rstrip('_hat').lstrip('A_') for r in allocation_mat_df.columns] # NOTE: We don't need to shift the dataframe because # at construction we stored the "forward returns" in the dataframe, and are using the # stock "forward returns" to predict the "index forward returns" realized_returns = holdout_df[predicted_indicies] portfolio_returns = np.sum(allocation_mat_df.iloc[:N, :].values * realized_returns.iloc[:N, :].values, axis=1) portfolio_returns_df = pd.DataFrame(portfolio_returns, columns=['Portfolio_Returns']) # Compute average returns, std, and sharpe avg_returns = portfolio_returns_df.mean().values[0] std_returns = portfolio_returns_df.std().values[0] sharpe_ratio = avg_returns / std_returns print(f"Portfolio Average Returns (BPS): {avg_returns : .3f}") print(f"Portfolio Std Returns: {std_returns : .3f}") print(f"Portfolio Sharpe Ratio: {sharpe_ratio : .3f}") # Convert values to annualized # Assuming t is in days, which may not be true anual_returns_bps = avg_returns * 252 anual_std_returns = std_returns * np.sqrt(252) anual_sharpe_ratio = anual_returns_bps / anual_std_returns print(f"In Annualized Terms (BPS): mu={anual_returns_bps : .3f}, sigma={anual_std_returns : .3f}, Sharpe={anual_sharpe_ratio : .3f}") portfolio_returns_df.hist(bins=100) plt.show()
Editor is loading...
Leave a Comment