# Optimization problem: Given Beta Bounds Maximize sharpe

I would like to maximize a portfolio's Sharpe Ratio while keeping Beta in bounds. Could anyone supply a calculation please?

***************Starting Metrics**********************
symbols          : ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
Beta             : [ 0.09  1.2   2.1  -1.3   1.1   0.3   0.9   1.2 ]
Sharpe           : [-1.7  5.4 -0.3  0.8  0.4  2.7  0.9  1.9]
optimized weights: [x0, x1, x2, x3, x4, x5, x6, x7]

***************Ajusted Portfolio**********************
Beta bounds: -.3 < x <.3
Maximize sharpe: X


Well, you didn't give a whole lot of information, so I'm going to make some assumptions here, but I think this is pretty darn close to what you want. Keep in mind, Beta = (Covar/Var), so you need to calculate that with what's given below, and then you will have everything you need.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.optimize as sco
import datetime as dt
import math
from datetime import datetime, timedelta
from pandas_datareader import data as wb
from sklearn.cluster import KMeans
np.random.seed(777)

start = '2019-02-28'
end = '2020-02-28'
# N = 90
# start = datetime.now() - timedelta(days=N)
# end = dt.datetime.today()

tickers = ['MMM',
'ABT',
'ABBV',
'ABMD',
'ACN',
'ATVI',
'AMD',
'AAP',
'AES',
'AMG',
'XEL',
'XRX',
'XLNX',
'XYL',
'YUM',
'ZBH',
'ZION',
'ZTS']

thelen = len(tickers)

price_data = []
for ticker in tickers:

df = pd.concat(price_data)
df.dtypes
df.shape

pd.set_option('display.max_columns', 500)

df = df.reset_index()
df = df.set_index('Date')
table = df.pivot(columns='ticker')
# By specifying col[1] in below list comprehension
# You can select the stock names under multi-level column
table.columns = [col[1] for col in table.columns]

###################################################

def portfolio_annualised_performance(weights, mean_returns, cov_matrix):
returns = np.sum(mean_returns*weights ) *252
std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
return std, returns

def random_portfolios(num_portfolios, mean_returns, cov_matrix, risk_free_rate):
results = np.zeros((3,num_portfolios))
weights_record = []
for i in range(num_portfolios):
weights = np.random.random(thelen)
weights /= np.sum(weights)
weights_record.append(weights)
portfolio_std_dev, portfolio_return = portfolio_annualised_performance(weights, mean_returns, cov_matrix)
results[0,i] = portfolio_std_dev
results[1,i] = portfolio_return
results[2,i] = (portfolio_return - risk_free_rate) / portfolio_std_dev
return results, weights_record

returns = table.pct_change()
mean_returns = returns.mean()
cov_matrix = returns.cov()
num_portfolios = 10000
risk_free_rate = 0.0178

###################################################

def display_simulated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate):
results, weights = random_portfolios(num_portfolios,mean_returns, cov_matrix, risk_free_rate)

max_sharpe_idx = np.argmax(results[2])
sdp, rp = results[0,max_sharpe_idx], results[1,max_sharpe_idx]
max_sharpe_allocation = pd.DataFrame(weights[max_sharpe_idx],index=table.columns,columns=['allocation'])
max_sharpe_allocation.allocation = [round(i*100,2)for i in max_sharpe_allocation.allocation]
max_sharpe_allocation = max_sharpe_allocation.T

min_vol_idx = np.argmin(results[0])
sdp_min, rp_min = results[0,min_vol_idx], results[1,min_vol_idx]
min_vol_allocation = pd.DataFrame(weights[min_vol_idx],index=table.columns,columns=['allocation'])
min_vol_allocation.allocation = [round(i*100,2)for i in min_vol_allocation.allocation]
min_vol_allocation = min_vol_allocation.T

print("-")
print("Maximum Sharpe Ratio Portfolio Allocation\n")
print("Annualised Return:", round(rp,2))
print("Annualised Volatility:", round(sdp,2))
print("\n")
print(max_sharpe_allocation)
print("-")
print("Minimum Volatility Portfolio Allocation\n")
print("Annualised Return:", round(rp_min,2))
print("Annualised Volatility:", round(sdp_min,2))
print("\n")
print(min_vol_allocation)

plt.figure(figsize=(10, 7))
plt.scatter(results[0,:],results[1,:],c=results[2,:],cmap='YlGnBu', marker='o', s=10, alpha=0.3)
plt.colorbar()
plt.scatter(sdp,rp,marker='*',color='r',s=500, label='Maximum Sharpe ratio')
plt.scatter(sdp_min,rp_min,marker='*',color='g',s=500, label='Minimum volatility')
plt.title('Simulated Portfolio Optimization based on Efficient Frontier')
plt.xlabel('annualised volatility')
plt.ylabel('annualised returns')
plt.legend(labelspacing=0.8)

display_simulated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate)


Result:

Maximum Sharpe Ratio Portfolio Allocation

Annualised Return: 0.2
Annualised Volatility: 0.16

AAP  ABBV  ABMD   ABT   ACN  ADBE   AES    AMD   AMG   ATVI  \
allocation  3.29  5.51  0.59  4.29  2.89  9.09  8.42  11.22  3.01  10.03

MMM    XEL  XLNX  XRX   XYL   YUM   ZBH  ZION   ZTS
allocation  0.12  11.39  2.95  6.7  2.89  5.91  3.02  0.79  7.88
-
Minimum Volatility Portfolio Allocation

Annualised Return: 0.05
Annualised Volatility: 0.13

AAP  ABBV  ABMD   ABT   ACN  ADBE   AES   AMD   AMG  ATVI   MMM  \
allocation  6.35  8.14  2.55  4.32  8.71  2.18  5.62  1.99  2.08  4.86  6.89

XEL  XLNX  XRX  XYL   YUM   ZBH  ZION   ZTS
allocation  10.1  1.93  1.9  5.5  7.92  5.57  6.01  7.39