aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/analytics/option.py31
1 files changed, 19 insertions, 12 deletions
diff --git a/python/analytics/option.py b/python/analytics/option.py
index 2604e073..60861c99 100644
--- a/python/analytics/option.py
+++ b/python/analytics/option.py
@@ -2,7 +2,6 @@ from __future__ import division
import array
import datetime
-import hashlib
import math
import numpy as np
import pandas as pd
@@ -18,6 +17,7 @@ except ImportError:
import pickle
from pickle import dumps
+from functools import wraps
from pyisda.curve import SpreadCurve
from pyisda.flat_hazard import pv_vec
from scipy.optimize import brentq
@@ -31,6 +31,19 @@ def calib(S0, fp, exercise_date, exercise_date_settle,
index.fixed_rate * 1e-4)
return np.inner(pv, w) - fp
+def memoize(f):
+ @wraps(f)
+ def cached_f(*args, **kwargs):
+ obj = args[0]
+ key = (f.__name__, hash(obj))
+ if key in obj._cache:
+ return obj._cache[key]
+ else:
+ v = f(*args, **kwargs)
+ obj._cache[key] = v
+ return v
+ return cached_f
+
def ATMstrike(index, exercise_date):
exercise_date_settle = (pd.Timestamp(exercise_date) + 3* BDay()).date()
fp = index.forward_pv(exercise_date) / index.notional
@@ -104,17 +117,13 @@ class Swaption(ForwardIndex):
V = self.df * (self.forward_pv - self._G)
return max(V, 0) if self.option_type == "payer" else max(-V, 0)
- @property
- def _state(self):
- return hashlib.md5(dumps(
- {k: v for k, v in self.__dict__.items() if k not in
- ['_cache', '_Z', '_w']}, protocol = pickle.HIGHEST_PROTOCOL)).digest()
+ def __hash__(self):
+ return hash(dumps([v for k, v in self.__dict__.items() if k not in
+ ['_cache', '_Z', '_w']], protocol=pickle.HIGHEST_PROTOCOL))
@property
+ @memoize
def pv(self):
- k = self._state
- if k in self._cache:
- return self._cache[k]
T = self.T
tilt = np.exp(-self.sigma**2/2 * T + self.sigma * self._Z * math.sqrt(T))
args = (self.forward_pv, self.exercise_date, self.exercise_date_settle,
@@ -145,9 +154,7 @@ class Swaption(ForwardIndex):
self.exercise_date_settle, self.index.start_date,
self.index.end_date, self.index.recovery, self.index.fixed_rate * 1e-4)
val = (r - self._G) * 1/math.sqrt(2*math.pi) * np.exp(-Z**2/2)
- pv = self.notional * simps(val, Z) * self.df
- self._cache[k] = pv
- return pv
+ return self.notional * simps(val, Z) * self.df
@pv.setter
def pv(self, val):