├── BlackScholes Correlated.ipynb ├── Black Scholes Merton.ipynb ├── Portfolio Optimization.ipynb ├── Capital Asset Pricing Model.ipynb ├── README.md └── Multivariate MC.ipynb /BlackScholes Correlated.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import pandas as pd\n", 11 | "from pandas_datareader import data as wb\n", 12 | "import matplotlib.pyplot as plt\n", 13 | "from scipy.stats import norm, gmean, cauchy\n", 14 | "import seaborn as sns\n", 15 | "from datetime import datetime, timedelta\n", 16 | "\n", 17 | "%matplotlib inline" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 5, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "name": "stdout", 27 | "output_type": "stream", 28 | "text": [ 29 | "Spread Option Price MC : 10.715123140813954\n", 30 | "Spread Option Price Margrabe : 10.709488336629235\n", 31 | "Basket Option Price on 3 stocks : 7.182811645972326\n" 32 | ] 33 | } 34 | ], 35 | "source": [ 36 | "# This code is from an online source, detailing how to use Cholesky decomposition in the BlackScholes process", 37 | "import numpy as np\n", 38 | "from scipy import stats\n", 39 | " \n", 40 | "class BlackScholes:\n", 41 | " @staticmethod\n", 42 | " def Generate_Asset(S_0,R,T,Vol,X):\n", 43 | " return S_0*np.exp((R-Vol**2/2)*T + Vol*np.sqrt(T)*X)\n", 44 | "\n", 45 | "class Monte_Carlo:\n", 46 | " @staticmethod\n", 47 | " def __Get_Correlated_Brownian(nb_assets,nb_simulation,correlation_matrix):\n", 48 | " #Function that returns a matrix with all the correlated brownian for all the simulations by proceeding a Cholesky decomposition\"\"\"\n", 49 | " X = np.random.randn(nb_simulation,nb_assets)\n", 50 | " lower_triang_cholesky = np.linalg.cholesky(correlation_matrix)\n", 51 | " for i in range(nb_simulation):\n", 52 | " X[i,:]=np.dot(lower_triang_cholesky,X[i,:]) #np.dot perform a matrix product\n", 53 | " return X\n", 54 | " \n", 55 | " @staticmethod\n", 56 | " def Get_Basket_Call_Price(starting_asset_values,correlation_matrix,asset_vol,maturity,nb_simulation,risk_free_rate,weights,strike):\n", 57 | " nb_assets = len(starting_asset_values)\n", 58 | " \n", 59 | " #Generate independant random variable:\n", 60 | " X = Monte_Carlo.__Get_Correlated_Brownian(nb_assets,nb_simulation,correlation_matrix)\n", 61 | " \n", 62 | " Final_Stock_values = BlackScholes.Generate_Asset(starting_asset_values[:],risk_free_rate,maturity,asset_vol[:],X[:])\n", 63 | " \n", 64 | " #print(Final_Stock_values[:])\n", 65 | " #print(weights)\n", 66 | " #print(Final_Stock_values[:]*weights)\n", 67 | " #print(np.sum(Final_Stock_values[:]*weights,axis=1))\n", 68 | " #print(np.maximum(np.sum(Final_Stock_values[:]*weights,axis=1)-strike,0))\n", 69 | " \n", 70 | " Payoffs = np.maximum(np.sum(Final_Stock_values[:]*weights,axis=1)-strike,0)\n", 71 | " return np.mean(Payoffs)*np.exp(-risk_free_rate*maturity)\n", 72 | "\n", 73 | "class Margrabe:\n", 74 | " @staticmethod\n", 75 | " def __d1(S1,S2,T,sigma_eq):\n", 76 | " return (np.log(S1/S2)+0.5*T*sigma_eq**2)/(sigma_eq*np.sqrt(T))\n", 77 | " \n", 78 | " @staticmethod\n", 79 | " def __d2(S1,S2,T,sigma_eq):\n", 80 | " return Margrabe.__d1(S1,S2,T,sigma_eq)-sigma_eq*np.sqrt(T)\n", 81 | " \n", 82 | " @staticmethod\n", 83 | " def __sigma(vol1,vol2,correlation):\n", 84 | " return np.sqrt(vol1**2 + vol2**2 - 2*correlation*vol1*vol2)\n", 85 | " \n", 86 | " @staticmethod\n", 87 | " def Spread_Call_Price(S1,S2,vol1,vol2,T,correlation):\n", 88 | " sigma_eq = Margrabe.__sigma(vol1,vol2,correlation)\n", 89 | " d1 = Margrabe.__d1(S1,S2,T,sigma_eq)\n", 90 | " d2 = Margrabe.__d2(S1,S2,T,sigma_eq)\n", 91 | " return S1*stats.norm.cdf(d1)-S2*stats.norm.cdf(d2)\n", 92 | "\n", 93 | "option_parameters_1 = {\n", 94 | " 'starting_asset_values' : np.array([100,100]),\n", 95 | " 'correlation_matrix':[[1,0.3],[0.3,1]],\n", 96 | " 'asset_vol' : np.array([0.2,0.25]),\n", 97 | " 'maturity' : 1,\n", 98 | " 'nb_simulation' : 5000000,\n", 99 | " 'risk_free_rate' : 0.01,\n", 100 | " 'weights' : np.array([1,-1]),\n", 101 | " 'strike' : 0\n", 102 | "}\n", 103 | " \n", 104 | "option_parameters_2 = {\n", 105 | " 'starting_asset_values' : np.array([100,100,100]),\n", 106 | " 'correlation_matrix':[[1,0.5,0.1],[0.5,1,0.7],[0.1,0.7,1]],\n", 107 | " 'asset_vol' : np.array([0.2,0.25,0.22]),\n", 108 | " 'maturity' : 1,\n", 109 | " 'nb_simulation' : 5000000,\n", 110 | " 'risk_free_rate' : 0.01,\n", 111 | " 'weights' : np.array([0.4,0.2,0.4]),\n", 112 | " 'strike' : 100\n", 113 | "}\n", 114 | " \n", 115 | "#Checking the result:\n", 116 | "spread_option_price_MC = Monte_Carlo.Get_Basket_Call_Price(**option_parameters_1)\n", 117 | "spread_option_price_margrabe = Margrabe.Spread_Call_Price(100,100,0.2,0.25,1,0.3)\n", 118 | " \n", 119 | "#Example on a basket option with 3 stocks :\n", 120 | "basket_option_price = Monte_Carlo.Get_Basket_Call_Price(**option_parameters_2)\n", 121 | " \n", 122 | "print(\"Spread Option Price MC : {0}\".format(spread_option_price_MC))\n", 123 | "print(\"Spread Option Price Margrabe : {0}\".format(spread_option_price_margrabe))\n", 124 | "print(\"Basket Option Price on 3 stocks : {0}\".format(basket_option_price))" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [] 133 | } 134 | ], 135 | "metadata": { 136 | "kernelspec": { 137 | "display_name": "Python 3", 138 | "language": "python", 139 | "name": "python3" 140 | }, 141 | "language_info": { 142 | "codemirror_mode": { 143 | "name": "ipython", 144 | "version": 3 145 | }, 146 | "file_extension": ".py", 147 | "mimetype": "text/x-python", 148 | "name": "python", 149 | "nbconvert_exporter": "python", 150 | "pygments_lexer": "ipython3", 151 | "version": "3.7.4" 152 | } 153 | }, 154 | "nbformat": 4, 155 | "nbformat_minor": 2 156 | } 157 | -------------------------------------------------------------------------------- /Black Scholes Merton.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import pandas as pd\n", 11 | "from pandas_datareader import data as wb\n", 12 | "from scipy.stats import norm" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "$$\n", 20 | "d_1 = \\frac{\\ln(\\frac{S}{K}) + (r + \\frac{stdev^2}{2})t}{s \\cdot \\sqrt{t}}\n", 21 | "$$\n", 22 | "\n", 23 | "$$\n", 24 | "d_2 = d_1 - s \\cdot \\sqrt{t} = \\frac{\\ln(\\frac{S}{K}) + (r - \\frac{stdev^2}{2})t}{s \\cdot \\sqrt{t}}\n", 25 | "$$" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 3, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "def d1(S, K, r, stdev, T):\n", 35 | " return (np.log(S/K) + ((r + (stdev**2)/2) * T)) / (stdev * np.sqrt(T))\n", 36 | " \n", 37 | "def d2(S, K, r, stdev, T):\n", 38 | " return (np.log(S/K) + ((r - (stdev**2)/2) * T)) / (stdev * np.sqrt(T))" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 4, 44 | "metadata": {}, 45 | "outputs": [ 46 | { 47 | "data": { 48 | "text/plain": [ 49 | "0.5" 50 | ] 51 | }, 52 | "execution_count": 4, 53 | "metadata": {}, 54 | "output_type": "execute_result" 55 | } 56 | ], 57 | "source": [ 58 | "norm.cdf(0)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 5, 64 | "metadata": {}, 65 | "outputs": [ 66 | { 67 | "data": { 68 | "text/plain": [ 69 | "0.6914624612740131" 70 | ] 71 | }, 72 | "execution_count": 5, 73 | "metadata": {}, 74 | "output_type": "execute_result" 75 | } 76 | ], 77 | "source": [ 78 | "norm.cdf(0.5)" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 6, 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "data": { 88 | "text/plain": [ 89 | "0.9999997133484281" 90 | ] 91 | }, 92 | "execution_count": 6, 93 | "metadata": {}, 94 | "output_type": "execute_result" 95 | } 96 | ], 97 | "source": [ 98 | "norm.cdf(5)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "$$\n", 106 | "\\textbf{C} = SN(d_1) - Ke^{-rt}N(d_2) \n", 107 | "$$" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 17, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "def BSM(S, K, r, stdev, T):\n", 117 | " d_uno = d1(S, K, r, stdev, T)\n", 118 | " d_dos = d2(S, K, r, stdev, T)\n", 119 | " return (S*norm.cdf(d_uno)) - (K*np.exp(-r*T)*norm.cdf(d_dos))" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 18, 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [ 128 | "ticker = 'NVDA'\n", 129 | "data = pd.DataFrame()\n", 130 | "data[ticker] = wb.DataReader(ticker, data_source='yahoo', start = '2010-1-1')['Adj Close']" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 19, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "data": { 140 | "text/plain": [ 141 | "NVDA 313.390015\n", 142 | "Name: 2020-05-12 00:00:00, dtype: float64" 143 | ] 144 | }, 145 | "execution_count": 19, 146 | "metadata": {}, 147 | "output_type": "execute_result" 148 | } 149 | ], 150 | "source": [ 151 | "S = data.iloc[-1]\n", 152 | "S" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": 20, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "log_ret = np.log(1+data.pct_change())" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 21, 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "data": { 171 | "text/plain": [ 172 | "NVDA 0.420421\n", 173 | "dtype: float64" 174 | ] 175 | }, 176 | "execution_count": 21, 177 | "metadata": {}, 178 | "output_type": "execute_result" 179 | } 180 | ], 181 | "source": [ 182 | "stdev = log_ret.std() * 250 **0.5\n", 183 | "stdev" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 34, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "r = 0.025\n", 193 | "K = 320\n", 194 | "T = 1" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": 35, 200 | "metadata": {}, 201 | "outputs": [ 202 | { 203 | "data": { 204 | "text/plain": [ 205 | "NVDA 0.220028\n", 206 | "dtype: float64" 207 | ] 208 | }, 209 | "execution_count": 35, 210 | "metadata": {}, 211 | "output_type": "execute_result" 212 | } 213 | ], 214 | "source": [ 215 | "d1(S, K, r, stdev, T)" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": 36, 221 | "metadata": {}, 222 | "outputs": [ 223 | { 224 | "data": { 225 | "text/plain": [ 226 | "NVDA -0.200393\n", 227 | "dtype: float64" 228 | ] 229 | }, 230 | "execution_count": 36, 231 | "metadata": {}, 232 | "output_type": "execute_result" 233 | } 234 | ], 235 | "source": [ 236 | "d2(S, K, r, stdev, T)" 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 37, 242 | "metadata": {}, 243 | "outputs": [ 244 | { 245 | "data": { 246 | "text/plain": [ 247 | "NVDA 52.718802\n", 248 | "Name: 2020-05-12 00:00:00, dtype: float64" 249 | ] 250 | }, 251 | "execution_count": 37, 252 | "metadata": {}, 253 | "output_type": "execute_result" 254 | } 255 | ], 256 | "source": [ 257 | "BSM(S, K, r, stdev, T)" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "metadata": {}, 264 | "outputs": [], 265 | "source": [] 266 | } 267 | ], 268 | "metadata": { 269 | "kernelspec": { 270 | "display_name": "Python 3", 271 | "language": "python", 272 | "name": "python3" 273 | }, 274 | "language_info": { 275 | "codemirror_mode": { 276 | "name": "ipython", 277 | "version": 3 278 | }, 279 | "file_extension": ".py", 280 | "mimetype": "text/x-python", 281 | "name": "python", 282 | "nbconvert_exporter": "python", 283 | "pygments_lexer": "ipython3", 284 | "version": "3.7.4" 285 | } 286 | }, 287 | "nbformat": 4, 288 | "nbformat_minor": 2 289 | } 290 | -------------------------------------------------------------------------------- /Portfolio Optimization.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 13, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import pandas as pd\n", 11 | "from pandas_datareader import data as wb\n", 12 | "import matplotlib.pyplot as plt\n", 13 | "from scipy.stats import norm, gmean, cauchy\n", 14 | "import seaborn as sns\n", 15 | "from datetime import datetime, timedelta\n", 16 | "\n", 17 | "%matplotlib inline" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 14, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "def import_stock_data(tickers, start = '2010-1-1', end = datetime.today().strftime('%Y-%m-%d')):\n", 27 | " data = pd.DataFrame()\n", 28 | " if len([tickers]) ==1:\n", 29 | " data[tickers] = wb.DataReader(tickers, data_source='yahoo', start = start)['Adj Close']\n", 30 | " data = pd.DataFrame(data)\n", 31 | " else:\n", 32 | " for t in tickers:\n", 33 | " data[t] = wb.DataReader(t, data_source='yahoo', start = start)['Adj Close']\n", 34 | " return(data)" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 15, 40 | "metadata": {}, 41 | "outputs": [ 42 | { 43 | "data": { 44 | "text/html": [ 45 | "
\n", 46 | "\n", 59 | "\n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | "
AAPLGOOG
Date
2010-01-0426.466835312.204773
2010-01-0526.512596310.829926
2010-01-0626.090879302.994293
2010-01-0726.042646295.940735
2010-01-0826.215786299.885956
.........
2020-06-01321.8500061431.819946
2020-06-02323.3399961439.219971
2020-06-03325.1199951436.380005
2020-06-04322.3200071412.180054
2020-06-05331.5000001438.390015
\n", 130 | "

2624 rows × 2 columns

