diff options
Diffstat (limited to 'python/analytics/cms_spread.py')
| -rw-r--r-- | python/analytics/cms_spread.py | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/python/analytics/cms_spread.py b/python/analytics/cms_spread.py index 32c16ed1..e518c498 100644 --- a/python/analytics/cms_spread.py +++ b/python/analytics/cms_spread.py @@ -1,9 +1,8 @@ import numpy as np import matplotlib.pyplot as plt -from .tranche_functions import GHquad from math import exp, sqrt, log from .black import bachelier, cnd_erf -from numba import jit, float64, boolean +from numba import cfunc, int64, float64, boolean, types from quantlib.time.api import ( Date, Period, Days, Months, Years, UnitedStates, Actual365Fixed, Following) from quantlib.termstructures.yields.api import YieldTermStructure @@ -21,23 +20,45 @@ from quantlib.quotes import SimpleQuote from quantlib.math.matrix import Matrix from scipy.interpolate import RectBivariateSpline from db import dbconn +from numba import cfunc -@jit(float64(float64, float64, float64, float64, float64, float64, float64, - float64, float64, boolean), cache=True, nopython=True) -def h(z, K, S1, S2, mu_x, mu_y, sigma_x, sigma_y, rho, call=True): - # z = (y - mu_y) / sigma_y +# @jit(float64(float64, float64, float64, float64, float64, float64, float64, +# float64, float64, boolean), cache=True, nopython=True) +# def h(z, K, S1, S2, mu_x, mu_y, sigma_x, sigma_y, rho, call=True): +# # z = (y - mu_y) / sigma_y +# u1 = mu_x + rho * sigma_x * z +# Ktilde = K + S2 * exp(mu_y + sigma_y * z) +# u2 = log(Ktilde / S1) + +# v = sigma_x * sqrt(1 - rho * rho) +# v2 = sigma_x * sigma_x * (1 - rho * rho) +# if call: +# x = (u1 - u2) / v +# return 0.5 * (S1 * exp(u1 + 0.5 * v2) * cnd_erf(x + v) - Ktilde * cnd_erf(x)) +# else: +# x = (u2 - u1) / v +# return 0.5 * (Ktilde * cnd_erf(x) - S1 * exp(u1 + 0.5 * v2) * cnd_erf(x - v)) + +sig = types.double(types.intc, types.CPointer(types.double)) +@cfunc(sig, cache=True, nopython=True) +def h1(n, args): + z = args[0] + K = args[1] + S1 = args[2] + S2 = args[3] + mu_x = args[4] + mu_y = args[5] + sigma_x = args[6] + sigma_y = args[7] + rho = args[8] u1 = mu_x + rho * sigma_x * z Ktilde = K + S2 * exp(mu_y + sigma_y * z) u2 = log(Ktilde / S1) v = sigma_x * sqrt(1 - rho * rho) v2 = sigma_x * sigma_x * (1 - rho * rho) - if call: - x = (u1 - u2) / v - return 0.5 * (S1 * exp(u1 + 0.5 * v2) * cnd_erf(x + v) - Ktilde * cnd_erf(x)) - else: - x = (u2 - u1) / v - return 0.5 * (Ktilde * cnd_erf(x) - S1 * exp(u1 + 0.5 * v2) * cnd_erf(x - v)) + x = (u1 - u2) / v + return 0.5 * (S1 * exp(u1 + 0.5 * v2) * cnd_erf(x + v) - Ktilde * cnd_erf(x)) def get_fixings(conn, tenor1, tenor2, fixing_date=None): @@ -88,7 +109,7 @@ def get_swaption_vol_data(source="ICPL", vol_type=VolatilityType.ShiftedLognorma with conn.cursor() as c: c.execute(sql_str, params) surf_data = next(c) - return surf_data[0], np.array(surf_data[1:-1], order='F').T + return surf_data[0], np.array(surf_data[1:-1], order='F', dtype='float64').T def get_swaption_vol_surface(date, vol_type): @@ -118,26 +139,33 @@ def get_swaption_vol_matrix(date, data, vol_type=VolatilityType.ShiftedLognormal def quantlib_model(date, spread_index, yc, cap, rho, maturity, mean_rev=0., - vol_type=VolatilityType.ShiftedLognormal): + vol_type=VolatilityType.ShiftedLognormal, + notional=300_000_000): date, surf = get_swaption_vol_data(date=date, vol_type=vol_type) atm_vol = get_swaption_vol_matrix(date, surf, vol_type) pricer = LinearTsrPricer(atm_vol, SimpleQuote(mean_rev), yc) vol_type = VolatilityType(atm_vol.volatility_type) - cmsspread_pricer = LognormalCmsSpreadPricer(pricer, - SimpleQuote(rho), - yc) + if isinstance(rho, float): + rho = SimpleQuote(rho) + cmsspread_pricer = LognormalCmsSpreadPricer(pricer, rho, yc) end_date = Date.from_datetime(maturity) pay_date = spread_index.fixing_calendar.advance(end_date, 0, Days) start_date = end_date - Period(1, Years) - end_date = Date(19, 1, 2020) - cms_spread_coupon = CappedFlooredCmsSpreadCoupon( - pay_date, 300_000_000, start_date, end_date, + end_date = Date.from_datetime(maturity) + # we build an in arrear floored coupon + # see line 38 in ql/cashflows/capflooredcoupon.hpp + # The payoff $P$ of a floored floating-rate coupon is: + # \[ P = N \times T \times \max(a L + b, F). \] + # where $N$ is the notional, $T$ is the accrual time, $L$ is the floating rate, + # $a$ is its gearing, $b$ is the spread, and $F$ the strike + capped_floored_cms_spread_coupon = CappedFlooredCmsSpreadCoupon( + pay_date, notional, start_date, end_date, spread_index.fixing_days, spread_index, 1., -cap, floor=0., day_counter=Actual365Fixed(), is_in_arrears=True) - cms_spread_coupon.set_pricer(cmsspread_pricer) - return cms_spread_coupon + capped_floored_cms_spread_coupon.set_pricer(cmsspread_pricer) + return capped_floored_cms_spread_coupon def plot_surf(surf, tenors): |
