diff options
Diffstat (limited to 'python/analytics/option.py')
| -rw-r--r-- | python/analytics/option.py | 63 |
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] |
