aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/analytics/index.py13
-rw-r--r--python/analytics/option.py68
2 files changed, 55 insertions, 26 deletions
diff --git a/python/analytics/index.py b/python/analytics/index.py
index 95ec5210..bc3db1e1 100644
--- a/python/analytics/index.py
+++ b/python/analytics/index.py
@@ -17,20 +17,18 @@ from yieldcurve import YC, ql_to_jp, roll_yc, rate_helpers
serenitasdb = dbconn('serenitasdb')
-def g(index, spread : float, exercise_date : datetime.date, use_rolled_curve = True):
+def g(index, spread : float, exercise_date : datetime.date, forward_yc = None):
""" computes the strike clean price using the expected forward yield curve """
- if use_rolled_curve:
- rolled_curve = roll_yc(index._yc, exercise_date)
- else:
- rolled_curve = index._yc
+ if forward_yc is None:
+ forward_yc = index._yc
step_in_date = exercise_date + datetime.timedelta(days=1)
exercise_date_settle = (pd.Timestamp(exercise_date) + 3* BDay()).date()
- sc = SpreadCurve(exercise_date, rolled_curve, index.start_date,
+ sc = SpreadCurve(exercise_date, forward_yc, index.start_date,
step_in_date, exercise_date_settle,
[index.end_date], array.array('d', [spread * 1e-4]),
index.recovery)
a = index._fee_leg.pv(exercise_date, step_in_date, exercise_date_settle,
- rolled_curve, sc, True)
+ forward_yc, sc, True)
return (spread - index.fixed_rate) * a *1e-4
class Index():
@@ -103,6 +101,7 @@ class Index():
clean_forward_annuity = a - Delta * df * q
forward_price = self.notional * clean_forward_annuity * (self._spread -
self.fixed_rate*1e-4)
+
fep = self.notional * (1 - self.recovery) * (1 - q)
return forward_price / df + fep
diff --git a/python/analytics/option.py b/python/analytics/option.py
index ce47bd9c..e016a066 100644
--- a/python/analytics/option.py
+++ b/python/analytics/option.py
@@ -14,7 +14,6 @@ from pyisda.flat_hazard import strike_vec
from scipy.optimize import brentq
from scipy.integrate import simps
-
def calib(S0, fp, exercise_date : datetime.date, exercise_date_settle :datetime.date,
index, rolled_curve, tilt, w):
S = S0 * tilt * 1e-4
@@ -40,13 +39,15 @@ class Swaption:
def __init__(self, index, exercise_date : datetime.date, strike : float, option_type="payer"):
self.index = index
self._exercise_date = exercise_date
- self._forward_yc = roll_yc(self.index._yc, exercise_date)
+ self._forward_yc = roll_yc(index._yc, exercise_date)
self.exercise_date_settle = (pd.Timestamp(exercise_date) + 3* BDay()).date()
self._T = None
- self.strike = strike
+ self._strike = strike
self.option_type = option_type.lower()
self._Z, self._w = GHquad(50)
self.notional = 1
+ self._G = g(index, strike, exercise_date, self._forward_yc)
+ self._fp = self.index.forward_pv(self.exercise_date) / self.index.notional
@property
def exercise_date(self):
@@ -57,18 +58,26 @@ class Swaption:
self._exercise_date = d
self.exercise_date_settle = (pd.Timestamp(d) + 3* BDay()).date()
self._forward_yc = roll_yc(self.index._yc, d)
+ self._G = g(self.index, self.strike, self.exercise_date, self._forward_yc)
+
+ @property
+ def strike(self):
+ return self._strike
+
+ @strike.setter
+ def strike(self, K : float):
+ self._strike = K
+ self._G = g(self.index, K, self.exercise_date, self._forward_yc)
@property
def pv(self):
- fp = self.index.forward_pv(self.exercise_date) / self.index.notional
T = self.T
tilt = np.exp(-self.sigma**2/2 * T + self.sigma * self._Z * math.sqrt(T))
- rolled_curve = roll_yc(self.index._yc, self.exercise_date)
- args = (fp, self.exercise_date, self.exercise_date_settle,
+ args = (self._fp, self.exercise_date, self.exercise_date_settle,
self.index, self._forward_yc, tilt, self._w)
eta = 1.1
a = self.index.spread
- b = self.index.spread * eta
+ b = a * eta
while True:
if calib(*((b,) + args)) > 0:
break
@@ -76,9 +85,9 @@ class Swaption:
S0 = brentq(calib, a, b, args)
- G = g(self.index, self.strike, self.exercise_date)
if T == 0:
- pv = self.notional * (g(self.index, self.index.spread, self.exercise_date) - G)
+ pv = self.notional * (
+ g(self.index, self.index.spread, self.exercise_date, self._forward_yc) - self._G)
if self.option_type == "payer":
return pv if self.index.spread > self.strike else 0
else:
@@ -89,26 +98,25 @@ class Swaption:
if self.option_type == "payer":
Z = Zstar + np.logspace(0, math.log(4 / (self.sigma * math.sqrt(T)), 10), 300) - 1
- #Z = Zstar + np.logspace(0, 1.5, 300) - 1
elif self.option_type == "receiver":
Z = Zstar - np.logspace(0, math.log(4 / (self.sigma * math.sqrt(T)), 10), 300) + 1
else:
raise ValueError("option_type needs to be either 'payer' or 'receiver'")
S = S0 * np.exp(-self.sigma**2/2 * T + self.sigma * Z * math.sqrt(T))
- a, b = strike_vec(S * 1e-4, rolled_curve, self.exercise_date,
+ a, b = strike_vec(S * 1e-4, self._forward_yc, self.exercise_date,
self.exercise_date_settle,
self.index.start_date, self.index.end_date, self.index.recovery)
- val = ((a - b * self.index.fixed_rate*1e-4) - G) * 1/math.sqrt(2*math.pi) * np.exp(-Z**2/2)
- df_scale = self.index._yc.discount_factor(self.exercise_date_settle)
- return self.notional * simps(val, Z) * df_scale
+ val = ((a - b * self.index.fixed_rate*1e-4) - self._G) * 1/math.sqrt(2*math.pi) * np.exp(-Z**2/2)
+ df = self.index._yc.discount_factor(self.exercise_date_settle)
+ return self.notional * simps(val, Z) * df
@property
- def pv2(self):
- G = g(self.index, self.strike, self.exercise_date)
- fp = self.index.forward_pv(self.exercise_date) / self.index.notional
+ def pv_black(self):
+ """compute pv using black-scholes formula"""
+ df = self.index._yc.discount_factor(self.exercise_date_settle)
forward_annuity = self.index.forward_annuity(self.exercise_date)
DA_forward_spread = fp / forward_annuity + self.index.fixed_rate * 1e-4
- strike_tilde = self.index.fixed_rate * 1e-4 + G / forward_annuity
+ strike_tilde = self.index.fixed_rate * 1e-4 + self._G / forward_annuity * df
return forward_annuity * black(DA_forward_spread,
strike_tilde,
self.T,
@@ -125,7 +133,6 @@ class Swaption:
self.index.spread -= 0.1
return delta
-
@property
def T(self):
if self._T:
@@ -152,3 +159,26 @@ class Swaption:
vega = self.pv - old_pv
self.sigma -= 0.01
return vega
+
+ @property
+ def DV01(self):
+ old_pv = self.pv
+ self.index.spread += 1
+ dv01 = self.pv - old_pv
+ self.index.spread -= 1
+ return dv01
+
+ @property
+ def breakeven(self):
+ pv = self.pv / self.notional
+ G = g(self.index, self.strike, self.exercise_date)
+ aux = lambda S: g(self.index, S, self.exercise_date) - G - pv
+ eta = 1.1
+ a = self.strike
+ b = a * eta
+ while True:
+ if aux(b) > 0:
+ break
+ b *= eta
+
+ return brentq(aux, a, b)