diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/risk/swaptions.py | 76 |
1 files changed, 52 insertions, 24 deletions
diff --git a/python/risk/swaptions.py b/python/risk/swaptions.py index 0b3752c3..9e5290d3 100644 --- a/python/risk/swaptions.py +++ b/python/risk/swaptions.py @@ -1,45 +1,73 @@ import logging -from serenitas.analytics.api import Portfolio, BlackSwaption +from itertools import chain +from serenitas.analytics.api import Portfolio, BlackSwaption, CreditIndex from serenitas.utils.db2 import DataError from psycopg import sql logger = logging.getLogger(__name__) -def get_swaption_portfolio(date, conn, fund="SERCGMAST", portfolio=None, **kwargs): - if portfolio is None: - params = (date, date, date, fund) - and_clause = "" - else: - params = (date, date, date, fund, portfolio) - and_clause = "AND portfolio=%s" +def get_swaption_portfolio(date, conn, **kwargs): + params = [date, date, date] + and_clause = [] + for key in ["fund", "portfolio"]: + if key in kwargs: + params.append(kwargs[key]) + and_clause.append(f"AND {key}=%s") with conn.cursor() as c: c.execute( - "SELECT swaptions.id, folder, dealid, (notional - terminated_amount) AS notional " + "SELECT security_id AS redcode, maturity," + " array_agg(swaptions.id) AS ids," + " array_agg(folder::text) AS folders," + " array_agg(buysell) AS buysells," + " array_agg(option_type::text) AS option_types," + " array_agg(notional - COALESCE(terminated_amount, 0.0)) AS notionals," + " array_agg(fund::text) AS funds, " + " array_agg(expiration_date) AS expiries, " + " array_agg(strike) AS strikes " "FROM swaptions LEFT JOIN (" "SELECT dealid, SUM(termination_amount) AS terminated_amount " "FROM terminations WHERE termination_date <= %s GROUP BY dealid) b " "USING (dealid) " - "WHERE notional IS DISTINCT FROM terminated_amount " + "WHERE (terminated_amount IS NULL OR notional > terminated_amount) " "AND expiration_date > %s AND trade_date <= %s " "AND swap_type='CD_INDEX_OPTION' " - f"AND fund=%s {and_clause} " - "ORDER BY expiration_date, strike", + f"{' '.join(and_clause)} " + "GROUP BY security_id, maturity", params, ) - try: - trade_ids, folders, deal_ids, notionals = zip(*c) - except ValueError: - return {} + trades = [] + trade_ids = [] + for row in c: + index = CreditIndex( + redcode=row.redcode, maturity=row.maturity, value_date=date + ) + index.mark() + trades.append( + [ + BlackSwaption( + index, + expiry, + strike, + ot.lower(), + "Long" if direction else "Short", + notional, + ) + for expiry, strike, ot, direction, notional in zip( + row.expiries, + row.strikes, + row.option_types, + row.buysells, + row.notionals, + ) + ] + ) + trade_ids.append(zip(row.folders, row.ids, row.funds)) portf = Portfolio( - [BlackSwaption.from_tradeid(t) for t in trade_ids], list(zip(folders, deal_ids)) + list(chain.from_iterable(trades)), list(chain.from_iterable(trade_ids)) ) - for t, ntl in zip(portf.trades, notionals): - if ntl is not None: - t.notional = ntl - portf.value_date = date - portf.mark(interp_method="bivariate_linear", **kwargs) + portf.mark(interp_method="bivariate_linear", mark_index=False, **kwargs) return portf @@ -61,9 +89,9 @@ def insert_swaption_portfolio(portf, conn, overwrite=True): "INSERT INTO swaption_marks VALUES({}) ON CONFLICT (dealid, date) {} " ).format(place_holders, update_str) with conn.cursor() as c: - for id, trade in portf.items(): + for (strat, tid, fund), trade in portf.items(): to_insert = ( - id[1], + f"SWPTN{tid}", trade.value_date, trade.pv, trade.delta, |
