aboutsummaryrefslogtreecommitdiffstats
path: root/python/parse_baml_swaption.py
blob: f72d407bceda803f1eb69afda809b27cfb7a9ab3 (plain)
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
128
129
130
131
132
133
134
135
from serenitas.utils.exchange import ExchangeMessage
import pandas as pd
from serenitas.utils.db import dawn_engine
from sqlalchemy.exc import IntegrityError
import datetime
import logging
import argparse
import re
from serenitas.ops.trade_dataclasses import CreditSwaptionDeal, desc_str

parser = argparse.ArgumentParser()
parser.add_argument(
    "workdate",
    nargs="?",
    default=str(datetime.date.today()),
    type=datetime.date.fromisoformat,
)
args = parser.parse_args()

logger = logging.getLogger(__name__)

columns = [
    "option_recap",
    "index_buyer",
    "index_seller",
    "trade_date",
    "effective_date",
    "execution_time",
    "notional",
    "price",
    "mid_price",
    "strike",
    "expiry_date",
    "option_type",
    "exercise_clearing_house",
    "premium_fee",
    "premium_fee_pay_date",
    "trade_id",
    "venue_mic",
]


# Counterparty Ticket to Database
_baml_funds = {
    "LMIL-Boston Patriot Bowdoin St LLC": "BOWDST",
    "Iso Selene Inc.": "ISOSEL",
    "Serenitas Credit Gamma Master Fund LP": "SERCGMAST",
    "Lmcg Investments, Llc": "SERCGMAST",
    "Reep-Ofc One Bowdoin Square Ma Llc Et Al (Cob)": "BOWDST",
}


def regex_baml_numbers(text: str):
    return float(re.search(r"[\d,]+", text)[0].replace(",", ""))


def from_baml_email(d: dict, conn):
    buysell = "Bank Of America" in d["Index Seller"]
    index, series = re.search(r"(HY|IG)\.([\d]{2})", d["OPTION RECAP"]).groups()
    security_desc = desc_str(index, series, "5")
    trade_date = datetime.datetime.strptime(d["Trade Date"], "%d-%b-%Y")
    price = float(d["Price"]) / 100
    sql_str = (
        "SELECT * FROM index_desc WHERE INDEX=%s AND series=%s "
        "AND lastdate >= %s AND tenor='5yr'"
    )
    with conn.cursor() as c:
        c.execute(sql_str, (index, series, trade_date))
        row = c.fetchone()

    return CreditSwaptionDeal(
        buysell=buysell,
        fund=_baml_funds[d["Index Buyer"]]
        if buysell
        else _baml_funds[d["Index Seller"]],
        cp_code="BAMSNY",
        portfolio="OPTIONS",
        folder=index + ("PAYER" if d["Option Type"] == "Payer" else "REC"),
        trade_date=trade_date,
        settle_date=datetime.datetime.strptime(d["Premium Fee Pay Date"], "%d-%b-%Y"),
        expiration_date=datetime.datetime.strptime(d["Expiry Date"], "%d-%b-%Y"),
        notional=regex_baml_numbers(d["Notional"]),
        option_type=d["Option Type"].upper(),
        strike=d["Strike"],
        swap_type="CD_INDEX_OPTION",
        fixed_rate=row.coupon / 100,
        maturity=row.maturity,
        security_desc=security_desc,
        security_id=row.redindexcode,
        currency="USD",
        price=price,
        initial_margin_percentage=(
            regex_baml_numbers(d["Collateral"])
            / regex_baml_numbers(d["Premium Fee"])
            * price
        )
        if d.get("Collateral")
        else None,
    )


em = ExchangeMessage()
start = datetime.datetime.combine(args.workdate, datetime.time.min).replace(
    tzinfo=em._account.default_timezone
)
for msg in em.get_msgs(
    path=["AutoBook", "BAML Swaption"], datetime_received__gte=start
):
    dfs = pd.read_html(msg.body)
    tickets = []
    for ticket in dfs:
        if len(ticket[0]) > 5:
            ticket = ticket.set_index(0).to_dict()[1]
            if "Block" in ticket or "Unwind Price" in ticket:
                continue
            tickets.append(ticket)
            trade = from_baml_email(ticket, dawn_engine.raw_connection())
            trade.stage()

    df = pd.DataFrame.from_dict(tickets)
    df.columns = df.columns.str.lower().str.replace(" ", "_")
    if "collateral" in df.columns:
        additional_columns = ["collateral"]
    else:
        additional_columns = []
    df = df[columns + additional_columns]
    try:
        df.to_sql(
            "baml_swaption_ticket", index=False, con=dawn_engine, if_exists="append"
        )
    except IntegrityError as e:
        logger.warning(e)
        CreditSwaptionDeal._insert_queue.clear()
    else:
        CreditSwaptionDeal.commit()