aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/swaption.py100
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']