aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/risk/__main__.py3
-rw-r--r--python/risk/indices.py70
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()