diff options
Diffstat (limited to 'python/swaption.py')
| -rw-r--r-- | python/swaption.py | 100 |
1 files changed, 94 insertions, 6 deletions
diff --git a/python/swaption.py b/python/swaption.py index 4e81acb2..c713e617 100644 --- a/python/swaption.py +++ b/python/swaption.py @@ -1,11 +1,22 @@ from pyisda.legs import ContingentLeg, FeeLeg from pyisda.flat_hazard import strike_vec from pyisda.curve import YieldCurve, BadDay, SpreadCurve +from pyisda.utils import build_yc +from pyisda.cdsone import upfront_charge + +import array import math from scipy.optimize import brentq from scipy.integrate import simps import datetime from tranche_functions import GHquad +import pandas as pd +from pandas.tseries.offsets import BDay +from db import dbconn +from psycopg2 import DataError +from dates import prev_immdate + +serenitasdb = dbconn('serenitasdb') class Index(): """ minimal class to represent a credit index """ @@ -18,6 +29,10 @@ class Index(): self._fee_leg = FeeLeg(start_date, end_date, True, 1, 1) self._default_leg = ContingentLeg(start_date, end_date, 1) + self._trade_date = None + self._yc = None + self._risky_annuity = None + self._spread = None @property def start_date(self): @@ -39,17 +54,90 @@ class Index(): self._default_leg = ContingentLeg(self.start_date, d, 1) self._end_date = d - def pv(self, trade_date, exercise_date, yc, sc, h = None): + def forward_pv(self, trade_date, exercise_date, yc, sc, h = None): step_in_date = exercise_date + datetime.timedelta(days=1) - a = self._fee_leg.pv(trade_date, step_in_date, trade_date, yc, sc, False) + value_date = (pd.Timestamp(trade_date) + 3* BDay()).date() + a = self._fee_leg.pv(trade_date, step_in_date, value_date, yc, sc, False) Delta = self._fee_leg.accrued(step_in_date) if exercise_date > trade_date: Delta *= math.exp(-h * year_frac(trade_date, exercise_date)) clean_forward_annuity = a - Delta dl_pv = self._default_leg.pv( - trade_date, step_in_date, trade_date, yc, sc, self.recovery) - return dl_pv - clean_forward_annuity * self.fixed_rate, clean_forward_annuity + trade_date, step_in_date, value_date, yc, sc, self.recovery) + return self.notional*(dl_pv - clean_forward_annuity * self.fixed_rate), clean_forward_annuity + + @property + def spread(self): + return self._spread * 1e4 + + @spread.setter + def spread(self, s: float): + """ s: spread in bps """ + self._spread = s * 1e-4 + self._sc = SpreadCurve(self.trade_date, self._yc, self.start_date, + self._step_in_date, self._value_date, + [self.end_date], array.array('d', [self._spread]), + self.recovery) + self._risky_annuity = self._fee_leg.pv(self.trade_date, self._step_in_date, + self._value_date, self._yc, + self._sc, False) + self._accrued = self._fee_leg.accrued(self._step_in_date) + self._dl_pv = self._default_leg.pv( + self._trade_date, self._step_in_date, self._value_date, + self._yc, self._sc, self.recovery) + + @property + def pv(self): + return self.notional * (self._dl_pv - self._risky_annuity * self.fixed_rate) + + @property + def clean_pv(self): + accrued = self.notional * self._accrued * self.fixed_rate + return self.pv + accrued + + @property + def risky_annuity(self): + return self._risky_annuity + + @property + def trade_date(self): + if self._trade_date is None: + raise AttributeError('Please set trade_date first') + else: + return self._trade_date + + @trade_date.setter + def trade_date(self, d): + self.start_date = prev_immdate(pd.Timestamp(d)).date() + self._yc = build_yc(d, True) + self._trade_date = d + self._step_in_date = self.trade_date + datetime.timedelta(days=1) + self._value_date = (pd.Timestamp(self._trade_date) + 3* BDay()).date() + + @classmethod + def from_name(cls, index, series, tenor, trade_date = datetime.date.today()): + try: + with serenitasdb.cursor() as c: + c.execute("SELECT maturity, coupon FROM index_maturity " \ + "WHERE index=%s AND series=%s AND tenor = %s", + (index.upper(), series, tenor)) + maturity, coupon = next(c) + except DataError as e: + raise + else: + recovery = 0.4 if index.lower() == "ig" else 0.3 + start_date = prev_immdate(pd.Timestamp(trade_date)).date() + instance = cls(start_date, maturity, recovery, coupon*1e-4) + instance.trade_date = trade_date + return instance + + def __repr__(self): + return """Notional: {} +Maturity Date: {} +Coupon (bp): {} +Rec Rate: {}""".format(self.notional, self.end_date, self.fixed_rate*10000, + self.recovery) def year_frac(d1, d2, day_count_conv = "Actual/365"): """ compute the year fraction between two dates """ @@ -76,10 +164,10 @@ def flat_hazard(spread, yc, trade_date=datetime.date.today(), start_date = datetime.date.today(), end_date = datetime.date(2021, 6, 20), recovery_rate = 0.4): - step_in_date = start_date + datetime.timedelta(days=1) + step_in_date = trade_date + datetime.timedelta(days=1) if cash_settle_date is None: cash_settle_date = (pd.Timestamp(trade_date) + 3* BDay()).date() - sc = SpreadCurve(trade_date, yc, trade_date, step_in_date, + sc = SpreadCurve(trade_date, yc, start_date, step_in_date, cash_settle_date, [end_date], array.array('d', [spread]), recovery_rate) sc_data = sc.inspect()['data'] |
