aboutsummaryrefslogtreecommitdiffstats
path: root/python/swaption.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/swaption.py')
-rw-r--r--python/swaption.py105
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)