diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/risk/__main__.py | 3 | ||||
| -rw-r--r-- | python/risk/indices.py | 70 |
2 files changed, 72 insertions, 1 deletions
diff --git a/python/risk/__main__.py b/python/risk/__main__.py index 49a85eca..3ef61be6 100644 --- a/python/risk/__main__.py +++ b/python/risk/__main__.py @@ -4,6 +4,7 @@ from . import dbconn, dbengine from pandas.tseries.offsets import BDay from .bonds import subprime_risk, clo_risk, crt_risk, insert_subprime_risk from analytics import init_ontr +from .indices import insert_curve_risk from .swaptions import get_swaption_portfolio, insert_swaption_portfolio from .tranches import get_tranche_portfolio, insert_tranche_portfolio @@ -29,6 +30,8 @@ with dbconn("dawndb") as conn: insert_swaption_portfolio(portf, conn) portf = get_tranche_portfolio(workdate, conn) insert_tranche_portfolio(portf, conn) + insert_curve_risk(d, conn, ("SER_IGCURVE", "SER_ITRXCURVE")) + with dbconn("etdb") as etconn, dbconn("dawndb") as dawnconn: subprime = subprime_risk(workdate, dawnconn, mysql_engine) diff --git a/python/risk/indices.py b/python/risk/indices.py index 02aabb5e..4238927e 100644 --- a/python/risk/indices.py +++ b/python/risk/indices.py @@ -1,11 +1,19 @@ import datetime +import pandas as pd from analytics import Portfolio, CreditIndex +from analytics.curve_trades import on_the_run +from analytics.index_data import index_returns +from math import sqrt from psycopg2.extensions import connection from typing import Tuple def get_index_portfolio( - d: datetime.date, conn: connection, strategies: Tuple[str] = None, **kwargs + d: datetime.date, + conn: connection, + strategies: Tuple[str] = None, + exclude_redcode=[], + **kwargs ): sql_str = ( "SELECT security_id AS redcode, notional, maturity " @@ -26,7 +34,67 @@ def get_index_portfolio( value_date=d, ) for rec in c + if rec.redcode not in exclude_redcode ] portf = Portfolio(trades) portf.mark() return portf + + +def VaR( + portf: Portfolio, + index_type: str = "IG", + quantile=0.05, + years: int = 5, + period="monthly", +): + df = index_returns( + index=index_type, years=years, tenor=["3yr", "5yr", "7yr", "10yr"] + ) + df = df.reset_index(["index"], drop=True).reorder_levels( + ["date", "series", "tenor"] + ) + returns = df.spread_return.dropna().reset_index("series") + returns["dist_on_the_run"] = returns.groupby("date")["series"].transform( + lambda x: x.max() - x + ) + del returns["series"] + returns = returns.set_index("dist_on_the_run", append=True).unstack("tenor") + returns.columns = returns.columns.droplevel(0) + portf.reset_pv() + + otr = on_the_run(index_type) + spreads = pd.DataFrame( + { + "spread": portf.spread, + "tenor": [ind.tenor for ind in portf.indices], + "dist_on_the_run": [otr - ind.series for ind in portf.indices], + } + ) + spreads = spreads.set_index(["dist_on_the_run", "tenor"]) + r = [] + for k, g in returns.groupby(level="date", as_index=False): + shocks = g.reset_index("date", drop=True).stack("tenor") + shocks.name = "shocks" + portf.spread = spreads.spread * (1 + spreads.join(shocks).shocks) + r.append((k, portf.pnl)) + pnl = pd.DataFrame.from_records(r, columns=["date", "pnl"], index=["date"]) + if period == "daily": + return float(pnl.quantile(quantile)) + elif period == "monthly": + return float(pnl.quantile(quantile)) * sqrt(20) + else: + raise ValueError("period needs to be either 'daily' or 'monthly'") + + +def insert_curve_risk(d: datetime.date, conn: connection, strategies=("SER_IGCURVE",)): + sql_str = "INSERT INTO curve_risk VALUES(%s, %s, %s, %s)" + with conn.cursor() as c: + for strat in strategies: + portf = get_index_portfolio( + d, conn, (strat,), exclude_redcode=["2I65BYDU6"] + ) + index_type = "IG" if "IG" in strat else "EU" + var = VaR(portf, index_type, period="daily") + c.execute(sql_str, (d, strat, var, "USD" if index_type == "IG" else "EUR")) + conn.commit() |
