<jupyter_start><jupyter_text>Portfolio Allocation and Optimization: Monte Carlo Simulation and Optimization Algorithm Uptil now we were focused more on analysing and forcasting Stock prices for Individual Stocks. A trader or a Hedge fund manager can optimize their Trading strategies based on the forcast Buy/Sell signal. We will now act as a Portfolio Manager and try to build a Trading Strategy using Sharpe Ratio and Optimization to demonstrate how a Portfolio can be optimized for higher gains.  Sharpe RatioThe Sharpe ratio measures the performance of an investment compared to a risk-free asset, after adjusting for its risk. It is defined as the difference between the returns of the investment and the risk-free return, divided by the standard deviation of the investment.<jupyter_code>import pandas as pd
import matplotlib.pyplot as plt
from pylab import rcParams
import numpy as np
import seaborn as sns
import os

from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score, train_test_split, GridSearchCV
from sklearn.feature_selection import RFECV, SelectFromModel, SelectKBest
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tqdm import tqdm_notebook
from sklearn.preprocessing import StandardScaler
from sklearn import metrics

from keras.optimizers import RMSprop, SGD, Adam
from keras.layers import LSTM, Dense, Dropout
from keras.models import Sequential
%matplotlib inline

os.chdir(r'N:\STOCK ADVISOR BOT')

mcd = pd.read_csv('MCD.csv')
#best features
features_selected = ['Date','Close(t)']
mcd = mcd[features_selected]
mcd = mcd.iloc[3500:-60, :]
mcd = mcd.rename(columns={'Close(t)':'Close'})
mcd = mcd.set_index('Date')
mcd
from matplotlib import pyplot as plt
plt.figure()
plt.plot(mcd["Close"])
plt.title('MCD stock price history')
plt.ylabel('Price (USD)')
plt.xlabel('Days')
plt.legend(['Close'], loc='upper left')
plt.show()<jupyter_output><empty_output><jupyter_text>Lets get the Stock prices for 3 more stocks (<NAME> , <NAME> and Johnsons & Johnsons)<jupyter_code>gs = pd.read_csv('GS.csv')
#best features
features_selected = ['Date','Close(t)']
gs = gs[features_selected]
gs = gs.iloc[3500:-60, :]
gs = gs.rename(columns={'Close(t)':'Close'})
gs = gs.set_index('Date')


jnj = pd.read_csv('JNJ.csv')
#best features
features_selected = ['Date','Close(t)']
jnj = jnj[features_selected]
jnj = jnj.iloc[3500:-60, :]
jnj = jnj.rename(columns={'Close(t)':'Close'})
jnj = jnj.set_index('Date')


ko = pd.read_csv('KO.csv')
#best features
features_selected = ['Date','Close(t)']
ko = ko[features_selected]
ko = ko.iloc[3500:-60, :]
ko = ko.rename(columns={'Close(t)':'Close'})
ko = ko.set_index('Date')
for stock_df in (mcd, ko, gs, jnj): 
    stock_df['Normed Return'] = stock_df['Close'] /stock_df.iloc[0]['Close']<jupyter_output><empty_output><jupyter_text>Normalized returns<jupyter_code>jnj.head()
ko.head()<jupyter_output><empty_output><jupyter_text>Portfolio Allocation Let take the starting Portfolio Allocations consisting of these 4 stocks as - - 25% in MCD- 10% in KO- 30% in JNJ- 35% in GS<jupyter_code>for stock_df, allo in zip((mcd, ko, jnj, gs),[.25,.1,.3,.35]):
    stock_df['Allocation'] = stock_df['Normed Return']*allo
mcd.head()<jupyter_output><empty_output><jupyter_text>Assuming the starting portfolio Position of 1 million $, lets look at how the value of our position changes in each stock<jupyter_code># value of each position
for stock_df in (mcd, ko, jnj, gs):
    stock_df['Position Value'] = stock_df['Allocation']*1000000
gs.head(10)<jupyter_output><empty_output><jupyter_text>You can see how the value in increasing. Lets create a single dataframe for all of the 4 stocks<jupyter_code># create list of all position values
all_pos_vals = [mcd['Position Value'], ko['Position Value'], jnj['Position Value'], gs['Position Value']]

