{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "** The following example is based on Karl Borch (1969, J. Economic Studies), where mean variance model fails to select efficient portfolios.**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Consider the investment universe with 3 assets,\n", "- with mean return vector:\n", "\n", "$$ \\mu = \\left[1,4,9\\right]^T $$\n", "\n", "- and the covariance matrix:\n", "\n", "$$\\Sigma=\\left[\\begin{array}{ccc}\n", "1 & 0 & 0\\\\\n", "0 & 4 & 0\\\\\n", "0 & 0 & 9\n", "\\end{array}\\right]$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Let's consider long position only\n", "- Efficient frontier can be obtained by solving the following quadratic programming problem:\n", "\n", "\\begin{align*}\n", "\\underset{w}{\\mathrm{argmin}}\\quad & w^{T}\\Sigma w\\\\\n", "\\mathrm{subject\\ to}\\quad & \\left[\\begin{array}{ccc}\n", "1 & 1 & 1\\\\\n", "1 & 4 & 9\n", "\\end{array}\\right]w=\\left[\\begin{array}{c}\n", "1\\\\\n", "a\n", "\\end{array}\\right]\\\\\n", " & w_{i}\\ge0,\\quad i=1,2,3\n", "\\end{align*}\n", "with $a$ varying from $1$ to $9$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Let's use python package cvxopt to obtain the efficient frontier**" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from cvxopt import solvers, matrix, spdiag\n", "from numpy import linspace, random\n", "solvers.options['show_progress'] = False\n", "solvers.options['abstol'] = 1e-10\n", "solvers.options['reltol'] = 1e-9\n", "solvers.options['feastol'] = 1e-10\n", "P = spdiag([1.0, 4.0, 9.0])\n", "q = matrix([0.0, 0.0, 0.0])\n", "G = -1.0 * spdiag([1.0, 1.0, 1.0])\n", "h = matrix([0.0, 0.0, 0.0])\n", "A = matrix([1.0, 1.0, 1.0, 4.0, 1.0, 9.0], (2, 3))\n", "Rs_ef, Vs_ef, Rs, Vs = linspace(1.0, 9.0, 100), [], [], []\n", "for R in Rs_ef:\n", " b = matrix([1.0, R])\n", " sol = solvers.qp(2.0 * P, q, G=G, h=h, A=A, b=b)\n", " Vs_ef.append(sol['primal objective'])\n", " ws = random.uniform(0.0, 1.0, 3)\n", " ws = ws / sum(ws)\n", " Rs.append(ws.dot([1.0, 4.0, 9.0]))\n", " Vs.append((ws*ws).dot([1.0, 4.0, 9.0]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Plot the efficient frontier**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "hide_input": true }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\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", " \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", " \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", " \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", " \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", " \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", " \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", " \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" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "%config InlineBackend.figure_format = 'svg'\n", "\n", "import matplotlib.pyplot as plt\n", "plt.plot(Vs_ef, Rs_ef)\n", "plt.xlabel('Variance')\n", "plt.ylabel('Mean')\n", "plt.scatter(Vs, Rs, s=0.2, c='k')\n", "#fig = plt.scatter(9.0, 9.0, s=10, c='r', zorder = 3)\n", "plt.scatter(9.0, 9.0, s=10, c='r', zorder = 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**However, let's take a look at one possible return distribution with the required moments**\n", "\n", "| $P$ | $0.5$ | $0.5$ |\n", "| :------: | :------: | :------: |\n", "| $X_1$ | $0$ | $2$ |\n", "| $X_2$ | $2$ | $6$ |\n", "| $X_3$ | $6$ | $12$ |\n", "\n", "- You don't need any math knowledge to get the obvious best portfolio, all in with $X_3$\n", "- How come we got a continuum of other choices equally attractive as this one?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "** What happened here? **\n", "\n", "Modern Portfolio Theory was introduced by Harry Markowitz in 1952, lead to Nobel price in economics. It is the first mean variance model. \n", "\n", "In this model, portfolio selection is only based the first two moments of the random return. This is also true for some other more sophisticated models (Black–Litterman, etc).\n", "\n", "Here the variance is chosen as risk measure, which choose non-efficient portfolios when the random return is not Gaussian. \n", "\n", "Is it the return normally distributed in the real world?\n", "\n", "We know it is not (skewed, fat tail, you name it). \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "** Can PyMCEF handle this situation? **\n", "- PyMCEF use risk measures that will produce efficient portfolios according to stochastic dominance theory. (Hadar and Russell 1969, Hanoch and Levy 1969 and Rothschild and Stiglitz 1970) \n", "\n", "** Two risk measures are used in PyMCEF **\n", "- Absolute semi-deviation (Ogryczak and Ruszczyński 1999)\n", "- Fixed-target under-performance (Fishburn 1977)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "** Let's use PyMCEF to solve this problem **" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from pymcef import SimpleEF, RiskMeasure\n", "import numpy as np\n", "# notice that each row corresponds of all realizations of one asset return\n", "\n", "returns = np.array([0,2,6,2,6,12]).reshape((3, 2))\n", "labels = ['Asset 1', 'Asset 2', 'Asset 3']\n", "sol = SimpleEF(training_set = returns, \\\n", " risk_measure = RiskMeasure.FixTargetUnderPerformance, \n", " target_return = 0,\\\n", " asset_names = labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The efficient frontier only contains one portfolio." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{2: 1.0}\n" ] } ], "source": [ "for prt in sol.frontier_in_sample:\n", " print(prt['weight'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Next example:\n", "\n", "[2. Black Scholes revisit, delta hedging as an efficient portfolio](http://nbviewer.jupyter.org/github/hzzyyy/pymcef/blob/master/examples/2.%20Black%20Scholes%20revisit%2C%20delta%20hedging%20as%20an%20efficient%20portfolio.ipynb)" ] } ], "metadata": { "hide_input": false, "kernelspec": { "display_name": "Python [conda env:jupyter27]", "language": "python", "name": "conda-env-jupyter27-py" }, "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.13" } }, "nbformat": 4, "nbformat_minor": 2 }