aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/swaption.py73
1 files changed, 60 insertions, 13 deletions
diff --git a/python/swaption.py b/python/swaption.py
index 20cd2d03..5d00c9c8 100644
--- a/python/swaption.py
+++ b/python/swaption.py
@@ -320,7 +320,7 @@ def calib(S0, fp, exercise_date, exercise_date_settle, index, tilt, w):
return np.inner(vec, w) - fp
def g(index, spread, exercise_date):
- """ computes the strike price using the expected forward yield curve """
+ """ computes the strike clean price using the expected forward yield curve """
rolled_curve = roll_yc(index._yc, exercise_date)
step_in_date = exercise_date + datetime.timedelta(days=1)
exercise_date_settle = (pd.Timestamp(exercise_date) + 3* BDay()).date()
@@ -332,10 +332,23 @@ def g(index, spread, exercise_date):
rolled_curve, sc, True)
return index.notional * (spread - index.fixed_rate) * a *1e-4
+def g2(index, spread, exercise_date):
+ """ computes the strike price using the expected forward yield curve """
+ step_in_date = exercise_date + datetime.timedelta(days=1)
+ exercise_date_settle = (pd.Timestamp(exercise_date) + 3* BDay()).date()
+ sc = SpreadCurve(exercise_date, index._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,
+ index._yc, sc, True)
+ dl_pv = index._default_leg.pv(
+ exercise_date, step_in_date, exercise_date_settle, index._yc,
+ sc, index.recovery)
+ return index.notional * (dl_pv - a * index.fixed_rate * 1e-4)
+
def ATMstrike(index, exercise_date):
exercise_date_settle = (pd.Timestamp(exercise_date) + 3* BDay()).date()
- # df = index._yc.discount_factor(exercise_date_settle) / \
- # index._yc.discount_factor(index._value_date)
fp = index.forward_pv(exercise_date)
closure = lambda S: g(index, S, exercise_date) - fp
eta = 1.1
@@ -350,15 +363,23 @@ def ATMstrike(index, exercise_date):
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 = exercise_date
self.exercise_date_settle = (pd.Timestamp(self.exercise_date) + 3* BDay()).date()
+ self._T = None
self.strike = strike
self.option_type = option_type.lower()
self._Z, self._w = GHquad(50)
self.notional = 1
@property
+ def exercise_date(self):
+ return self._exercise_date
+ @exercise_date.setter
+ def exercise_date(self, d : datetime.date):
+ self._exercise_date = d
+ self.exercise_date_settle = (pd.Timestamp(d) + 3* BDay()).date()
+
+ @property
def pv(self):
fp = self.index.forward_pv(self.exercise_date)/self.index.notional
T = self.T
@@ -374,15 +395,20 @@ class Option:
b *= eta
S0 = brentq(calib, a, b, args)
-
G = g(self.index, self.strike, self.exercise_date)
- print(S0)
+ if T == 0:
+ pv = self.notional * (g(self.index, self.index.spread, self.exercise_date) - G)
+ if self.option_type == "payer":
+ return pv if self.index.spread > self.strike else 0
+ else:
+ return - pv if self.index.spread < self.strike else 0
+
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
+ Z = Zstar + np.logspace(0, 2, 300) - 1
elif self.option_type == "receiver":
- Z = Zstar - np.logspace(0, 1.1, 100) + 1
+ Z = Zstar - np.logspace(0, 2, 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))
@@ -390,9 +416,17 @@ class Option:
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)
+ df_scale = self.index._yc.discount_factor(self.exercise_date_settle)
+ return self.notional * simps(val, Z) * df_scale
+
+ @property
+ def pv2(self):
+ G = g(self.index, self.strike, self.exercise_date)
+ fp = self.index.forward_pv(self.exercise_date)
+ 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
+ return forward_annuity * black(DA_forward_spread, strike_tilde, self.T, self.sigma, self.option_type)
@property
def delta(self):
@@ -410,7 +444,7 @@ class Option:
if self._T:
return self._T
else:
- return year_frac(self.index.trade_date, self.exercise_date)
+ return year_frac(self.index.trade_date, self.exercise_date) + 1/365
@property
def gamma(self):
@@ -432,6 +466,19 @@ class Option:
self.sigma -= 0.01
return vega
+def d1(F, K, sigma, T):
+ return (np.log(F / K) + sigma**2 * T / 2) / (sigma * np.sqrt(T))
+
+def d2(F, K, sigma, T):
+ return d1(F, K, sigma, T) - sigma * np.sqrt(T)
+
+def black(F, K, T, sigma, option_type = "payer"):
+ chi = 1 if option_type == "payer" else -1
+ if option_type == "payer":
+ return F * norm.cdf(d1(F, K, sigma, T)) - K * norm.cdf(d2(F, K, sigma, T))
+ else:
+ return K * norm.cdf(- d2(F, K, sigma, T)) - F * norm.cdf(- d1(F, K, sigma, T))
+
def option(index, exercise_date, sigma, K, option_type="payer"):
""" computes the pv of an option using Pedersen's model """
fp = index.forward_pv(exercise_date)/index.notional