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
|
import datetime
from serenitas.utils.db import dbconn
from serenitas.ops.trade_dataclasses import CDSDeal
from serenitas.ops.funds import Service
def calculate_attach_detach(redcode, orig_attach, orig_detach, conn):
with conn.cursor() as c:
c.execute(
"SELECT indexfactor, cumulativeloss FROM index_factors WHERE redindexcode=%s",
(redcode,),
)
(factor, cumulativeloss) = c.fetchone()
detach = factor * min(max((orig_detach - cumulativeloss) / factor, 0), 1)
attach = factor * min(max((orig_attach - cumulativeloss) / factor, 0.0), 1.0)
return attach, detach
def upload_new_trades(index, affected_series, fund, event_date, conn, event_name):
NEW_TRADES_QUERY = (
"SELECT trg.*, b.security_id, cds.currency, cds.fixed_rate, cds.cp_code as custodian_cpty, cds.cp_code, cds.protection, cds.account_code, cds.frequency, "
"cds.dealid, cds.portfolio, cds.folder, cds.swap_type, cds.clearing_facility, a.custodian, a.cash_account "
"FROM tranche_risk_globeop trg "
"LEFT JOIN LATERAL (SELECT redindexcode as security_id FROM index_desc WHERE index_desc.lastdate >%s AND index_desc.index=trg.index AND index_desc.series=trg.series LIMIT 1) b ON TRUE "
"LEFT JOIN cds ON trg.trade_id=cds.id "
"LEFT JOIN accounts a ON cds.account_code=a.code "
"WHERE date=%s AND trg.fund=%s AND index=%s AND series in %s"
)
with conn.cursor() as c:
c.execute(
NEW_TRADES_QUERY,
(
event_date,
event_date,
fund,
index,
affected_series,
),
)
service = Service[fund]
for row in c:
d = row._asdict()
d["notional"] = abs(d["notional"])
d["traded_level"] = None
d["upfront"] = (d["serenitas_clean_nav"] + d["serenitas_accrued"]) * -1
d["trade_date"] = event_date
d["dealid"] = f'{d["dealid"]}_{event_name}'
d["attach"], d["detach"] = calculate_attach_detach(
d["security_id"], d["orig_attach"], d["orig_detach"], conn
)
trade = CDSDeal.from_dict(**d)
service.push_trade(trade, "NEW")
service.build_buffer(trade_type="cds")
service.staging_queue.clear()
def terminate_old_trades(
index, affected_series, fund, event_date, settlement_date, conn, event_name
):
OLD_TRADES_QUERY = "SELECT trg.*, coalesce(tc.principal,0) + coalesce(tc.accrued,0) as event_cashflow FROM tranche_risk_globeop trg LEFT JOIN (SELECT principal, accrued, tranche_id FROM tranche_cashflows WHERE date=%s) tc ON trg.trade_id=tc.tranche_id WHERE trg.date=%s AND trg.fund=%s AND trg.index=%s AND trg.series in %s"
with conn.cursor() as c:
c.execute(
OLD_TRADES_QUERY,
(settlement_date, event_date, fund, index, affected_series),
)
trade_defaults = {
"Deal Type": "CreditDefaultSwapDeal",
"Action": "Update",
"Client": "Serenitas",
"TerminationDate": event_date,
"SubAction": "Termination",
"PartialTermination": "N",
}
service = Service[fund]
for row in c:
d = row._asdict() | trade_defaults
d["TerminationAmount"] = abs(d["notional"]) * d["tranche_factor"]
total_cashflow = (
d["serenitas_clean_nav"] + d["serenitas_accrued"] + d["event_cashflow"]
)
d["FeesPaid" if total_cashflow < 0 else "FeesReceived"] = abs(
total_cashflow
)
d["Deal Id"] = f"GO:{d['globeop_id']}"
service.staging_queue.append(d)
service.build_buffer(trade_type=("cds", "T"))
service.staging_queue.clear()
if __name__ == "__main__":
index = "HY"
affected_series = (
34,
35,
36,
37,
38,
39,
)
fund = "BOWDST"
event_date = datetime.date(2023, 4, 13)
settlement_date = datetime.date(2023, 4, 18)
event_name = "DIAMOND"
conn = dbconn("dawndb")
upload_new_trades(index, affected_series, fund, event_date, conn, event_name)
terminate_old_trades(
index, affected_series, fund, event_date, settlement_date, conn, event_name
)
|