aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/analytics/index.py2
-rw-r--r--python/analytics/option.py33
-rw-r--r--python/tests/test_swaption.py63
3 files changed, 58 insertions, 40 deletions
diff --git a/python/analytics/index.py b/python/analytics/index.py
index 06cd329c..4fcfc3d0 100644
--- a/python/analytics/index.py
+++ b/python/analytics/index.py
@@ -251,7 +251,6 @@ class ForwardIndex:
else:
self.forward_date = forward_date
self.exercise_date_settle = pd.Timestamp(forward_date) + 3 * BDay()
- self.df = index._yc.discount_factor(self.exercise_date_settle)
self._update()
if observer:
self.index.observe(self)
@@ -293,6 +292,7 @@ class ForwardIndex:
return hash(tuple(getattr(self, k) for k in ForwardIndex.__slots__[:-1]))
def _update(self, *args):
+ self.df = self.index._yc.discount_factor(self.exercise_date_settle)
if self.index.value_date > self.forward_date:
raise ValueError(
f"Option expired: value_date {self.index.value_date}"
diff --git a/python/analytics/option.py b/python/analytics/option.py
index c900900f..0908e854 100644
--- a/python/analytics/option.py
+++ b/python/analytics/option.py
@@ -168,11 +168,26 @@ class BlackSwaption(ForwardIndex):
def value_date(self, d):
self.index.value_date = d
strike, factor, cumloss = self._orig_params
+
if factor != self.index.factor:
cum_recovery = 100 * (factor - self.index.factor) - (
self.index.cumloss - cumloss
)
self.strike = (strike * factor - cum_recovery) / self.index.factor
+ else:
+ self._update_strike()
+
+ def _update_strike(self, K=None):
+ if self.index._quote_is_price:
+ if K:
+ self._G = (100 - K) / 100
+ self._strike = g(
+ self.index, self.index.fixed_rate, self.exercise_date, self._G
+ )
+ else:
+ if K:
+ self._strike = K
+ self._G = g(self.index, self._strike, self.exercise_date)
@property
def exercise_date(self):
@@ -182,12 +197,7 @@ class BlackSwaption(ForwardIndex):
def exercise_date(self, d):
self.forward_date = d
ForwardIndex.__init__(self, self.index, d)
- if self.index._quote_is_price:
- self._strike = g(
- self.index, self.index.fixed_rate, self.exercise_date, self._G
- )
- else:
- self._G = g(self.index, self._strike, self.exercise_date)
+ self._update_strike()
@property
def strike(self):
@@ -198,14 +208,7 @@ class BlackSwaption(ForwardIndex):
@strike.setter
def strike(self, K):
- if self.index._quote_is_price:
- self._G = (100 - K) / 100
- self._strike = g(
- self.index, self.index.fixed_rate, self.exercise_date, self._G
- )
- else:
- self._G = g(self.index, K, self.exercise_date)
- self._strike = K
+ self._update_strike(K)
@property
def atm_strike(self):
@@ -241,7 +244,7 @@ class BlackSwaption(ForwardIndex):
def intrinsic_value(self):
V = self.df * (self.forward_pv - self._G)
intrinsic = max(V, 0) if self.option_type == "payer" else max(-V, 0)
- return self._direction * intrinsic * self.notional
+ return self._direction * intrinsic * self.notional * self.index.factor
def __hash__(self):
return hash(
diff --git a/python/tests/test_swaption.py b/python/tests/test_swaption.py
index 40237b79..64b7e71c 100644
--- a/python/tests/test_swaption.py
+++ b/python/tests/test_swaption.py
@@ -2,14 +2,14 @@ import unittest
import datetime
import sys
-sys.path.append('..')
+
+sys.path.append("..")
from analytics.index import g
from analytics import CreditIndex, Swaption, BlackSwaption
class TestPutCallParity(unittest.TestCase):
- index = CreditIndex("ig", 27, "5yr",
- value_date=datetime.date(2016, 10, 25))
+ index = CreditIndex("ig", 27, "5yr", value_date=datetime.date(2016, 10, 25))
index.spread = 74
exercise_date = datetime.date(2017, 3, 15)
strike = 82.5
@@ -20,19 +20,23 @@ class TestPutCallParity(unittest.TestCase):
payer.sigma = 0.416
receiver.sigma = 0.416
df = self.index._yc.discount_factor(payer.exercise_date_settle)
- self.assertAlmostEqual(payer.pv - receiver.pv,
- df * (payer.forward_pv -
- g(self.index, self.strike, self.exercise_date)))
+ self.assertAlmostEqual(
+ payer.pv - receiver.pv,
+ df * (payer.forward_pv - g(self.index, self.strike, self.exercise_date)),
+ )
def test_parity_black(self):
payer = BlackSwaption(self.index, self.exercise_date, self.strike)
- receiver = BlackSwaption(self.index, self.exercise_date, self.strike, "receiver")
+ receiver = BlackSwaption(
+ self.index, self.exercise_date, self.strike, "receiver"
+ )
payer.sigma = 0.416
receiver.sigma = 0.416
df = self.index._yc.discount_factor(payer.exercise_date_settle)
- self.assertAlmostEqual(payer.pv - receiver.pv,
- df * (payer.forward_pv -
- g(self.index, self.strike, self.exercise_date)))
+ self.assertAlmostEqual(
+ payer.pv - receiver.pv,
+ df * (payer.forward_pv - g(self.index, self.strike, self.exercise_date)),
+ )
def test_calibration(self):
payer = Swaption(self.index, self.exercise_date, self.strike)
@@ -43,8 +47,7 @@ class TestPutCallParity(unittest.TestCase):
self.assertAlmostEqual(payer.sigma, 0.37648716)
def test_hy(self):
- index = CreditIndex("hy", 27, "5yr",
- value_date=datetime.date(2016, 11, 8))
+ index = CreditIndex("hy", 27, "5yr", value_date=datetime.date(2016, 11, 8))
index.price = 103.875
exercise_date = datetime.date(2017, 3, 15)
strike = 102.5
@@ -52,44 +55,56 @@ class TestPutCallParity(unittest.TestCase):
payer.pv = 1.948 * 1e-2
self.assertAlmostEqual(payer.sigma, 0.4156000826)
+
class TestBreakeven(unittest.TestCase):
exercise_date = datetime.date(2017, 3, 15)
- hyindex = CreditIndex("hy", 27, "5yr",
- value_date=datetime.date(2016, 11, 16))
+ hyindex = CreditIndex("hy", 27, "5yr", value_date=datetime.date(2016, 11, 16))
hyindex.price = 103.75
hystrike = 102.5
- igindex = CreditIndex("ig", 27, "5yr",
- value_date=datetime.date(2016, 11, 18))
+ igindex = CreditIndex("ig", 27, "5yr", value_date=datetime.date(2016, 11, 18))
igindex.spread = 76.5
igstrike = 80
def test_hypayer(self):
payer = Swaption(self.hyindex, self.exercise_date, self.hystrike)
- payer.sigma = .4
+ payer.sigma = 0.4
payer.notional = 100_000_000
self.assertAlmostEqual(payer.breakeven, 100.67426187413359)
def test_hyreceiver(self):
- receiver = Swaption(self.hyindex, self.exercise_date,
- self.hystrike, "receiver")
- receiver.sigma = .4
+ receiver = Swaption(self.hyindex, self.exercise_date, self.hystrike, "receiver")
+ receiver.sigma = 0.4
receiver.notional = 100_000_000
self.assertAlmostEqual(receiver.breakeven, 103.95644740397454)
def test_igpayer(self):
payer = Swaption(self.igindex, self.exercise_date, self.igstrike)
- payer.sigma = .4
+ payer.sigma = 0.4
payer.notional = 1e7
self.assertAlmostEqual(payer.breakeven, 88.366980851176223)
def test_igreceiver(self):
- receiver = Swaption(self.igindex, self.exercise_date,
- self.igstrike, "receiver")
- receiver.sigma = .4
+ receiver = Swaption(self.igindex, self.exercise_date, self.igstrike, "receiver")
+ receiver.sigma = 0.4
receiver.notional = 1e7
self.assertAlmostEqual(receiver.breakeven, 73.71594264020226)
+
+class TestMoveForward(unittest.TestCase):
+ trade = BlackSwaption.from_tradeid(7)
+
+ def test_move_value_date(self):
+ trade = BlackSwaption.from_tradeid(7)
+ trade.value_date = datetime.date(2017, 6, 5)
+ trade.mark()
+ ig23 = CreditIndex("IG", 28, "5yr", value_date=datetime.date(2017, 6, 5))
+ trade2 = BlackSwaption(ig23, datetime.date(2017, 6, 21), 65.0)
+ trade2.notional = 150_000_000
+ trade2.mark()
+ self.assertAlmostEqual(trade.pv, trade2.pv)
+
+
if __name__ == "__main__":
unittest.main()