aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics/option.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/analytics/option.py')
-rw-r--r--python/analytics/option.py70
1 files changed, 65 insertions, 5 deletions
diff --git a/python/analytics/option.py b/python/analytics/option.py
index 6f52bf3d..2ffbe462 100644
--- a/python/analytics/option.py
+++ b/python/analytics/option.py
@@ -8,6 +8,7 @@ import pandas as pd
from db import dbengine
from .black import black, Nx
+from .sabr import sabr
from .utils import GHquad, build_table
from .index import g, ForwardIndex, Index, engine
from yieldcurve import roll_yc
@@ -26,6 +27,7 @@ import matplotlib.pyplot as plt
from multiprocessing import Pool
from functools import partial
from itertools import chain
+from scipy.optimize import least_squares
from scipy.special import logit, expit
@@ -437,13 +439,16 @@ def compute_vol(option, strike, mid):
else:
return np.array([option.sigma, option.tail_prob, option.vega, option.moneyness, option.strike])
-def _get_keys(df):
+def _get_keys(df, models=["black", "precise"]):
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)
+ if models:
+ for model in models:
+ yield (quotedate, source, option_type, model)
+ else:
+ yield (quotedate, source, option_type)
class VolatilitySurface(ForwardIndex):
def __init__(self, index_type, series, tenor='5yr', trade_date=datetime.date.today()):
@@ -529,9 +534,9 @@ class VolatilitySurface(ForwardIndex):
swaption_class = Swaption
moneyness, T, r = [], [], []
if option_type == "payer":
- quotes = quotes.assign(mid = quotes[['pay_bid','pay_offer']].mean(1) * 1e-4)
+ 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)
+ quotes = quotes.assign(mid=quotes[['rec_bid','rec_offer']].mean(1) * 1e-4)
quotes = quotes.dropna(subset=['mid'])
with Pool(4) as p:
for expiry, df in quotes.groupby(['expiry']):
@@ -556,3 +561,58 @@ class VolatilitySurface(ForwardIndex):
else:
return self._surfaces[surface_id]
+def calib_sabr(x, option, strikes, pv, beta):
+ alpha, rho, nu = x
+ F = option.forward_spread
+ T = option.T
+ r = np.empty_like(strikes)
+ for i, K in enumerate(strikes):
+ option.strike = K
+ option.sigma = sabr(alpha, beta, rho, nu, F, option._strike, T)
+ r[i] = option.pv - pv[i]
+ return r
+
+class SABRVolatilitySurface(VolatilitySurface):
+ def __init__(self, index_type, series, tenor='5yr',
+ trade_date=datetime.date.today(), beta=None):
+ VolatilitySurface.__init__(self, index_type, series, tenor='5yr',
+ trade_date=datetime.date.today())
+ if index_type == "HY":
+ self.beta = 3.19
+ elif index_type == "IG":
+ self.beta = 1.84
+
+ def list(self, source=None, option_type=None):
+ """returns list of vol surfaces"""
+ r = []
+ 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):
+ r.append(k)
+ return r
+
+ def __getitem__(self, surface_id):
+ if surface_id not in self._surfaces:
+ quotedate, source, option_type = surface_id
+ quotes = self._quotes[(self._quotes.quotedate == quotedate) &
+ (self._quotes.quote_source == source)]
+ self._index.ref = quotes.ref.iat[0]
+
+ 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)
+ quotes = quotes.dropna(subset=['mid'])
+ for expiry, df in quotes.groupby(['expiry']):
+ option = BlackSwaption(self._index, expiry.date(), 100, option_type)
+ prog = least_squares(calib_sabr, (0.01, 0.3, 3.5),
+ bounds=([0, -1, 0], [np.inf, 1, np.inf]),
+ args=(option, df.strike.values, df.mid.values, self.beta))
+ T.append(option.T)
+ r.append(prog.x)
+ print(prog)
+ self._surfaces[surface_id] = (T, r)
+ return self._surfaces[surface_id]
+ else:
+ return self._surfaces[surface_id]