aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--python/analytics/exceptions.py2
-rw-r--r--python/analytics/option.py34
-rw-r--r--python/analytics/tranche_basket.py7
3 files changed, 31 insertions, 12 deletions
diff --git a/python/analytics/exceptions.py b/python/analytics/exceptions.py
new file mode 100644
index 00000000..42dc11b0
--- /dev/null
+++ b/python/analytics/exceptions.py
@@ -0,0 +1,2 @@
+class MissingDataError(Exception):
+ pass
diff --git a/python/analytics/option.py b/python/analytics/option.py
index 803f6500..c334a47e 100644
--- a/python/analytics/option.py
+++ b/python/analytics/option.py
@@ -1,13 +1,15 @@
import bottleneck as bn
import datetime
+import logging
import math
import numpy as np
import pandas as pd
import analytics
from .black import black, Nx
+from .exceptions import MissingDataError
from .sabr import sabr
-from .utils import GHquad, build_table
+from .utils import GHquad, build_table, bus_day
from .index import g, ForwardIndex, CreditIndex
from .db import serenitas_engine, dawn_engine
from .utils import memoize
@@ -30,6 +32,8 @@ from scipy.integrate import quad
from scipy.special import logit, expit
+logger = logging.getLogger(__name__)
+
def calib(S0, fp, tilt, w, ctx):
return expected_pv(tilt, w, S0, ctx) - fp
@@ -94,22 +98,34 @@ class BlackSwaption(ForwardIndex):
instance._orig_params = (rec.strike, index.factor, index.cumloss)
return instance
- def mark(self, source_list=[], surface_id=None, **args):
+ def mark(self, source_list=[], surface_id=None, **kwargs):
ind = self.index
ind.mark()
# add None so that we always try everything
source_list = source_list + [None]
- vs = BlackSwaptionVolSurface(ind.index_type,
- ind.series,
- ind.tenor,
- ind.value_date,
- **args)
+ surface_date = kwargs.get("surface_date", ind.value_date)
+ i = 0
+ while i < 5:
+ try:
+ vs = BlackSwaptionVolSurface(ind.index_type,
+ ind.series,
+ ind.tenor,
+ surface_date,
+ **kwargs)
+
+ except MissingDataError as e:
+ logger.warning(str(e))
+ surface_date -= bus_day
+ logger.info(f"trying {self.value_date - bus_day}")
+ i += 1
+ else:
+ break
if surface_id is None:
for source in source_list:
if len(vs.list(source, self.option_type)) >= 1:
break
else:
- raise ValueError("No market data available for this day")
+ raise MissingDataError(f"{type(self).__name__}: No quote for type {self.option_type} and date {self.value_date}")
surface_id = vs.list(source, self.option_type)[-1]
try:
self.sigma = float(vs[surface_id](self.T, np.log(self.moneyness)))
@@ -508,7 +524,7 @@ class QuoteSurface():
self._quotes.loc[(self._quotes.quote_source == "GS") & (self._quotes['index'] =="HY"),
["pay_bid", "pay_offer", "rec_bid", "rec_offer"]] *=100
if self._quotes.empty:
- raise ValueError(f"No quotes for date: {value_date}")
+ raise MissingDataError(f"{type(self).__name__}: No market quote for date {value_date}")
self._quotes['quotedate'] = (self._quotes['quotedate'].dt.
tz_convert('America/New_York').
dt.tz_localize(None))
diff --git a/python/analytics/tranche_basket.py b/python/analytics/tranche_basket.py
index 48353b46..56d5b0f2 100644
--- a/python/analytics/tranche_basket.py
+++ b/python/analytics/tranche_basket.py
@@ -3,6 +3,7 @@ from .tranche_functions import (
credit_schedule, adjust_attachments, GHquad, BCloss_recov_dist,
BCloss_recov_trunc, tranche_cl, tranche_pl, tranche_pl_trunc,
tranche_cl_trunc)
+from .exceptions import MissingDataError
from .index_data import get_tranche_quotes
from .utils import memoize, build_table, bus_day, next_twentieth
from collections import namedtuple
@@ -72,7 +73,7 @@ class Skew():
conn.commit()
serenitas_pool.putconn(conn)
if not K:
- raise ValueError(f"No skew for {index_type}{series} {tenor} on {value_date}")
+ raise MissingDataError(f"No skew for {index_type}{series} {tenor} on {value_date}")
K.append(100)
K = np.array(K) / 100
K = adjust_attachments(K, cumloss/100, factor/100)
@@ -406,7 +407,7 @@ class DualCorrTranche():
try:
ref, = c.fetchone()
except TypeError:
- raise ValueError(f"No quote for date {self.value_date}")
+ raise MissingDataError(f"{type(self).__name__}: No market quote for date {self.value_date}")
try:
self._index.tweak([ref])
except NameError:
@@ -424,7 +425,7 @@ class DualCorrTranche():
self.series,
self.tenor,
value_date=d))
- except ValueError as e:
+ except MissingDataError as e:
logger.warning(str(e))
d -= bus_day
logger.info(f"trying {d}")