# concatenate the list of position values
portfolio_val = pd.concat(all_pos_vals, axis=1)

# set the column names
portfolio_val.columns = ['MCD', 'KO', 'JNJ', 'GS']

# add a total portfolio column
portfolio_val['Total'] = portfolio_val.sum(axis=1)
portfolio_val.head(10)<jupyter_output><empty_output><jupyter_text>we can see day-by-day how our positions and portfolio value is changing.<jupyter_code># plot our portfolio
import matplotlib.pyplot as plt
%matplotlib inline
portfolio_val['Total'].plot(figsize=(10,8))<jupyter_output><empty_output><jupyter_text>We have made 150k for the yearLets also look at individual contributions of each stock in our portfolio<jupyter_code>portfolio_val.drop('Total',axis=1).plot(figsize=(10,8))<jupyter_output><empty_output><jupyter_text>Let's move towards implementing MCMC and Optimization<jupyter_code># Daily Return
portfolio_val['Daily Return'] = portfolio_val['Total'].pct_change(1)
# average daily return
portfolio_val['Daily Return'].mean()

# standard deviation
portfolio_val['Daily Return'].std()

# plot histogram of daily returns
portfolio_val['Daily Return'].plot(kind='hist', bins=50, figsize=(4,5))<jupyter_output><empty_output><jupyter_text>Calculating the total portfolio return<jupyter_code># cumulative portfolio return
cum_return = 100 * (portfolio_val['Total'][-1]/portfolio_val['Total'][0] - 1)
cum_return<jupyter_output><empty_output><jupyter_text>Calculate Sharpe Ratio The Sharpe Ratio is the mean (portfolio return - the risk free rate) % standard deviation.<jupyter_code>sharpe_ratio = portfolio_val['Daily Return'].mean() / portfolio_val['Daily Return'].std()
ASR = (252**0.5) * sharpe_ratio
ASR<jupyter_output><empty_output><jupyter_text>Annualized Share Ratio is 0.79  Optimization using Monte Carlo Simulation We will check a bunch of random allocations and analyse which one has the best Sharpe Ratio. This process of randomly guessing is known as a Monte Carlo Simulation.We will randomly assign weights to our stocks in the portfolio using mcmc and then calculate the average daily return & SD (Standard deviation) of return. Then we can calculate the Sharpe Ratio for many randomly selected allocations.  We will further use Optimzation Algorithm to minimize for this. Minimization is a similar concept to optimization - let's say we have a simple equation y = x2 - the idea is we're trying to figure out what value of x will minimize y, in this example 0.This idea of a minimizer will allow us to build an optimizer.<jupyter_code># concatenate them and rename the columns
stocks = pd.concat([mcd.Close, ko.Close, gs.Close, jnj.Close], axis=1)
stocks.columns = ['MCD', 'KO', 'GS', 'JNJ']
stocks
stocks.pct_change(1).mean()
stocks.pct_change(1).head()
# log daily return
log_return = np.log(stocks/stocks.shift(1))
log_return.head()
print(stocks.columns)

weights = np.array(np.random.random(4))
print('Random Weights:')
print(weights)

print('Rebalance')
weights = weights/np.sum(weights)
print(weights)
# expected return
print('Expected Portfolio Return')
exp_ret = np.sum((log_return.mean()*weights)*252)
print(exp_ret)

# expected volatility
print('Expected Volatility')
exp_vol = np.sqrt(np.dot(weights.T,np.dot(log_return.cov()*252, weights)))
print(exp_vol)

# Sharpe Ratio
print('Sharpe Ratio')
SR = exp_ret/exp_vol
print(SR)<jupyter_output>Expected Portfolio Return
0.08988210291523915
Expected Volatility
0.141941703080142
Sharpe Ratio
0.6332325240911801<jupyter_text>Now we will repeat the above process over 1000 times<jupyter_code>num_ports = 8000
all_weights = np.zeros((num_ports, len(stocks.columns)))
ret_arr = np.zeros(num_ports)
vol_arr = np.zeros(num_ports)
sharpe_arr = np.zeros(num_ports)

