diff options
Diffstat (limited to 'python/swaption.py')
| -rw-r--r-- | python/swaption.py | 105 |
1 files changed, 95 insertions, 10 deletions
diff --git a/python/swaption.py b/python/swaption.py index 50dbdc4d..ba164e62 100644 --- a/python/swaption.py +++ b/python/swaption.py @@ -8,6 +8,7 @@ import array import math from scipy.optimize import brentq from scipy.integrate import simps +import numpy as np import datetime from tranche_functions import GHquad import pandas as pd @@ -223,29 +224,114 @@ def ATMstrike(index, exercise_date): b *= eta return brentq(closure, a, b) +class Option: + def __init__(self, index, exercise_date, strike, option_type="payer"): + self.index = index + self.exercise_date = exercise_date + self._T = None + self.exercise_date_settle = (pd.Timestamp(self.exercise_date) + 3* BDay()).date() + self.strike = strike + self.option_type = option_type.lower() + self._Z, self._w = GHquad(50) + self.notional = 1 + + @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)) + args = (fp, self.exercise_date, self.exercise_date_settle, + self.index, tilt, self._w) + eta = 1.1 + a = self.index.spread + b = self.index.spread * eta + while True: + if calib(*((b,) + args)) > 0: + break + b *= eta + + S0 = brentq(calib, a, b, args) + + G = g(self.index, self.strike, self.exercise_date) + print(S0) + Zstar = (math.log(self.strike/S0) + self.sigma**2/2 * T) / \ + (self.sigma * math.sqrt(T)) + if self.option_type == "payer": + Z = Zstar + np.logspace(0, 1.1, 100) - 1 + elif self.option_type == "receiver": + Z = Zstar - np.logspace(0, 1.1, 100) + 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, self.index._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) / \ + self.index._yc.discount_factor(self.index._value_date) + return self.notional * (simps(val, Z) * df_scale) + + @property + def delta(self): + old_index_pv = self.index.pv + old_pv = self.pv + self.index.spread += 0.1 + notional_ratio = self.index.notional/self.option.notional + delta = (self.pv - old_pv)/(self.index.pv - old_index_pv) * notional_ratio + self.index.spread -= 0.1 + return delta + + + @property + def T(self): + if self._T: + return self._T + else: + return year_frac(self.index.trade_date, self.exercise_date) + + @property + def gamma(self): + pass + + @property + def theta(self): + old_pv = self.pv + self._T = self.T - 1/365 + theta = self.pv - old_pv + self._T = None + return theta + + @property + def vega(self): + old_pv = self.pv + self.sigma += 0.01 + vega = self.pv - old_pv + self.sigma -= 0.01 + return vega + def option(index, exercise_date, sigma, K, option_type="payer"): """ computes the pv of an option using Pedersen's model """ - fp = index.forward_price(exercise_date) + fp = index.forward_pv(exercise_date)/index.notional #forward_yc = yield_curve.expected_forward_curve(exercise_date) #expiry is end of day (not sure if this is right) - T = year_frac(trade_date, exercise_date) + T = year_frac(index.trade_date, exercise_date) Z, w = GHquad(50) tilt = np.exp(-sigma**2/2 * T + sigma * Z * math.sqrt(T)) exercise_date_settle = (pd.Timestamp(exercise_date) + 3* BDay()).date() - args = (fp, forward_yc, exercise_date_settle, index, tilt, w) + args = (fp, exercise_date, exercise_date_settle, index, tilt, w) ## atm forward is greater than spread eta = 1.1 - a = ref - b = ref * eta + a = index.spread + b = index.spread * eta while True: if calib(*((b,) + args)) > 0: break b *= eta S0 = brentq(calib, a, b, args) S = S0 * tilt - G = g(K, forward_yc, index) - handle = lambda Z: g(S0 * math.exp(-sigma**2/2 * T + sigma * Z * math.sqrt(T)), - forward_yc, index) - G + G = g(index, K, exercise_date) + handle = lambda Z: g(index, S0 * math.exp(-sigma**2/2 * T + sigma * Z * math.sqrt(T)), + exercise_date) - G Zstar = brentq(handle, -3, 3) if option_type.lower() == "payer": Z = Zstar + np.logspace(0, 1.1, 300) - 1 @@ -254,8 +340,7 @@ def option(index, exercise_date, sigma, K, option_type="payer"): else: raise ValueError("option_type needs to be either 'payer' or 'receiver'") S = S0 * np.exp(-sigma**2/2 * T + sigma * Z * math.sqrt(T)) - df = forward_yc.discount_factor(exercise_date_settle) - a, b = strike_vec(S, forward_yc, exercise_date_settle, + a, b = strike_vec(S, index._yc, exercise_date, exercise_date_settle, index.start_date, index.end_date, index.recovery) val = ((a - b * index.fixed_rate)/df - G) * 1/math.sqrt(2*math.pi) * np.exp(-Z**2/2) return simps(val, Z) * yield_curve.discount_factor(exercise_date_settle) |
