diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/analytics/cms_spread.py | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/python/analytics/cms_spread.py b/python/analytics/cms_spread.py index c4f0bf58..ff222268 100644 --- a/python/analytics/cms_spread.py +++ b/python/analytics/cms_spread.py @@ -1,10 +1,16 @@ +import datetime +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D from .tranche_functions import GHquad from math import exp, sqrt, log -from .black import cnd_erf +from .black import bachelier from bbg_helpers import BBG_IP, retrieve_data, init_bbg_session -from quantlib.time.api import Date, Period, Days, Years, UnitedStates +from quantlib.time.api import ( + Date, Period, Days, Years, UnitedStates, Actual365Fixed, today) from quantlib.time.calendars.united_states import GOVERNMENTBOND from quantlib.indexes.swap.usd_libor_swap import UsdLiborSwapIsdaFixAm +from scipy.interpolate import RectBivariateSpline from yieldcurve import YC from db import dbconn @@ -62,18 +68,41 @@ def get_forward_spread(tenor1, tenor2, maturity): Date.from_datetime(maturity), 0, Days) - USFS1 = USISDA1.underlying_swap(Date.from_datetime(maturity)) - USFS2 = USISDA2.underlying_swap(Date.from_datetime(maturity)) + USFS1 = USISDA1.underlying_swap(expiration) + USFS2 = USISDA2.underlying_swap(expiration) return USFS2.fair_rate - USFS1.fair_rate -def get_swaption_vol_surface(): - sql_str = "SELECT * FROM swaption_vol ORDER BY date DESC LIMIT 1" +def get_swaption_vol_surface(source="ICPL", vol_type="N"): + if vol_type == "N": + table_name = "swaption_normal_vol" + else: + table_name = "swaption_lognormal_vol" + sql_str = "SELECT * FROM {table_name} WHERE source = %s ORDER BY date DESC LIMIT 1" conn = dbconn('serenitasdb') with conn.cursor() as c: - c.execute(sql_str) - return next(c) + c.execute(sql_str, (source,)) + surf_data = next(c) + date, surf = surf_data[0], np.array(surf_data[1:-1]) + if source == "ICPL": + tenors = [1/12, 0.25, 0.5] + list(range(1, 11)) + [15., 20., 25., 30.] + else: + tenors = [1/12, 0.25, 0.5, 0.75] + list(range(1, 11)) + [15., 20., 25., 30.] + return RectBivariateSpline(tenors, tenors[-14:], surf.T) + +def plot_surf(surf, tenors): + xx, yy = np.meshgrid(tenors, tenors[-14:]) + fig = plt.figure() + ax = fig.gca(projection='3d') + ax.plot_surface(xx, yy, surf.ev(xx, yy)) def globeop_model(tenor1, tenor2, rho, strike, maturity): forward = get_forward_spread(tenor1, tenor2, maturity) - vol_spread = sqrt(sigma0202**2 + sigma0230**2 - 2 * rho * sigma02 * sigma0230) - return black(forward, strike, T, False) + surf = get_swaption_vol_surface() + + T = Actual365Fixed().year_fraction(today(), Date.from_datetime(maturity)) + vol1 = float(surf(T, tenor1 )) * 0.01 + vol2 = float(surf(T, tenor2)) * 0.01 + vol_spread = sqrt(vol1**2 + vol2**2 - 2 * rho * vol1 * vol2) + yc = YC() + # the normal vols are not scale invariant. We multiply by 100 to get in percent terms. + return yc.discount(T) * bachelier(forward*100, strike*100, T, vol_spread) |