for ind in range(num_ports): 
    # weights 
    weights = np.array(np.random.random(4)) 
    weights = weights/np.sum(weights)  
    # save the weights
    all_weights[ind,:] = weights
    # expected return 
    ret_arr[ind] = np.sum((log_return.mean()*weights)*252)

    # expected volatility 
    vol_arr[ind] = np.sqrt(np.dot(weights.T,np.dot(log_return.cov()*252, weights)))

    # Sharpe Ratio 
    sharpe_arr[ind] = ret_arr[ind]/vol_arr[ind]
sharpe_arr.max()<jupyter_output><empty_output><jupyter_text>If we then get the location of the maximum Sharpe Ratio and then get the allocation for that index. This shows us the optimal allocation out of the 8000 random allocations:<jupyter_code>sharpe_arr.argmax()
all_weights[7098, :]<jupyter_output><empty_output><jupyter_text>These are the best allocations we have received using MCMC. Lets compare how we did from the original Allocation Original Allocation - - 25% in MCD- 10% in KO- 30% in JNJ- 35% in GSMCMC Allocation - - 54% in MCD- 42% in KO- 3% in JNJ- 0.1% IN gs  Initial Allocation<jupyter_code>import matplotlib.pyplot as plt

# Pie chart, where the slices will be ordered and plotted counter-clockwise:
labels = 'MCD', 'KO', 'JNJ', 'GS'
sizes = [25, 10, 30, 35]
explode = (0, 0.1, 0, 0)  # only "explode" the 2nd slice (i.e. 'Hogs')

fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
        shadow=True, startangle=90)
ax1.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.

plt.show()<jupyter_output><empty_output><jupyter_text>After MCMC<jupyter_code>import matplotlib.pyplot as plt

# Pie chart, where the slices will be ordered and plotted counter-clockwise:
labels = 'MCD', 'KO', 'JNJ', 'GS'
sizes = [54, 42, 3, 0.1]
explode = (0, 0.1, 0, 0)  # only "explode" the 2nd slice (i.e. 'Hogs')

fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
        shadow=True, startangle=90)
ax1.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.

plt.show()<jupyter_output><empty_output><jupyter_text>Portfolio Optimization: Optimization AlgorithmLet's now move on from random allocations to a mathematical optimization algorithm.All of the heavy lifting for this optimization will be done with SciPy, so we just have to do a few things to set up the optimization function.<jupyter_code>from scipy.optimize import minimize

def get_ret_vol_sr(weights): 
    weights = np.array(weights)
    ret = np.sum(log_return.mean() * weights) * 252
    vol = np.sqrt(np.dot(weights.T,np.dot(log_return .cov()*252,weights)))
    sr = ret/vol 
    return np.array([ret,vol,sr])


# minimize negative Sharpe Ratio
def neg_sharpe(weights): 
    return get_ret_vol_sr(weights)[2] * -1

# check allocation sums to 1
def check_sum(weights): 
    return np.sum(weights) - 1
# create constraint variable
cons = ({'type':'eq','fun':check_sum})
# create weight boundaries
bounds = ((0,1),(0,1),(0,1),(0,1))
# initial guess
init_guess = [0.25, 0.25, 0.25, 0.25]<jupyter_output><empty_output><jupyter_text>First we call minimize and pass in what we're trying to minimize - negative Sharpe, our initial guess, we set the minimization method to SLSQP, and we set our bounds and constraints:<jupyter_code>opt_results = minimize(neg_sharpe, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
opt_results
opt_results.x
get_ret_vol_sr(opt_results.x)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11446986201888162, 'fraction_numerical': 0.023602033405954976, 'mean_word_length': 5.928930817610063, 'pattern_counts': {'":': 0, '<': 74, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '18', 'dir': 'jupyter-structured-clean-dedup', 'id': '307477', 'license': 'MIT', 'n_tokens_mistral': 3944, 'n_tokens_neox': 3661, 'n_words': 1104, 'path': 'Portfolio Optimization/.ipynb_checkpoints/ADS_Portfolio_Allocation_Optmization-checkpoint.ipynb', 'repo_name': 'Chowry000/Stock-Prediction-Using-LSTM', 'size': '11026'}