diff options
Diffstat (limited to 'python/analytics/portfolio.py')
| -rw-r--r-- | python/analytics/portfolio.py | 158 |
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") |
