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