import pandas as pd
import pandas_datareader.data as web
import matplotlib.pyplot as plt
import numpy as np

# Defines the chart color scheme using Tableu's Tableau10 
plt.style.use('https://gist.githubusercontent.com/mbonix/8478091db6a2e6836341c2bb3f55b9fc/raw/7155235ed03e235c38b66c160d402192ad4d94d9/tableau10.mplstyle')

%matplotlib inline

"""
Explanation: Finance notebooks
Some basics: Portfolio finance
Let's make some portfolio math, as usual with python (https://www.python.org/) and pandas (http://pandas.pydata.org/).
End of explanation
"""


# List of stocks tickers
STOCKS = ['NASDAQ:AAPL', 'NASDAQ:GOOGL', 'NASDAQ:MSFT', 'NYSE:MCD', 'NYSE:KO']

# Analysis period
START = '12-30-2006'
END = '12-31-2016'

data = web.DataReader(STOCKS, 'google', pd.to_datetime(START), pd.to_datetime(END))

# Only Close prices are relevant for analysis
prices = data.loc['Close', :, :]
prices.tail(10)

"""
Explanation: We are going to download some prices, just as an example. We'll work on Apple (AAPL), Alphabet (former Google, GOOGL), Microsoft (MSFT), McDonald's (MCD), Coca-Cola (KO) over a ten-year period.
End of explanation
"""


compound_returns = (1 + (prices.iloc[-1, :]).to_frame().T / (prices.iloc[0, :])) ** 0.1 - 1
compound_returns.index = ['Compound Annual Return']
compound_returns

"""
Explanation: Now, let's calculate an annualized return for each of the stocks over the entire period.
End of explanation
"""


annual_volatility = prices.fillna(method='pad').pct_change().std().apply(lambda x: x * 260 ** 0.5).to_frame().T
annual_volatility.index = ['Annual Volatility']
annual_volatility

"""
Explanation: Then we could compute an annual volatility over the period, daily sampled.
End of explanation
"""


stock_moments = pd.concat((compound_returns, annual_volatility))
stock_moments

"""
Explanation: Let's join these stats into a single dataframe.
End of explanation
"""


f = plt.figure(figsize=(10, 8));
ax = f.add_subplot(111);
for n in range(len(stock_moments.columns)):
    ax.plot(stock_moments.loc['Annual Volatility', stock_moments.columns[n]], stock_moments.loc['Compound Annual Return', stock_moments.columns[n]], ls='', marker='o', label=stock_moments.columns[n]);
ax.legend(loc='best');
ax.set_xlabel(stock_moments.index[1]);
ax.set_ylabel(stock_moments.index[0]);
ax.set_title('Stock risk reward profile');

"""
Explanation: And let's make a chart, plotting volatities on X-axis and returns on Y-axis.
End of explanation
"""


WEIGHTS = [0.2, 0.2, 0.2, 0.2, 0.2]
port_moments = pd.DataFrame(index=stock_moments.index, columns=['Equally-weighted Portfolio'])
port_moments.loc['Compound Annual Return', 'Equally-weighted Portfolio'] = (stock_moments.loc['Compound Annual Return', :] * WEIGHTS).sum()
port_moments

"""
Explanation: A few considerations: Apple (AAPL) has delivered a superb return over the period, but at the cost of the highest volatility (risk), while the old-economy stocks (Coca-Cola: KO e McDonald's: MCD) have been characterized by a lower risk and a lower return.
Now, let's calculate the risk-reward profile of a equally-weighted portfolio composed by these five stocks. First of all, the return of the portfolio, which is the average of the stock returns, equally-weighted.
End of explanation
"""


cov_mat = prices.fillna(method='pad').pct_change().cov().apply(lambda x: x * 260)
cov_mat

"""
Explanation: In order to calculate volatility, we need a covariance matrix. Luckily enough, Pandas has a function to do exactly that!
End of explanation
"""


pd.DataFrame(data=[cov_mat.iloc[n, n] ** 0.5 for n in range(len(cov_mat.columns))], index=cov_mat.columns, columns=['Annual Volatility']).T

"""
Explanation: Let's check that the roots of the diagonal of the matrix are the (annualized) standard deviations of the stocks.
End of explanation
"""


port_moments.loc['Annual Volatility', 'Equally-weighted Portfolio'] = np.array(WEIGHTS).dot(cov_mat.values).dot(np.array(WEIGHTS).T) ** 0.5
port_moments

"""
Explanation: The volatility of the portfolio is easily computed.
End of explanation
"""


f = plt.figure(figsize=(10, 8));
ax = f.add_subplot(111);
for n in range(len(stock_moments.columns)):
    ax.plot(stock_moments.loc['Annual Volatility', stock_moments.columns[n]], stock_moments.loc['Compound Annual Return', stock_moments.columns[n]], ls='', marker='o', label=stock_moments.columns[n]);
ax.plot(port_moments.loc['Annual Volatility','Equally-weighted Portfolio'], port_moments.loc['Compound Annual Return', 'Equally-weighted Portfolio'], ls='', marker='d', label='Equally-weighted Portfolio');
ax.legend(loc='best');
ax.set_xlabel(stock_moments.index[1]);
ax.set_ylabel(stock_moments.index[0]);
ax.set_title('Stock risk reward profile');

"""
Explanation: So, we can plot the risk-reward profile of the portfolio on the previous chart.
End of explanation
"""


wgts = pd.DataFrame(np.array(np.random.uniform(0, 1, (5000, 5))), columns=prices.columns)
w = wgts.apply(lambda x: x / wgts.sum(axis=1))
w

"""
Explanation: We can notice that the portfolio risk profile is similar to old economy stocks, but the historical return benefits from the higher returns of tech stocks. Diversification at work!
Now, let's build some random portfolios and calculate their risk-reward profile. First of all, the weights matrix.
End of explanation
"""


sim_ports = pd.DataFrame(index=w.index, columns=port_moments.index)
sim_ports.loc[:, 'Compound Annual Return'] = (stock_moments.loc['Compound Annual Return', :] * w).sum(axis=1)
sim_ports.loc[:, 'Annual Volatility'] = np.diag(w.values.dot(cov_mat.values).dot(w.values.T)) ** 0.5
sim_ports

"""
Explanation: Let's compute first two moments of the simulated portfolios.
End of explanation
"""


f = plt.figure(figsize=(10, 8));
ax = f.add_subplot(111);
ax.plot(sim_ports.loc[0, 'Annual Volatility'], sim_ports.loc[0, 'Compound Annual Return'], ls='', marker='.', color='#cccccc', label='Random-weighted Portfolios');
for m in range(len(sim_ports.index)):
    ax.plot(sim_ports.loc[m, 'Annual Volatility'], sim_ports.loc[m, 'Compound Annual Return'], ls='', marker='.', color='#cccccc');
for n in range(len(stock_moments.columns)):
    ax.plot(stock_moments.loc['Annual Volatility', stock_moments.columns[n]], stock_moments.loc['Compound Annual Return', stock_moments.columns[n]], ls='', marker='o', label=stock_moments.columns[n]);
ax.plot(port_moments.loc['Annual Volatility','Equally-weighted Portfolio'], port_moments.loc['Compound Annual Return', 'Equally-weighted Portfolio'], ls='', marker='d', label='Equally-weighted Portfolio');
ax.legend(loc='best');
ax.set_xlabel(stock_moments.index[1]);
ax.set_ylabel(stock_moments.index[0]);
ax.set_title('Stock risk reward profile');

"""
Explanation: And let's plot those fancy random portfolios on the risk-reward chart.
End of explanation
"""


