diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/notebooks/swaption_risk.ipynb | 58 | ||||
| -rw-r--r-- | python/notebooks/swaption_scenarios.ipynb (renamed from python/notebooks/Option Trades.ipynb) | 210 |
2 files changed, 165 insertions, 103 deletions
diff --git a/python/notebooks/swaption_risk.ipynb b/python/notebooks/swaption_risk.ipynb index 8c38ecf8..00b5db55 100644 --- a/python/notebooks/swaption_risk.ipynb +++ b/python/notebooks/swaption_risk.ipynb @@ -84,64 +84,6 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "from analytics.scenarios import run_portfolio_scenarios\n", - "from analytics import BlackSwaptionVolSurface, CreditIndex\n", - "import analytics\n", - "import datetime\n", - "import numpy as np\n", - "\n", - "today = datetime.datetime.now()\n", - "yesterday = datetime.date.today() - pd.offsets.BDay()\n", - "\n", - "portf = get_swaption_portfolio(yesterday, conn, source_list=['GS'])\n", - "for i, amt in hedges.iteritems():\n", - " portf.add_trade(CreditIndex(i[:2], i[2:4], '5yr', value_date=yesterday, notional=amt), ('delta', i))\n", - "\n", - "vol_surface = {}\n", - "for trade in portf.swaptions:\n", - " vs = BlackSwaptionVolSurface(trade.index.index_type, trade.index.series, \n", - " value_date=today.date(), 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 = today\n", - "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, [today], params=['pnl', 'hy_equiv', 'sigma'],\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', value_date = today)\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" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pnl, hy_equiv" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], "source": [] } ], diff --git a/python/notebooks/Option Trades.ipynb b/python/notebooks/swaption_scenarios.ipynb index 32cd5b04..13639918 100644 --- a/python/notebooks/Option Trades.ipynb +++ b/python/notebooks/swaption_scenarios.ipynb @@ -9,17 +9,20 @@ "import datetime\n", "import pandas as pd\n", "import numpy as np\n", + "import analytics\n", + "import math\n", "\n", "from graphics import plot_color_map\n", "from analytics import Swaption, BlackSwaption, BlackSwaptionVolSurface, CreditIndex, Portfolio\n", "from analytics.scenarios import run_swaption_scenarios, run_index_scenarios, run_portfolio_scenarios, run_portfolio_scenarios_module\n", "from scipy.interpolate import SmoothBivariateSpline\n", - "from db import dbengine\n", + "from utils.db import dbconn, dbengine\n", + "from risk.swaptions import get_swaption_portfolio\n", "\n", - "from db import dbconn\n", - "from analytics import init_ontr\n", "conn = dbconn('dawndb')\n", - "init_ontr()\n", + "dawn_engine = dbengine('dawndb')\n", + "conn.autocommit=True\n", + "analytics.init_ontr()\n", "pd.options.display.float_format = \"{:,.2f}\".format" ] }, @@ -29,7 +32,46 @@ "metadata": {}, "outputs": [], "source": [ - "#Delta Chart: Red = Long Risk, Blue = Short Risk" + "portf = get_swaption_portfolio(datetime.date.today() - pd.offsets.BDay(), conn, source_list=['GS'])\n", + "\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", + " 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", + " 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'])\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", + " 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" ] }, { @@ -38,17 +80,26 @@ "metadata": {}, "outputs": [], "source": [ - "#Trade Analysis - see if the trade is net positive gamma\n", + "pnl, hy_equiv" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Trade Analysis - pre-trade analytics\n", "index = 'IG'\n", "series = 32\n", "option_delta = CreditIndex(index, series, '5yr') \n", - "option_delta.spread = 64\n", - "option1 = BlackSwaption(option_delta, datetime.date(2019, 7, 17), 60, option_type=\"payer\") \n", - "option2 = BlackSwaption(option_delta, datetime.date(2019, 7, 17), 75, option_type=\"payer\") \n", - "option1.sigma = .394 \n", - "option2.sigma = .52\n", - "option1.notional = 200_000_000 \n", - "option2.notional = 200_000_000 \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", + "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", @@ -61,7 +112,21 @@ "metadata": {}, "outputs": [], "source": [ - "portf" + "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", + "spread_shock = np.arange(-.2, 2, 0.01)\n", + "vol_surface = {}\n", + "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", + "\n", + "df = run_portfolio_scenarios(portf, date_range, params=[\"pnl\"],\n", + " spread_shock = spread_shock,\n", + " vol_shock = vol_shock,\n", + " vol_surface = vol_surface)\n", + "df = df.reset_index()\n", + "df.vol_shock = df.vol_shock.round(2)" ] }, { @@ -151,7 +216,7 @@ "outputs": [], "source": [ "plot_trade_scenarios(portf)\n", - "plot_trade_scenarios(portf, -.15, .8, vol_time_roll=False)" + "plot_trade_scenarios(portf, -.15, .5, vol_time_roll=False)" ] }, { @@ -248,36 +313,49 @@ "metadata": {}, "outputs": [], "source": [ - "#Current Positions\n", - "today = datetime.date.today()\n", - "swaption_sql_string = (\"select id, folder, expiration_date from swaptions where date(expiration_date) \"\n", - " \"> %s and swap_type = 'CD_INDEX_OPTION' \"\n", - " \"AND trade_date <= %s AND termination_date iS NULL\")\n", - "index_sql_string = (\"SELECT id, folder, sum(notional * case when protection='Buyer' then -1 else 1 end) \"\n", - " \"OVER (partition by security_id, attach) AS ntl_agg \"\n", - " \"FROM cds WHERE swap_type='CD_INDEX' AND termination_cp IS null \"\n", - " \"AND trade_date <= %s AND maturity > %s\")\n", - "conn = dawn_engine.raw_connection()\n", - "with conn.cursor() as c:\n", - " c.execute(swaption_sql_string, (today, today))\n", - " swaption_trades = [[dealid, f\"{folder}_{dealid}\", expiration_date] for dealid, folder, expiration_date in c]\n", - " c.execute(index_sql_string, (today, today))\n", - " index_trades = [[dealid, f\"{folder}_{dealid}\"] for dealid, folder, ntl in c if ntl != 0]\n", - "conn.close()\n", + "#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 = Portfolio([BlackSwaption.from_tradeid(dealid) for dealid, _, _ in swaption_trades],\n", - " [trade_id for _, trade_id, _ in swaption_trades])\n", - "index_trades = list(filter(lambda x: \"CURVE\" not in x[1], index_trades))\n", - "index_trades = list(filter(lambda x: \"SER_IGINDX\" not in x[1], index_trades))\n", - "index_trades = list(filter(lambda x: \"HEDGE_MBS\" not in x[1], index_trades))\n", - "index_trades = list(filter(lambda x: \"IGINX\" not in x[1], index_trades))\n", + "portf = get_swaption_portfolio(rundate, conn)\n", "\n", - "for trade_id, name in index_trades:\n", - " portf.add_trade(CreditIndex.from_tradeid(trade_id), name)\n", - " \n", - "portf.value_date = today\n", - " \n", - "results = calc_simple_scenario(portf, shock_min=-.3, shock_max=.3)" + "#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)" ] }, { @@ -285,7 +363,49 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "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)" + ] } ], "metadata": { @@ -308,5 +428,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } |
