# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ## 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 Ratio
#
# The 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. 

# +
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()

# ### Lets get the Stock prices for 3 more stocks (Coka cola , <NAME> and Johnsons & Johnsons) 

# +
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']

# ### Normalized returns 

jnj.head()

ko.head()

# ### 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

for stock_df, allo in zip((mcd, ko, jnj, gs),[.25,.1,.3,.35]):
    stock_df['Allocation'] = stock_df['Normed Return']*allo

mcd.head()

#  Assuming the starting portfolio Position of 1 million $, lets look at how the value of our position changes in each stock

# value of each position
for stock_df in (mcd, ko, jnj, gs):
    stock_df['Position Value'] = stock_df['Allocation']*1000000

gs.head(10)

# You can see how the value in increasing. Lets create a single dataframe for all of the 4 stocks

# +
# 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)

# ### we can see day-by-day how our positions and portfolio value is changing.

# plot our portfolio
import matplotlib.pyplot as plt
# %matplotlib inline
portfolio_val['Total'].plot(figsize=(10,8))

# ### We have made 150k for the year
#
# Lets also look at individual contributions of each stock in our portfolio

portfolio_val.drop('Total',axis=1).plot(figsize=(10,8))

# ### Let's move towards implementing MCMC and Optimization

# 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))
# -

# Calculating the total portfolio return 

# cumulative portfolio return
cum_return = 100 * (portfolio_val['Total'][-1]/portfolio_val['Total'][0] - 1)
cum_return

# ### Calculate Sharpe Ratio

# The Sharpe Ratio is the mean (portfolio return - the risk free rate) % standard deviation.

sharpe_ratio = portfolio_val['Daily Return'].mean() / portfolio_val['Daily Return'].std()
ASR = (252**0.5) * sharpe_ratio
ASR

# 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.

# 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)
# -

# Now we will repeat the above process over 1000 times 

# +
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()

# 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:

sharpe_arr.argmax()

all_weights[7098, :]

# 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 GS
#
# MCMC Allocation - 
#
# - 54% in MCD
# - 42% in KO
# - 3% in JNJ
# - 0.1% IN gs
#

# ### Initial Allocation

# +
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()
# -

# ### After MCMC

# +
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()
# -

# ### Portfolio Optimization: Optimization Algorithm
# Let'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.

# +
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]

# 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:

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)

# The Optimal results of the Optimization algorithm are 1.2367

# ### Conclusion 
#
# We have implemented Monte carlo Simulation technique to randomly take a sample and simulate it to find the best sharpe ratio for a given portfolio. 
# Then we moved to a better appraoch using Optimization Algorithm by Minimize function in Spicy library. 
#
# We get around same Sharpe ratio for both which improves on the initial portfolio allocation we started off with. 
#
# We can form more trading strategies based on other methods too like Pairs trading, Butterfly spread, Bull-bear spread etc. But we just wanted to implement a Trading strategy and see how we can optimize a portfolio. 

# ### License
# MIT License
#
# Copyright (c) 2020 <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



StarcoderdataJupyterScriptsDedupFiltered