\n", 131 | "
" 132 | ], 133 | "text/plain": [ 134 | " AAPL GOOG\n", 135 | "Date \n", 136 | "2010-01-04 26.466835 312.204773\n", 137 | "2010-01-05 26.512596 310.829926\n", 138 | "2010-01-06 26.090879 302.994293\n", 139 | "2010-01-07 26.042646 295.940735\n", 140 | "2010-01-08 26.215786 299.885956\n", 141 | "... ... ...\n", 142 | "2020-06-01 321.850006 1431.819946\n", 143 | "2020-06-02 323.339996 1439.219971\n", 144 | "2020-06-03 325.119995 1436.380005\n", 145 | "2020-06-04 322.320007 1412.180054\n", 146 | "2020-06-05 331.500000 1438.390015\n", 147 | "\n", 148 | "[2624 rows x 2 columns]" 149 | ] 150 | }, 151 | "execution_count": 15, 152 | "metadata": {}, 153 | "output_type": "execute_result" 154 | } 155 | ], 156 | "source": [ 157 | "import_stock_data(['AAPL','GOOG'])" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 16, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "def log_returns(data):\n", 167 | " return (np.log(1+data.pct_change()))\n", 168 | "def simple_returns(data):\n", 169 | " return ((data/data.shift(1))-1)" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 17, 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "def market_data_combination(data, mark_ticker = \"^GSPC\", start='2010-1-1'):\n", 179 | " market_data = import_stock_data(mark_ticker, start)\n", 180 | " market_rets = log_returns(market_data).dropna()\n", 181 | " ann_return = np.exp(market_rets.mean()*252).values-1\n", 182 | " data = data.merge(market_data, left_index=True, right_index=True)\n", 183 | " return data, ann_return" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 18, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "def beta_sharpe(data, mark_ticker = \"^GSPC\", start='2010-1-1', riskfree = 0.025):\n", 193 | " \n", 194 | " \"\"\"\n", 195 | " Input: \n", 196 | " 1. data: dataframe of stock price data\n", 197 | " 2. mark_ticker: ticker of the market data you want to compute CAPM metrics with (default is ^GSPC)\n", 198 | " 3. start: data from which to download data (default Jan 1st 2010)\n", 199 | " 4. riskfree: the assumed risk free yield (US 10 Year Bond is assumed: 2.5%)\n", 200 | " \n", 201 | " Output:\n", 202 | " 1. Dataframe with CAPM metrics computed against specified market procy\n", 203 | " \"\"\"\n", 204 | " # Beta\n", 205 | " dd, mark_ret = market_data_combination(data, mark_ticker, start)\n", 206 | " log_ret = log_returns(dd)\n", 207 | " covar = log_ret.cov()*252\n", 208 | " covar = pd.DataFrame(covar.iloc[:-1,-1])\n", 209 | " mrk_var = log_ret.iloc[:,-1].var()*252\n", 210 | " beta = covar/mrk_var\n", 211 | " \n", 212 | " stdev_ret = pd.DataFrame(((log_ret.std()*250**0.5)[:-1]), columns=['STD'])\n", 213 | " beta = beta.merge(stdev_ret, left_index=True, right_index=True)\n", 214 | " \n", 215 | " # CAPM\n", 216 | " for i, row in beta.iterrows():\n", 217 | " beta.at[i,'CAPM'] = riskfree + (row[mark_ticker] * (mark_ret-riskfree))\n", 218 | " # Sharpe\n", 219 | " for i, row in beta.iterrows():\n", 220 | " beta.at[i,'Sharpe'] = ((row['CAPM']-riskfree)/(row['STD']))\n", 221 | " beta.rename(columns={\"^GSPC\":\"Beta\"}, inplace=True)\n", 222 | " \n", 223 | " return beta" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": 21, 229 | "metadata": {}, 230 | "outputs": [], 231 | "source": [ 232 | "def montecarlo_sharpe_optimal_portfolio(tickers, trials, riskfree=0.025, plot_eff = True, start_date = '2010-1-1', end_date=None):\n", 233 | " if end_date == None:\n", 234 | " end_date = datetime.today().strftime('%Y-%m-%d')\n", 235 | " \n", 236 | " data = market_data_combination(tickers)\n", 237 | " allWeights = np.zeros((trials, len(data.columns)))\n", 238 | " allReturns = np.zeros(trials)\n", 239 | " allVolatility = np.zeros(trials)\n", 240 | " allSharpeValues = np.zeros(trials)\n", 241 | " \n", 242 | " log_return = log_returns(data)\n", 243 | " \n", 244 | " for t in range(trials):\n", 245 | " weights = np.random.rand(len(data.columns))\n", 246 | " weights = weights/np.sum(weights) \n", 247 | " allWeights[t,:]=weights\n", 248 | " \n", 249 | " allReturns[t] = np.sum((log_return.mean()*weights)*252)\n", 250 | " \n", 251 | " allVolatility[t] = np.sqrt(np.dot(weights.T, np.dot(log_return.cov()*252, weights)))\n", 252 | " \n", 253 | " allSharpeValues[t] = (allReturns[t]-riskfree)/allVolatility[t]\n", 254 | " \n", 255 | " maxsharpe = allSharpeValues.max()\n", 256 | " pointsharpe = allSharpeValues.argmax()\n", 257 | " weightSharpe = allWeights[pointsharpe]\n", 258 | " x_sharpe = allVolatility[pointsharpe]\n", 259 | " y_sharpe = allReturns[pointsharpe]\n", 260 | " \n", 261 | " maxret = allReturns.max()\n", 262 | " pointret = allReturns.argmax()\n", 263 | " weightRet = allWeights[pointret]\n", 264 | " x_ret = allVolatility[pointret]\n", 265 | " y_ret = allReturns[pointret]\n", 266 | " \n", 267 | " \n", 268 | " if plot_eff == True:\n", 269 | " plt.figure(figsize=(14,9))\n", 270 | " plt.scatter(allVolatility, allReturns, c=allSharpeValues, cmap='plasma')\n", 271 | " plt.colorbar(label='Sharpe Ratio')\n", 272 | " plt.xlabel('Volatility')\n", 273 | " plt.ylabel('Expected Return')\n", 274 | " \n", 275 | " plt.scatter(x_sharpe,y_sharpe,c='black')\n", 276 | " plt.scatter(x_ret, y_ret, c='black')\n", 277 | " \n", 278 | " optim_dic = []\n", 279 | " for i in range(len(tickers)):\n", 280 | " optim_dic.append({'ticker':tickers[i],'Weight':weightSharpe[i]})\n", 281 | " print(pd.DataFrame(optim_dic))" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 22, 287 | "metadata": {}, 288 | "outputs": [ 289 | { 290 | "ename": "AttributeError", 291 | "evalue": "'list' object has no attribute 'merge'", 292 | "output_type": "error", 293 | "traceback": [ 294 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 295 | "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", 296 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mmontecarlo_sharpe_optimal_portfolio\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'MSFT'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34m'AMZN'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34m'AMZN'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m1000\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 297 | "\u001b[1;32m\u001b[0m in \u001b[0;36mmontecarlo_sharpe_optimal_portfolio\u001b[1;34m(tickers, trials, riskfree, plot_eff, start_date, end_date)\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mend_date\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdatetime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtoday\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'%Y-%m-%d'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmarket_data_combination\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtickers\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[0mallWeights\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtrials\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[0mallReturns\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtrials\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 298 | "\u001b[1;32m\u001b[0m in \u001b[0;36mmarket_data_combination\u001b[1;34m(data, mark_ticker, start)\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mmarket_rets\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlog_returns\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmarket_data\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdropna\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mann_return\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmarket_rets\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmean\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m*\u001b[0m\u001b[1;36m252\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmerge\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmarket_data\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mleft_index\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mright_index\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mann_return\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 299 | "\u001b[1;31mAttributeError\u001b[0m: 'list' object has no attribute 'merge'" 300 | ] 301 | } 302 | ], 303 | "source": [ 304 | "montecarlo_sharpe_optimal_portfolio(['MSFT','AMZN','AMZN'],1000)" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "metadata": {}, 311 | "outputs": [], 312 | "source": [] 313 | } 314 | ], 315 | "metadata": { 316 | "kernelspec": { 317 | "display_name": "Python 3", 318 | "language": "python", 319 | "name": "python3" 320 | }, 321 | "language_info": { 322 | "codemirror_mode": { 323 | "name": "ipython", 324 | "version": 3 325 | }, 326 | "file_extension": ".py", 327 | "mimetype": "text/x-python", 328 | "name": "python", 329 | "nbconvert_exporter": "python", 330 | "pygments_lexer": "ipython3", 331 | "version": "3.7.4" 332 | } 333 | }, 334 | "nbformat": 4, 335 | "nbformat_minor": 2 336 | } 337 | -------------------------------------------------------------------------------- /Capital Asset Pricing Model.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "___\n", 8 | "\n", 9 | " \n", 10 | "# Finance with Python\n", 11 | "### Capital Asset Pricing Model\n", 12 | "___\n", 13 | "

by Elias Melul, Data Scientist

\n", 14 | "\n", 15 | "___\n", 16 | "\n", 17 | "\n", 18 | "The CAPM model describes the relationship between expected returns and volatility (systematic risk). Why does this matter? Because investors expect to be compensated for risk and time value of money. So the CAPM is used as a theoretical model that adjusts for risk when evaluating the value of a stock.\n", 19 | "\n", 20 | "This model assumes the existance of a market portfolio - all possible investments in the world combined - hence the existance of a risk-free asset. However, this is not true. It also assumes that all investors are rational, and therefore hold the optimal portfolio. This is in consequence of the mutual fund theorem: _all investors hold the same portfolio of risky assets, the tangency portfolio_. Therefore, the CAPM assumes that the tangency portfolio is the market portfolio. Again... not true.\n", 21 | "\n", 22 | "In this context, the tangency portfolio is the portfolio with the largest Sharpe Ratio. But what is the _Sharpe Ratio?_\n", 23 | "\n", 24 | "\n", 25 | "**Sharpe Ratio**: measures the performance of a security compared to a risk-free asset, after adjusting for its risk. This is the excess return per unit of risk of an investment.\n", 26 | "$$\n", 27 | "Sharpe = \\frac{\\overline{r_{i}} - r_f}{\\sigma_{i}}\n", 28 | "$$\n", 29 | " When Sharpe > 1, GOOD risk-adjusted returns\n", 30 | " \n", 31 | " When Sharpe > 2, VERY GOOD risk-adjusted returns\n", 32 | " \n", 33 | " When Sharpe > 3, EXCELLENT risk-adjusted returns\n", 34 | "\n", 35 | "\n", 36 | "_How do we measure risk?_ There are many ways to measure risk, although variance (standard deviation) is one of the most common. However, when it comes to the risk that cannot be avoided through diversification, the Beta is king!\n", 37 | "\n", 38 | "**Beta**: measures the market risk that cannot be avoided through diversification. This is the relationship between the stock and the market portfolio. In other words, it is a measure of how much risk the investment will add to a portfolio that looks like the market.\n", 39 | "$$ \n", 40 | "\\beta_{i} = \\frac{\\sigma_{i,m}}{\\sigma_{m}^2}\n", 41 | "$$\n", 42 | "\n", 43 | " When beta = 0, it means that there's no relationship.\n", 44 | " \n", 45 | " When beta < 1, it means that the stock is defensive (less prone to high highs and low lows)\n", 46 | " \n", 47 | " When beta > 1, it means that the stock is aggresive (more prone to high highs and low lows)\n", 48 | " \n", 49 | "Amazing! We're only one small step away. The risk-adjusted returns. \n", 50 | "\n", 51 | "**Expected Return CAPM**: calculates the expected return of a security adjusted to the risk taken. This equates to the return expected from taking the extra risk of purchasing this security.\n", 52 | "$$\n", 53 | "\\overline{r_{i}} = r_f + \\beta_{i}(\\overline{r_{m}} - r_f) \n", 54 | "$$\n", 55 | "\n", 56 | "Awesome! There are a couple more things we will discuss later, but for now, now that we understand the underlying theory of the CAPM model, let's get coding!\n", 57 | "\n", 58 | "---\n", 59 | "\n", 60 | "**Step 1**:Import necessary libraries" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 1, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "import numpy as np\n", 70 | "import pandas as pd\n", 71 | "from pandas_datareader import data as wb" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "**Step 2**: Import data for a stock and the market data. In this case we will use:\n", 79 | " 1. Amazon\n", 80 | " 2. S&P 500 (as a proxy for the market)" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 2, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "tickers = ['AMZN','^GSPC']\n", 90 | "data = pd.DataFrame()\n", 91 | "for t in tickers:\n", 92 | " data[t] = wb.DataReader(t, data_source='yahoo', start='2010-1-1')['Adj Close']" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "**Step 3**: compute the logarthmic returns of the daily data. This is logarithmic daily returns of the data. \n", 100 | " \n", 101 | " Why logarithmic and not simple returns?\n", 102 | " \n", 103 | " We usually use logarithmic returns when making calculations about a single asset over time.\n", 104 | " We use simple returns when dealing with multiple assets over the same timeframe." 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 3, 110 | "metadata": {}, 111 | "outputs": [ 112 | { 113 | "data": { 114 | "text/html": [ 115 | "
\n", 116 | "\n", 129 | "\n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | "
AMZN^GSPC
Date
2010-01-04NaNNaN
2010-01-050.0058830.003111
2010-01-06-0.0182820.000545
2010-01-07-0.0171600.003993
2010-01-080.0267170.002878
\n", 170 | "
" 171 | ], 172 | "text/plain": [ 173 | " AMZN ^GSPC\n", 174 | "Date \n", 175 | "2010-01-04 NaN NaN\n", 176 | "2010-01-05 0.005883 0.003111\n", 177 | "2010-01-06 -0.018282 0.000545\n", 178 | "2010-01-07 -0.017160 0.003993\n", 179 | "2010-01-08 0.026717 0.002878" 180 | ] 181 | }, 182 | "execution_count": 3, 183 | "metadata": {}, 184 | "output_type": "execute_result" 185 | } 186 | ], 187 | "source": [ 188 | "sec_returns = np.log(data / data.shift(1))\n", 189 | "sec_returns.head()" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "**Step 4**: Compute covariance and market variance.\n", 197 | "\n", 198 | " As we can see from the Beta function in the introduction, we need the covariance between Amazon stock and the market. We also need the variance of market returns. We need these annualized, so we will multiply them by 252, since there are 252 trading days in an actual year. " 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": 4, 204 | "metadata": {}, 205 | "outputs": [ 206 | { 207 | "data": { 208 | "text/html": [ 209 | "
\n", 210 | "\n", 223 | "\n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | "
AMZN^GSPC
AMZN0.0988640.030647
^GSPC0.0306470.030551
\n", 244 | "
" 245 | ], 246 | "text/plain": [ 247 | " AMZN ^GSPC\n", 248 | "AMZN 0.098864 0.030647\n", 249 | "^GSPC 0.030647 0.030551" 250 | ] 251 | }, 252 | "execution_count": 4, 253 | "metadata": {}, 254 | "output_type": "execute_result" 255 | } 256 | ], 257 | "source": [ 258 | "cov = sec_returns.cov() *252\n", 259 | "cov" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": 5, 265 | "metadata": {}, 266 | "outputs": [ 267 | { 268 | "data": { 269 | "text/plain": [ 270 | "0.030647075713743515" 271 | ] 272 | }, 273 | "execution_count": 5, 274 | "metadata": {}, 275 | "output_type": "execute_result" 276 | } 277 | ], 278 | "source": [ 279 | "cov_with_market = cov.iloc[0,1]\n", 280 | "cov_with_market" 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": 6, 286 | "metadata": {}, 287 | "outputs": [ 288 | { 289 | "data": { 290 | "text/plain": [ 291 | "0.030550882514637476" 292 | ] 293 | }, 294 | "execution_count": 6, 295 | "metadata": {}, 296 | "output_type": "execute_result" 297 | } 298 | ], 299 | "source": [ 300 | "market_var = sec_returns['^GSPC'].var()*252\n", 301 | "market_var" 302 | ] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "metadata": {}, 307 | "source": [ 308 | "**Step 5**: Calculate Beta\n", 309 | "$$ \n", 310 | "\\beta_{pg} = \\frac{\\sigma_{pg,m}}{\\sigma_{m}^2}\n", 311 | "$$" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": 7, 317 | "metadata": {}, 318 | "outputs": [ 319 | { 320 | "data": { 321 | "text/plain": [ 322 | "1.0031486225990347" 323 | ] 324 | }, 325 | "execution_count": 7, 326 | "metadata": {}, 327 | "output_type": "execute_result" 328 | } 329 | ], 330 | "source": [ 331 | "amazon_beta = cov_with_market / market_var\n", 332 | "amazon_beta" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": {}, 338 | "source": [ 339 | "**Step 6**: Expected Return CAPM\n", 340 | "$$\n", 341 | "\\overline{r_{pg}} = r_f + \\beta_{pg}(\\overline{r_{m}} - r_f) \n", 342 | "$$\n", 343 | "\n", 344 | "Here, we need to make a couple assumptions. \n", 345 | "1. A 10 year US government bond is a good proxy for a risk-free asset, with a yield of 2.5%\n", 346 | "2. The common risk premium is between 4.5% and 5.5%, so we will use 5%. Risk premium is the expected return of the market minus the risk-free return.\n" 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": 8, 352 | "metadata": {}, 353 | "outputs": [ 354 | { 355 | "data": { 356 | "text/plain": [ 357 | "0.07515743112995174" 358 | ] 359 | }, 360 | "execution_count": 8, 361 | "metadata": {}, 362 | "output_type": "execute_result" 363 | } 364 | ], 365 | "source": [ 366 | "riskfree = 0.025\n", 367 | "riskpremium = 0.05\n", 368 | "amazon_capm_return = riskfree + amazon_beta*riskpremium\n", 369 | "amazon_capm_return" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "Let's try the same calculation, but this time, we use the mean of the returns of the market as part of the risk premium." 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "execution_count": 9, 382 | "metadata": {}, 383 | "outputs": [ 384 | { 385 | "data": { 386 | "text/plain": [ 387 | "0.09264355940041935" 388 | ] 389 | }, 390 | "execution_count": 9, 391 | "metadata": {}, 392 | "output_type": "execute_result" 393 | } 394 | ], 395 | "source": [ 396 | "riskfree = 0.025\n", 397 | "riskpremium = (sec_returns['^GSPC'].mean()*252) - riskfree\n", 398 | "amazon_capm_return = riskfree + amazon_beta*riskpremium\n", 399 | "amazon_capm_return" 400 | ] 401 | }, 402 | { 403 | "cell_type": "markdown", 404 | "metadata": {}, 405 | "source": [ 406 | "Using the returns of the market yields a higher risk-adjusted returns. This makes sense since the market has been doing well since 2010 (the beginning of our dataset). There's only one more important calculation left: the _Sharpe Ratio_\n", 407 | "\n", 408 | "**Step 7: Sharpe Ratio**\n", 409 | "$$\n", 410 | "Sharpe = \\frac{\\overline{r_{amazon}} - r_f}{\\sigma_{amazon}}\n", 411 | "$$" 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": 10, 417 | "metadata": {}, 418 | "outputs": [ 419 | { 420 | "data": { 421 | "text/plain": [ 422 | "0.2159918670500646" 423 | ] 424 | }, 425 | "execution_count": 10, 426 | "metadata": {}, 427 | "output_type": "execute_result" 428 | } 429 | ], 430 | "source": [ 431 | "log_returns = np.log(data / data.shift(1))\n", 432 | "sharpe_amazon = (amazon_capm_return-riskfree)/(log_returns['AMZN'].std()*250**0.5)\n", 433 | "sharpe_amazon" 434 | ] 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "metadata": {}, 439 | "source": [ 440 | "##### There it goes!\n", 441 | "\n", 442 | "The next part just creates functions for each of these metrics, so that we can easily access them for any stock with a simple function." 443 | ] 444 | }, 445 | { 446 | "cell_type": "code", 447 | "execution_count": 13, 448 | "metadata": {}, 449 | "outputs": [], 450 | "source": [ 451 | "from datetime import datetime" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": 14, 457 | "metadata": {}, 458 | "outputs": [], 459 | "source": [ 460 | "#Import the data of any stock of set of stocks\n", 461 | "def import_stock_data(tickers, start = '2010-1-1', end = datetime.today().strftime('%Y-%m-%d')):\n", 462 | " data = pd.DataFrame()\n", 463 | " if len([tickers]) ==1:\n", 464 | " data[tickers] = wb.DataReader(tickers, data_source='yahoo', start = start)['Adj Close']\n", 465 | " data = pd.DataFrame(data)\n", 466 | " else:\n", 467 | " for t in tickers:\n", 468 | " data[t] = wb.DataReader(t, data_source='yahoo', start = start)['Adj Close']\n", 469 | " return(data)" 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": 60, 475 | "metadata": {}, 476 | "outputs": [ 477 | { 478 | "data": { 479 | "text/html": [ 480 | "
\n", 481 | "\n", 494 | "\n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | "
AMZN^GSPC
Date
2010-01-04133.8999941132.989990
2010-01-05134.6900021136.520020
2010-01-06132.2500001137.140015
2010-01-07130.0000001141.689941
2010-01-08133.5200041144.979980
\n", 535 | "
" 536 | ], 537 | "text/plain": [ 538 | " AMZN ^GSPC\n", 539 | "Date \n", 540 | "2010-01-04 133.899994 1132.989990\n", 541 | "2010-01-05 134.690002 1136.520020\n", 542 | "2010-01-06 132.250000 1137.140015\n", 543 | "2010-01-07 130.000000 1141.689941\n", 544 | "2010-01-08 133.520004 1144.979980" 545 | ] 546 | }, 547 | "execution_count": 60, 548 | "metadata": {}, 549 | "output_type": "execute_result" 550 | } 551 | ], 552 | "source": [ 553 | "data = import_stock_data(['AMZN','^GSPC'], start = '2010-1-1')\n", 554 | "data.head()" 555 | ] 556 | }, 557 | { 558 | "cell_type": "code", 559 | "execution_count": 61, 560 | "metadata": {}, 561 | "outputs": [], 562 | "source": [ 563 | "def compute_beta(data, stock, market):\n", 564 | " log_returns = np.log(data / data.shift(1))\n", 565 | " cov = log_returns.cov()*250\n", 566 | " cov_w_market = cov.loc[stock,market]\n", 567 | " market_var = log_returns[market].var()*250\n", 568 | " return cov_w_market/market_var" 569 | ] 570 | }, 571 | { 572 | "cell_type": "code", 573 | "execution_count": 62, 574 | "metadata": {}, 575 | "outputs": [ 576 | { 577 | "data": { 578 | "text/plain": [ 579 | "1.0031486225990347" 580 | ] 581 | }, 582 | "execution_count": 62, 583 | "metadata": {}, 584 | "output_type": "execute_result" 585 | } 586 | ], 587 | "source": [ 588 | "compute_beta(data, 'AMZN',\"^GSPC\")" 589 | ] 590 | }, 591 | { 592 | "cell_type": "code", 593 | "execution_count": 65, 594 | "metadata": {}, 595 | "outputs": [], 596 | "source": [ 597 | "def compute_capm(data, stock, market, riskfree = 0.025, riskpremium = 'market'):\n", 598 | " log_returns = np.log(data / data.shift(1))\n", 599 | " if riskpremium == 'market':\n", 600 | " riskpremium = (log_returns[market].mean()*252) - riskfree\n", 601 | " beta = compute_beta(data, stock, market)\n", 602 | " return (riskfree + (beta*riskpremium))" 603 | ] 604 | }, 605 | { 606 | "cell_type": "code", 607 | "execution_count": 66, 608 | "metadata": {}, 609 | "outputs": [ 610 | { 611 | "data": { 612 | "text/plain": [ 613 | "0.09264355940041935" 614 | ] 615 | }, 616 | "execution_count": 66, 617 | "metadata": {}, 618 | "output_type": "execute_result" 619 | } 620 | ], 621 | "source": [ 622 | "compute_capm(data, 'AMZN', '^GSPC')" 623 | ] 624 | }, 625 | { 626 | "cell_type": "code", 627 | "execution_count": 67, 628 | "metadata": {}, 629 | "outputs": [], 630 | "source": [ 631 | "def compute_sharpe(data, stock, market, riskfree = 0.025, riskpremium='market'):\n", 632 | " log_returns = np.log(data / data.shift(1))\n", 633 | " ret = compute_capm(data, stock, market, riskfree, riskpremium)\n", 634 | " return ((ret-riskfree)/(log_returns[stock].std()*250**0.5))" 635 | ] 636 | }, 637 | { 638 | "cell_type": "code", 639 | "execution_count": 68, 640 | "metadata": {}, 641 | "outputs": [ 642 | { 643 | "data": { 644 | "text/plain": [ 645 | "0.2159918670500646" 646 | ] 647 | }, 648 | "execution_count": 68, 649 | "metadata": {}, 650 | "output_type": "execute_result" 651 | } 652 | ], 653 | "source": [ 654 | "compute_sharpe(data, \"AMZN\",\"^GSPC\")" 655 | ] 656 | }, 657 | { 658 | "cell_type": "code", 659 | "execution_count": 41, 660 | "metadata": {}, 661 | "outputs": [], 662 | "source": [ 663 | "def stock_CAPM(stock_ticker, market_ticker, start_date = '2010-1-1', riskfree = 0.025, riskpremium = 'set'):\n", 664 | " data = import_stock_data([stock_ticker,market_ticker], start = start_date)\n", 665 | " beta = compute_beta(data, stock_ticker, market_ticker)\n", 666 | " capm = compute_capm(data, stock_ticker, market_ticker)\n", 667 | " sharpe = compute_sharpe(data, stock_ticker, market_ticker)\n", 668 | " #listcapm = [beta,capm,sharpe]\n", 669 | " capmdata = pd.DataFrame([beta,capm,sharpe], columns=[stock_ticker], index=['Beta','Return','Sharpe'])\n", 670 | " return capmdata.T" 671 | ] 672 | }, 673 | { 674 | "cell_type": "code", 675 | "execution_count": 42, 676 | "metadata": {}, 677 | "outputs": [ 678 | { 679 | "data": { 680 | "text/html": [ 681 | "
\n", 682 | "\n", 695 | "\n", 696 | " \n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | "
BetaReturnSharpe
AAPL1.0465390.0773270.189984
\n", 713 | "
" 714 | ], 715 | "text/plain": [ 716 | " Beta Return Sharpe\n", 717 | "AAPL 1.046539 0.077327 0.189984" 718 | ] 719 | }, 720 | "execution_count": 42, 721 | "metadata": {}, 722 | "output_type": "execute_result" 723 | } 724 | ], 725 | "source": [ 726 | "stock_CAPM(\"AAPL\",\"^GSPC\")" 727 | ] 728 | }, 729 | { 730 | "cell_type": "markdown", 731 | "metadata": {}, 732 | "source": [ 733 | "Let's give it a go with a different stock. NVIDIA!" 734 | ] 735 | }, 736 | { 737 | "cell_type": "code", 738 | "execution_count": 20, 739 | "metadata": {}, 740 | "outputs": [ 741 | { 742 | "name": "stdout", 743 | "output_type": "stream", 744 | "text": [ 745 | "Beta: 1.5861\n", 746 | "CAPM Expected Return: 0.1043\n", 747 | "Sharpe Ratio: 0.1308\n" 748 | ] 749 | } 750 | ], 751 | "source": [ 752 | "stock='NVDA'\n", 753 | "market='^GSPC'\n", 754 | "data = import_stock_data([stock,market], start = '2000-1-1')\n", 755 | "print(f\"Beta: {round(compute_beta(data,stock,market),4)}\")\n", 756 | "print(f\"CAPM Expected Return: {round(compute_capm(data, stock, market),4)}\")\n", 757 | "print(f\"Sharpe Ratio: {round(compute_sharpe(data, stock, market),4)}\")" 758 | ] 759 | } 760 | ], 761 | "metadata": { 762 | "kernelspec": { 763 | "display_name": "Python 3", 764 | "language": "python", 765 | "name": "python3" 766 | }, 767 | "language_info": { 768 | "codemirror_mode": { 769 | "name": "ipython", 770 | "version": 3 771 | }, 772 | "file_extension": ".py", 773 | "mimetype": "text/x-python", 774 | "name": "python", 775 | "nbconvert_exporter": "python", 776 | "pygments_lexer": "ipython3", 777 | "version": "3.7.4" 778 | } 779 | }, 780 | "nbformat": 4, 781 | "nbformat_minor": 2 782 | } 783 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ___ 2 | 3 | 4 | # Finance with Python 5 | 6 | ___ 7 |

by Elias Melul, Data Scientist

8 | 9 | ___ 10 | 11 | # Table of Contents 12 | 13 | In this repository, I will include: 14 | 15 | 1. Introduction to CAPM, Beta and Sharpe Ratio 16 | 2. Introduction to Monte-Carlo Simulations 17 | 3. Portfolio Optimization 18 | 4. Predicting Stock Prices: Monte Carlo Simulations Automated (coded to an easy-to-use function) 19 | 5. Predicting Stock Prices: Monte Carlo Simulations with Cholesky Decomposition (as a means to correlate returns) 20 | 6. Predicting Stock Prices: Monte Carlo Simulations with Cholesky Automated (coded to an easy-to-use function) 21 | 7. Introduction to Time Series: ETS, EWMA, ARIMA, ACF, PACF 22 | 7. Momentum Metrics: Relative Strength Index and MACD 23 | 8. Predicting Option Prices: Introduction to Black-Scholes-Merton 24 | 9. Predicting Option Prices: Monte Carlo Simulations with Euler Discretization 25 | 10. Introduction to Quantopian 26 | 27 | ## Capital Asset Pricing Model 28 | The CAPM model describes the relationship between expected returns and volatility (systematic risk). Why does this matter? Because investors expect to be compensated for risk and time value of money. So the CAPM is used as a theoretical model that adjusts for risk when evaluating the value of a stock. 29 | 30 | This model assumes the existance of a market portfolio - all possible investments in the world combined - hence the existance of a risk-free asset. However, this is not true. It also assumes that all investors are rational, and therefore hold the optimal portfolio. This is in consequence of the mutual fund theorem: _all investors hold the same portfolio of risky assets, the tangency portfolio_. Therefore, the CAPM assumes that the tangency portfolio is the market portfolio. Again... not necessarily true. However, the model is great for understanding and conceptualizing the intricacies of risk in investing and the concept of diversification, so let's continue. 31 | 32 | In this context, the tangency portfolio is the portfolio with the largest Sharpe Ratio. But what is the _Sharpe Ratio?_ 33 | 34 | 35 | **Sharpe Ratio**: measures the performance of a security compared to a risk-free asset, after adjusting for its risk. This is the excess return per unit of risk of an investment. 36 | 37 | sharpe 38 | 39 | When Sharpe > 1, GOOD risk-adjusted returns 40 | 41 | When Sharpe > 2, VERY GOOD risk-adjusted returns 42 | 43 | When Sharpe > 3, EXCELLENT risk-adjusted returns 44 | 45 | 46 | _How do we measure risk?_ There are many ways to measure risk, although variance (standard deviation) is one of the most common. However, when it comes to the risk that cannot be avoided through diversification, the Beta is king! 47 | 48 | **Beta**: measures the market risk that cannot be avoided through diversification. This is the relationship between the stock and the market portfolio. In other words, it is a measure of how much risk the investment will add to a portfolio that looks like the market. 49 | 50 | beta 51 | 52 | When beta = 0, it means that there's no relationship. 53 | 54 | When beta < 1, it means that the stock is defensive (less prone to high highs and low lows) 55 | 56 | When beta > 1, it means that the stock is aggresive (more prone to high highs and low lows) 57 | 58 | Amazing! We're only one small step away. The risk-adjusted returns. 59 | 60 | **Expected Return CAPM**: calculates the expected return of a security adjusted to the risk taken. This equates to the return expected from taking the extra risk of purchasing this security. 61 | 62 | return 63 | 64 | Awesome! There are a couple more things we will discuss later, but for now, now that we understand the underlying theory of the CAPM model, let's get coding! 65 | 66 | ``` 67 | # Import libraries 68 | import numpy as np 69 | import pandas as pd 70 | from pandas_datareader import data as wb 71 | 72 | # Load stock and market data 73 | tickers = ['AMZN','^GSPC'] 74 | data = pd.DataFrame() 75 | for t in tickers: 76 | data[t] = wb.DataReader(t, data_source='yahoo', start='2010-1-1')['Adj Close'] 77 | 78 | #Calculate logarithmic daily returns 79 | sec_returns = np.log(data / data.shift(1)) 80 | 81 | # To calculate the beta, we need the covariance between the specific stock and the market... 82 | cov = sec_returns.cov() *252 #Annualize by multiplying by 252 (trading days in a year) 83 | cov_with_market = cov.iloc[0,1] 84 | # ...we also need the variance of the daily returns of the market 85 | market_var = sec_returns['^GSPC'].var()*252 86 | 87 | # Calculate Beta 88 | amazon_beta = cov_with_market / market_var 89 | ``` 90 | 91 | Before calculating the expected risk-adjusted return, we must clarify a couple assumptions: 92 | 1. A 10 year US government bond is a good proxy for a risk-free asset, with a yield of 2.5% 93 | 2. The common risk premium is between 4.5% and 5.5%, so we will use 5%. Risk premium is the expected return of the market minus the risk-free return. 94 | 95 | ``` 96 | riskfree = 0.025 97 | riskpremium = 0.05 98 | amazon_capm_return = riskfree + amazon_beta*riskpremium 99 | ``` 100 | This yields an annualized risk-adjusted return of 7.52% (as per May 23rd 2020). Let's try the same procedure with the arithmetic mean of the returns of the market, instead of assuming a risk premium of 5%. 101 | 102 | ``` 103 | riskfree = 0.025 104 | riskpremium = (sec_returns['^GSPC'].mean()*252) - riskfree 105 | amazon_capm_return = riskfree + amazon_beta*riskpremium 106 | ``` 107 | This yields a 9.26% return - a considerable significant change. 108 | 109 | Last but not least, the Sharpe Ratio! 110 | ``` 111 | log_returns = np.log(data / data.shift(1)) 112 | sharpe_amazon = (amazon_capm_return-riskfree)/(log_returns['AMZN'].std()*250**0.5) 113 | ``` 114 | 115 | Great! Now that we have demonstrated how to compute the metrics derived from the CAPM, let's make it into a convenient way of using it. 116 | 117 | ``` 118 | from datetime import datetime 119 | #Import the data of any stock of set of stocks 120 | def import_stock_data(tickers, start = '2010-1-1', end = datetime.today().strftime('%Y-%m-%d')): 121 | data = pd.DataFrame() 122 | if len([tickers]) ==1: 123 | data[tickers] = wb.DataReader(tickers, data_source='yahoo', start = start)['Adj Close'] 124 | data = pd.DataFrame(data) 125 | else: 126 | for t in tickers: 127 | data[t] = wb.DataReader(t, data_source='yahoo', start = start)['Adj Close'] 128 | return(data) 129 | 130 | # Compute beta function 131 | def compute_beta(data, stock, market): 132 | log_returns = np.log(data / data.shift(1)) 133 | cov = log_returns.cov()*250 134 | cov_w_market = cov.loc[stock,market] 135 | market_var = log_returns[market].var()*250 136 | return cov_w_market/market_var 137 | 138 | #Compute risk adjusted return function 139 | def compute_capm(data, stock, market, riskfree = 0.025, riskpremium = 'market'): 140 | log_returns = np.log(data / data.shift(1)) 141 | if riskpremium == 'market': 142 | riskpremium = (log_returns[market].mean()*252) - riskfree 143 | beta = compute_beta(data, stock, market) 144 | return (riskfree + (beta*riskpremium)) 145 | 146 | #Compute Sharpe Ratio 147 | def compute_sharpe(data, stock, market, riskfree = 0.025, riskpremium='market'): 148 | log_returns = np.log(data / data.shift(1)) 149 | ret = compute_capm(data, stock, market, riskfree, riskpremium) 150 | return ((ret-riskfree)/(log_returns[stock].std()*250**0.5)) 151 | 152 | # All in one function 153 | def stock_CAPM(stock_ticker, market_ticker, start_date = '2010-1-1', riskfree = 0.025, riskpremium = 'set'): 154 | data = import_stock_data([stock_ticker,market_ticker], start = start_date) 155 | beta = compute_beta(data, stock_ticker, market_ticker) 156 | capm = compute_capm(data, stock_ticker, market_ticker) 157 | sharpe = compute_sharpe(data, stock_ticker, market_ticker) 158 | #listcapm = [beta,capm,sharpe] 159 | capmdata = pd.DataFrame([beta,capm,sharpe], columns=[stock_ticker], index=['Beta','Return','Sharpe']) 160 | return capmdata.T 161 | 162 | stock_CAPM("AAPL","^GSPC") 163 | ``` 164 | aapl 165 | 166 | ## Monte Carlo Simulations 167 | Monte Carlo Simulations are an incredibly powerful tool in numerous contexts, including operations research, game theory, physics, business and finance, among others. It is a technique used to understand the impact of risk and uncertainty when making a decision. Simply put, a Monte Carlo simulation runs an enourmous amount of trials with different random numbers generated from an underlying distribution for the uncertain variables. 168 | 169 | Here, we will dive into how to predict stock prices using a Monte Carlo simulation! 170 | 171 | **What do we need to understand before we start?** 172 | 173 | aapl 174 | 175 | 176 | * We know yesterday's price. 177 | 178 | * We want to predict today's price. 179 | 180 | * What we do not know is the rate of return, r, of the share price between yesterday and today. 181 | 182 | This is where the Monte Carlo simulation comes in! But first, how do we compute the return? 183 | 184 | ### Brownian Motion 185 | 186 | Brownian motion will be the main driver for estimating the return. It is a stochastic process used for modeling random behavior over time. For simplicity, we will use regular brownian motion, instead of the Geometric Brownian Motion, which is more common and less questionable in stock pricing applications. 187 | 188 | **Brownian Motion** has two main main components: 189 | 1. Drift - the direction that rates of returns have had in the past. That is, the expected return of the stock. 190 | 191 | drift 192 | Why do we multiply the variance by 0.5? Because historical values are eroded in the future. 193 | 194 | 195 | 2. Volatility - random variable. This is the historical volatility multiplied by a random, standard normally distributed variable. 196 | 197 | Volatility 198 | 199 | Therefore, our asset pricing equation ends up looking like this: 200 | 201 | Pricing-Eq 202 | 203 | 204 | This technique will be used for every day into the future you want to predict, and for however many trials the monte carlo simulation will run! 205 | 206 | --- 207 | 208 | First, import required libraries. 209 | ``` 210 | #Import libraries 211 | import numpy as np 212 | import pandas as pd 213 | from pandas_datareader import data as wb 214 | import matplotlib.pyplot as plt 215 | from scipy.stats import norm, gmean, cauchy 216 | import seaborn as sns 217 | from datetime import datetime 218 | 219 | %matplotlib inline 220 | ``` 221 | Import data for one or multiple stocks from a specified date until the last available data. Data source: yahoo finance. 222 | 223 | For this, it's better if we define a function that imports stock(s) daily data for any publicly traded company as defined by the user starting at a user-defined date until today. We will use the Adjusted Close price. We will continue using Amazon as a running example. 224 | 225 | ``` 226 | #Import stock data function 227 | ticker = 'AMZN' 228 | data = pd.DataFrame() 229 | data[ticker] = wb.DataReader(ticker, data_source='yahoo', start='2010-1-1')['Adj Close'] 230 | data.head() 231 | 232 | #Compute log or simple returns 233 | def log_returns(data): 234 | return (np.log(1+data.pct_change())) 235 | 236 | def simple_returns(data): 237 | return ((data/data.shift(1))-1) 238 | 239 | log_return = log_returns(data) 240 | 241 | #Plot returns histogram for AMZN 242 | sns.distplot(log_returns.iloc[1:]) 243 | plt.xlabel("Daily Return") 244 | plt.ylabel("Frequency") 245 | ``` 246 | AMZNREts 247 | 248 | ``` 249 | data.plot(figsize=(15,6)) 250 | ``` 251 | AMZNStock 252 | 253 | Great! Next, we have to calculate the Brownian Motion with randomly generated returns. 254 | ``` 255 | #Calculate the Drift 256 | u = log_returns.mean() 257 | var = log_returns.var() 258 | drift = u - (0.5*var) 259 | ``` 260 | Before we generate the variable portion of the generated returns, I'll show you how to generate uncorrelated random daily returns. Note that correlated returns are very valuable when discussing derivates that are based on an underlying basket of assets. We will discuss the Cholesky Decomposition method in a later. 261 | ``` 262 | #Returns random variables between 0 and 1 263 | x = np.random.rand(10,2) 264 | 265 | #Percent Point Function - the inverse of a CDF 266 | norm.ppf(x) 267 | ``` 268 | Using these, we can generate random returns. For example, we can run 1,000 iterations of random walks consisting of 50 steps (days). Now we can generate the variable part of the Brownian Motion. 269 | ``` 270 | #Calculate standard deviation of returns 271 | stddev = log_returns.std() 272 | #Calculate expected daily returns for all of the iterations 273 | daily_returns = np.exp(drift.values + stddev.values * norm.ppf(np.random.rand(50,1000))) 274 | ``` 275 | So close! Now that we have randomly generated 50 random returns for every one of the ten thousand trials, all we need is to calculate the price path for each of the trials! 276 | ``` 277 | # Create matrix with same size as daily returns matrix 278 | price_list = np.zeros_like(daily_returns) 279 | 280 | # Introduce the last known price for the stock in the first item of every iteration - ie Day 0 for every trial in the simulation 281 | price_list[0] = data.iloc[-1] 282 | 283 | # Run a loop to calculate the price today for every simulation based on the daily returns generated 284 | for t in range(1,50): 285 | price_list[t] = price_list[t-1]*daily_returns[t] 286 | ``` 287 | Voila! We have officially finished the Monte Carlo simulation to predict stock prices. Let's see how it looks! 288 | 289 | The first 30 simulations: 290 | 291 | amazonpred 292 | 293 | The histogram of the final prices for each simulation: 294 | 295 | Amznpredhist 296 | 297 | With these predictions, we can now calcualte Value at Risk, or simply the probability of a certain event occuring and the expected annualized return. We will do this once we create automated versions of this process that can handle multiple stocks and reports certain metrics, included the aforementioned and other CAPM metrics! 298 | 299 | But first, let's create a Monte Carlo simulation that returns some basic statistics with it and that is highly flexible! 300 | 301 | ## Monte Carlo Simulation Easy-to-Use Functions 302 | 303 | We first import the required libraries 304 | ``` 305 | import numpy as np 306 | import pandas as pd 307 | from pandas_datareader import data as wb 308 | import matplotlib.pyplot as plt 309 | from scipy.stats import norm, gmean, cauchy 310 | import seaborn as sns 311 | from datetime import datetime 312 | 313 | %matplotlib inline 314 | ``` 315 | Then we create the functions for: 316 | 1. Import stock data 317 | 2. Compute log or simple returns of stocks 318 | 3. Append market data (default S&P) with the imported stock data 319 | 4. Compute the CAPM metrics: Beta, Standard Deviation, Risk-adjusted return, and Sharpe Ratio 320 | 5. Compute Drift - Brownian Motion 321 | 6. Generate Daily Returns - Brownian Motion - for all simulations 322 | 7. Probability Function - computes rpobability of something happening 323 | 324 | ``` 325 | def import_stock_data(tickers, start = '2010-1-1', end = datetime.today().strftime('%Y-%m-%d')): 326 | data = pd.DataFrame() 327 | if len([tickers]) ==1: 328 | data[tickers] = wb.DataReader(tickers, data_source='yahoo', start = start)['Adj Close'] 329 | data = pd.DataFrame(data) 330 | else: 331 | for t in tickers: 332 | data[t] = wb.DataReader(t, data_source='yahoo', start = start)['Adj Close'] 333 | return(data) 334 | 335 | def log_returns(data): 336 | return (np.log(1+data.pct_change())) 337 | def simple_returns(data): 338 | return ((data/data.shift(1))-1) 339 | 340 | def market_data_combination(data, mark_ticker = "^GSPC", start='2010-1-1'): 341 | market_data = import_stock_data(mark_ticker, start) 342 | market_rets = log_returns(market_data).dropna() 343 | ann_return = np.exp(market_rets.mean()*252).values-1 344 | data = data.merge(market_data, left_index=True, right_index=True) 345 | return data, ann_return 346 | 347 | def beta_sharpe(data, mark_ticker = "^GSPC", start='2010-1-1', riskfree = 0.025): 348 | 349 | """ 350 | Input: 351 | 1. data: dataframe of stock price data 352 | 2. mark_ticker: ticker of the market data you want to compute CAPM metrics with (default is ^GSPC) 353 | 3. start: data from which to download data (default Jan 1st 2010) 354 | 4. riskfree: the assumed risk free yield (US 10 Year Bond is assumed: 2.5%) 355 | 356 | Output: 357 | 1. Dataframe with CAPM metrics computed against specified market procy 358 | """ 359 | # Beta 360 | dd, mark_ret = market_data_combination(data, mark_ticker, start) 361 | log_ret = log_returns(dd) 362 | covar = log_ret.cov()*252 363 | covar = pd.DataFrame(covar.iloc[:-1,-1]) 364 | mrk_var = log_ret.iloc[:,-1].var()*252 365 | beta = covar/mrk_var 366 | 367 | stdev_ret = pd.DataFrame(((log_ret.std()*250**0.5)[:-1]), columns=['STD']) 368 | beta = beta.merge(stdev_ret, left_index=True, right_index=True) 369 | 370 | # CAPM 371 | for i, row in beta.iterrows(): 372 | beta.at[i,'CAPM'] = riskfree + (row[mark_ticker] * (mark_ret-riskfree)) 373 | # Sharpe 374 | for i, row in beta.iterrows(): 375 | beta.at[i,'Sharpe'] = ((row['CAPM']-riskfree)/(row['STD'])) 376 | beta.rename(columns={"^GSPC":"Beta"}, inplace=True) 377 | 378 | return beta 379 | 380 | def drift_calc(data, return_type='log'): 381 | if return_type=='log': 382 | lr = log_returns(data) 383 | elif return_type=='simple': 384 | lr = simple_returns(data) 385 | u = lr.mean() 386 | var = lr.var() 387 | drift = u-(0.5*var) 388 | try: 389 | return drift.values 390 | except: 391 | return drift 392 | 393 | def daily_returns(data, days, iterations, return_type='log'): 394 | ft = drift_calc(data, return_type) 395 | if return_type == 'log': 396 | try: 397 | stv = log_returns(data).std().values 398 | except: 399 | stv = log_returns(data).std() 400 | elif return_type=='simple': 401 | try: 402 | stv = simple_returns(data).std().values 403 | except: 404 | stv = simple_returns(data).std() 405 | #Oftentimes, we find that the distribution of returns is a variation of the normal distribution where it has a fat tail 406 | # This distribution is called cauchy distribution 407 | dr = np.exp(ft + stv * norm.ppf(np.random.rand(days, iterations))) 408 | return dr 409 | 410 | def probs_find(predicted, higherthan, ticker = None, on = 'value'): 411 | """ 412 | This function calculated the probability of a stock being above a certain threshhold, which can be defined as a value (final stock price) or return rate (percentage change) 413 | Input: 414 | 1. predicted: dataframe with all the predicted prices (days and simulations) 415 | 2. higherthan: specified threshhold to which compute the probability (ex. 0 on return will compute the probability of at least breakeven) 416 | 3. on: 'return' or 'value', the return of the stock or the final value of stock for every simulation over the time specified 417 | 4. ticker: specific ticker to compute probability for 418 | """ 419 | if ticker == None: 420 | if on == 'return': 421 | predicted0 = predicted.iloc[0,0] 422 | predicted = predicted.iloc[-1] 423 | predList = list(predicted) 424 | over = [(i*100)/predicted0 for i in predList if ((i-predicted0)*100)/predicted0 >= higherthan] 425 | less = [(i*100)/predicted0 for i in predList if ((i-predicted0)*100)/predicted0 < higherthan] 426 | elif on == 'value': 427 | predicted = predicted.iloc[-1] 428 | predList = list(predicted) 429 | over = [i for i in predList if i >= higherthan] 430 | less = [i for i in predList if i < higherthan] 431 | else: 432 | print("'on' must be either value or return") 433 | else: 434 | if on == 'return': 435 | predicted = predicted[predicted['ticker'] == ticker] 436 | predicted0 = predicted.iloc[0,0] 437 | predicted = predicted.iloc[-1] 438 | predList = list(predicted) 439 | over = [(i*100)/predicted0 for i in predList if ((i-predicted0)*100)/predicted0 >= higherthan] 440 | less = [(i*100)/predicted0 for i in predList if ((i-predicted0)*100)/predicted0 < higherthan] 441 | elif on == 'value': 442 | predicted = predicted.iloc[-1] 443 | predList = list(predicted) 444 | over = [i for i in predList if i >= higherthan] 445 | less = [i for i in predList if i < higherthan] 446 | else: 447 | print("'on' must be either value or return") 448 | return (len(over)/(len(over)+len(less))) 449 | ``` 450 | Great! With all these functions we can create yet antoher function that does a Monte Carlo simulation for each stock. 451 | 452 | How does it work? 453 | 454 | 1. Calculate the daily returns for every day and every iteration (simulation) of the data. 455 | 2. Creates an equally large matrix of size [days x iteration] full of zeroes. 456 | 3. Input the last stock price value in the first row (day 0) of the "empty" matrix (part 2). This is our starting point. 457 | 4. Calculate "today's price" based on yesterday's multiplied by the daily return generated. That is, multiply the daily return generated for every simulation with the stock price calculated for the previous day (the previous row) for every simulation. 458 | 459 | Does that sounds familiar? The fourth step multiplies the daily returns with the price of the stock of the previous day! 460 | 461 | ``` 462 | def simulate_mc(data, days, iterations, return_type='log', plot=True): 463 | # Generate daily returns 464 | returns = daily_returns(data, days, iterations, return_type) 465 | # Create empty matrix 466 | price_list = np.zeros_like(returns) 467 | # Put the last actual price in the first row of matrix. 468 | price_list[0] = data.iloc[-1] 469 | # Calculate the price of each day 470 | for t in range(1,days): 471 | price_list[t] = price_list[t-1]*returns[t] 472 | 473 | # Plot Option 474 | if plot == True: 475 | x = pd.DataFrame(price_list).iloc[-1] 476 | fig, ax = plt.subplots(1,2, figsize=(14,4)) 477 | sns.distplot(x, ax=ax[0]) 478 | sns.distplot(x, hist_kws={'cumulative':True},kde_kws={'cumulative':True},ax=ax[1]) 479 | plt.xlabel("Stock Price") 480 | plt.show() 481 | 482 | #CAPM and Sharpe Ratio 483 | 484 | # Printing information about stock 485 | try: 486 | [print(nam) for nam in data.columns] 487 | except: 488 | print(data.name) 489 | print(f"Days: {days-1}") 490 | print(f"Expected Value: ${round(pd.DataFrame(price_list).iloc[-1].mean(),2)}") 491 | print(f"Return: {round(100*(pd.DataFrame(price_list).iloc[-1].mean()-price_list[0,1])/pd.DataFrame(price_list).iloc[-1].mean(),2)}%") 492 | print(f"Probability of Breakeven: {probs_find(pd.DataFrame(price_list),0, on='return')}") 493 | 494 | 495 | return pd.DataFrame(price_list) 496 | 497 | simulate_mc(data, 252, 1000, 'log') 498 | ``` 499 | 500 | Now, let's loop through all the stated securities and generate the visualizations and statistics that will help us understand the expected performance of a stock. 501 | 502 | ``` 503 | def monte_carlo(tickers, days_forecast, iterations, start_date = '2000-1-1', return_type = 'log', plotten=False): 504 | data = import_stock_data(tickers, start=start_date) 505 | inform = beta_sharpe(data, mark_ticker="^GSPC", start=start_date) 506 | simulatedDF = [] 507 | for t in range(len(tickers)): 508 | y = simulate_mc(data.iloc[:,t], (days_forecast+1), iterations, return_type) 509 | if plotten == True: 510 | forplot = y.iloc[:,0:10] 511 | forplot.plot(figsize=(15,4)) 512 | print(f"Beta: {round(inform.iloc[t,inform.columns.get_loc('Beta')],2)}") 513 | print(f"Sharpe: {round(inform.iloc[t,inform.columns.get_loc('Sharpe')],2)}") 514 | print(f"CAPM Return: {round(100*inform.iloc[t,inform.columns.get_loc('CAPM')],2)}%") 515 | y['ticker'] = tickers[t] 516 | cols = y.columns.tolist() 517 | cols = cols[-1:] + cols[:-1] 518 | y = y[cols] 519 | simulatedDF.append(y) 520 | simulatedDF = pd.concat(simulatedDF) 521 | return simulatedDF 522 | 523 | start = "2015-1-1" 524 | days_to_forecast= 252 525 | simulation_trials= 10000 526 | ret_sim_df = monte_carlo(['GOOG','AAPL'], days_to_forecast, simulation_trials, start_date=start, plotten=False) 527 | ``` 528 | imgsim 529 | 530 | Now, we can do Monte Carlo simulations on individual stocks, assuming they are uncorrelated. But usually, people don't choose between stocks A or B. Investors have to choose from an sea of stocks and other possible securities they can invest in! Investors target to maximize returns while avoiding risk, and one way an investor can do that is by diversifying their portfolio. Hence, the next two sections are: Portfolio Optimization theory and code, and Cholesky Decomposition to generate correlated returns. 531 | 532 | ## Portfolio Optimization 533 | To understand portfolio optimization, we must introduce Markowitz and the Efficient Frontier. 534 | 535 | The efficiency frontier is a set of optimal portfolios that offer the highest expected returns for a given volatility - ie risk. Hence, any portfolio that does not lie in the frontier, is suboptimal. This is because these portfolios could provide higher returns for the same amount of risk. 536 | 537 | Let's exemplify with the case of a portfolio that can only hold 2 stocks: 538 | 1. Microsoft (MSFT) 539 | 2. UnitedHealth (UNH) 540 | 541 | ``` 542 | import numpy as np 543 | import pandas as pd 544 | from pandas_datareader import data as wb 545 | import matplotlib.pyplot as plt 546 | %matplotlib inline 547 | 548 | assets = ['MSFT','UNH'] 549 | 550 | pf_data = pd.DataFrame() 551 | for t in assets: 552 | pf_data[t] = wb.DataReader(t, data_source='yahoo', start='2015-1-1')['Adj Close'] 553 | 554 | (pf_data / pf_data.iloc[0]*100).plot(figsize=(15,6)) 555 | ``` 556 | msftunh 557 | 558 | ``` 559 | log_returns = np.log(pf_data / pf_data.shift(1)) 560 | log_returns.mean()*250 561 | 562 | num_assets = len(assets) 563 | 564 | weights = np.random.random(num_assets) 565 | weights /= np.sum(weights) 566 | 567 | pfolio_returns = [] 568 | pfolio_volatilities = [] 569 | 570 | for x in range(1000): 571 | weights = np.random.random(num_assets) 572 | weights /= np.sum(weights) 573 | 574 | pfolio_returns.append(np.sum(weights*log_returns.mean())*252) 575 | pfolio_volatilities.append(np.sqrt(np.dot(weights.T, np.dot(log_returns.cov()*250, weights)))) 576 | 577 | pfolio_returns = np.array(pfolio_returns) 578 | pfolio_volatilities = np.array(pfolio_volatilities) 579 | 580 | portfolios = pd.DataFrame({'Return':pfolio_returns,'Volatility':pfolio_volatilities}) 581 | 582 | portfolios.plot(x='Volatility',y='Return', kind='scatter', figsize=(10,6)) 583 | #plt.axis([0,]) 584 | plt.xlabel('Expected Volatility') 585 | plt.ylabel('Expected Return') 586 | 587 | print(f"Expected Portfolio Return: {round(np.sum(weights * log_returns.mean())*252*100,2)}%") 588 | print(f"Expected Portfolio Variance: {round(100*np.dot(weights.T, np.dot(log_returns.cov() *252, weights)),2)}%") 589 | print(f"Expected Portfolio Volatility: {round(100*np.sqrt(np.dot(weights.T, np.dot(log_returns.cov()*252, weights))),2)}%") 590 | ``` 591 | efficientfrontier 592 | 593 | Expected Portfolio Return: 26.97% 594 | 595 | Expected Portfolio Variance: 6.78% 596 | 597 | Expected Portfolio Volatility: 26.03% 598 | 599 | The image above shows the efficient frontier, with each dot being a portfolio made of the two stocks. The difference between all portfolios is the weight of it attributed to each stock. As we can observe, for the same expected risk (volatility), there are different expected returns. If an investor targets a certain risk and is not on the part of the frontier than maximizes returns, the portfolio is suboptimal. 600 | 601 | Next we will leverage Monte Carlo simulations, to calculate the 602 | -------------------------------------------------------------------------------- /Multivariate MC.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 47, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import pandas as pd\n", 11 | "from pandas_datareader import data as wb\n", 12 | "import matplotlib.pyplot as plt\n", 13 | "from scipy.stats import norm, gmean, cauchy, multivariate_normal\n", 14 | "import seaborn as sns\n", 15 | "# import plotly as py\n", 16 | "# import plotly.graph_objs as go\n", 17 | "# import cufflinks\n", 18 | "# cufflinks.go_offline(connected=True)\n", 19 | "#init_notebook_mode(connected=True)\n", 20 | "\n", 21 | "%matplotlib inline" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 521, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "def import_stock_data(tickers, start = '2010-1-1'):\n", 31 | " data = pd.DataFrame()\n", 32 | " if len([tickers]) ==1:\n", 33 | " data[tickers] = wb.DataReader(tickers, data_source='yahoo', start = start)['Adj Close']\n", 34 | " data = pd.DataFrame(data)\n", 35 | " else:\n", 36 | " for t in tickers:\n", 37 | " data[t] = wb.DataReader(t, data_source='yahoo', start = start)['Adj Close']\n", 38 | " return(data)" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 687, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "data = import_stock_data([\"MSFT\",\"BAM\"])" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 688, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "data": { 57 | "text/html": [ 58 | "
\n", 59 | "\n", 72 | "\n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | "
MSFTBAM
Date
2020-05-08184.67999333.400002
2020-05-11186.74000533.669998
2020-05-12182.50999532.500000
2020-05-13179.75000031.000000
2020-05-14176.25000030.040001
\n", 113 | "
" 114 | ], 115 | "text/plain": [ 116 | " MSFT BAM\n", 117 | "Date \n", 118 | "2020-05-08 184.679993 33.400002\n", 119 | "2020-05-11 186.740005 33.669998\n", 120 | "2020-05-12 182.509995 32.500000\n", 121 | "2020-05-13 179.750000 31.000000\n", 122 | "2020-05-14 176.250000 30.040001" 123 | ] 124 | }, 125 | "execution_count": 688, 126 | "metadata": {}, 127 | "output_type": "execute_result" 128 | } 129 | ], 130 | "source": [ 131 | "data.tail()" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 689, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "def log_returns(data):\n", 141 | " return (np.log(1+data.pct_change()))" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 690, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "log_return = log_returns(data)" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 691, 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "def drift_calc(data, return_type='log'):\n", 160 | " if return_type=='log':\n", 161 | " lr = log_returns(data)\n", 162 | " elif return_type=='simple':\n", 163 | " lr = simple_returns(data)\n", 164 | " u = lr.mean()\n", 165 | " var = lr.var()\n", 166 | " drift = u-(0.5*var)\n", 167 | " try:\n", 168 | " return drift.values\n", 169 | " except:\n", 170 | " return drift" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": 692, 176 | "metadata": {}, 177 | "outputs": [ 178 | { 179 | "data": { 180 | "text/plain": [ 181 | "array([0.00063468, 0.00043409])" 182 | ] 183 | }, 184 | "execution_count": 692, 185 | "metadata": {}, 186 | "output_type": "execute_result" 187 | } 188 | ], 189 | "source": [ 190 | "drif = drift_calc(data)\n", 191 | "drif" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 693, 197 | "metadata": {}, 198 | "outputs": [ 199 | { 200 | "data": { 201 | "text/html": [ 202 | "
\n", 203 | "\n", 216 | "\n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | "
MSFTBAM
MSFT0.0002500.000135
BAM0.0001350.000250
\n", 237 | "
" 238 | ], 239 | "text/plain": [ 240 | " MSFT BAM\n", 241 | "MSFT 0.000250 0.000135\n", 242 | "BAM 0.000135 0.000250" 243 | ] 244 | }, 245 | "execution_count": 693, 246 | "metadata": {}, 247 | "output_type": "execute_result" 248 | } 249 | ], 250 | "source": [ 251 | "covi = log_return.cov()\n", 252 | "covi" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": 694, 258 | "metadata": {}, 259 | "outputs": [ 260 | { 261 | "data": { 262 | "text/plain": [ 263 | "array([[0.01582137, 0. ],\n", 264 | " [0.00855895, 0.01328055]])" 265 | ] 266 | }, 267 | "execution_count": 694, 268 | "metadata": {}, 269 | "output_type": "execute_result" 270 | } 271 | ], 272 | "source": [ 273 | "L = np.linalg.cholesky(covi)\n", 274 | "L" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 695, 280 | "metadata": {}, 281 | "outputs": [ 282 | { 283 | "data": { 284 | "text/plain": [ 285 | "array([[-0.63535887, 0.74412729],\n", 286 | " [-0.04965299, -1.12963893]])" 287 | ] 288 | }, 289 | "execution_count": 695, 290 | "metadata": {}, 291 | "output_type": "execute_result" 292 | } 293 | ], 294 | "source": [ 295 | "randi =norm.ppf(np.random.rand(2,2))\n", 296 | "randi" 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": 696, 302 | "metadata": {}, 303 | "outputs": [], 304 | "source": [ 305 | "V = L.dot(randi)" 306 | ] 307 | }, 308 | { 309 | "cell_type": "code", 310 | "execution_count": 697, 311 | "metadata": {}, 312 | "outputs": [ 313 | { 314 | "data": { 315 | "text/plain": [ 316 | "array([-0.00566333, -0.00819919])" 317 | ] 318 | }, 319 | "execution_count": 697, 320 | "metadata": {}, 321 | "output_type": "execute_result" 322 | } 323 | ], 324 | "source": [ 325 | "V[0]+drif[0]\n", 326 | "V[1]+drif[1]" 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": 698, 332 | "metadata": {}, 333 | "outputs": [], 334 | "source": [ 335 | "def daily_returns(data, days, iterations, return_type='log'):\n", 336 | " ft = drift_calc(data, return_type)\n", 337 | " if return_type == 'log':\n", 338 | " try:\n", 339 | " stv = log_returns(data).std().values\n", 340 | " except:\n", 341 | " stv = log_returns(data).std()\n", 342 | " elif return_type=='simple':\n", 343 | " try:\n", 344 | " stv = simple_returns(data).std().values\n", 345 | " except:\n", 346 | " stv = simple_returns(data).std() \n", 347 | " covall = log_return.cov()\n", 348 | " chol = np.linalg.cholesky(covall)\n", 349 | " numstocks = len(data.columns)\n", 350 | " \n", 351 | " randim = norm.ppf(np.random.rand(days,numstocks,iterations))\n", 352 | " V = chol.dot(randim)\n", 353 | " \n", 354 | " stocks = []\n", 355 | " for s in range(numstocks):\n", 356 | " dr = np.exp(ft[s] + stv[s] * V[s])\n", 357 | " stocks.append(dr)\n", 358 | " return stocks" 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": 699, 364 | "metadata": {}, 365 | "outputs": [ 366 | { 367 | "data": { 368 | "text/plain": [ 369 | "[array([[1.00063095, 1.00042563, 1.00072601, ..., 1.00085974, 1.00013756,\n", 370 | " 1.00073716],\n", 371 | " [1.0005216 , 1.00103468, 1.00027371, ..., 1.00036319, 1.0006482 ,\n", 372 | " 1.00067034],\n", 373 | " [1.00050731, 1.0005184 , 1.0005587 , ..., 1.00076939, 1.00073355,\n", 374 | " 1.00123768],\n", 375 | " ...,\n", 376 | " [1.00097811, 1.00066512, 1.00064245, ..., 1.00084161, 1.00036875,\n", 377 | " 1.00064948],\n", 378 | " [1.00090632, 1.00017733, 1.00037685, ..., 1.0009542 , 1.00096629,\n", 379 | " 1.00024594],\n", 380 | " [1.00066723, 1.00019856, 1.00040366, ..., 1.00073135, 1.00061282,\n", 381 | " 1.00045776]]),\n", 382 | " array([[1.00059664, 1.00050136, 1.0006171 , ..., 1.0006403 , 1.00021676,\n", 383 | " 1.0006405 ],\n", 384 | " [1.00029186, 1.00083392, 0.99995482, ..., 1.00037867, 1.00024418,\n", 385 | " 1.00033445],\n", 386 | " [1.00010908, 1.0006944 , 1.00068495, ..., 1.00066815, 1.00043831,\n", 387 | " 1.00064332],\n", 388 | " ...,\n", 389 | " [1.00066348, 1.00063742, 1.00033304, ..., 1.00102092, 1.00008157,\n", 390 | " 1.00038373],\n", 391 | " [1.00077437, 0.99970512, 1.00016482, ..., 1.00059864, 1.00070681,\n", 392 | " 1.00036813],\n", 393 | " [1.00067395, 1.00013839, 1.00044939, ..., 1.00008544, 1.00081371,\n", 394 | " 1.00049692]])]" 395 | ] 396 | }, 397 | "execution_count": 699, 398 | "metadata": {}, 399 | "output_type": "execute_result" 400 | } 401 | ], 402 | "source": [ 403 | "xxx = daily_returns(data, days = 250, iterations = 10)\n", 404 | "xxx" 405 | ] 406 | }, 407 | { 408 | "cell_type": "code", 409 | "execution_count": 812, 410 | "metadata": {}, 411 | "outputs": [], 412 | "source": [ 413 | "def daily_returns(data, days, iterations, return_type='log'):\n", 414 | " ft = drift_calc(data, return_type)\n", 415 | " if return_type == 'log':\n", 416 | " try:\n", 417 | " stv = log_returns(data).std().values\n", 418 | " except:\n", 419 | " stv = log_returns(data).std()\n", 420 | " elif return_type=='simple':\n", 421 | " try:\n", 422 | " stv = simple_returns(data).std().values\n", 423 | " except:\n", 424 | " stv = simple_returns(data).std() \n", 425 | " \n", 426 | " numstocks = len(data.columns)\n", 427 | " \n", 428 | " covall = log_return.cov()\n", 429 | " chol = np.linalg.cholesky(covall)\n", 430 | " \n", 431 | "# totals = []\n", 432 | "# for d in range(days):\n", 433 | "# uncorr_x = np.random.normal(0,1,(numstocks,iterations))\n", 434 | "# corr_x = np.dot(chol,uncorr_x)\n", 435 | "# df = pd.DataFrame(corr_x[0]).T\n", 436 | "# totals.append(df)\n", 437 | " #print(corr_x[0])\n", 438 | " simstock = np.zeros_like(5)\n", 439 | " for d in range(days):\n", 440 | " uncorr_x = np.random.normal(0,1,(2,5))\n", 441 | " corr_x = np.dot(chol,uncorr_x)\n", 442 | " row = (corr_x[0]).transpose()\n", 443 | " simstock = simstock+row\n", 444 | " print(row)\n", 445 | " \n", 446 | "# randim = norm.ppf(np.random.rand(days,numstocks,iterations))\n", 447 | "# V = chol.dot(randim)\n", 448 | " \n", 449 | "# stocks = []\n", 450 | "# for s in range(numstocks):\n", 451 | "# dr = np.exp(ft[s] + stv[s] * V[s])\n", 452 | "# stocks.append(dr)\n", 453 | "# return pd.DataFrame(totals)" 454 | ] 455 | }, 456 | { 457 | "cell_type": "code", 458 | "execution_count": 813, 459 | "metadata": {}, 460 | "outputs": [ 461 | { 462 | "name": "stdout", 463 | "output_type": "stream", 464 | "text": [ 465 | "[-0.02798762 0.00095786 -0.00286049 0.01195356 0.01390655]\n", 466 | "[ 0.00183776 0.00287248 0.00752141 -0.0081006 -0.0092608 ]\n", 467 | "[-0.00685823 0.01189147 -0.03323479 -0.00680896 -0.0271409 ]\n", 468 | "[ 0.02310806 0.00497634 -0.00284405 -0.01411448 0.00114843]\n", 469 | "[ 0.01385737 -0.00391318 0.00827926 0.02361273 0.01237567]\n", 470 | "[-0.00228244 0.0008686 -0.00014131 0.00983564 -0.00332632]\n", 471 | "[ 0.00528386 0.00290303 -0.00445274 -0.00784282 0.01310952]\n", 472 | "[-0.03828386 0.01942595 -0.01807462 0.00093317 0.00024271]\n", 473 | "[0.0039186 0.00558545 0.00895796 0.05409972 0.01540161]\n", 474 | "[-0.00114879 0.02167204 -0.01712268 -0.00415929 0.00804233]\n", 475 | "[-0.00593376 -0.02069442 0.02082081 -0.01392585 -0.02519956]\n", 476 | "[-0.01270916 -0.01686727 0.01219254 -0.00291816 -0.01472463]\n", 477 | "[ 0.00227085 0.0018318 -0.00361256 -0.01019478 -0.00954079]\n", 478 | "[ 3.35089373e-04 -9.97839035e-03 1.21668666e-02 2.65728287e-02\n", 479 | " 7.20339085e-05]\n", 480 | "[ 0.02617279 -0.01735791 0.00396194 0.01219799 -0.00223278]\n", 481 | "[ 0.00758806 -0.00928369 0.01415692 -0.02140927 -0.01353105]\n", 482 | "[-0.00736759 -0.01141806 -0.00779247 0.00320235 0.00761884]\n", 483 | "[-0.01858403 -0.01089678 0.00528897 -0.0059215 0.0041481 ]\n", 484 | "[-0.01180983 -0.02331269 -0.02223826 0.00754872 -0.00482577]\n", 485 | "[-0.00134492 -0.00451383 0.00115834 0.01274606 -0.00261823]\n", 486 | "[ 1.29906576e-02 -1.03014432e-02 -5.31251809e-03 -2.16241927e-05\n", 487 | " -2.53497405e-03]\n", 488 | "[-0.00273979 0.02285495 -0.00836981 0.00714722 0.01995172]\n", 489 | "[ 0.01193405 -0.01762388 -0.03589069 -0.00706878 0.01301784]\n", 490 | "[-0.01138343 0.0109919 0.00912598 0.01896028 0.00908519]\n", 491 | "[-0.01795239 -0.00425007 -0.00370694 -0.01133471 0.01351071]\n", 492 | "[-0.0076983 -0.01221957 -0.00494052 0.03166954 -0.0158883 ]\n", 493 | "[-0.00863462 -0.00772928 0.01046597 -0.01721129 -0.02025852]\n", 494 | "[ 0.02804326 -0.02808818 -0.00185048 -0.02276821 -0.00673162]\n", 495 | "[-0.00505532 -0.00280102 -0.00411059 -0.01288772 -0.00365187]\n", 496 | "[ 0.01586609 -0.01732991 0.00326761 -0.02744397 -0.00492621]\n", 497 | "[-0.02513908 -0.00138776 -0.00498426 0.01094022 0.01427483]\n", 498 | "[-0.02243289 -0.00758825 0.03582429 -0.00961185 0.0073056 ]\n", 499 | "[ 0.00894166 0.00866576 -0.01042887 0.00744595 -0.02522145]\n", 500 | "[0.0134924 0.00442498 0.00625065 0.01975451 0.00517012]\n", 501 | "[-0.00678799 0.00139398 -0.00355391 0.00109182 0.00798725]\n", 502 | "[-0.01242474 0.00475813 0.00584133 -0.01082959 -0.00566571]\n", 503 | "[-0.0058967 0.01029579 0.03062019 0.00183187 -0.02162042]\n", 504 | "[ 0.00411703 -0.01943948 0.02556646 0.02299719 -0.01241454]\n", 505 | "[-0.02711426 -0.01526744 -0.03225964 -0.01855478 -0.03077478]\n", 506 | "[ 0.00891266 -0.00647478 0.00259103 0.01042741 0.0163917 ]\n", 507 | "[ 0.00543268 -0.00074525 -0.01184744 -0.01549022 0.03411407]\n", 508 | "[0.0031347 0.01023811 0.00279583 0.02589644 0.00093684]\n", 509 | "[ 1.70553378e-02 1.11835240e-02 2.63903297e-05 1.11954863e-02\n", 510 | " -2.57042819e-02]\n", 511 | "[-0.01982051 0.01617395 -0.03248179 -0.00037964 -0.01688146]\n", 512 | "[-0.00690618 -0.01521116 -0.0178515 0.00779882 0.00268843]\n", 513 | "[ 0.03253556 -0.00156998 -0.0161041 0.00077608 0.00749423]\n", 514 | "[ 0.02158561 0.01327702 0.00221374 -0.00559455 -0.03259558]\n", 515 | "[-6.80737570e-03 -6.74843004e-03 1.03231510e-05 5.01875337e-03\n", 516 | " -6.88627056e-04]\n", 517 | "[-0.00915518 -0.01838845 0.00348616 -0.01398492 -0.02329264]\n", 518 | "[-0.01025398 0.03115516 -0.00476469 0.02479426 -0.0004455 ]\n", 519 | "[-0.02162587 0.01009566 0.00095277 0.01727036 0.02495429]\n", 520 | "[ 0.0235349 0.02023717 -0.00349983 -0.00726221 0.00582883]\n", 521 | "[ 0.01418803 -0.02810625 0.01451526 0.03367083 0.01395305]\n", 522 | "[-0.00186468 -0.00541796 0.02678223 0.00282776 0.01696348]\n", 523 | "[ 0.00764135 -0.00467615 -0.01847312 -0.0252144 -0.03549757]\n", 524 | "[ 0.03012403 -0.02363581 -0.00302344 -0.00619503 0.00360187]\n", 525 | "[ 0.01801576 0.00126461 0.0023104 0.00623838 -0.02301118]\n", 526 | "[ 0.0032751 0.01400867 0.00648841 0.01277489 -0.01796038]\n", 527 | "[-0.00861949 0.02854481 -0.00897571 0.01835435 -0.03207216]\n", 528 | "[ 0.02870211 -0.03276487 -0.00641708 0.02084308 0.00576054]\n", 529 | "[-0.00686433 -0.02240854 -0.02884306 0.00770002 -0.02428001]\n", 530 | "[-0.01685706 -0.00852984 -0.00689973 0.01244992 -0.00279662]\n", 531 | "[-0.01232047 0.0112587 -0.01335785 0.00543136 0.00965424]\n", 532 | "[ 0.00887867 -0.00709726 0.00744577 -0.01660375 -0.02077061]\n", 533 | "[-0.01098522 0.00428598 -0.0002259 0.01837975 -0.0225374 ]\n", 534 | "[-0.01068724 -0.01706391 -0.00994208 -0.0230624 -0.00686264]\n", 535 | "[ 0.01730023 0.00884952 -0.01309061 0.00346184 -0.00781505]\n", 536 | "[0.0131293 0.0205074 0.00513356 0.01791848 0.01722405]\n", 537 | "[-0.0200401 -0.00207079 -0.00186803 -0.01865912 -0.00822684]\n", 538 | "[ 0.01001636 0.00137201 -0.00112761 0.02035147 -0.00838347]\n", 539 | "[-0.00485908 -0.00273098 -0.01914524 -0.01348568 0.0329398 ]\n", 540 | "[-0.02089274 -0.03734408 -0.0090903 0.00069104 -0.0167656 ]\n", 541 | "[ 0.02437676 -0.00756691 -0.00697849 0.03052319 0.02773539]\n", 542 | "[ 0.0252328 0.01852461 0.00927091 0.00651423 -0.00223346]\n", 543 | "[-0.03145451 0.01470235 -0.00695939 -0.00024724 0.02714662]\n", 544 | "[-0.00482713 0.00142157 0.01677866 0.01226856 0.0010498 ]\n", 545 | "[ 0.00116244 -0.01761185 -0.00915927 -0.01366289 0.01579559]\n", 546 | "[ 0.0083222 0.00026993 -0.00841473 -0.01369158 -0.03777902]\n", 547 | "[-0.01897958 -0.0013088 -0.00223029 0.00668095 -0.02837602]\n", 548 | "[ 0.00801958 0.00894725 0.01154295 0.00996732 -0.01849142]\n", 549 | "[ 0.00794348 0.01262892 0.01358004 -0.02834451 -0.01050968]\n", 550 | "[ 0.01479325 -0.02764282 0.02032934 -0.01516911 -0.02420769]\n", 551 | "[ 6.48741685e-05 1.55937940e-02 -8.63345022e-03 1.10797908e-02\n", 552 | " -2.20488867e-02]\n", 553 | "[ 0.01032376 0.0036628 0.03610289 -0.03780797 -0.01108558]\n", 554 | "[-0.01315695 0.02702273 0.00627238 0.00758954 0.0197275 ]\n", 555 | "[ 0.01111611 0.00455154 -0.01208451 0.00811077 -0.01036562]\n", 556 | "[-0.0155195 0.01656185 0.01025912 0.02284043 0.00444757]\n", 557 | "[-0.01680674 0.0030297 -0.00260692 -0.00944214 -0.0129453 ]\n", 558 | "[ 0.00439037 0.00150098 -0.00694871 -0.00919541 0.01470625]\n", 559 | "[-0.00337701 -0.00679857 0.01552647 -0.00841325 0.00986726]\n", 560 | "[-0.00052591 0.0276439 -0.01317263 -0.01019261 0.00475685]\n", 561 | "[-1.84896403e-02 3.41070471e-03 1.11571593e-02 9.41573294e-03\n", 562 | " 9.99261774e-05]\n", 563 | "[0.01648224 0.00642596 0.00640394 0.00718286 0.00970699]\n", 564 | "[ 0.01001916 -0.00631698 -0.01551572 -0.01796238 0.00143041]\n", 565 | "[ 0.01055662 -0.00083422 0.00828017 0.02200702 -0.04668607]\n", 566 | "[-0.00566552 -0.01674445 -0.00678037 0.01877835 -0.00396326]\n", 567 | "[-0.0382858 0.01126481 -0.01877818 -0.0244184 -0.00156326]\n", 568 | "[ 0.00321063 -0.0113949 -0.01797047 0.00573833 -0.000259 ]\n", 569 | "[ 0.00666064 0.00874919 -0.02246081 0.00848704 -0.02385203]\n", 570 | "[ 0.03341188 -0.02638314 0.05150311 0.01042819 -0.02146648]\n", 571 | "[0.01342663 0.00339295 0.00047662 0.00936212 0.02498385]\n", 572 | "[-0.02133528 -0.0037041 0.02797533 0.01767089 0.01011519]\n", 573 | "[ 0.00493165 0.02341662 -0.00062464 0.00554805 -0.00988063]\n", 574 | "[-0.01538604 -0.01490913 0.01194373 -0.01495726 -0.0065579 ]\n", 575 | "[-0.00685504 0.00471192 -0.00702506 0.00177564 -0.03147096]\n", 576 | "[-0.00137365 0.00104935 0.0010385 0.02316497 0.01156872]\n", 577 | "[-0.03304168 -0.00521536 0.03882778 0.0156989 0.00404378]\n", 578 | "[-0.00792258 -0.01683416 -0.0190596 0.02956919 -0.0346233 ]\n", 579 | "[ 0.00423405 0.01394675 -0.00056256 -0.02494787 -0.02977274]\n", 580 | "[ 0.00042915 -0.00834765 -0.00457841 0.01716952 0.0340825 ]\n", 581 | "[-0.02175541 0.00030321 0.02170528 -0.01534615 -0.01238504]\n", 582 | "[-0.00387156 0.01025793 0.0226507 0.00257536 0.00342953]\n", 583 | "[0.01039997 0.02339524 0.03978525 0.01313765 0.01935781]\n", 584 | "[ 0.00027158 -0.02983096 -0.00555734 0.00627307 0.01106771]\n", 585 | "[-0.00147089 -0.02458457 -0.0124654 -0.02053452 0.01286492]\n", 586 | "[ 0.00527384 -0.04594101 0.04363283 0.00651871 0.02355506]\n", 587 | "[-0.01433269 -0.00542705 -0.00287616 -0.00282895 0.01577858]\n", 588 | "[ 0.00701767 0.02404602 -0.01533253 -0.03637366 0.00455474]\n", 589 | "[ 0.00121014 -0.0265458 0.01056279 0.02059003 -0.00875855]\n", 590 | "[-0.01367898 0.01349658 0.017892 -0.01130402 0.00330204]\n", 591 | "[ 0.01442214 0.01311334 -0.01404642 0.02634197 -0.0060094 ]\n", 592 | "[ 0.01644413 -0.00538251 -0.00722571 0.00692722 -0.00498887]\n", 593 | "[ 0.01039886 0.00024927 -0.01236159 -0.02478995 -0.02209485]\n", 594 | "[ 0.00275879 -0.0205124 -0.01317028 -0.00971381 0.00648609]\n", 595 | "[0.02424799 0.01181629 0.02015542 0.01354316 0.00236931]\n", 596 | "[ 0.00423145 -0.01670816 -0.0183619 0.0401179 -0.00477224]\n", 597 | "[ 0.02061924 -0.00324322 -0.03469232 -0.00978567 -0.00531869]\n", 598 | "[ 0.01325512 -0.02587745 0.02569996 -0.00369277 -0.02378188]\n", 599 | "[-0.01616763 -0.00147183 -0.00582007 -0.01073985 -0.00499691]\n", 600 | "[ 0.00479221 -0.01036469 0.02037071 -0.01138089 -0.02111271]\n", 601 | "[-0.00042901 0.00921828 0.01484841 0.01729201 0.0232793 ]\n", 602 | "[ 0.00345558 -0.00169635 0.03252435 0.0160109 -0.02715913]\n", 603 | "[-0.00071531 0.01015447 0.01291336 -0.00245042 -0.00930446]\n", 604 | "[-0.02168962 0.00389927 0.00672047 0.01803794 0.00057685]\n", 605 | "[-0.00236143 -0.01972194 -0.00310506 0.01615047 0.02837673]\n", 606 | "[ 0.0001524 0.02881478 0.01966336 -0.02044979 -0.00513532]\n", 607 | "[ 0.01323571 -0.00400094 -0.0088465 0.01400706 -0.02389436]\n", 608 | "[ 0.0091159 0.01293502 -0.01579046 -0.01420149 -0.00437596]\n", 609 | "[-0.01774023 -0.01450352 -0.01113574 -0.00137341 0.0192933 ]\n", 610 | "[-0.00627231 0.01547426 0.01357518 0.00998441 0.01702171]\n", 611 | "[ 0.00681427 0.00062264 -0.00905569 0.0083259 -0.01368922]\n", 612 | "[0.03235681 0.01101971 0.01696416 0.01962783 0.00528952]\n", 613 | "[ 0.01617199 -0.02023275 0.02716858 -0.00017813 -0.00042114]\n", 614 | "[-0.01131766 0.01599871 -0.00649346 -0.01000028 0.00237153]\n", 615 | "[ 0.02652414 -0.00119351 0.01390551 -0.00485267 -0.00648113]\n", 616 | "[-0.00894029 -0.01372284 0.01117215 -0.05272486 -0.00461392]\n", 617 | "[-0.02656952 0.00437057 -0.0208504 -0.01606313 0.01842719]\n", 618 | "[-0.01825178 0.02308432 0.0202062 -0.00466366 -0.00497149]\n", 619 | "[ 0.01287529 -0.00409903 -0.01224527 -0.02468253 -0.00964188]\n", 620 | "[-0.01986065 0.02355062 -0.01870046 0.00942067 0.00394691]\n", 621 | "[ 0.01974615 -0.01152267 -0.01578262 -0.00234532 -0.00886651]\n", 622 | "[-0.0079016 0.00375895 0.00930342 -0.00594101 -0.00526999]\n", 623 | "[-0.01495051 -0.00405886 -0.00330167 0.02661201 -0.02963075]\n", 624 | "[ 0.00804086 -0.00695882 -0.01106761 0.04312284 0.01226365]\n", 625 | "[-0.02851296 0.01809855 0.03559375 -0.01135075 0.0198933 ]\n", 626 | "[-0.01758596 -0.00329298 0.01576601 0.01581022 -0.00578561]\n", 627 | "[ 0.01429139 -0.04776848 -0.01621829 -0.00666995 -0.02330843]\n", 628 | "[-0.00180441 -0.01706343 -0.01112582 -0.0046974 -0.01746604]\n", 629 | "[-0.02070884 -0.00496436 -0.00037374 0.0111478 -0.01259526]\n", 630 | "[ 0.03589277 0.01145335 -0.00972114 -0.00094839 -0.00735237]\n", 631 | "[ 0.01907228 0.01949622 0.00296611 0.00328028 -0.02134078]\n", 632 | "[-0.00315057 -0.00450441 0.00620967 0.02242745 -0.01069511]\n", 633 | "[-0.00834375 -0.03158447 -0.0043016 -0.00142405 0.01411761]\n", 634 | "[ 0.02378429 -0.00370995 0.01446482 0.01198049 0.00780724]\n", 635 | "[ 0.00055397 -0.008728 -0.00352028 -0.00050039 -0.00145594]\n", 636 | "[-2.13459150e-02 1.36210522e-02 9.82848334e-03 -2.52792046e-02\n", 637 | " -8.93198005e-05]\n", 638 | "[ 0.01143295 -0.00735084 0.00562678 -0.00386454 -0.02555543]\n", 639 | "[-0.00801467 0.01267452 -0.00487269 0.02359208 -0.00065171]\n", 640 | "[-0.00154475 -0.0061652 -0.03143804 -0.01006407 -0.00122283]\n", 641 | "[ 0.00165955 -0.00980031 0.01982414 -0.01126637 -0.00583459]\n", 642 | "[-0.00875728 0.00553918 -0.00513903 -0.01666029 -0.00343069]\n", 643 | "[-0.02515919 -0.01140877 0.01579106 -0.0085666 -0.01054911]\n", 644 | "[-0.01252448 0.00231413 0.00098105 0.01976908 0.01824211]\n", 645 | "[-0.02642212 -0.03212741 -0.01652984 0.02090688 -0.00097479]\n", 646 | "[ 0.00998166 0.00667862 0.01362662 -0.04259505 0.00479392]\n", 647 | "[ 0.00679861 0.01169115 -0.0032946 0.00582799 0.01915638]\n", 648 | "[ 0.02519165 -0.00875209 0.01205164 -0.01472176 -0.00943196]\n", 649 | "[-0.01398123 -0.01001388 -0.00078482 0.00118295 0.01891326]\n", 650 | "[-0.00678352 0.0015028 0.02620988 0.0106104 -0.01655877]\n", 651 | "[-0.03068499 -0.01627675 -0.01804748 0.01053077 -0.00218856]\n", 652 | "[-0.00770523 0.01533203 -0.01420164 0.004685 0.02473926]\n", 653 | "[ 0.00018697 0.01976097 -0.01938882 0.00169327 0.00140747]\n", 654 | "[-0.01321958 -0.0080501 0.01725902 0.01911841 -0.01573922]\n", 655 | "[ 0.01435583 -0.02266508 0.02382353 -0.00177122 -0.02568865]\n", 656 | "[ 0.00743474 -0.01425775 -0.0034566 0.02144977 0.0183732 ]\n", 657 | "[-0.01721347 -0.01595073 0.02298761 -0.00858877 -0.0438839 ]\n", 658 | "[ 0.01853538 0.00374552 -0.00841292 -0.02735454 -0.00432298]\n", 659 | "[-0.02696848 -0.0004798 -0.00679415 -0.00164122 0.0090044 ]\n", 660 | "[-0.01299329 0.01925623 0.00511109 -0.01248896 0.01341596]\n", 661 | "[-0.02764957 -0.01194102 -0.00656453 -0.01507736 -0.00306265]\n", 662 | "[-0.00894722 -0.01970139 0.0119217 -0.03046812 0.0024657 ]\n", 663 | "[ 0.00062759 0.02919302 -0.00067425 -0.00786435 0.02546431]\n", 664 | "[ 0.04025163 0.00820066 -0.01101352 0.011385 0.01425853]\n", 665 | "[-0.02572658 -0.00869796 0.01791901 -0.01501927 -0.00742588]\n", 666 | "[-0.01334624 0.01893571 -0.02593634 -0.02008356 0.02671374]\n", 667 | "[ 0.01375195 -0.00481584 0.03087765 0.00608823 -0.01321779]\n", 668 | "[-0.00304202 0.01122589 0.00875395 0.02557615 0.01032127]\n", 669 | "[ 0.01081484 -0.00746084 0.00029272 0.00767812 -0.00660901]\n", 670 | "[-0.00493189 0.0194909 0.00275273 0.00507886 -0.01876871]\n", 671 | "[-0.0035727 -0.01829489 -0.01238798 0.01401494 -0.00329418]\n", 672 | "[ 0.02013534 -0.02774306 0.00373421 0.00190729 -0.01819549]\n", 673 | "[ 2.33485445e-03 -9.46974571e-03 -8.11254822e-03 -4.99695839e-05\n", 674 | " 1.13158816e-02]\n", 675 | "[ 0.00573819 -0.0086543 0.04022219 0.00997219 -0.00985246]\n", 676 | "[ 0.00105294 0.01294046 0.00631939 -0.01187544 -0.01763813]\n", 677 | "[ 0.01678374 -0.00157227 0.01626419 0.0194738 0.02954694]\n", 678 | "[-0.01118128 0.004605 0.02346611 -0.0159843 0.00627957]\n", 679 | "[-0.00473547 -0.01258488 0.00764135 -0.0146564 0.0042547 ]\n", 680 | "[-0.0095852 -0.01069527 0.00449794 -0.01012156 -0.01560065]\n", 681 | "[ 0.0151628 0.02728992 0.00974524 0.00845737 -0.01402463]\n", 682 | "[-0.0017908 -0.00150532 -0.0097897 -0.0079369 0.01649191]\n", 683 | "[-0.01191295 0.00983658 0.0010516 0.00331748 0.01044295]\n", 684 | "[ 0.01594943 -0.00689045 -0.02684985 0.00078092 -0.00047548]\n", 685 | "[ 0.00221316 -0.01716204 -0.01566525 0.00877377 0.00363388]\n", 686 | "[-0.01600222 0.00210999 -0.02047907 -0.03424772 0.02761972]\n", 687 | "[ 0.02935701 0.00104841 0.00311701 -0.01263301 0.01436273]\n", 688 | "[-0.01520047 -0.00426927 -0.00649836 -0.00221161 -0.01604215]\n", 689 | "[ 0.01144736 -0.00101795 -0.00915275 0.00462945 -0.02119316]\n", 690 | "[-0.04550794 0.00090329 0.01105583 0.01759381 -0.00474434]\n", 691 | "[-0.00967736 0.01087482 0.02863818 -0.03269669 0.01076941]\n", 692 | "[ 0.01896024 -0.00707833 -0.00634243 0.01919443 0.00982438]\n", 693 | "[-0.00689542 0.01526172 0.00514957 -0.0136652 0.00240895]\n", 694 | "[-0.03080718 -0.00962556 -0.02256655 -0.02609326 0.01753814]\n", 695 | "[-0.01173518 0.0045041 -0.01412291 0.00165137 0.0299196 ]\n", 696 | "[-0.02448871 -0.01355705 0.00631873 0.00192677 0.0109804 ]\n", 697 | "[ 0.0210574 -0.00604352 -0.01480664 -0.00358949 0.03617316]\n", 698 | "[ 0.03213314 -0.0045597 -0.03161206 -0.00737115 -0.01476838]\n", 699 | "[-5.98796688e-03 -5.04705021e-05 3.10040928e-03 7.36554924e-03\n", 700 | " -1.50637213e-02]\n", 701 | "[-0.01199906 -0.00209029 0.01019152 0.00654768 -0.00347684]\n", 702 | "[-0.0074792 0.01234112 -0.00233874 -0.00031049 -0.00135507]\n", 703 | "[ 0.00430306 0.02408922 0.01227636 -0.00102491 0.0310803 ]\n", 704 | "[-0.00041622 0.00608535 0.01798705 -0.0091039 -0.0101047 ]\n", 705 | "[ 0.01043835 -0.00523601 0.00511532 -0.00187451 -0.00732025]\n", 706 | "[-0.01926945 -0.01359024 0.00128469 0.018024 0.01001712]\n", 707 | "[ 0.00550997 0.00126116 -0.01496504 -0.01678156 0.04041414]\n", 708 | "[-0.01231695 -0.00035825 0.00629274 -0.00098095 -0.02913842]\n", 709 | "[-0.0262534 -0.03530072 -0.00376678 0.00673553 -0.03606686]\n", 710 | "[ 0.0006386 0.02129314 -0.01489792 0.02062453 -0.00325296]\n", 711 | "[ 0.00230136 -0.01489827 0.00950466 -0.0257387 -0.01655989]\n", 712 | "[ 0.0247473 0.0003374 -0.04463984 0.01048385 0.00779956]\n", 713 | "[ 0.00404786 0.02125074 0.01583476 0.0004557 -0.00339556]\n", 714 | "[-0.00436572 0.01479638 -0.0084775 0.04140231 -0.00466672]\n", 715 | "[ 0.00535565 0.0035785 0.00703324 -0.01574833 0.00488844]\n", 716 | "[ 0.00464273 -0.01927272 0.00869561 0.00534682 0.00654531]\n", 717 | "[-0.01133588 -0.00341111 -0.00571853 0.00267709 -0.01717837]\n", 718 | "[ 0.01254765 -0.01136911 -0.00763063 0.02855432 -0.00395887]\n", 719 | "[ 0.01366614 0.01836223 0.00019875 0.01424539 -0.01681622]\n", 720 | "[-0.01688314 -0.02555079 -0.03461805 0.03431965 -0.00627561]\n", 721 | "[ 0.01497298 0.0153103 -0.00408617 0.02037411 -0.0125449 ]\n", 722 | "[-0.00738626 -0.02325619 0.0030692 0.01715554 0.00199669]\n", 723 | "[-0.00180241 -0.01062647 -0.00365457 -0.02114424 -0.0079488 ]\n" 724 | ] 725 | }, 726 | { 727 | "data": { 728 | "text/html": [ 729 | "
\n", 730 | "\n", 743 | "\n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | "
\n", 752 | "
" 753 | ], 754 | "text/plain": [ 755 | "Empty DataFrame\n", 756 | "Columns: []\n", 757 | "Index: []" 758 | ] 759 | }, 760 | "execution_count": 813, 761 | "metadata": {}, 762 | "output_type": "execute_result" 763 | } 764 | ], 765 | "source": [ 766 | "xxx = daily_returns(data, days = 250, iterations = 10)\n", 767 | "pd.DataFrame(xxx)" 768 | ] 769 | }, 770 | { 771 | "cell_type": "code", 772 | "execution_count": null, 773 | "metadata": {}, 774 | "outputs": [], 775 | "source": [] 776 | }, 777 | { 778 | "cell_type": "code", 779 | "execution_count": null, 780 | "metadata": {}, 781 | "outputs": [], 782 | "source": [] 783 | }, 784 | { 785 | "cell_type": "code", 786 | "execution_count": null, 787 | "metadata": {}, 788 | "outputs": [], 789 | "source": [] 790 | }, 791 | { 792 | "cell_type": "code", 793 | "execution_count": 681, 794 | "metadata": {}, 795 | "outputs": [], 796 | "source": [ 797 | "stock1 = xxx[0]\n", 798 | "stock2 = xxx[1]" 799 | ] 800 | }, 801 | { 802 | "cell_type": "code", 803 | "execution_count": 682, 804 | "metadata": {}, 805 | "outputs": [], 806 | "source": [ 807 | "price_list1 = np.zeros_like(stock1)\n", 808 | "price_list2 = np.zeros_like(stock2)" 809 | ] 810 | }, 811 | { 812 | "cell_type": "code", 813 | "execution_count": 683, 814 | "metadata": {}, 815 | "outputs": [], 816 | "source": [ 817 | "price_list1[0] = data.iloc[-1,0]\n", 818 | "price_list2[0] = data.iloc[-1,1]" 819 | ] 820 | }, 821 | { 822 | "cell_type": "code", 823 | "execution_count": 684, 824 | "metadata": {}, 825 | "outputs": [ 826 | { 827 | "ename": "IndexError", 828 | "evalue": "index 10 is out of bounds for axis 0 with size 10", 829 | "output_type": "error", 830 | "traceback": [ 831 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 832 | "\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)", 833 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m250\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mprice_list1\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mt\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mprice_list1\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mt\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mstock1\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mt\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0mprice_list2\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mt\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mprice_list2\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mt\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mstock2\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mt\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 834 | "\u001b[1;31mIndexError\u001b[0m: index 10 is out of bounds for axis 0 with size 10" 835 | ] 836 | } 837 | ], 838 | "source": [ 839 | "for t in range(1,250):\n", 840 | " price_list1[t] = price_list1[t-1]*stock1[t]\n", 841 | " price_list2[t] = price_list2[t-1]*stock2[t]" 842 | ] 843 | }, 844 | { 845 | "cell_type": "code", 846 | "execution_count": 685, 847 | "metadata": {}, 848 | "outputs": [ 849 | { 850 | "data": { 851 | "text/plain": [ 852 | "" 853 | ] 854 | }, 855 | "execution_count": 685, 856 | "metadata": {}, 857 | "output_type": "execute_result" 858 | }, 859 | { 860 | "data": { 861 | "image/png": "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\n", 862 | "text/plain": [ 863 | "
" 864 | ] 865 | }, 866 | "metadata": { 867 | "needs_background": "light" 868 | }, 869 | "output_type": "display_data" 870 | } 871 | ], 872 | "source": [ 873 | "pd.DataFrame(price_list1).plot()" 874 | ] 875 | }, 876 | { 877 | "cell_type": "code", 878 | "execution_count": 686, 879 | "metadata": {}, 880 | "outputs": [ 881 | { 882 | "data": { 883 | "text/plain": [ 884 | "array([0.01582102, 0.01579913, 0.02508055])" 885 | ] 886 | }, 887 | "execution_count": 686, 888 | "metadata": {}, 889 | "output_type": "execute_result" 890 | } 891 | ], 892 | "source": [ 893 | "stv = log_returns(data).std()\n", 894 | "stv.values" 895 | ] 896 | }, 897 | { 898 | "cell_type": "code", 899 | "execution_count": 572, 900 | "metadata": {}, 901 | "outputs": [ 902 | { 903 | "data": { 904 | "text/plain": [ 905 | "[]" 906 | ] 907 | }, 908 | "execution_count": 572, 909 | "metadata": {}, 910 | "output_type": "execute_result" 911 | }, 912 | { 913 | "data": { 914 | "image/png": "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\n", 915 | "text/plain": [ 916 | "
" 917 | ] 918 | }, 919 | "metadata": { 920 | "needs_background": "light" 921 | }, 922 | "output_type": "display_data" 923 | } 924 | ], 925 | "source": [ 926 | "plt.plot(path_b, label = 'stock A', linewidth = 2)\n", 927 | "plt.plot(path_a)" 928 | ] 929 | }, 930 | { 931 | "cell_type": "code", 932 | "execution_count": null, 933 | "metadata": {}, 934 | "outputs": [], 935 | "source": [] 936 | }, 937 | { 938 | "cell_type": "code", 939 | "execution_count": null, 940 | "metadata": {}, 941 | "outputs": [], 942 | "source": [] 943 | }, 944 | { 945 | "cell_type": "code", 946 | "execution_count": 15, 947 | "metadata": {}, 948 | "outputs": [], 949 | "source": [ 950 | "from scipy.stats import multivariate_normal\n", 951 | "multivariate_normal." 952 | ] 953 | }, 954 | { 955 | "cell_type": "code", 956 | "execution_count": 626, 957 | "metadata": {}, 958 | "outputs": [ 959 | { 960 | "data": { 961 | "text/plain": [ 962 | "array([[-0.03359063, 0.0203465 ],\n", 963 | " [-0.0121689 , 0.00981183],\n", 964 | " [ 0.0170836 , 0.00869911],\n", 965 | " [ 0.02294507, 0.00722137],\n", 966 | " [ 0.00447463, 0.0258734 ],\n", 967 | " [-0.00591023, -0.00898699],\n", 968 | " [ 0.01314865, 0.00510189],\n", 969 | " [ 0.01273059, 0.01416167],\n", 970 | " [-0.00710064, -0.01984411],\n", 971 | " [-0.02975933, 0.00459368],\n", 972 | " [-0.01437084, 0.00067072],\n", 973 | " [ 0.01294426, 0.02729374],\n", 974 | " [-0.02051075, -0.02345113],\n", 975 | " [ 0.0316306 , 0.01259794],\n", 976 | " [-0.0016515 , 0.00738523],\n", 977 | " [ 0.01201199, -0.00350337],\n", 978 | " [ 0.0131466 , 0.01564099],\n", 979 | " [ 0.00770997, -0.00498231],\n", 980 | " [-0.0116516 , 0.01359717],\n", 981 | " [ 0.01059225, 0.0138144 ]])" 982 | ] 983 | }, 984 | "execution_count": 626, 985 | "metadata": {}, 986 | "output_type": "execute_result" 987 | } 988 | ], 989 | "source": [ 990 | "np.random.multivariate_normal((log_return.mean()),covi,20)" 991 | ] 992 | }, 993 | { 994 | "cell_type": "code", 995 | "execution_count": null, 996 | "metadata": {}, 997 | "outputs": [], 998 | "source": [] 999 | } 1000 | ], 1001 | "metadata": { 1002 | "kernelspec": { 1003 | "display_name": "Python 3", 1004 | "language": "python", 1005 | "name": "python3" 1006 | }, 1007 | "language_info": { 1008 | "codemirror_mode": { 1009 | "name": "ipython", 1010 | "version": 3 1011 | }, 1012 | "file_extension": ".py", 1013 | "mimetype": "text/x-python", 1014 | "name": "python", 1015 | "nbconvert_exporter": "python", 1016 | "pygments_lexer": "ipython3", 1017 | "version": "3.7.4" 1018 | } 1019 | }, 1020 | "nbformat": 4, 1021 | "nbformat_minor": 2 1022 | } 1023 | --------------------------------------------------------------------------------