aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics/cms_spread.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/analytics/cms_spread.py')
-rw-r--r--python/analytics/cms_spread.py23
1 files changed, 15 insertions, 8 deletions
diff --git a/python/analytics/cms_spread.py b/python/analytics/cms_spread.py
index 2d5b2109..d9b0ecce 100644
--- a/python/analytics/cms_spread.py
+++ b/python/analytics/cms_spread.py
@@ -43,6 +43,7 @@ def close_dbs():
@vectorize([float64(float64, float64, float64, float64, float64, float64, float64,
float64, float64)], cache=True, nopython=True)
def h_call(z, K, S1, S2, mu_x, mu_y, sigma_x, sigma_y, rho):
+ # conditionned on S2, integral wrt S1
# z = (y - mu_y) / sigma_y
u1 = mu_x + rho * sigma_x * z
Ktilde = K + S2 * exp(mu_y + sigma_y * z)
@@ -215,8 +216,8 @@ def globeop_model(date, spread_index, yc, strike, rho, maturity,
vol1 = atm_vol.volatility(maturity, spread_index.swap_index1.tenor, 0.)
vol2 = atm_vol.volatility(maturity, spread_index.swap_index2.tenor, 0.)
vol_spread = sqrt(vol1**2 + vol2**2 - 2 * rho * vol1 * vol2)
- # normal vol is not scale independent and is computed in percent terms, so we scale
- # everything by 100.
+ # normal vol is not scale independent and is computed in percent terms, so
+ # we scale everything by 100.
return 0.01 * yc.discount(T) * bachelier(forward * 100, strike * 100, T, vol_spread)
def get_cms_coupons(trade_date, notional, option_tenor, spread_index,
@@ -263,7 +264,8 @@ def get_params(cms_beta, cms_gamma, atm_vol):
class CmsSpread:
def __init__(self, maturity, tenor1, tenor2, strike, option_tenor=None,
value_date=datetime.date.today(), notional=100_000_000,
- fixing_days=2, corr=0.8, mean_reversion=0.1):
+ conditional1=None, conditional2=None, fixing_days=2, corr=0.8,
+ mean_reversion=0.1):
""" tenor1 < tenor2"""
self._value_date = value_date
if maturity is None:
@@ -305,6 +307,8 @@ class CmsSpread:
self.cms2.set_pricer(self._cms_pricer)
self._params = get_params(self.cms1, self.cms2, atm_vol)
self._x, self._w = roots_hermitenorm(20)
+ self.conditional1 = conditional1
+ self.conditional2 = conditional2
@staticmethod
def from_tradeid(trade_id):
@@ -313,7 +317,7 @@ class CmsSpread:
"amount, expiration_date, floating_rate_index, strike, trade_date "
"FROM capfloors WHERE id = %s", (trade_id,))
r = c.fetchone()
- m = re.match("USD(\d{1,2})-(\d{1,2})CMS", r['floating_rate_index'])
+ m = re.match(r"USD(\d{1,2})-(\d{1,2})CMS", r['floating_rate_index'])
if m:
tenor2, tenor1 = map(int, m.groups())
instance = CmsSpread(r['expiration_date'], tenor1, tenor2, r['strike'] * 0.01,
@@ -326,7 +330,7 @@ class CmsSpread:
@corr.setter
def corr(self, val):
- self._corr.set_value(val)
+ self._corr.value = val
@property
def value_date(self):
@@ -344,6 +348,9 @@ class CmsSpread:
@property
def pv(self):
- return self.notional * 1 / sqrt(2 * pi) * \
- np.dot(self._w, h_call(self._x, self.strike, *self._params, self.corr)) * \
- self.yc.discount(self.cms1.fixing_date)
+ if self.conditional1 is not None:
+ bound = (log(self.conditional1 / self._params[1]) - self._params[3]) / self._params[-1]
+ else:
+ return self.notional * 1 / sqrt(2 * pi) * \
+ np.dot(self._w, h_call(self._x, self.strike, *self._params, self.corr)) * \
+ self.yc.discount(self.cms1.fixing_date)