aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics/tranche_functions.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/analytics/tranche_functions.py')
-rw-r--r--python/analytics/tranche_functions.py66
1 files changed, 50 insertions, 16 deletions
diff --git a/python/analytics/tranche_functions.py b/python/analytics/tranche_functions.py
index 00fd0ec1..606457cd 100644
--- a/python/analytics/tranche_functions.py
+++ b/python/analytics/tranche_functions.py
@@ -1,17 +1,21 @@
import numpy as np
from ctypes import POINTER, c_int, c_double, byref
from numpy.ctypeslib import ndpointer
-from quantlib.time.schedule import Schedule, CDS2015
+from pyisda.legs import FeeLeg
+from pyisda.date import previous_twentieth
+from quantlib.time.schedule import Schedule, CDS2015, OldCDS
from quantlib.time.api import (
Actual360,
+ Date,
Period,
WeekendsOnly,
ModifiedFollowing,
Unadjusted,
+ pydate_from_qldate,
)
-from quantlib.util.converter import pydate_to_qldate
import pandas as pd
from scipy.special import h_roots
+from .utils import next_twentieth
import os
@@ -441,32 +445,62 @@ def tranche_pv(L, R, cs, K1, K2):
return tranche_pl(L, cs, K1, K2) + tranche_cl(L, R, cs, K2, K2)
-def credit_schedule(tradedate, tenor, coupon, yc, enddate=None):
- tradedate = pydate_to_qldate(tradedate)
+def credit_schedule(tradedate, coupon, yc, enddate=None, tenor=None, rule=CDS2015):
+ tradedate = Date.from_datetime(tradedate)
if enddate is None:
enddate = tradedate + Period(tenor)
else:
- enddate = pydate_to_qldate(enddate)
+ enddate = Date.from_datetime(enddate)
cal = WeekendsOnly()
DC = Actual360()
start_date = tradedate + 1
sched = Schedule.from_rule(
- tradedate, enddate, Period("3M"), cal, ModifiedFollowing, Unadjusted, CDS2015
+ start_date, enddate, Period("3M"), cal, ModifiedFollowing, Unadjusted, rule
)
- dates = sched.to_npdates()
- pydates = dates.astype("O")
- df = [yc.discount_factor(d) for d in pydates if d > start_date]
+ payment_dates = [pydate_from_qldate(cal.adjust(d)) for d in sched[1:]]
+ df = [yc.discount_factor(d) for d in payment_dates]
coupons = [
- DC.year_fraction(d1, d2) * coupon
- for d1, d2 in zip(sched[:-2], sched[1:-1])
- if d2 > start_date
+ DC.year_fraction(d1, d2) * coupon for d1, d2 in zip(sched[:-2], sched[1:-1])
]
coupons.append(Actual360(True).year_fraction(sched[-2], sched[-1]) * coupon)
- if dates[1] <= start_date:
- dates = dates[2:]
+ dates = sched.to_npdates()
+ start_dates = dates[:-1]
+ end_dates = dates[1:]
+ return pd.DataFrame(
+ {
+ "df": df,
+ "coupons": coupons,
+ "start_dates": start_dates,
+ "payment_dates": payment_dates,
+ },
+ index=end_dates,
+ )
+
+
+def credit_schedule_pyisda(
+ tradedate, coupon, yc, enddate=None, tenor=None, rule=CDS2015
+):
+ tradedate = Date.from_datetime(tradedate)
+ if enddate is None:
+ enddate = tradedate + Period(tenor)
else:
- dates = dates[1:]
- return pd.DataFrame({"df": df, "coupons": coupons}, index=dates)
+ enddate = Date.from_datetime(enddate)
+ start_date = pydate_from_qldate(tradedate + 1)
+ if (next_twentieth(start_date) - start_date).days < 30:
+ stub = "f/l"
+ else:
+ stub = "f/s"
+ print(stub)
+ if rule is CDS2015:
+ start_date = previous_twentieth(start_date)
+ fl = FeeLeg(start_date, pydate_from_qldate(enddate), True, 1.0, coupon, stub=stub)
+ df = pd.DataFrame({"coupons": [t[1] for t in fl.cashflows], **fl.inspect()})
+ df["df"] = [yc.discount_factor(d) for d in df.pay_dates]
+
+ df = df.rename(
+ columns={"acc_start_dates": "start_dates", "pay_dates": "payment_dates"}
+ ).set_index("acc_end_dates")
+ return df
def cds_accrued(tradedate, coupon):