1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
import numpy as np
import logging
import pandas as pd
from serenitas.analytics.base import Trade
from serenitas.analytics.index_data import on_the_run
from serenitas.analytics.api import CreditIndex, BlackSwaptionVolSurface
from serenitas.analytics.exceptions import MissingDataError
from copy import deepcopy
from .tranches import get_tranche_portfolio
from .swaptions import get_swaption_portfolio
from .bonds import subprime_risk, clo_risk, crt_risk
from .indices import get_index_portfolio
from serenitas.utils.db import dbengine
from serenitas.utils.db2 import dbconn
from serenitas.utils.pool import dawn_pool
from pandas.tseries.offsets import BDay
logger = logging.getLogger(__name__)
def hy_equiv_trade(value_date, notional):
return CreditIndex(
"HY",
on_the_run("HY", value_date),
"5yr",
value_date=value_date,
notional=notional,
)
def gen_bond_proxies(position_date, fund, conn):
rmbs_pos = subprime_risk(position_date, conn, dbengine("rmbs_model"), fund=fund)
crt_pos = crt_risk(position_date, conn, fund=fund)
with dbconn("etdb") as etconn:
clo_pos = clo_risk(position_date, conn, etconn, fund=fund)
return {"rmbs_bonds": rmbs_pos, "crt_bonds": crt_pos, "clo_bonds": clo_pos}
def build_portfolio(position_date, value_date, fund="SERCGMAST"):
"""
Output two portfolios:
1) All synthetic + curve with just delta-proxy + dummy index as cash bonds proxy (portf)
2) Tranches +Swaption + Index for JTD
"""
Trade.init_ontr(value_date)
with dawn_pool.connection() as conn:
portf = get_tranche_portfolio(position_date, conn, False, [fund])
swaption_portf = get_swaption_portfolio(position_date, conn, fund=fund)
swaption_portf.trade_ids = [tid[:-1] for tid in swaption_portf.trade_ids]
portf += swaption_portf
syn_portf = deepcopy(portf)
syn_portf += get_index_portfolio(position_date, conn, fund)
nocurve_portf = get_index_portfolio(
position_date, conn, fund, exclude_strategies="%CURVE"
)
portf += nocurve_portf
basis_portf = get_index_portfolio(
position_date, conn, fund, include_strategies="%BASIS"
)
portf.add_trade(
hy_equiv_trade(value_date, -basis_portf.hy_equiv),
("CASH_BASIS", "negate_basis_trades"),
)
curve_portf = get_index_portfolio(
position_date, conn, fund, include_strategies="%CURVE"
)
curve_portf.value_date = value_date
curve_portf.mark()
portf.add_trade(
hy_equiv_trade(value_date, curve_portf.hy_equiv),
("curve_trades", "curve_trades"),
)
# Add the bond proxies to the portfolio only
for name, pos in gen_bond_proxies(position_date, fund, conn).items():
portf.add_trade(
hy_equiv_trade(value_date, -pos.hy_equiv.sum()), (name, name)
)
for p in [portf, syn_portf]:
p.value_date = value_date
p.mark(interp_method="bivariate_linear")
p.reset_pv()
return portf, syn_portf
def generate_vol_surface(portf, lookback=5, source_list=["MS"]):
vol_surface = {}
for trade in portf.swaptions:
index_type, series, option_type = (
trade.index.index_type,
trade.index.series,
trade.option_type,
)
if (k := (index_type, series, option_type)) in vol_surface:
continue
i = 0
while i < lookback:
try:
vs = BlackSwaptionVolSurface(
index_type,
series,
value_date=portf.value_date - BDay(i),
interp_method="bivariate_linear",
)
except MissingDataError as e:
i += 1
logger.info(f"Trying {portf.value_date - BDay(i)}")
else:
break
for source in source_list:
if len(vs.list(source, option_type)) >= 1:
break
else:
raise MissingDataError(
f"{type(vs).__name__}: No quote for type {option_type} and date {portf.value_date}"
)
vol_surface[k] = vs[vs.list(source=source, option_type=option_type)[-1]]
return vol_surface
|