diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/analytics/tranche_basket.py | 9 | ||||
| -rw-r--r-- | python/notebooks/tranche and swaption portfolio strategy.ipynb | 121 |
2 files changed, 73 insertions, 57 deletions
diff --git a/python/analytics/tranche_basket.py b/python/analytics/tranche_basket.py index ae2d73e2..853f8468 100644 --- a/python/analytics/tranche_basket.py +++ b/python/analytics/tranche_basket.py @@ -46,9 +46,9 @@ class DualCorrTranche(): self._Ngrid = 201 self._Z, self._w = GHquad(self._Ngh) self.rho = np.array([corr_attach, corr_detach]) - self.notional = notional self.tranche_running = tranche_running self._direction = -1. if notional > 0 else 1. + self.notional = abs(notional) self.cs = credit_schedule(value_date, None, 1., self._index.yc, self._index.maturities[0]) self._accrued = cds_accrued(value_date, tranche_running * 1e-4) @@ -176,15 +176,16 @@ class DualCorrTranche(): else: # TODO: handle factor change days_accrued = (self.value_date - self._trade_date).days / 360 - return self.notional * self._direction * -(self.pv - self._original_pv + + return self.notional * self._direction * (-self.pv + self._original_pv + self.tranche_running/10000 * days_accrued) def __repr__(self): s = ["{}{} {} Tranche".format(self.index_type, self.series, self.tenor), "", "{:<20}\t{:>15}".format("Value Date", ('{:%m/%d/%y}'. - format(self.value_date)))] - rows = [["Notional", self.notional * self._direction, "PV", self.pv *100], + format(self.value_date))), + "{:<20}\t{:>15}".format("Direction", self.direction)] + rows = [["Notional", self.notional, "PV", self.pv *100], ["Attach", self.attach, "Detach", self.detach], ["Attach Corr", self.rho[0] * 100, "Detach Corr", self.rho[1] * 100]] format_strings = [[None, '{:,.0f}', None, '{:,.4f}%'], diff --git a/python/notebooks/tranche and swaption portfolio strategy.ipynb b/python/notebooks/tranche and swaption portfolio strategy.ipynb index 0e521ed8..1b0e0a08 100644 --- a/python/notebooks/tranche and swaption portfolio strategy.ipynb +++ b/python/notebooks/tranche and swaption portfolio strategy.ipynb @@ -14,13 +14,11 @@ "from analytics.scenarios import run_tranche_scenarios, run_portfolio_scenarios, run_tranche_scenarios_rolldown\n", "from analytics import Swaption, BlackSwaption, CreditIndex, BlackSwaptionVolSurface, Portfolio, ProbSurface\n", "from analytics import DualCorrTranche\n", - "from db import dbengine\n", + "from db import dbconn\n", "from datetime import date\n", "from graphics import plot_color_map\n", "\n", - "dawnengine = dbengine('dawndb')\n", - "\n", - "value_date = (pd.datetime.today() - pd.offsets.BDay(1)).date()" + "value_date = (pd.datetime.today() - pd.offsets.BDay(2)).date()" ] }, { @@ -33,19 +31,48 @@ "index = 'IG'\n", "series = 30\n", "option_delta = CreditIndex(index, series, '5yr', value_date=value_date)\n", - "option_delta.spread = 65\n", - "option1 = BlackSwaption(option_delta, date(2018, 10, 17), 60, option_type=\"payer\")\n", - "option1.sigma = .398\n", + "option_delta.spread = 60\n", + "option1 = BlackSwaption(option_delta, date(2018, 11, 21), 62.5, option_type=\"payer\")\n", + "option1.sigma = .404\n", "option1.direction = 'Long'\n", - "option2 = BlackSwaption(option_delta, date(2018, 10, 17), 100, option_type=\"payer\")\n", - "option2.sigma = .609\n", + "option2 = BlackSwaption(option_delta, date(2018, 11, 21), 85, option_type=\"payer\")\n", + "option2.sigma = .588\n", "option2.direction = 'Short'\n", "option1.notional = 100_000_000\n", "option2.notional = 300_000_000\n", "option_delta.notional = option1.notional * option1.delta + option2.notional * option2.delta\n", "\n", - "portf = Portfolio([option1, option2, option_delta], trade_ids=['opt1', 'opt2', 'delta'])\n", - "portf.reset_pv()" + "#Get current Tranche positions\n", + "sql_string = (\"SELECT id, 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_TRANCHE' AND termination_cp IS NULL\")\n", + "conn = dbconn('dawndb')\n", + "with conn.cursor() as c:\n", + " c.execute(sql_string)\n", + " trade_ids = [dealid for dealid, ntl in c if ntl != 0]\n", + "portf = Portfolio([DualCorrTranche.from_tradeid(dealid) for dealid in trade_ids],\n", + " trade_ids)\n", + "portf.trades.extend([option1, option2, option_delta])\n", + "portf.trade_ids.extend(['opt1', 'opt2', 'delta'])\n", + "\n", + "spread_shock = np.arange(-.3, 1.1, .1)\n", + "corr_shock = np.arange(0, .1, 0.1)\n", + "vol_shock = np.arange(-.1, .3, 0.1)\n", + "earliest_expiry = min(portf.swaptions, key=lambda x: x.exercise_date).exercise_date\n", + "date_range = pd.date_range(value_date, earliest_expiry, periods=5)\n", + "vs = BlackSwaptionVolSurface(index, series, value_date=value_date)\n", + "ps = ProbSurface(index, series, value_date=value_date)\n", + "vol_surface = vs[vs.list(option_type='payer')[-1]]\n", + "portf.value_date = value_date\n", + "portf.mark()\n", + "portf.reset_pv()\n", + "\n", + "scens = run_portfolio_scenarios(portf, date_range, params=[\"pnl\"],\n", + " spread_shock=spread_shock,\n", + " corr_shock=corr_shock,\n", + " vol_shock=vol_shock,\n", + " vol_surface=vol_surface)\n", + "scens = round(scens,2)" ] }, { @@ -54,25 +81,29 @@ "metadata": {}, "outputs": [], "source": [ - "#Run Swaption sensitivities\n", - "#Set Shock range\n", - "shock_min = -.3\n", - "shock_max = 1.25\n", - "spread_shock = np.arange(shock_min, shock_max, 0.05)\n", - "#Set Date range\n", - "earliest_expiry = min(portf.swaptions, key=lambda x: x.exercise_date).exercise_date\n", - "date_range = pd.bdate_range(value_date, earliest_expiry - pd.offsets.BDay(), freq='20B')\n", - "#date_range = [earliest_expiry - pd.offsets.BDay()]\n", - "#Setup Vol Surface\n", - "vs = BlackSwaptionVolSurface(index,series, value_date=value_date)\n", - "ps = ProbSurface(index,series, value_date=value_date)\n", - "vol_surface = vs[vs.list(option_type='payer')[-1]]\n", - "swaption_scens = run_portfolio_scenarios(portf, date_range, params=[\"pnl\", \"delta\"],\n", - " spread_shock=spread_shock,\n", - " vol_shock = np.array([0]),\n", - " vol_surface=vol_surface)\n", - "#swaption delta is in protection terms: switch to risk terms\n", - "swaption_scens.delta = -swaption_scens.delta" + "sort_order = [True, False]\n", + "output = scens.xs((0,0), level=['corr_shock', 'vol_shock']).sum(axis=1)\n", + "(1+output.index.get_level_values(1)) * portf.swaptions[0].ref\n", + "output.name = 'pnl'\n", + "plot_color_map(output, sort_order)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#negative notional == sell protection\n", + "hy_tranche = DualCorrTranche('HY', 29, '5yr', attach=0, detach=15, corr_attach=np.nan, \n", + " corr_detach=.35, tranche_running=500, notional=-10000000)\n", + "portf1 = Portfolio([hy_tranche], [1])\n", + "scens = run_portfolio_scenarios(portf1, date_range, params=[\"pnl\"],\n", + " spread_shock=spread_shock,\n", + " corr_shock=corr_shock,\n", + " vol_shock=vol_shock,\n", + " vol_surface=vol_surface)\n", + "scens.xs((0,0), level=['corr_shock', 'vol_shock'])" ] }, { @@ -81,31 +112,15 @@ "metadata": {}, "outputs": [], "source": [ - "#Get current Tranche positions\n", - "sql_string = (\"select sum(notional * case when protection='Buyer' then -1 else 1 end) as ntl, security_id, attach \"\n", - " \"from cds where swap_type='CD_INDEX_TRANCHE' and termination_cp is null group by security_id, notional, attach\")\n", - "open_pos = pd.read_sql_query(sql_string, dawnengine)\n", - "for i, r in open_pos[open_pos.ntl != 0].iterrows():\n", - " sql_string = \"select id from cds where security_id = %s and attach = %s\" \n", - " trade_ids = pd.read_sql_query(sql_string, dawnengine, params=[r.security_id, r.attach])\n", - " for i1, r1 in trade_ids.iterrows():\n", - " portf.add_trades(bkt.DualCorrTranche.from_tradeid(r1[0]), i1)\n", "\n", - "#Set up portfolio scenarios\n", - "spread_shock = np.arange(-.05, .05, 0.05)\n", - "corr_shock = np.arange(-.1, .1, 0.1)\n", - "vol_shock = np.arange(-.1, .3, 0.5)\n", - "earliest_expiry = min(portf.swaptions, key=lambda x: x.exercise_date).exercise_date\n", - "date_range = pd.bdate_range(value_date, earliest_expiry - pd.offsets.BDay(), freq='20B')\n", - "vs = BlackSwaptionVolSurface(index,series, value_date=value_date)\n", - "ps = ProbSurface(index,series, value_date=value_date)\n", - "vol_surface = vs[vs.list(option_type='payer')[-1]]\n", - "portf.reset_pv()\n", - "scens = run_portfolio_scenarios(portf, date_range, params=[\"pnl\"],\n", + "##\n", + "scens_more = run_portfolio_scenarios(portf, date_range, params=['pnl', 'delta'],\n", " spread_shock=spread_shock,\n", " corr_shock=corr_shock,\n", - " vol_shock = vol_shock,\n", - " vol_surface=vol_surface)" + " vol_shock=vol_shock,\n", + " vol_surface=vol_surface)\n", + "#swaption delta is in protection terms: switch to risk terms\n", + "swaption_scens.delta = -swaption_scens.delta" ] }, { @@ -364,7 +379,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.6" + "version": "3.7.0" } }, "nbformat": 4, |
