aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/analytics/__init__.py2
-rw-r--r--python/analytics/credit_default_swap.py103
-rw-r--r--python/analytics/index.py10
3 files changed, 62 insertions, 53 deletions
diff --git a/python/analytics/__init__.py b/python/analytics/__init__.py
index e5a378b1..62cd168c 100644
--- a/python/analytics/__init__.py
+++ b/python/analytics/__init__.py
@@ -1,6 +1,8 @@
import sys
sys.path.append("..")
+# indicates whether we use local pricing
+_local = True
from utils.db import serenitas_engine, dawn_engine, dbconn, DataError, serenitas_pool
from functools import lru_cache
from .index import CreditIndex, ForwardIndex
diff --git a/python/analytics/credit_default_swap.py b/python/analytics/credit_default_swap.py
index e863de12..b6b2a16c 100644
--- a/python/analytics/credit_default_swap.py
+++ b/python/analytics/credit_default_swap.py
@@ -1,3 +1,4 @@
+import analytics
import array
import datetime
import math
@@ -11,8 +12,7 @@ from pandas.tseries.offsets import BDay
from pyisda.curve import SpreadCurve
from pyisda.date import previous_twentieth
from pyisda.legs import ContingentLeg, FeeLeg
-from termcolor import colored
-from .utils import build_table, get_fx
+from .utils import get_fx
from typing import Union
from weakref import WeakSet
from yieldcurve import get_curve, rate_helpers, YC, ql_to_jp
@@ -129,9 +129,10 @@ class CreditDefaultSwap:
@start_date.setter
def start_date(self, d):
- self._fee_leg = FeeLeg(d, self.end_date, True, 1.0, 1.0)
- self._default_leg = ContingentLeg(d, self.end_date, True)
- self._start_date = d
+ if d != self._start_date:
+ self._fee_leg = FeeLeg(d, self.end_date, True, 1.0, 1.0)
+ self._default_leg = ContingentLeg(d, self.end_date, True)
+ self._start_date = d
@end_date.setter
def end_date(self, d):
@@ -171,10 +172,10 @@ class CreditDefaultSwap:
else:
raise ValueError("Direction needs to be either 'Buyer' or 'Seller'")
- def _update(self):
+ def _update_spread_curve(self):
if self._spread is not None:
self._sc = SpreadCurve(
- self._yc.base_date,
+ self.value_date,
self._yc,
self.start_date,
self._step_in_date,
@@ -213,7 +214,7 @@ class CreditDefaultSwap:
""" s: spread in bps """
if self._spread is None or s != self.spread:
self._spread = s * 1e-4
- self._update()
+ self._update_spread_curve()
self.notify()
@property
@@ -224,7 +225,15 @@ class CreditDefaultSwap:
@property
def pv(self):
- return self.notional * self._factor * self._pv
+ if not analytics._local:
+ return (
+ self.notional
+ * self._factor
+ * self._pv
+ * get_fx(self.currency, self.value_date)
+ )
+ else:
+ return self.notional * self._factor * self._pv
@pv.setter
def pv(self, val):
@@ -233,15 +242,11 @@ class CreditDefaultSwap:
self.price = 100 * (1 - self._clean_pv)
@property
- def local_pv(self):
- if self.currency == "USD":
- return self.pv
- else:
- return self.pv * get_fx(self.currency, self.value_date)
-
- @property
def accrued(self):
- return -self.notional * self._factor * self._accrued * self.fixed_rate * 1e-4
+ r = -self.notional * self._factor * self._accrued * self.fixed_rate * 1e-4
+ if not analytics._local:
+ r *= get_fx(self.currency, self.value_date)
+ return r
@property
def days_accrued(self):
@@ -249,22 +254,17 @@ class CreditDefaultSwap:
@property
def clean_pv(self):
- return self.notional * self._factor * self._clean_pv
-
- @property
- def local_clean_pv(self):
- return self.clean_pv * get_fx(self.currency, self.value_date)
+ r = self.notional * self._factor * self._clean_pv
+ if not analytics._local:
+ r *= get_fx(self.currency, self.value_date)
+ return r
@property
def price(self):
- return self._price
-
- @property
- def local_price(self):
- if self.currency == "USD":
- return self._price
+ if not analytics._local:
+ return 100 + (self._price - 100) / get_fx(self.currency, self.value_date)
else:
- return 100 + (self.price - 100) / get_fx(self.currency, self.value_date)
+ return self._price
@price.setter
def price(self, val):
@@ -318,10 +318,12 @@ class CreditDefaultSwap:
old_pv, old_value_date = self.clean_pv, self.value_date
with warnings.catch_warnings():
warnings.simplefilter("ignore")
- self.value_date = self.value_date + relativedelta(days=1)
+ self._update_dates(self.value_date + relativedelta(days=1))
carry = -self.notional * self._factor * self.fixed_rate * 1e-4 / 360
+ if not analytics._local:
+ carry *= get_fx(self.currency, old_value_date)
roll_down = self.clean_pv - old_pv
- self.value_date = old_value_date
+ self._update_dates(old_value_date)
return carry + roll_down
@property
@@ -335,25 +337,25 @@ class CreditDefaultSwap:
rh.quote.value += 1e-4
ql_yc = YC(helpers)
self._yc = ql_to_jp(ql_yc)
- self._update() # to force recomputation
+ self._update_spread_curve() # to force recomputation
new_pv = self.pv
# for r in self._helpers:
# r.quote -= 1e-4
self._yc = old_yc
- self._update()
+ self._update_spread_curve()
return new_pv - old_pv
@property
def rec_risk(self):
old_recovery = self.recovery
self.recovery = old_recovery - 0.01
- self._update()
+ self._update_spread_curve()
pv_minus = self.pv
self.recovery = old_recovery + 0.01
- self._update()
+ self._update_spread_curve()
pv_plus = self.pv
self.recovery = old_recovery
- self._update()
+ self._update_spread_curve()
return (pv_plus - pv_minus) / 2
@property
@@ -375,52 +377,49 @@ class CreditDefaultSwap:
def value_date(self, d):
if self._value_date and d == self.value_date:
return
+ self._update_dates(d)
+ self._yc = get_curve(self.value_date, self.currency)
+ self._update_spread_curve()
+ self.notify()
+
+ def _update_dates(self, d):
if isinstance(d, datetime.datetime):
d = d.date()
self.start_date = previous_twentieth(d)
- self._yc = get_curve(d, self.currency)
self._value_date = d
self._step_in_date = d + datetime.timedelta(days=1)
self._accrued = self._fee_leg.accrued(self._step_in_date)
self._cash_settle_date = pd.Timestamp(self._value_date) + 3 * BDay()
- self._update()
- self.notify()
def reset_pv(self):
- self._original_clean_pv = self._clean_pv
- self._original_local_clean_pv = self._clean_pv * get_fx(
+ self._original_clean_pv = self._clean_pv * get_fx(
self.currency, self.value_date
)
+ self._original_local_clean_pv = self._clean_pv
self._trade_date = self._value_date
@property
def pnl(self):
if self._original_clean_pv is None:
raise ValueError("original pv not set")
- else:
- days_accrued = (self.value_date - self._trade_date).days / 360
+
+ days_accrued = (self.value_date - self._trade_date).days / 360
+ if not analytics._local:
return (
self.notional
* self._factor
* (
- self._clean_pv
+ self._clean_pv * get_fx(self.currency, self.value_date)
- self._original_clean_pv
- days_accrued * self.fixed_rate * 1e-4
)
)
-
- @property
- def local_pnl(self):
- if self.currency == "USD":
- return self.pnl
else:
- days_accrued = (self.value_date - self._trade_date).days / 360
return (
self.notional
* self._factor
* (
- (self._clean_pv - days_accrued * self.fixed_rate * 1e-4)
- * get_fx(self.currency, self.value_date)
+ self._clean_pv
- self._original_local_clean_pv
- days_accrued * self.fixed_rate * 1e-4
)
diff --git a/python/analytics/index.py b/python/analytics/index.py
index 9504451a..b4805df2 100644
--- a/python/analytics/index.py
+++ b/python/analytics/index.py
@@ -12,6 +12,9 @@ except ModuleNotFoundError:
pass
from pandas.tseries.offsets import BDay
from pyisda.curve import SpreadCurve
+from pyisda.date import previous_twentieth
+from termcolor import colored
+from .utils import build_table
def g(index, spread, exercise_date, pv=None):
@@ -114,7 +117,12 @@ class CreditIndex(CreditDefaultSwap):
else:
recovery = 0.3 if index_type == "HY" else 0.4
super().__init__(
- value_date, maturity, recovery, coupon, notional, df.issue_date[0]
+ previous_twentieth(value_date),
+ maturity,
+ recovery,
+ coupon,
+ notional,
+ df.issue_date[0],
)
self._quote_is_price = index_type == "HY"
self._indic = tuple(