diff options
Diffstat (limited to 'python/analytics')
| -rw-r--r-- | python/analytics/option.py | 94 |
1 files changed, 57 insertions, 37 deletions
diff --git a/python/analytics/option.py b/python/analytics/option.py index 4fcc5023..e2177d6d 100644 --- a/python/analytics/option.py +++ b/python/analytics/option.py @@ -25,7 +25,10 @@ from scipy.optimize import brentq from scipy.integrate import simps from scipy.interpolate import SmoothBivariateSpline from matplotlib import cm +from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt +from joblib import Parallel, delayed +from itertools import chain def calib(S0, fp, exercise_date, exercise_date_settle, index, rolled_curve, tilt, w): @@ -364,24 +367,14 @@ class Swaption(ForwardIndex): ] return "\n".join(s) -def compute_vols(quote, option): - option.strike = quote.strike - option.ref = quote.ref - r = [] - for pv_type in ['pv', 'pv_black']: - for option_type in ['pay', 'rec']: - mid = (getattr(quote, '{}_bid'.format(option_type)) + - getattr(quote, '{}_offer'.format(option_type))) / 2 * 1e-4 - option.option_type = 'payer' if option_type == 'pay' else 'receiver' - - try: - setattr(option, pv_type, mid) - except ValueError as e: - r.append(None) - print(e) - else: - r.append(option.sigma) - return r +def compute_vol(option, strike, mid, pv_type): + option.strike = strike + try: + setattr(option, pv_type, mid) + except ValueError as e: + return None + else: + return option.sigma class VolatilitySurface(ForwardIndex): def __init__(self, index_type, series, tenor='5yr', trade_date=datetime.date.today()): @@ -394,23 +387,14 @@ class VolatilitySurface(ForwardIndex): parse_dates = ['quotedate', 'expiry'], params=(trade_date, index_type, series)) self._quotes['quotedate'] = (self._quotes['quotedate']. - dt.tz_convert('America/New_York')) + dt.tz_convert('America/New_York'). + dt.tz_localize(None)) + self._quotes = self._quotes.sort_values('quotedate') self._surfaces = {} for k, g in self._quotes.groupby(['quotedate', 'quote_source']): quotedate, source = k - self._index.spread = g.ref.iat[0] - moneyness, T, r = [], [], [] - for expiry, df in g.groupby(['expiry']): - atm_strike = ATMstrike(self._index, expiry.date(), index_type == "HY") - option = Swaption(self._index, expiry.date(), 100, - strike_is_price=index_type == "HY") - for quote in df.itertuples(index=False): - r.append(compute_vols(quote, option)) - moneyness.append(quote.strike/atm_strike) - T.append(option.T) - r = np.array(r) - f = SmoothBivariateSpline(T, moneyness, r[:,0], bbox=[0, 1, 0.5, 2]) - self._surfaces[(quotedate, source)] = f + for surface_type in ["payer", "receiver", "payer_black", "receiver_black"]: + self._surfaces[(quotedate, source, surface_type)] = None def vol(self, T, moneyness, surface_id): """computes the vol for a given moneyness and term.""" @@ -420,13 +404,49 @@ class VolatilitySurface(ForwardIndex): """returns list of vol surfaces""" return list(self._surfaces.keys()) + def __iter__(self): + return self._surfaces.items() + def plot(self, surface_id): fig = plt.figure() ax = fig.gca(projection='3d') - xx, yy = np.meshgrid(np.arange(0, 1, 0.01), - np.arange(0.5, 2, 0.01)) - surf = ax.plot_surface(xx, yy, self._surfaces[surface_id].ev(xx, yy), + 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[surface_id].ev(xx, yy), cmap = cm.viridis) + ax.set_xlabel("Year fraction") + ax.set_ylabel("Moneyness") + ax.set_zlabel("Volatility") - def get(self, surface_id): - return self._surfaces[surface_id] + def __getitem__(self, surface_id): + if self._surfaces[surface_id] is None: + quotedate, source, surface_type = surface_id + quotes = self._quotes[(self._quotes.quotedate == quotedate) & + (self._quotes.quote_source == source)] + + self._index.ref = quotes.ref.iat[0] + if "_" in surface_type: + option_type, _ = surface_type.split("_") + pv_type = "pv_black" + else: + option_type = surface_type + pv_type = "pv" + moneyness, T, r = [], [], [] + if option_type == "payer": + quotes = quotes.assign(mid = quotes[['pay_bid','pay_offer']].mean(1) * 1e-4) + else: + quotes = quotes.assign(mid = quotes[['rec_bid','rec_offer']].mean(1) * 1e-4) + for expiry, df in quotes.groupby(['expiry']): + atm_strike = ATMstrike(self._index, expiry.date()) + option = Swaption(self._index, expiry.date(), 100, option_type) + T.append(option.T * np.ones(df.shape[0])) + moneyness.append(df.strike.values / atm_strike) + r.append(Parallel(n_jobs=4)( + delayed(compute_vol)(option, strike, mid, pv_type) for strike, mid in + df[['strike', 'mid']].values)) + r = np.fromiter(chain(*r), np.float, quotes.shape[0]) + f = SmoothBivariateSpline(np.hstack(T), np.hstack(moneyness), r) + self._surfaces[surface_id] = f + return f + else: + return self._surfaces[surface_id] |
