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