"""
![](http://m.economictimes.com/thumb/msid-70616931,width-3684,height-2068,resizemode-4,imgsize-550306/stocks-market.jpg)
"""
"""
## Portfolio Optimization using Monte Carlo Simulation
"""
"""
Hold up! This is an attempt by to explore the nuances of investment portfolio management and how can we optimize the same; after all at the end of the day we look to make more money with the stocks we have. I would urge you to watch the 2011 film "Margin call" to get the vitality of how portfolio mismanagement during increased volatility could kill one's investments.




"""
"""
I've chosen some stocks of my interest here. Although if you feel you have different choices, you can get the historical data of the desired stocks NSE website [Link](https://www1.nseindia.com/products/content/equities/equities/eq_security.htm) in .csv (Comma Separated Values) format. I've downloaded the data between the time range of **16th August 2019 - 14th August 2020** (not so historical!)


"""
"""
## Stocks chosen 

1. Hindustan Unilever 
2. ITC 
3. Larson & Tourbo
4. Nestle India
5. Reliance  

The above chosen stocks are purely based on my preferences, feel free to explore with more and more stocks out there!
"""
#importing necessary libraries
import pandas as pd
import numpy as np
%matplotlib inline 
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import seaborn as sns
from collections import Counter   #An extremely useful library under itertools
sns.set()
#taking a gander at the files we have
file_dir = '../input/historical-stock-data-of-select-common-stocks'
x= !ls $file_dir
x

stock_dict={}
stock_dict['HINDUNILVR']=pd.read_csv('../input/historical-stock-data-of-select-common-stocks/HINDUNILVR.csv')
stock_dict['ITC']=pd.read_csv('../input/historical-stock-data-of-select-common-stocks/ITC.csv')
stock_dict['LT']=pd.read_csv('../input/historical-stock-data-of-select-common-stocks/LT.csv')
stock_dict['NESTLEIND']=pd.read_csv('../input/historical-stock-data-of-select-common-stocks/NESTLEIND.csv')
stock_dict['RELIANCE']=pd.read_csv('../input/historical-stock-data-of-select-common-stocks/RELIANCE.csv')

   
"""
Our dataset should consist only Equities, i.e. Series column equals to 'EQ'. In case if it's not the case with your dataset, try to filter out the Equity trades, as we are mainly concerned with the equity portfolio at the moment. The code for filtering out goes something like this... 
"""
#filtering out the equities for ITC stocks
stock_dict['ITC'][(stock_dict['ITC'].Series=='EQ')]

"""
# Note: 
Before filtering out, you might be interested to know what are the different series apart from EQ. The code below returns the types of different types of series pertaining to each column. 
"""
for i in Counter(stock_dict).keys():
    print(i,':', stock_dict[i].Series.unique())


"""
# Heads up!
BL series is meant to indicate Block deals in the stock market. The criteria for a certain trade to qualify under BL is to have a minimum 500,000 shares or minimum value of Rs. 5 crore, executed through a single transaction viz the special “Block Deal window”. The window is opened for only 35 minutes in the morning from 9:15 to 9:50AM. Interesting, right?

Check out this link to know more about the different series used in NSE. [Types of Series in NSE](https://help.tradesmartonline.in/what-does-eq-and-be-series-stand-for-in-nse/#:~:text=BL%3A%20This%20series%20is%20for,or%20minimum%20value%20of%20Rs.&text=IL%20%E2%80%93%20This%20series%20allows%20only,for%20FIIs%20is%20not%20breached.)
"""
filtered_stocks={}
for i in Counter(stock_dict).keys():
    filtered_stocks[i]= stock_dict[i][(stock_dict[i].Series=='EQ')].reset_index()


filtered_stocks.items()
"""
# Market capitalization
First things first, let's try to calculate the market capitalization of the stocks and attach them to our dataset for ease. 
"""


for i in Counter(filtered_stocks).keys():
    pd.DataFrame(filtered_stocks[i])['Market Cap']=pd.DataFrame(filtered_stocks[i])['Average Price']*pd.DataFrame(filtered_stocks[i])['Total Traded Quantity']
    
filtered_stocks.items()


for i in Counter(filtered_stocks).keys(): 
    filtered_stocks[i].plot.line(x='Date', y='Market Cap', figsize=(20,10))
    patch = mpatches.Patch(color='blue', label= i)
    plt.legend(handles=[patch])
    

