{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Populating the interactive namespace from numpy and matplotlib\n" ] } ], "source": [ "%pylab inline\n", "import pandas as pd\n", "import numpy as np\n", "import fmt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Homework Set 7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This homework is to price [synthetic CDO](https://en.wikipedia.org/wiki/Synthetic_CDO) using the one factor Gaussian Copula model. \n", "\n", "A synthetic CDO consists of $n$ CDS, the total loss of the portfolio is defned as:\n", "\n", "$$ l(t) = \\sum_i^n w_i \\tilde {\\mathbb{1}}_i(t) (1-r_i(t)) $$\n", "\n", "where $w_i$ and $r_i(t)$ are the notional weights and recovery rate of the i-th name in the portfolio. The notional weighs sum up to 1: $\\sum_i w_i = 1 $. The $ \\tilde {\\mathbb{1}}_i(t) $ is the default indicator of the i-th name defaulted before time $t$, the default probability is therefore $p_i(t) = \\mathbb E[\\tilde {\\mathbb{1}}_i(t) ]$\n", "\n", "For the purpose of this homework, we consider a simplified synthetic CDO that has no coupon payments, therefore the PV of a \\$1 notional synthetic CDO tranche with maturity $t$, attachment $a$ and detachment $d$ is:\n", "\n", "$$ v(a, d) = \\frac{d(t)}{d-a} \\min\\left((l(t) - a)^+, d-a\\right) $$\n", "\n", "where $d(t)$ is the discount factor.\n", "\n", "The following are the parameters to the synthetic CDO, and a straight forward Monte Carlo pricer:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "portfolio expected loss is 0.043182264890472034\n" ] } ], "source": [ "n = 125\n", "t = 5.\n", "defProbs = 1 - exp(-(np.random.uniform(size=n)*.03)*t)\n", "recovery = 0.4*np.ones(n)\n", "w = 1./n*np.ones(n)\n", "rho = 0.5\n", "discf = .9\n", "npath = 1000\n", "\n", "# a list of attachements and detachements, they pair up by elements\n", "attachements = np.array([0, .03, .07, .1, .15, .3])\n", "detachements = np.array([.03, .07, .1, .15, .3, .6])\n", "\n", "#portfolio expected loss\n", "el = np.sum(w*defProbs*(1-recovery))\n", "print(\"portfolio expected loss is \", el)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from scipy.stats import norm\n", "\n", "class CDO(object) :\n", " def __init__(self, w, defProbs, recovery, a, d) :\n", " self.w = w/np.sum(w)\n", " self.p = defProbs\n", " self.rec = recovery\n", " self.rho = rho\n", " self.a = a\n", " self.d = d\n", "\n", " def drawDefaultIndicator(self, z, rho) :\n", " '''return a list of default indicators given common factor z, using one factor Gaussian Copula\n", " '''\n", " e = np.random.normal(size=np.shape(self.p))\n", " x = z*np.sqrt(self.rho) + np.sqrt(1-self.rho)*e\n", " return np.less(norm.cdf(x), self.p)\n", "\n", " def portfolioLoss(self, defIndicator) :\n", " '''compute portfolio loss given default indicators'''\n", " return np.sum(defIndicator*self.w*(1-self.rec))\n", "\n", " def tranchePV(self, portfLoss, discf) :\n", " '''compute tranche PV from portfolio loss\n", " Args:\n", " portfLoss: the total portfolio loss\n", " discf: discount factor\n", " Returns:\n", " tranche PVs'''\n", " \n", " sz = self.d - self.a\n", " return discf/sz*np.minimum(np.maximum(portfLoss - self.a, 0), sz)\n", "\n", " def drawPV(self, z, rho, discf) :\n", " ''' compute PV and portfolio Loss conditioned on a common factor z'''\n", " di = self.drawDefaultIndicator(z, rho)\n", " pfLoss = self.portfolioLoss(di)\n", " return self.tranchePV(pfLoss, discf), pfLoss\n", " \n", " \n", "cdo = CDO(w, defProbs, recovery, attachements, detachements)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "## price the tranches using simulation\n", "def simCDO(cdo, rho, disc, paths) :\n", " zs = np.random.normal(size=[paths])\n", " pv = np.zeros(np.shape(cdo.a))\n", " pv2 = np.zeros(np.shape(cdo.d))\n", " for z in zs:\n", " thisPV, _ = cdo.drawPV(z, rho, discf)\n", " pv += thisPV\n", " pv2 += thisPV*thisPV\n", " \n", " v = pv/paths\n", " var = pv2/paths - v**2\n", " return pv/paths, np.sqrt(var/paths)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "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", "
012345
Attach00.030.070.10.150.3
Detach0.030.070.10.150.30.6
PV0.46950.2490.15190.090730.037660.003708
MC err0.012270.011840.010210.0081280.0049880.001249
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pv_0, err_0 = simCDO(cdo, rho, discf, npath)\n", "df = pd.DataFrame(np.array([cdo.a, cdo.d, pv_0, err_0]), index=['Attach', 'Detach', 'PV', 'MC err'])\n", "\n", "fmt.displayDF(df, fmt='4g')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Problem 1\n", "\n", "Modify the simCDO function to implement the following variance reduction techniques, and show whether the technique is effective:\n", "\n", "For this homework, we only apply the variance reduction in the common market factor $z$, you should not change the random number $e$ that were drew with in the drawDefaultIndicator function, i.e., only modify the simCDO code, re-use but do not modify the CDO class. Unless explicitly mentioned, keep the simulation path the same as the base case above.\n", "\n", "1. anti-thetic variate, reduce the number of paths by half to account for the 2x increase in computation\n", "1. importance sampling, shift $z$ by -1\n", "1. sobol sequence\n", "\n", "Compute the **variance** reduction factor for each technique, and comment on the effectiveness of these variance reduction techniques." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 1 }