From 0e2872aabcd587111dfb1cf4e46910b393cb6380 Mon Sep 17 00:00:00 2001 From: Arthur DANJOU Date: Mon, 25 Nov 2024 14:45:09 +0100 Subject: [PATCH] Add Project Portfolio management --- M1/Portfolio Management/TP-Project.ipynb | 518 +++++++++++++++++++++++ 1 file changed, 518 insertions(+) create mode 100644 M1/Portfolio Management/TP-Project.ipynb diff --git a/M1/Portfolio Management/TP-Project.ipynb b/M1/Portfolio Management/TP-Project.ipynb new file mode 100644 index 0000000..843e152 --- /dev/null +++ b/M1/Portfolio Management/TP-Project.ipynb @@ -0,0 +1,518 @@ +{ + "cells": [ + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "# Project - Portfolio Management\n", + "\n", + "## Group: Danjou Arthur & Forest Thais\n", + "\n", + "### Time period studied from 2017-01-01 to 2018-01-01\n", + "\n", + "### Risk-free rate: 2%" + ], + "id": "81049114d821d00e" + }, + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-11-25T13:43:46.298758Z", + "start_time": "2024-11-25T13:43:46.293696Z" + } + }, + "source": [ + "import yfinance as yf\n", + "import pandas as pd\n", + "import numpy as np" + ], + "outputs": [], + "execution_count": 51 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:43:47.318911Z", + "start_time": "2024-11-25T13:43:47.198820Z" + } + }, + "cell_type": "code", + "source": [ + "# Data Extraction\n", + "Tickers = [\"^RUT\", \"^IXIC\", \"^GSPC\", \"XWD.TO\"]\n", + "start_input = \"2017-01-01\"\n", + "end_input = \"2018-01-01\"\n", + "S = pd.DataFrame()\n", + "for t in Tickers:\n", + " S[t] = yf.Tickers(t).history(start=start_input, end=end_input)[\"Close\"]\n", + "\n", + "S = S.interpolate(method=\"pad\")\n", + "\n", + "# Show the first five and last five values extracted\n", + "display(S.head())\n", + "display(S.tail())\n", + "print(S.shape)" + ], + "id": "9f9fc36832c97e0", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[*********************100%***********************] 1 of 1 completed\n", + "[*********************100%***********************] 1 of 1 completed\n", + "[*********************100%***********************] 1 of 1 completed\n", + "[*********************100%***********************] 1 of 1 completed\n", + "/var/folders/tp/_ld5_pzs6nx6mv1pbjhq1l740000gn/T/ipykernel_92506/348989065.py:9: FutureWarning: DataFrame.interpolate with method=pad is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.\n", + " S = S.interpolate(method=\"pad\")\n" + ] + }, + { + "data": { + "text/plain": [ + " ^RUT ^IXIC ^GSPC XWD.TO\n", + "Date \n", + "2017-01-03 00:00:00+00:00 1365.489990 5429.080078 2257.830078 38.499630\n", + "2017-01-04 00:00:00+00:00 1387.949951 5477.000000 2270.750000 38.553375\n", + "2017-01-05 00:00:00+00:00 1371.939941 5487.939941 2269.000000 38.481716\n", + "2017-01-06 00:00:00+00:00 1367.280029 5521.060059 2276.979980 38.517544\n", + "2017-01-09 00:00:00+00:00 1357.489990 5531.819824 2268.899902 38.383186" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
^RUT^IXIC^GSPCXWD.TO
Date
2017-01-03 00:00:00+00:001365.4899905429.0800782257.83007838.499630
2017-01-04 00:00:00+00:001387.9499515477.0000002270.75000038.553375
2017-01-05 00:00:00+00:001371.9399415487.9399412269.00000038.481716
2017-01-06 00:00:00+00:001367.2800295521.0600592276.97998038.517544
2017-01-09 00:00:00+00:001357.4899905531.8198242268.89990238.383186
\n", + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + " ^RUT ^IXIC ^GSPC XWD.TO\n", + "Date \n", + "2017-12-22 00:00:00+00:00 1542.930054 6959.959961 2683.340088 44.323349\n", + "2017-12-26 00:00:00+00:00 1544.229980 6936.250000 2680.500000 44.323349\n", + "2017-12-27 00:00:00+00:00 1543.939941 6939.339844 2682.620117 44.052303\n", + "2017-12-28 00:00:00+00:00 1548.930054 6950.160156 2687.540039 43.857414\n", + "2017-12-29 00:00:00+00:00 1535.510010 6903.390137 2673.610107 43.784576" + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
^RUT^IXIC^GSPCXWD.TO
Date
2017-12-22 00:00:00+00:001542.9300546959.9599612683.34008844.323349
2017-12-26 00:00:00+00:001544.2299806936.2500002680.50000044.323349
2017-12-27 00:00:00+00:001543.9399416939.3398442682.62011744.052303
2017-12-28 00:00:00+00:001548.9300546950.1601562687.54003943.857414
2017-12-29 00:00:00+00:001535.5100106903.3901372673.61010743.784576
\n", + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(251, 4)\n" + ] + } + ], + "execution_count": 52 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:43:50.080380Z", + "start_time": "2024-11-25T13:43:50.073119Z" + } + }, + "cell_type": "code", + "source": [ + "R = S / S.shift() - 1\n", + "R = R[1:]\n", + "mean_d = R.mean()\n", + "covar_d = R.cov()\n", + "corr = R.corr()" + ], + "id": "53483cf3a925a4db", + "outputs": [], + "execution_count": 53 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:43:50.965092Z", + "start_time": "2024-11-25T13:43:50.961969Z" + } + }, + "cell_type": "code", + "source": [ + "mean = mean_d * 252\n", + "covar = covar_d * 252\n", + "std = np.sqrt(np.diag(covar))" + ], + "id": "c327ed5967b1f442", + "outputs": [], + "execution_count": 54 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:43:51.701725Z", + "start_time": "2024-11-25T13:43:51.695020Z" + } + }, + "cell_type": "code", + "source": [ + "print(\"Mean:\\n\")\n", + "print(mean)\n", + "print(\"\\nCovariance:\\n\")\n", + "print(covar)\n", + "print(\"\\nStandard Deviation:\\n\")\n", + "print(std)\n", + "print(\"\\nCorrelation:\\n\")\n", + "print(corr)" + ], + "id": "6bc6a850bf06cc9d", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mean:\n", + "\n", + "^RUT 0.125501\n", + "^IXIC 0.246863\n", + "^GSPC 0.172641\n", + "XWD.TO 0.133175\n", + "dtype: float64\n", + "\n", + "Covariance:\n", + "\n", + " ^RUT ^IXIC ^GSPC XWD.TO\n", + "^RUT 0.014417 0.008400 0.006485 0.004797\n", + "^IXIC 0.008400 0.009182 0.005583 0.004337\n", + "^GSPC 0.006485 0.005583 0.004426 0.003309\n", + "XWD.TO 0.004797 0.004337 0.003309 0.006996\n", + "\n", + "Standard Deviation:\n", + "\n", + "[0.12007222 0.09582499 0.06653127 0.08364295]\n", + "\n", + "Correlation:\n", + "\n", + " ^RUT ^IXIC ^GSPC XWD.TO\n", + "^RUT 1.000000 0.730047 0.811734 0.477668\n", + "^IXIC 0.730047 1.000000 0.875687 0.541087\n", + "^GSPC 0.811734 0.875687 1.000000 0.594658\n", + "XWD.TO 0.477668 0.541087 0.594658 1.000000\n" + ] + } + ], + "execution_count": 55 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Question 1", + "id": "fc4bec874f710f7c" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:43:53.113423Z", + "start_time": "2024-11-25T13:43:53.109514Z" + } + }, + "cell_type": "code", + "source": [ + "r = 0.02\n", + "d = len(Tickers)\n", + "vec1 = np.linspace(1, 1, d)\n", + "sigma = covar\n", + "inv_sigma = np.linalg.inv(sigma)\n", + "\n", + "a = vec1.T.dot(inv_sigma).dot(vec1)\n", + "b = mean.T.dot(inv_sigma).dot(vec1)" + ], + "id": "780c9cca6e0ed2d3", + "outputs": [], + "execution_count": 56 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:43:54.545400Z", + "start_time": "2024-11-25T13:43:54.541579Z" + } + }, + "cell_type": "code", + "source": [ + "# Tangent portfolio\n", + "pi_T = inv_sigma.dot(mean - r * vec1) / (b - r * a)\n", + "sd_T = np.sqrt(pi_T.T.dot(sigma).dot(pi_T)) # Variance\n", + "m_T = pi_T.T.dot(mean) # expected return\n", + "\n", + "print(f\"Expected return m_T: {m_T}\")\n", + "print(f\"Standard deviation sd_T: {sd_T}\")\n", + "print(f\"Allocation pi_T: {pi_T}\")\n", + "print(\n", + " f\"We can verify that the allocation is possible as the sum of the allocations for the different indices is {sum(pi_T)}, that is very close to 1\")" + ], + "id": "81c956f147c68070", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expected return m_T: 0.2364033641931515\n", + "Standard deviation sd_T: 0.07276528490265963\n", + "Allocation pi_T: [-0.60853811 0.45748917 1.17944152 -0.02839259]\n", + "We can verify that the allocation is possible as the sum of the allocations for the different indices is 0.9999999999999993, that is very close to 1\n" + ] + } + ], + "execution_count": 57 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Question 2", + "id": "2e121c2dfb946f3c" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:43:59.797115Z", + "start_time": "2024-11-25T13:43:59.792462Z" + } + }, + "cell_type": "code", + "source": [ + "for i in range(len(std)):\n", + " print(f\"The annualized volatilities of the index {Tickers[i]} is {std[i]}\")\n", + " print(f\"The annualized expected returns of the index {Tickers[i]} is {mean[Tickers[i]]}\")\n", + " print(\"\")\n", + "\n", + "print(f\"The annualized volatility of the Tangent Portfolio is {sd_T * np.sqrt(252)}\")\n", + "print(f\"The annualized expected return of the Tangent Portfolio is {m_T * 252}\")" + ], + "id": "c169808384ca1112", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The annualized volatilities of the index ^RUT is 0.12007221535411407\n", + "The annualized expected returns of the index ^RUT is 0.12550141384538263\n", + "\n", + "The annualized volatilities of the index ^IXIC is 0.09582499431305072\n", + "The annualized expected returns of the index ^IXIC is 0.24686267015709437\n", + "\n", + "The annualized volatilities of the index ^GSPC is 0.06653126757186174\n", + "The annualized expected returns of the index ^GSPC is 0.17264098207081371\n", + "\n", + "The annualized volatilities of the index XWD.TO is 0.08364295296865466\n", + "The annualized expected returns of the index XWD.TO is 0.1331750489518068\n", + "\n", + "The annualized volatility of the Tangent Portfolio is 1.155113087587201\n", + "The annualized expected return of the Tangent Portfolio is 59.57364777667418\n" + ] + } + ], + "execution_count": 58 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "# Question 3", + "id": "af8d29ecdbf2ae1" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-11-25T13:44:01.393591Z", + "start_time": "2024-11-25T13:44:01.388830Z" + } + }, + "cell_type": "code", + "source": [ + "print(\"sharpe ratio of the Tangent portfolio :\", (m_T - r) / sd_T)\n", + "\n", + "for i in range(4):\n", + " print(f\"the sharpe ratio of the index {Tickers[i]} is {(mean[Tickers[i]] - r) / std[i]}\")" + ], + "id": "2e0215ab7904906a", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sharpe ratio of the Tangent portfolio : 2.9739918490340687\n", + "the sharpe ratio of the index ^RUT is 0.8786496820620858\n", + "the sharpe ratio of the index ^IXIC is 2.3674686524473625\n", + "the sharpe ratio of the index ^GSPC is 2.294274371158541\n", + "the sharpe ratio of the index XWD.TO is 1.353073330567601\n" + ] + } + ], + "execution_count": 59 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}