"""
# Inference

1. The massive surge of market capitalization between April-May 2020 of the Hindustan Unilever stocks. The reason can be attributed to the rise in the sales of essential commodities like alcohol based hand sanitizers (Lifebuoy), bathroom cleaners (Domex) and washing powder which has seen a demand shock owinig to the hygiene precautions during the pandemic. This amplified the positive sentiments towards the 'HINDUNILVR' stocks.
2. Simlar trends can be observed with ITC's stocks. It's imperative that Hindustan Unilever and ITC are on a **'FMCG Race'**** this year, given that a major chunk of the consumer spending has been channelized into acquiring the essentials. Apart from that, a massive spike is seen in mid-October which is the market's reaction to ITC investing Rs. 700 Crores to open a food park in Madhya Pradesh. Check out this [link](https://www.itcportal.com/media-centre/press-reports-content.aspx?id=2189&type=C&news=itc-to-invest-700-crores-in-state-of-the-art-food-processing-facility-in-mp#:~:text=The%20ITC%20Limited%20%2D%20one%20of,processing%20facility%20in%20Madhya%20Pradesh.)
3.  All eyes on Reliance Industries Limited, for it has become the most valuable company in India. The plethora of investments made in Reliance facilitated this mammoth growth even during hostile business conditions. Check out this [link](https://www.jagranjosh.com/general-knowledge/list-of-top-investors-in-reliance-jio-1594630586-1) here for better understaning.


"""
#How abot we take a gander at the trends in close prices 

fig, axes = plt.subplots(nrows=5, ncols=1) 
num=0
for i in Counter(filtered_stocks).keys(): 
    filtered_stocks[i].plot(x='Date',y='Close Price', label=i, ax=axes[num], figsize=(15,15))
    num += 1
plt.show()


"""
# Inference#2 
The close prices of all the stocks have hit a low duting late march because of the announcement on 'Nationwide lockdown' made by our honourable Prime Minister on March 24, 2020. Negative business sentiments certainly caused the NSE to tank almost 25% in March, 2020. 
A gradual rebound can be seen from early June because of the government's ease in restrictions on business activities.
"""
#Let's build a dataframe which has only the closing prices. This is a small trick which will be handy later.
close={}
for i in Counter(filtered_stocks).keys():
    close[i]=filtered_stocks[i]['Close Price']
close_price=pd.DataFrame(close)
close_price

"""
# Pre-requisites for the simulation 
We will generate the returns, mean returns and the weights for our selected stocks 
"""
returns= close_price.pct_change().dropna()
mean_returns=returns.mean()
weights=np.array([])
x=1/5 #Weights assigned are given by 1/n, where n is the number of stocks and in our case n=5
for i in range(5):
    weights = np.append(weights, x)
weights

"""
# Portfolio return

To put it in simple words, it is the gain or loss of your portfolio consisting of several investments: in our case the 5 equities. We are interested to find the net profit/loss of all the stocks taken together rather than individual stocks. 

The formula for the same is given by 

![](https://www.wallstreetmojo.com/wp-content/uploads/2019/04/Portfolio-Return-Formula.jpg)


**where w and r represent the weight and return of a particular stock
**
"""
"""
## Portfolio variance for a portfolio 
![](https://cdn.corporatefinanceinstitute.com/assets/portfolio-variance-formula-1024x84.png)

### Here sigma is standard deviation and Cov is covariance

The standard deviation (i.e. sqrt of variance) can help us measure the volatility of our portfolio and is generally considered a vital statistical tool when it comes to comparing multiple values and their behavior.
"""
#Calculating Portfolio Return
port_return = np.sum(weights * mean_returns)

#Annual portfolio return by multiplying 252*100, where 252 is the active number of working days
port_annual=port_return*252*100
port_annual
#Calculating Portfolio Volatility
cov = returns.cov()
port_vol = np.sqrt(np.dot(weights.T,np.dot(cov,weights)))
port_vol


"""
# MONTE CARLO SIMULATION
According to Investopedia, Monte Carlo simulations are used to model the probability of different outcomes in a process that cannot easily be predicted due to the intervention of random variables. It is a technique used to understand the impact of risk and uncertainty in prediction and forecasting models.
In our case, we will try to return the optimal portfolio allocation to maximize the returns using the historical data we have. 

"""
#Let's declare the number of Portfolio to be generated
num_portfolio = 50000

#Create an empty list for storing returns,volatility,sharpe_ratio(return/volatility) and weightage of each stock in portfolio
stats = np.zeros((3 + len(returns.columns),num_portfolio))



