aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics
diff options
context:
space:
mode:
Diffstat (limited to 'python/analytics')
-rw-r--r--python/analytics/index.py98
-rw-r--r--python/analytics/option.py38
-rw-r--r--python/analytics/portfolio.py24
-rw-r--r--python/analytics/scenarios.py6
4 files changed, 83 insertions, 83 deletions
diff --git a/python/analytics/index.py b/python/analytics/index.py
index 58cada76..f27bef6d 100644
--- a/python/analytics/index.py
+++ b/python/analytics/index.py
@@ -53,11 +53,11 @@ class Index(object):
""" minimal class to represent a credit index """
__slots__ = ['fixed_rate', 'notional', '_start_date', '_end_date',
'recovery', '_version', '_fee_leg', '_default_leg',
- '_trade_date', '_yc', '_sc', '_risky_annuity', '_spread',
+ '_value_date', '_yc', '_sc', '_risky_annuity', '_spread',
'_price', 'name', 'issue_date', '_quote_is_price',
'_direction', 'currency', '_step_in_date', '_accrued',
- '_value_date', '_dl_pv', '_pv', '_clean_pv',
- '_original_clean_pv', '_original_trade_date',
+ '_cash_settle_date', '_dl_pv', '_pv', '_clean_pv',
+ '_original_clean_pv', '_trade_date',
'index_type', 'series', 'tenor', '_observed']
def __init__(self, start_date, end_date, recovery, fixed_rate,
notional=10e6, quote_is_price=False, issue_date=None):
@@ -80,7 +80,7 @@ class Index(object):
self._fee_leg = FeeLeg(self._start_date, end_date, True, 1., 1.)
self._default_leg = ContingentLeg(self._start_date, end_date, True)
- self._trade_date = None
+ self._value_date = None
self._yc, self._sc = None, None
self._risky_annuity = None
self._spread, self._price = None, None
@@ -88,9 +88,9 @@ class Index(object):
self.issue_date = issue_date
self._quote_is_price = quote_is_price
self._direction = -1.
- for attr in ['currency', '_step_in_date', '_value_date', '_accrued',
+ for attr in ['currency', '_step_in_date', '_cash_settle_date', '_accrued',
'_dl_pv', '_pv', '_clean_pv', '_original_clean_pv',
- '_original_trade_date', 'index_type', 'series', 'tenor']:
+ '_trade_date', 'index_type', 'series', 'tenor']:
setattr(self, attr, None)
self._observed = WeakSet()
@@ -148,16 +148,16 @@ class Index(object):
raise ValueError("Direction needs to be either 'Buyer' or 'Seller'")
def _update(self):
- self._sc = SpreadCurve(self.trade_date, self._yc, self.start_date,
- self._step_in_date, self._value_date,
+ self._sc = SpreadCurve(self.value_date, self._yc, self.start_date,
+ self._step_in_date, self._cash_settle_date,
[self.end_date], np.array([self._spread]), np.zeros(1),
np.array([self.recovery]))
- self._risky_annuity = self._fee_leg.pv(self.trade_date, self._step_in_date,
- self._value_date, self._yc,
+ self._risky_annuity = self._fee_leg.pv(self.value_date, self._step_in_date,
+ self._cash_settle_date, self._yc,
self._sc, False)
self._dl_pv = self._default_leg.pv(
- self.trade_date, self._step_in_date, self._value_date,
+ self.value_date, self._step_in_date, self._cash_settle_date,
self._yc, self._sc, self.recovery)
self._pv = self._dl_pv - self._risky_annuity * self.fixed_rate * 1e-4
self._clean_pv = self._pv + self._accrued * self.fixed_rate * 1e-4
@@ -209,16 +209,16 @@ class Index(object):
if self._price is None or math.fabs(val-self._price) > 1e-6:
self._clean_pv = (100 - val) / 100
self._sc = SpreadCurve(
- self.trade_date, self._yc, self.start_date,
- self._step_in_date, self._value_date,
+ self.value_date, self._yc, self.start_date,
+ self._step_in_date, self._cash_settle_date,
[self.end_date], array.array('d',[self.fixed_rate*1e-4]),
array.array('d', [self._clean_pv]),
array.array('d', [self.recovery]))
self._risky_annuity = self._fee_leg.pv(
- self.trade_date, self._step_in_date, self._value_date,
+ self.value_date, self._step_in_date, self._cash_settle_date,
self._yc, self._sc, False)
self._dl_pv = self._default_leg.pv(
- self.trade_date, self._step_in_date, self._value_date,
+ self.value_date, self._step_in_date, self._cash_settle_date,
self._yc, self._sc, self.recovery)
self._pv = self._clean_pv - self._accrued * self.fixed_rate * 1e-4
self._spread = self._clean_pv / (self._risky_annuity - self._accrued) \
@@ -250,13 +250,13 @@ class Index(object):
@property
def theta(self):
- old_pv, old_trade_date = self.clean_pv, self.trade_date
+ old_pv, old_value_date = self.clean_pv, self.value_date
with warnings.catch_warnings():
warnings.simplefilter("ignore")
- self.trade_date = self.trade_date + relativedelta(days=1)
+ self.value_date = self.value_date + relativedelta(days=1)
carry = self.notional * self._direction * self.fixed_rate * 1e-4/360
roll_down = self.clean_pv - old_pv
- self.trade_date = old_trade_date
+ self.value_date = old_value_date
return carry + roll_down
@property
@@ -265,7 +265,7 @@ class Index(object):
# for rh in self._helpers:
# rh.quote += 1e-4
# self._yc = ql_to_jp(self._ql_yc)
- helpers = rate_helpers(self.currency, evaluation_date=self.trade_date)
+ helpers = rate_helpers(self.currency, evaluation_date=self.value_date)
for rh in helpers:
rh.quote += 1e-4
ql_yc = YC(helpers)
@@ -301,32 +301,32 @@ class Index(object):
return self._risky_annuity - self._accrued
@property
- def trade_date(self):
- if self._trade_date is None:
- raise AttributeError('Please set trade_date first')
+ def value_date(self):
+ if self._value_date is None:
+ raise AttributeError('Please set value_date first')
else:
- return self._trade_date
+ return self._value_date
- @trade_date.setter
- def trade_date(self, d):
+ @value_date.setter
+ def value_date(self, d):
if isinstance(d, datetime.datetime):
d = d.date()
self.start_date = previous_twentieth(d)
self._yc = get_curve(d, self.currency)
# use the rolled forward curve if we price something in the future
- if self._yc.base_date < d:
- self._yc = self._yc.expected_forward_curve(d)
- self._trade_date = d
- self._step_in_date = self.trade_date + datetime.timedelta(days=1)
+ # if self._yc.base_date < d:
+ # self._yc = self._yc.expected_forward_curve(d)
+ self._value_date = d
+ self._step_in_date = d + datetime.timedelta(days=1)
self._accrued = self._fee_leg.accrued(self._step_in_date)
- self._value_date = pd.Timestamp(self._trade_date) + 3* BDay()
+ self._cash_settle_date = pd.Timestamp(self._value_date) + 3* BDay()
if self._spread is not None:
self._update()
self.notify()
def reset_pv(self):
self._original_clean_pv = self._clean_pv
- self._original_trade_date = self._trade_date
+ self._trade_date = self._value_date
@property
def pnl(self):
@@ -334,7 +334,7 @@ class Index(object):
raise ValueError("original pv not set")
else:
## TODO: handle factor change
- days_accrued = (self.trade_date - self._original_trade_date).days / 360
+ days_accrued = (self.value_date - self._trade_date).days / 360
return - self._direction * self.notional * self.factor * \
(self._clean_pv - self._original_clean_pv -
days_accrued * self.fixed_rate * 1e-4)
@@ -347,7 +347,7 @@ class Index(object):
self._observed.add(obj)
def mark(self):
- if self.trade_date == datetime.date.today():
+ if self.value_date == datetime.date.today():
with init_bbg_session(BBG_IP) as session:
security = self.name + " Corp"
field = "PX_LAST"
@@ -356,14 +356,14 @@ class Index(object):
else:
run = _engine.execute("""SELECT * FROM index_quotes
WHERE index=%s AND series=%s AND tenor=%s AND date=%s""",
- (self.index_type, self.series, self.tenor, self.trade_date))
+ (self.index_type, self.series, self.tenor, self.value_date))
rec = run.fetchone()
self.spread = rec.closespread
@property
def factor(self):
for lastdate, factor, _ in self._version:
- if lastdate >= self.trade_date:
+ if lastdate >= self.value_date:
return factor
else:
return 1
@@ -371,13 +371,13 @@ class Index(object):
@property
def version(self):
for lastdate, _, version in self._version:
- if lastdate >= self.trade_date:
+ if lastdate >= self.value_date:
return version
else:
return None
@classmethod
- def from_name(cls, index=None, series=None, tenor=None, trade_date=datetime.date.today(),
+ def from_name(cls, index=None, series=None, tenor=None, value_date=datetime.date.today(),
notional=10_000_000, redcode=None, maturity=None):
if all([index, series, tenor]):
sql_str = "SELECT indexfactor, lastdate, maturity, coupon, " \
@@ -409,7 +409,7 @@ class Index(object):
return None
else:
recovery = 0.4 if index_type in ['IG', 'EU'] else 0.3
- instance = cls(trade_date, maturity, recovery, coupon, notional,
+ instance = cls(value_date, maturity, recovery, coupon, notional,
index_type == "HY", df.issue_date[0])
instance._version = tuple((ld.date(), factor / 100, version) for ld, factor, version in \
df[['lastdate', 'indexfactor', 'version']].itertuples(index=False))
@@ -428,7 +428,7 @@ class Index(object):
instance.currency = "USD"
else:
instance.currency = "EUR"
- instance.trade_date = trade_date
+ instance.value_date = value_date
return instance
@classmethod
@@ -452,10 +452,10 @@ class Index(object):
instance.name = rec.security_desc
instance.currency = rec.currency
instance.direction = rec.protection
- instance.trade_date = rec.trade_date
+ instance.value_date = rec.trade_date
instance.pv = rec.upfront
instance._original_clean_pv = instance._clean_pv
- instance._original_trade_date = rec.trade_date
+ instance._trade_date = rec.trade_date
instance.index_type = index_type
instance.series = rec.series
instance.tenor = rec.tenor
@@ -488,8 +488,8 @@ class Index(object):
s += build_table(rows, format_strings, "{:<20}{:>19}\t\t{:<20}{:>15}")
s += ["",
colored("Calculator", attrs = ['bold'])]
- rows = [["Valuation Date", self.trade_date],
- ["Cash Settled On", self._value_date]]
+ rows = [["Valuation Date", self.value_date],
+ ["Cash Settled On", self._cash_settle_date]]
format_strings = [[None, '{:%m/%d/%y}'],
[None, '{:%m/%d/%y}']]
s += build_table(rows, format_strings, "{:<20}\t{:>15}")
@@ -524,8 +524,8 @@ class ForwardIndex(object):
@classmethod
def from_name(cls, index_type, series, tenor, forward_date,
- trade_date=datetime.date.today(), notional=10e6):
- index = Index.from_name(index_type, series, tenor, trade_date, notional)
+ value_date=datetime.date.today(), notional=10e6):
+ index = Index.from_name(index_type, series, tenor, value_date, notional)
return cls(index, forward_date)
@property
@@ -552,12 +552,12 @@ class ForwardIndex(object):
return hash(tuple(getattr(self, k) for k in ForwardIndex.__slots__ if k != '__weakref__'))
def _update(self, *args):
- if self.index.trade_date > self.forward_date:
- return
+ if self.index.value_date > self.forward_date:
+ raise ValueError("Option expired")
if self.index._sc is not None:
step_in_date = self.forward_date + datetime.timedelta(days=1)
- a = self.index._fee_leg.pv(self.index.trade_date, step_in_date,
- self.index.trade_date, self.index._yc, self.index._sc, False)
+ a = self.index._fee_leg.pv(self.index.value_date, step_in_date,
+ self.index.value_date, self.index._yc, self.index._sc, False)
Delta = self.index._fee_leg.accrued(step_in_date)
q = self.index._sc.survival_probability(self.forward_date)
self._forward_annuity = a - Delta * self.df * q
diff --git a/python/analytics/option.py b/python/analytics/option.py
index f21f683f..4257b4e9 100644
--- a/python/analytics/option.py
+++ b/python/analytics/option.py
@@ -104,7 +104,7 @@ class BlackSwaption(ForwardIndex):
if rec is None:
return ValueError("trade_id doesn't exist")
if index is None:
- index = Index.from_name(redcode=rec.security_id, maturity=rec.maturity, trade_date=rec.trade_date)
+ index = Index.from_name(redcode=rec.security_id, maturity=rec.maturity, value_date=rec.trade_date)
index.ref = rec.index_ref
instance = cls(index, rec.expiration_date, rec.strike, rec.swaption_type.lower(),
direction="Long" if rec.buysell else "Short")
@@ -243,7 +243,7 @@ class BlackSwaption(ForwardIndex):
if self._original_pv is None:
raise ValueError("original pv not set")
else:
- if self.index.trade_date > self.forward_date: #TODO: do the right thing
+ if self.index.value_date > self.forward_date: #TODO: do the right thing
return 0 - self._original_pv
else:
return self.pv - self._original_pv
@@ -268,7 +268,7 @@ class BlackSwaption(ForwardIndex):
if self._T:
return self._T
else:
- return ((self.exercise_date - self.index.trade_date).days + 0.25)/365
+ return ((self.exercise_date - self.index.value_date).days + 0.25)/365
@property
def gamma(self):
@@ -330,7 +330,7 @@ class BlackSwaption(ForwardIndex):
s = ["{:<20}{}".format(self.index.name, self.option_type),
"",
"{:<20}\t{:>15}".format("Trade Date", ('{:%m/%d/%y}'.
- format(self.index.trade_date)))]
+ format(self.index.value_date)))]
rows = [["Ref Sprd (bp)", self.index.spread, "Coupon (bp)", self.index.fixed_rate],
["Ref Price", self.index.price, "Maturity Date", self.index.end_date]]
format_strings = [[None, "{:.2f}", None, "{:,.2f}"],
@@ -448,7 +448,7 @@ def _get_keys(df, models=["black", "precise"]):
yield (quotedate, source, option_type)
class QuoteSurface():
- def __init__(self, index_type, series, tenor='5yr', trade_date=datetime.date.today()):
+ def __init__(self, index_type, series, tenor='5yr', value_date=datetime.date.today()):
self._quotes = pd.read_sql_query(
"SELECT quotedate, index, series, ref, fwdspread, expiry, " \
"swaption_quotes.*, quote_source " \
@@ -459,7 +459,7 @@ class QuoteSurface():
"ORDER BY quotedate DESC",
_engine,
parse_dates=['quotedate', 'expiry'],
- params=(trade_date, index_type.upper(), series))
+ params=(value_date, index_type.upper(), series))
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:
@@ -468,7 +468,7 @@ class QuoteSurface():
dt.tz_convert('America/New_York').
dt.tz_localize(None))
self._quotes = self._quotes.sort_values('quotedate')
- self.trade_date = trade_date
+ self.value_date = value_date
def list(self, source=None):
"""returns list of quotes"""
@@ -481,8 +481,8 @@ class QuoteSurface():
return r
class VolSurface(QuoteSurface):
- def __init__(self, index_type, series, tenor='5yr', trade_date=datetime.date.today()):
- super().__init__(index_type, series, tenor, trade_date)
+ def __init__(self, index_type, series, tenor='5yr', value_date=datetime.date.today()):
+ super().__init__(index_type, series, tenor, value_date)
self._surfaces = {}
def __getitem__(self, surface_id):
@@ -491,7 +491,7 @@ class VolSurface(QuoteSurface):
quotes = self._quotes[(self._quotes.quotedate == quotedate) &
(self._quotes.quote_source == source)]
quotes = quotes.assign(moneyness=quotes.strike / quotes.fwdspread,
- time=((quotes.expiry - self.trade_date).dt.days + 0.25) / 365)
+ time=((quotes.expiry - self.value_date).dt.days + 0.25) / 365)
spline = lambda df: CubicSpline(np.log(df.moneyness), df.vol, bc_type="natural")
h = quotes.sort_values('moneyness').groupby('time').apply(spline)
self._surfaces[surface_id] = MyInterp(h.index.values, h.values)
@@ -552,9 +552,9 @@ def _calibrate(index, quotes, option_type, **kwargs):
return _calibrate_sabr(index, quotes, option_type, kwargs['beta'])
class ModelBasedVolSurface(VolSurface):
- def __init__(self, index_type, series, tenor='5yr', trade_date=datetime.date.today()):
- super().__init__(index_type, series, tenor, trade_date)
- self._index = Index.from_name(index_type, series, tenor, trade_date, notional=1.)
+ def __init__(self, index_type, series, tenor='5yr', value_date=datetime.date.today()):
+ super().__init__(index_type, series, tenor, value_date)
+ self._index = Index.from_name(index_type, series, tenor, value_date, notional=1.)
self._surfaces = {}
self._quotes = self._quotes.assign(
pay_mid=self._quotes[['pay_bid', 'pay_offer']].mean(1) * 1e-4,
@@ -619,18 +619,18 @@ def _forward_annuity(expiry, index):
step_in_date = expiry + datetime.timedelta(days=1)
expiry_settle = pd.Timestamp(expiry) + 3* BDay()
df = index._yc.discount_factor(expiry_settle)
- a = index._fee_leg.pv(index.trade_date, step_in_date,
- index.trade_date, index._yc, index._sc, False)
+ a = index._fee_leg.pv(index.value_date, step_in_date,
+ index.value_date, index._yc, index._sc, False)
Delta = index._fee_leg.accrued(step_in_date)
q = index._sc.survival_probability(expiry)
return a - Delta * df * q
class ProbSurface(QuoteSurface):
- def __init__(self, index_type, series, tenor='5yr', trade_date=datetime.date.today()):
- super().__init__(index_type, series, tenor, trade_date)
+ def __init__(self, index_type, series, tenor='5yr', value_date=datetime.date.today()):
+ super().__init__(index_type, series, tenor, value_date)
self._surfaces = {}
- self._index = Index.from_name(index_type, series, tenor, trade_date)
+ self._index = Index.from_name(index_type, series, tenor, value_date)
def __getitem__(self, surface_id):
if surface_id not in self._surfaces:
@@ -638,7 +638,7 @@ class ProbSurface(QuoteSurface):
quotes = self._quotes[(self._quotes.quotedate == quotedate) &
(self._quotes.quote_source == source)]
self._index.ref = quotes.ref.iat[0]
- quotes = quotes.assign(time=((quotes.expiry - self.trade_date).dt.days + 0.25) / 365,
+ quotes = quotes.assign(time=((quotes.expiry - self.value_date).dt.days + 0.25) / 365,
pay_mid=quotes[['pay_bid','pay_offer']].mean(1),
rec_mid=quotes[['rec_bid','rec_offer']].mean(1),
forward_annuity=quotes.expiry.apply(_forward_annuity,
diff --git a/python/analytics/portfolio.py b/python/analytics/portfolio.py
index bea0f5cd..fd73e0e5 100644
--- a/python/analytics/portfolio.py
+++ b/python/analytics/portfolio.py
@@ -33,14 +33,14 @@ class Portfolio:
self.trades = trades
self.indices = [t for t in trades if isinstance(t, Index)]
self.swaptions = [t for t in trades if isinstance(t, BlackSwaption)]
- trade_dates = set(index.trade_date for index in self.indices)
+ value_dates = set(index.value_date for index in self.indices)
self._keys = [(index.index_type, index.series, index.tenor) for index in self.indices]
for swaption in self.swaptions:
- trade_dates.add(swaption.index.trade_date)
- self._trade_date = trade_dates.pop()
- if len(trade_dates) >= 1:
+ value_dates.add(swaption.index.value_date)
+ self._value_date = value_dates.pop()
+ if len(value_dates) >= 1:
warn("not all instruments have the same trade date, picking {}".
- format(self._trade_date))
+ format(self._value_date))
self._vs = {}
@property
@@ -64,18 +64,18 @@ class Portfolio:
t.reset_pv()
@property
- def trade_date(self):
- return self._trade_date
+ def value_date(self):
+ return self._value_date
- @trade_date.setter
- def trade_date(self, d):
+ @value_date.setter
+ def value_date(self, d):
#we try to keep everybody in sync
for index in self.indices:
- index.trade_date = d
+ index.value_date = d
if len(self.indices) == 0:
for swaption in self.swaptions:
- self.swaption.trade_date = d
- self._trade_date = d
+ self.swaption.value_date = d
+ self._value_date = d
def mark(self, source_list=[], option_type=None, model="black", surface_id=None):
#add None so that we always try everything
diff --git a/python/analytics/scenarios.py b/python/analytics/scenarios.py
index 65f77563..52aadcfd 100644
--- a/python/analytics/scenarios.py
+++ b/python/analytics/scenarios.py
@@ -28,7 +28,7 @@ def run_swaption_scenarios(swaption, date_range, spread_shock, vol_shock,
r = []
for date in date_range:
- swaption.index.trade_date = date.date()
+ swaption.index.value_date = date.date()
if vol_time_roll: T = swaption.T
for s in spreads:
swaption.ref = s
@@ -46,7 +46,7 @@ def run_index_scenarios(index, date_range, spread_shock, params=['pnl']):
r = []
for date in date_range:
- index.trade_date = date.date()
+ index.value_date = date.date()
for s in spreads:
index.spread = s
r.append([date, s] + [getattr(index, p) for p in params])
@@ -86,7 +86,7 @@ def run_portfolio_scenarios(portf, date_range, spread_shock, vol_shock,
with MaybePool(nproc) as pool:
pmap = pool.map if pool else map
for date in date_range:
- portf.trade_date = date.date()
+ portf.value_date = date.date()
if vol_time_roll:
t = [swaption.T for swaption in portf.swaptions]
for s in spreads: