diff options
Diffstat (limited to 'python/analytics/option.py')
| -rw-r--r-- | python/analytics/option.py | 68 |
1 files changed, 49 insertions, 19 deletions
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) |
