aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics
diff options
context:
space:
mode:
Diffstat (limited to 'python/analytics')
-rw-r--r--python/analytics/option.py63
1 files changed, 38 insertions, 25 deletions
diff --git a/python/analytics/option.py b/python/analytics/option.py
index a0c00167..e3b8d21e 100644
--- a/python/analytics/option.py
+++ b/python/analytics/option.py
@@ -27,6 +27,8 @@ from multiprocessing import Pool
from functools import partial
from itertools import chain
+from scipy.special import logit, expit
+
def calib(S0, fp, exercise_date, exercise_date_settle,
index, rolled_curve, tilt, w):
S = S0 * tilt * 1e-4
@@ -427,10 +429,18 @@ def compute_vol(option, strike, mid):
try:
option.pv = mid
except ValueError as e:
- return None
+ return np.array([np.nan, np.nan, np.nan, option.moneyness, strike])
else:
return np.array([option.sigma, option.tail_prob, option.vega, option.moneyness, option.strike])
+def _get_keys(df):
+ for quotedate, source in (df[['quotedate', 'quote_source']].
+ drop_duplicates().
+ itertuples(index=False)):
+ for option_type in ["payer", "receiver"]:
+ for model in ["black", "precise"]:
+ yield (quotedate, source, option_type, model)
+
class VolatilitySurface(ForwardIndex):
def __init__(self, index_type, series, tenor='5yr', trade_date=datetime.date.today()):
self._index = Index.from_name(index_type, series, tenor, trade_date, notional=1.)
@@ -453,12 +463,6 @@ class VolatilitySurface(ForwardIndex):
self._quotes = self._quotes.sort_values('quotedate')
self._surfaces = {}
self._prob_surfaces = {}
- for k, g in self._quotes.groupby(['quotedate', 'quote_source']):
- quotedate, source = k
- for option_type in ["payer", "receiver"]:
- for model in ["black", "precise"]:
- self._surfaces[(quotedate, source, option_type, model)] = None
- self._prob_surfaces[(quotedate, source, option_type, model)] = None
def vol(self, T, moneyness, surface_id):
"""computes the vol for a given moneyness and term."""
@@ -467,7 +471,7 @@ class VolatilitySurface(ForwardIndex):
def list(self, source=None, option_type=None, model=None):
"""returns list of vol surfaces"""
r = []
- for k in self._surfaces.keys():
+ for k in _get_keys(self._quotes):
if (source is None or k[1] == source) and \
(option_type is None or k[2] == option_type) and \
(model is None or k[3] == model):
@@ -480,8 +484,10 @@ class VolatilitySurface(ForwardIndex):
def plot(self, surface_id):
fig = plt.figure()
ax = fig.gca(projection='3d')
- xx, yy = np.meshgrid(np.arange(0.1, 0.5, 0.01),
- np.arange(0.8, 1.7, 0.01))
+ surf = self[surface_id]
+ time, moneyness = surf.get_knots()
+ xx, yy = np.meshgrid(np.arange(time[0], time[-1], 0.01),
+ np.arange(moneyness[0], moneyness[-1], 0.01))
surf = ax.plot_surface(xx, yy, self[surface_id].ev(xx, yy),
cmap = cm.viridis)
ax.set_xlabel("Year fraction")
@@ -489,23 +495,26 @@ class VolatilitySurface(ForwardIndex):
ax.set_zlabel("Volatility")
def prob_surf(self, surface_id):
- if self._prob_surfaces[surface_id] is None:
+ if surface_id not in self._prob_surfaces:
self[surface_id]
return self._prob_surfaces[surface_id]
def prob_plot(self, surface_id):
fig = plt.figure()
ax = fig.gca(projection='3d')
- xx, yy = np.meshgrid(np.arange(0.1, 0.5, 0.01),
- np.arange(0.8, 1.7, 0.01))
- surf = ax.plot_surface(xx, yy, self.prob_surf(surface_id).ev(xx, yy),
- cmap = cm.viridis, vmax = 1)
+ surf = self.prob_surf(surface_id)
+ time, moneyness = surf.get_knots()
+ print(time[0], time[-1], moneyness[0], moneyness[-1])
+ xx, yy = np.meshgrid(np.arange(time[0], time[-1], 0.01),
+ np.arange(moneyness[0], moneyness[-1], 0.01))
+ surf = ax.plot_surface(xx, yy, expit(surf.ev(xx, yy)),
+ cmap=cm.viridis, vmax=1)
ax.set_xlabel("Year fraction")
ax.set_ylabel("Moneyness")
ax.set_zlabel("Tail Probability")
def __getitem__(self, surface_id):
- if self._surfaces[surface_id] is None:
+ if surface_id not in self._surfaces:
quotedate, source, option_type, model = surface_id
quotes = self._quotes[(self._quotes.quotedate == quotedate) &
(self._quotes.quote_source == source)]
@@ -524,19 +533,23 @@ class VolatilitySurface(ForwardIndex):
for expiry, df in quotes.groupby(['expiry']):
option = swaption_class(self._index, expiry.date(), 100, option_type)
T.append(option.T * np.ones(df.shape[0]))
- r.append(p.starmap(partial(compute_vol, option), df[['strike', 'mid']].values))
+ r.append(np.stack(p.starmap(partial(compute_vol, option), df[['strike', 'mid']].values)))
r = np.concatenate(r)
+ vol = r[:,0]
+ non_nan = ~np.isnan(vol)
+ vol = vol[non_nan]
time = np.hstack(T)
- moneyness = np.hstack(r[:,3])
- strike = np.hstack(r[:,4])
- f = SmoothBivariateSpline(time, moneyness, r[:,0])
- skew = SmoothBivariateSpline(time, strike, r[:,0]).ev(time, strike, dy=1)
- tail_prob = r[:,1] + (r[:,2] * 100) * (skew * 100)
- time, moneyness, tail_prob = fill_the_box(time, moneyness, tail_prob)
- g = SmoothBivariateSpline(time, moneyness, tail_prob)
+ time = time[non_nan]
+ moneyness = r[non_nan,3]
+ strike = r[non_nan,4]
+ f = SmoothBivariateSpline(time, moneyness, vol)
+ skew = SmoothBivariateSpline(time, strike, vol).ev(time, strike, dy=1)
+ tail_prob = r[non_nan,1] + r[non_nan,2] * skew * 1e4
+ # time, moneyness, tail_prob = fill_the_box(time, moneyness, tail_prob)
+ g = SmoothBivariateSpline(time, moneyness, logit(tail_prob))
self._surfaces[surface_id] = f
self._prob_surfaces[surface_id] = g
- return f
+ return self._surfaces[surface_id]
else:
return self._surfaces[surface_id]