aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics/portfolio.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/analytics/portfolio.py')
-rw-r--r--python/analytics/portfolio.py158
1 files changed, 121 insertions, 37 deletions
diff --git a/python/analytics/portfolio.py b/python/analytics/portfolio.py
index acef2a88..01ddd795 100644
--- a/python/analytics/portfolio.py
+++ b/python/analytics/portfolio.py
@@ -7,6 +7,7 @@ import logging
logger = logging.getLogger(__name__)
+
def portf_repr(method):
def f(*args):
obj = args[0]
@@ -17,23 +18,29 @@ def portf_repr(method):
return "N/A"
else:
return f"{100*x:.2f}%"
+
header = f"Portfolio {obj.value_date}\n\n"
- kwargs = {'formatters': {'Notional': thousands,
- 'PV': thousands,
- 'Delta': percent,
- 'Gamma': percent,
- 'Theta': thousands,
- 'Vega': thousands,
- 'Vol': percent,
- 'Ref': thousands,
- 'Attach Rho': percent,
- 'Detach Rho': percent,
- 'HY Equiv': thousands},
- 'index': False}
- if method == 'string':
- kwargs['line_width'] = 100
- s = getattr(obj._todf(), 'to_' + method)(**kwargs)
+ kwargs = {
+ "formatters": {
+ "Notional": thousands,
+ "PV": thousands,
+ "Delta": percent,
+ "Gamma": percent,
+ "Theta": thousands,
+ "Vega": thousands,
+ "Vol": percent,
+ "Ref": thousands,
+ "Attach Rho": percent,
+ "Detach Rho": percent,
+ "HY Equiv": thousands,
+ },
+ "index": False,
+ }
+ if method == "string":
+ kwargs["line_width"] = 100
+ s = getattr(obj._todf(), "to_" + method)(**kwargs)
return header + s
+
return f
@@ -44,7 +51,9 @@ class Portfolio:
value_dates = set(t.value_date for t in self.trades)
self._value_date = value_dates.pop()
if len(value_dates) >= 1:
- logger.warn(f"not all instruments have the same trade date, picking {self._value_date}")
+ logger.warn(
+ f"not all instruments have the same trade date, picking {self._value_date}"
+ )
def add_trade(self, trades, trade_ids):
self.trades.append(trades)
@@ -116,7 +125,9 @@ class Portfolio:
raise
def shock(self, params=["pnl"], **kwargs):
- return {trade_id: trade.shock(params, **kwargs) for trade_id, trade in self.items()}
+ return {
+ trade_id: trade.shock(params, **kwargs) for trade_id, trade in self.items()
+ }
@property
def ref(self):
@@ -158,18 +169,22 @@ class Portfolio:
for index, val in zip(self.indices, val):
index.spread = val
else:
- raise ValueError("The number of spreads doesn't match the number of indices")
+ raise ValueError(
+ "The number of spreads doesn't match the number of indices"
+ )
@property
def delta(self):
"""returns the equivalent protection notional
makes sense only where there is a single index."""
- return sum([getattr(t, 'delta', t._direction) * t.notional for t in self.trades])
+ return sum(
+ [getattr(t, "delta", t._direction) * t.notional for t in self.trades]
+ )
@property
def gamma(self):
- return sum([getattr(t, 'gamma', 0) * t.notional for t in self.trades])
+ return sum([getattr(t, "gamma", 0) * t.notional for t in self.trades])
@property
def dv01(self):
@@ -184,34 +199,103 @@ class Portfolio:
return sum(t.hy_equiv for t in self.trades)
def _todf(self):
- headers = ["Product", "Index", "Notional", "Ref", "Strike", "Direction",
- "Type", "Expiry", "Vol", "PV", "Delta", "Gamma", "Theta",
- "Vega", "attach", "detach", "Attach Rho", "Detach Rho", "HY Equiv"]
+ headers = [
+ "Product",
+ "Index",
+ "Notional",
+ "Ref",
+ "Strike",
+ "Direction",
+ "Type",
+ "Expiry",
+ "Vol",
+ "PV",
+ "Delta",
+ "Gamma",
+ "Theta",
+ "Vega",
+ "attach",
+ "detach",
+ "Attach Rho",
+ "Detach Rho",
+ "HY Equiv",
+ ]
rec = []
for t in self.trades:
if isinstance(t, CreditIndex):
name = f"{t.index_type}{t.series} {t.tenor}"
- r = ("Index", name, t.notional, t.ref, "N/A",
- t.direction, "N/A", "N/A", None, t.pv,
- 1., 0., t.theta, 0.,
- None, None, None, None, t.hy_equiv)
+ r = (
+ "Index",
+ name,
+ t.notional,
+ t.ref,
+ "N/A",
+ t.direction,
+ "N/A",
+ "N/A",
+ None,
+ t.pv,
+ 1.0,
+ 0.0,
+ t.theta,
+ 0.0,
+ None,
+ None,
+ None,
+ None,
+ t.hy_equiv,
+ )
elif isinstance(t, BlackSwaption):
name = f"{t.index.index_type}{t.index.series} {t.index.tenor}"
- r = ("Swaption", name, t.notional, t.ref, t.strike,
- t.direction, t.option_type, t.forward_date, t.sigma, t.pv,
- t.delta, t.gamma, t.theta, t.vega,
- None, None, None, None, t.hy_equiv)
+ r = (
+ "Swaption",
+ name,
+ t.notional,
+ t.ref,
+ t.strike,
+ t.direction,
+ t.option_type,
+ t.forward_date,
+ t.sigma,
+ t.pv,
+ t.delta,
+ t.gamma,
+ t.theta,
+ t.vega,
+ None,
+ None,
+ None,
+ None,
+ t.hy_equiv,
+ )
elif isinstance(t, DualCorrTranche):
name = f"{t.index_type}{t.series} {t.tenor}"
- r = ("Tranche", name, t.notional, None, None,
- t.direction, None, None, None, t.upfront,
- t.delta, t.gamma, None, None,
- t.attach, t.detach, t.rho[0], t.rho[1], t.hy_equiv)
+ r = (
+ "Tranche",
+ name,
+ t.notional,
+ None,
+ None,
+ t.direction,
+ None,
+ None,
+ None,
+ t.upfront,
+ t.delta,
+ t.gamma,
+ None,
+ None,
+ t.attach,
+ t.detach,
+ t.rho[0],
+ t.rho[1],
+ t.hy_equiv,
+ )
else:
raise TypeError
rec.append(r)
return pd.DataFrame.from_records(rec, columns=headers, index=self.trade_ids)
- __repr__ = portf_repr('string')
+ __repr__ = portf_repr("string")
- _repr_html_ = portf_repr('html')
+ _repr_html_ = portf_repr("html")