#Monte Carlo Simulation
for i in range(num_portfolio):
    
    weight = np.random.rand(len(returns.columns)) #Declaring random weights
    weight = weight/np.sum(weight) #So that sum of all weight will be equal to 1

    p_annual_return = np.sum(weight * mean_returns) * 252 #Annual Return
    p_annual_volatility = np.sqrt(np.dot(weight.T,np.dot(cov,weight))) * np.sqrt(252) #Annual Volatility
    
    #Storing the values in results list
    stats[0,i] = p_annual_return
    stats[1,i] = p_annual_volatility
    stats[2,i] = stats[0,i]/stats[1,i]

    for j in range(len(weight)):
        stats[j+3,i] =  weight[j]
        
        
        
#Making a dataframe for results list of all generated Portfolio
cols = ['Annual Return','Annual Volatility','Sharpe Ratio']
for num in range(len(list(returns.columns))):
    cols.append(list(returns.columns)[num])

    
stats_df = pd.DataFrame(stats.T,columns=cols)

stats_df
"""
# Locating 3 different portfolios

1. **The portfolio with the highest Sharpe Ratio.**
To get the gravity of this portfolio, let's dive in a bit deep to understand the significance of Sharpe Ratio in portfolio management. Sharpe Ratio has been widely used to identify risk-adjusted return. Modern Portfolio Theory states that adding assets to a diversified portfolio that has low correlations can decrease portfolio risk without sacrificing return. Apart from that, Sharpe ratio can be used to evaluate a portfolio’s performance history (as seen above). Explanation on whether a portfolio's excess returns are due to smart investment decisions or a result of too much risk can be deduced from Sharpe ratio.

2. **The portfolio with the lowest volatility/lowest risk**
In a beginner's perspective, a low risk portfolio is what that is desired. And this is what that separates out the speculators from the investors: calculated risks taken by the latter. 

3. **The portfolio with the highest volatility/highest risk**
Seasoned investors choose this owing to their market knowledge. A higher risk can generate good returns given a diversified portfolio. But if you're a beginner, think twice. Do some research on the investment trends. Check out the book:"The Intelligent Investor" by Benjamin Graham to gain insights into investments.
"""
#locating 
#Portfolio 1 - Sharpe ratio is the highest (Return/Volatility)
#Portfolio 2 - Volatility is the lowest
            

#Portfolio 1
max_sharpe = stats_df.iloc[stats_df['Sharpe Ratio'].idxmax()]

#Portfolio 2
min_vol = stats_df.iloc[stats_df['Annual Volatility'].idxmin()]

#Portfolio 3
max_vol = stats_df.iloc[stats_df['Annual Volatility'].idxmax()]

"""
   # The showdown
   
   Let's see all the 3 portfolios which we defined earlier. Remember this is the result of the Monte Carlo simulation which we deployed earlier.
"""
#Portfolio 1
print('The Portfolio allocation with maximum Sharpe Ratio) is:')
print('All values in percentage')
round(max_sharpe* 100,2)
#Portfolio 2
print('The Portfolio allocation with least Volatility is:')
print('All values in percentage')
round(min_vol * 100,2)

#Portfolio 3
print('The Portfolio allocation with most Volatility is:')
print('All values in percentage')
round(max_vol * 100,2)

#Plotting the simulation
plt.figure(figsize=(20,10))
plt.scatter(stats_df['Annual Volatility'],stats_df['Annual Return'],c =stats_df['Sharpe Ratio'],cmap='RdYlBu')
plt.colorbar()

plt.scatter(max_sharpe[1],max_sharpe[0],marker = (5,1,3),color='red',s=700) #Red - Portfolio 1
plt.scatter(min_vol[1],min_vol[0],marker = (5,1,3),color='green',s=700) #Green - Portfolio 2
plt.scatter(max_vol[1],max_vol[0],marker = (5,1,3),color='black',s=700) #Black - Portfolio 3
            

plt.xlabel('Volatility',fontsize = 20)
plt.ylabel('Annual Returns',fontsize = 20)
plt.show()
"""
As a heads up, I would urge you to try to analyze the trends between deliverable quantity and the total traded quantity. There's quite some untold facts in them. Check the [link](https://www.goodreturns.in/classroom/2015/10/understanding-the-importance-shares-delivery-quantity-total-traded-quantity-400097.html) to know about the same. 
Thank you! 
"""