diff options
Diffstat (limited to 'python/notebooks/swaption_scenarios.ipynb')
| -rw-r--r-- | python/notebooks/swaption_scenarios.ipynb | 225 |
1 files changed, 85 insertions, 140 deletions
diff --git a/python/notebooks/swaption_scenarios.ipynb b/python/notebooks/swaption_scenarios.ipynb index e632d922..6399d8e4 100644 --- a/python/notebooks/swaption_scenarios.ipynb +++ b/python/notebooks/swaption_scenarios.ipynb @@ -18,6 +18,8 @@ "from scipy.interpolate import SmoothBivariateSpline\n", "from utils.db import dbconn, dbengine\n", "from risk.swaptions import get_swaption_portfolio\n", + "from scipy.optimize import brentq\n", + "from pandas.tseries.offsets import BDay\n", "\n", "conn = dbconn('dawndb')\n", "dawn_engine = dbengine('dawndb')\n", @@ -32,50 +34,45 @@ "metadata": {}, "outputs": [], "source": [ + "############# Current portfolio one day PNL/Delta scenario\n", "portf = get_swaption_portfolio(datetime.date.today() - pd.offsets.BDay(), conn, source_list=['GS'])\n", "\n", - "hedges = pd.read_sql_query(\"SELECT security_id as redcode, maturity, notional, folder FROM list_cds_positions_by_strat(%s) \"\n", + "hedges = pd.read_sql_query(\"SELECT security_desc, notional FROM list_cds_positions_by_strat(%s) \"\n", " \"WHERE folder in ('IGOPTDEL', 'HYOPTDEL')\",\n", " conn, params=(datetime.date.today(),))\n", "\n", "for i, r in hedges.iterrows():\n", - " strategy = r.pop(\"folder\")\n", - " trade_index = CreditIndex(**r, value_date=datetime.date.today() - pd.offsets.BDay())\n", - " trade_index.mark()\n", - " portf.add_trade(trade_index, (strategy, i))\n", + " portf.add_trade(CreditIndex(r['security_desc'].split(\" \")[1],\n", + " r['security_desc'].split(\" \")[3][1:],\n", + " '5yr', value_date=datetime.date.today() - pd.offsets.BDay(),\n", + " notional = r['notional']), ('delta', i))\n", "\n", "vol_surface = {}\n", "for trade in portf.swaptions:\n", - " k = (trade.index.index_type, trade.index.series, trade.option_type)\n", - " if k not in vol_surface:\n", - " vs = BlackSwaptionVolSurface(trade.index.index_type, trade.index.series, \n", - " value_date=datetime.date.today(), interp_method = \"bivariate_linear\")\n", - " vol_surface[k] = vs[vs.list('GS', option_type=trade.option_type)[-1]]\n", + " vs = BlackSwaptionVolSurface(trade.index.index_type, trade.index.series, \n", + " value_date=datetime.date.today(), interp_method = \"bivariate_linear\")\n", + " vol_surface[(trade.index.index_type, trade.index.series, trade.option_type)] = vs[vs.list(source='GS', option_type=trade.option_type)[-1]]\n", "\n", "#Set original_pv as of yesterday's EOD levels, don't reset PV after this time\n", + "portf.mark(interp_method=\"bivariate_linear\", source_list=['GS'])\n", "portf.reset_pv()\n", "\n", "#set ref to today's levels\n", "portf.value_date = datetime.date.today()\n", - "portf.mark(interp_method=\"bivariate_linear\", source_list=['GS'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ + "portf.mark(interp_method=\"bivariate_linear\", source_list=['GS'])\n", + "\n", "spread_shock = np.round(np.arange(-.1, .1, .01), 4)\n", - "scens = run_portfolio_scenarios(portf, [datetime.datetime.now()], params=['pnl', 'hy_equiv', 'sigma'],\n", + "scens = run_portfolio_scenarios(portf, [datetime.datetime.now()], params=['pnl', 'hy_equiv'],\n", " spread_shock=spread_shock,\n", " vol_shock=[0],\n", + " corr_shock=[0],\n", " vol_surface=vol_surface)\n", "pnl = scens.xs('pnl', level = 2, axis=1).sum(axis=1)\n", "hy_equiv = scens.xs('hy_equiv', level = 2, axis=1).sum(axis=1)\n", "\n", "ig = CreditIndex('IG', 32, '5yr')\n", "ig.mark()\n", + "\n", "pnl.index = pnl.index.set_levels((1+pnl.index.get_level_values('spread_shock')) * ig.spread, level = 'spread_shock')\n", "hy_equiv.index = pnl.index" ] @@ -86,16 +83,8 @@ "metadata": {}, "outputs": [], "source": [ - "pnl.reset_index([\"date\", \"vol_shock\"], drop=True).to_frame(\"pnl\").plot()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hy_equiv.reset_index([\"date\", \"vol_shock\"], drop=True).to_frame(\"hy_equiv\").plot()" + "pnl, hy_equiv\n", + "#plot_trade_scenarios(portf)" ] }, { @@ -104,7 +93,40 @@ "metadata": {}, "outputs": [], "source": [ - "pnl, hy_equiv" + "#breakeven calc\n", + "index = 'HY'\n", + "series = 32\n", + "value_date = datetime.date.today()\n", + "option_delta = CreditIndex(index, series, '5yr')\n", + "#option_delta.spread = 56.5\n", + "option_delta.price = 106.0\n", + "option1 = BlackSwaption(option_delta, datetime.date(2019, 12, 16), 106.5, option_type=\"receiver\") \n", + "option1.sigma = .35\n", + "option1.notional = 100_000_000 \n", + "option_delta.notional = -option1.delta * option1.notional\n", + "portf = Portfolio([option1, option_delta], trade_ids=['opt1', 'delta'])\n", + "portf.value_date = value_date\n", + "portf.reset_pv()\n", + "portf.value_date = value_date + BDay(1)\n", + "orig_ref = portf.ref\n", + "\n", + "def get_pnl(portf, x):\n", + " portf.ref = x\n", + " portf.sigma = float(vs[surface_id](self.T, np.log(self.moneyness)))\n", + " return portf.pnl\n", + "\n", + "if index == 'IG':\n", + " widening = brentq(lambda x: get_pnl(portf, x), portf.ref, portf.ref + 10)\n", + " portf.ref = orig_ref\n", + " tightening = brentq(lambda x: get_pnl(portf, x), portf.ref-10, portf.ref)\n", + " portf.ref = orig_ref\n", + "else: \n", + " widening = brentq(lambda x: get_pnl(portf, x), portf.ref-3, portf.ref)\n", + " portf.ref = orig_ref\n", + " tightening = brentq(lambda x: get_pnl(portf, x), portf.ref, portf.ref + 3)\n", + " portf.ref = orig_ref\n", + "\n", + "tightening, orig_ref, widening" ] }, { @@ -117,16 +139,16 @@ "index = 'IG'\n", "series = 32\n", "option_delta = CreditIndex(index, series, '5yr') \n", - "option_delta.spread = 60\n", - "option1 = BlackSwaption(option_delta, datetime.date(2019, 9, 17), 90, option_type=\"payer\") \n", - "option2 = BlackSwaption(option_delta, datetime.date(2019, 11, 19), 90, option_type=\"payer\") \n", - "option1.sigma = .6\n", - "option2.sigma = .58\n", + "option_delta.spread = 55\n", + "option1 = BlackSwaption(option_delta, datetime.date(2019, 10, 16), 50, option_type=\"receiver\") \n", + "option2 = BlackSwaption(option_delta, datetime.date(2019, 10, 16), 77.5, option_type=\"payer\") \n", + "option1.sigma = .4\n", + "option2.sigma = .63\n", "option1.notional = 100_000_000 \n", "option2.notional = 100_000_000 \n", "option1.direction = 'Long' \n", "option2.direction = 'Short' \n", - "option_delta.notional = option1.delta * option1.notional + option2.delta * option2.notional\n", + "option_delta.notional = -option1.delta * option1.notional - option2.delta * option2.notional\n", "portf = Portfolio([option1, option2, option_delta], trade_ids=['opt1', 'opt2', 'delta'])" ] }, @@ -135,6 +157,13 @@ "execution_count": null, "metadata": {}, "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "date_range = pd.bdate_range(portf.value_date, portf.value_date + pd.tseries.offsets.BDay(30), freq='3B')\n", "vol_shock = np.arange(-.15, .31, 0.01)\n", @@ -143,7 +172,7 @@ "for trade in portf.swaptions:\n", " vs = BlackSwaptionVolSurface(trade.index.index_type, trade.index.series, \n", " value_date=portf.value_date, interp_method = \"bivariate_linear\")\n", - " vol_surface[(trade.index.index_type, trade.index.series)] = vs[vs.list(option_type='payer')[-1]]\n", + " vol_surface[(trade.index.index_type, trade.index.series, trade.option_type)] = vs[vs.list(source='GS', option_type=trade.option_type)[-1]]\n", "\n", "df = run_portfolio_scenarios(portf, date_range, params=[\"pnl\"],\n", " spread_shock = spread_shock,\n", @@ -171,7 +200,7 @@ " for trade in portf.swaptions:\n", " vs = BlackSwaptionVolSurface(trade.index.index_type, trade.index.series, \n", " value_date=portf.value_date, interp_method = \"bivariate_linear\")\n", - " vol_surface[(trade.index.index_type, trade.index.series)] = vs[vs.list(option_type='payer')[-1]]\n", + " vol_surface[(trade.index.index_type, trade.index.series, trade.option_type)] = vs[vs.list(option_type=trade.option_type)[-1]]\n", " \n", " df = run_portfolio_scenarios(portf, date_range, params=[\"pnl\",\"delta\"],\n", " spread_shock = spread_shock,\n", @@ -188,11 +217,16 @@ " else:\n", " df['spread'] = portf.indices[0].spread * (1 + df.spread_shock)\n", " df = df.set_index(['date', 'spread', 'vol_shock'])\n", - " sort_order = [True, True]\n", - " \n", + " sort_order = [True, False]\n", + " \n", + " #If the multilevels index contains strategy drop it\n", + " if df.columns.nlevels == 3: \n", + " df.columns = df.columns.droplevel(level=0)\n", " pnl = df.xs('pnl', axis=1, level=1).sum(axis=1)\n", " for trade_id, t in portf.items():\n", " if isinstance(t, BlackSwaption):\n", + " if len(trade_id) == 2:\n", + " trade_id = trade_id[1]\n", " df[(trade_id, 'delta')] *= -t.notional \n", " delta = df.xs('delta', axis=1, level=1).sum(axis=1).xs(0, level='vol_shock')\n", " delta += sum([x.notional * -1 if x.direction == 'Buyer' else 1 for x in portf.indices])\n", @@ -223,7 +257,7 @@ " for trade in portf.swaptions:\n", " vs = BlackSwaptionVolSurface(trade.index.index_type, trade.index.series, \n", " value_date=portf.value_date, interp_method = \"bivariate_linear\")\n", - " vol_surface[(trade.index.index_type, trade.index.series)] = vs[vs.list(option_type='payer')[-1]]\n", + " vol_surface[(trade.index.index_type, trade.index.series, trade.option_type)] = vs[vs.list(option_type=trade.option_type)[-1]]\n", "\n", " df = run_portfolio_scenarios(portf, date_range, params=[\"pnl\"],\n", " spread_shock = spread_shock,\n", @@ -239,16 +273,6 @@ "metadata": {}, "outputs": [], "source": [ - "plot_trade_scenarios(portf)\n", - "plot_trade_scenarios(portf, -.15, .5, vol_time_roll=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ "#Dec Jan 2017 Trade\n", "option_delta = CreditIndex.from_tradeid(864)\n", "option1 = BlackSwaption.from_tradeid(3, option_delta)\n", @@ -336,100 +360,21 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "#Set up Portfolio\n", - "from risk.swaptions import get_swaption_portfolio\n", - "from risk.tranches import get_tranche_portfolio\n", - "rundate = datetime.date(2019,6,21)\n", - "\n", - "portf = get_swaption_portfolio(rundate, conn)\n", - "\n", - "#index positions\n", - "df = pd.read_sql_query(\"SELECT * from list_cds_positions_by_strat(%s)\",\n", - " dawn_engine, params=(rundate,))\n", - "df = df[df.folder.str.contains(\"OPT\")]\n", - "for t in df.itertuples(index=False):\n", - " portf.add_trade(CreditIndex(redcode=t.security_id, maturity=t.maturity, notional=t.notional),\n", - " (t.folder, t.security_desc))\n", - "\n", - "portf.value_date = rundate\n", - "portf.mark(interp_method=\"bivariate_linear\")\n", - "portf.reset_pv()\n", - "\n", - "#------------------------Calc Scenarios\n", - "vol_surface = {}\n", - "for trade in portf.swaptions:\n", - " vs = BlackSwaptionVolSurface(trade.index.index_type, trade.index.series, \n", - " value_date=rundate, interp_method = \"bivariate_linear\")\n", - " vol_surface[(trade.index.index_type, trade.index.series)] = vs[vs.list(option_type='payer')[-1]]\n", - "vol_shock = [0]\n", - "corr_shock = [0]\n", - "spread_shock = np.round(np.arange(-.2, 1, .05), 3)\n", - "scens = run_portfolio_scenarios(portf, [pd.Timestamp(rundate)], params=['pnl', 'delta'],\n", - " spread_shock=spread_shock,\n", - " vol_shock=vol_shock,\n", - " corr_shock=[0],\n", - " vol_surface=vol_surface)\n", - "\n", - "pnl = scens.xs('pnl', axis=1, level=2)\n", - "pnl = pnl.xs(0, level='vol_shock')\n", - "\n", - "scenarios = (pnl.\n", - " reset_index(level=['date'], drop=True).\n", - " groupby(level=0, axis=1).sum())\n", - "\n", - "options = ['HYOPTDEL', 'HYPAYER', 'HYREC', 'IGOPTDEL', 'IGPAYER', 'IGREC']\n", - "scenarios['options'] = scenarios[set(scenarios.columns).intersection(options)].sum(axis=1)" - ] + "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "#Now say that it widens by X percentage, then rebalance, then do the shock again\n", - "rundate = datetime.date(2019,6,21)\n", - "x = 1.2\n", - "for t in portf.swaptions:\n", - " t.index.spread *= x\n", - " vs = vol_surface[(t.index.index_type, t.index.series)]\n", - " t.sigma = max(0.2, float(vs(t.T, math.log(t.moneyness))))\n", - "for t in portf.indices:\n", - " t.spread *= x\n", - "pnl = portf.pnl\n", - "\n", - "analytics.init_ontr(value_date=rundate)\n", - "rebal = analytics._ontr()\n", - "rebal.notional = portf.hy_equiv\n", - "rebal.direction = 'Seller'\n", - "\n", - "rebal.spread *= x\n", - "portf.add_trade(rebal, ('rebalance', 'HYOPTDEL'))\n", - "portf.reset_pv()\n", - "\n", - "swaptions_scens = portf.swaptions[0].shock(params=['pnl', 'pv'],\n", - " spread_shock=spread_shock,\n", - " vol_shock=vol_shock,\n", - " vol_surface=vol_surface)\n", - "\n", - "#------------------------Calc Scenarios\n", - "scens = run_portfolio_scenarios(portf, [pd.Timestamp(rundate)], params=['pnl', 'pv'],\n", - " spread_shock=spread_shock,\n", - " vol_shock=vol_shock,\n", - " corr_shock=[0],\n", - " vol_surface=vol_surface)\n", - "\n", - "pnl = scens.xs('pnl', axis=1, level=2)\n", - "pnl = pnl.xs(0, level='vol_shock')\n", - "\n", - "scenarios = (pnl.\n", - " reset_index(level=['date'], drop=True).\n", - " groupby(level=0, axis=1).sum())\n", - "\n", - "options = ['HYOPTDEL', 'HYPAYER', 'HYREC', 'IGOPTDEL', 'IGPAYER', 'IGREC', 'rebalance']\n", - "scenarios['options'] = scenarios[set(scenarios.columns).intersection(options)].sum(axis=1)" - ] + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { |
