diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/book_bbg2.py | 80 | ||||
| -rw-r--r-- | python/trade_dataclasses.py | 160 |
2 files changed, 240 insertions, 0 deletions
diff --git a/python/book_bbg2.py b/python/book_bbg2.py new file mode 100644 index 00000000..b3c53de1 --- /dev/null +++ b/python/book_bbg2.py @@ -0,0 +1,80 @@ +from serenitas.utils.env import DAILY_DIR +from serenitas.utils.remote import SftpClient +from zoneinfo import ZoneInfo +import datetime +import csv +from trade_dataclasses import CDSDeal +from decimal import Decimal + +_funds = {"SERENITAS_CGMF": "SERCGMAST", "BOWDOINST": "BOWDST"} +_fcms = {"Bank of America, N.A.": "BAML", "Goldman Sachs": "GS"} + + +def download_files(date: datetime.date): + sftp = SftpClient.from_creds("bbg") + dst = DAILY_DIR / str(date) / "bbg_tickets" + if not dst.exists(): + dst.mkdir() + EST = ZoneInfo("US/Eastern") + + def by_date(f, date): + local_dt = datetime.datetime.fromtimestamp( + f.st_mtime, tz=datetime.timezone.utc + ).astimezone(EST) + return local_dt.date() == date + + sftp.download_files("/", dst, (lambda f: by_date(f, date),)) + + +def get_indic_data(conn, redcode, tenor): + sql_str = ( + "SELECT maturity, coupon " + "FROM index_desc " + "WHERE tenor=%s AND redindexcode=%s " + ) + with conn.cursor() as c: + c.execute(sql_str, (redcode, tenor)) + return c.fetchone() + + +def cdx_booking_process(path, conn): + with open(path) as fh: + reader = csv.DictReader(fh) + for line in reader: + tenor = line["Security"].rsplit(" ", 1)[-1].lower() + "r" + maturity, coupon = get_indic_data(conn, tenor, line["Red Code"]) + trade = CDSDeal( + fund=_funds[line["Account"]], + folder="*", + portfolio="CURVE", + security_id=line["Red Code"], + security_desc=line["Security"], + traded_level=Decimal(line["Price (Dec)"]), + notional=line["Quantity"], + fixed_rate=coupon * 0.01, + trade_date=datetime.datetime.strptime( + line["Trade Dt"], "%m/%d/%Y" + ).date(), + maturity=maturity, + currency=line["Curncy"], + protection="Buyer" if line["Side"] == "B" else "Seller", + upfront=line["Principal"], + cp_code="BNPBNY", + account_code=_fcms[line["Client FCM"]], + ) + trade.stage() + CDSDeal.commit() + + +def book_trades(conn, date=datetime.date.today()): + download_files(date) + for p in (DAILY_DIR / str(date) / "bbg_tickets").glob("CDX*"): + cdx_booking_process(p, conn) + + +if __name__ == "__main__": + from serenitas.utils.db import serenitas_pool + + d = datetime.date(2022, 2, 7) + conn = serenitas_pool.getconn() + book_trades(conn, d) diff --git a/python/trade_dataclasses.py b/python/trade_dataclasses.py new file mode 100644 index 00000000..e64ab63a --- /dev/null +++ b/python/trade_dataclasses.py @@ -0,0 +1,160 @@ +from dataclasses import dataclass, field, fields +from typing import ClassVar +from decimal import Decimal +from typing import Literal +import datetime +from enum import Enum +from psycopg2.extensions import register_adapter, AsIs +from serenitas.analytics.dates import next_business_day, previous_twentieth +from serenitas.analytics.index import CreditIndex +from serenitas.utils.db import dbconn + +Fund = Literal["SERCGMAST", "BRINKER", "BOWDST"] +Portfolio = Literal[ + "OPTIONS", "IR", "MORTGAGES", "CURVE", "TRANCHE", "CLO", "HEDGE_MAC" +] # deprecated IG, HY, STRUCTURED + + +class BusDayConvention(str, Enum): + modified_following = "Modified Following" + following = "Following" + modified_preceding = "Modified Preceding" + second_day_after = "Second-Day-After" + end_of_month = "End-of-Month" + + +DayCount = Literal["ACT/360", "ACT/ACT", "30/360", "ACT/365"] + +IsdaDoc = Literal["ISDA2014", "ISDA2003Cred"] + + +class Frequency(Enum): + Quarterly = 4 + Monthly = 12 + + +Ccy = Literal["USD", "CAD", "EUR", "YEN"] + + +SwapType = Literal[ + "CD_INDEX", "CD_INDEX_TRANCHE", "CD_BASKET_TRANCHE", "ABS_CDS", "BESPOKE" +] +ClearingFacility = Literal["ICE-CREDIT", "NOT CLEARED"] +CdsStrat = Literal[ + "HEDGE_CSO", + "HEDGE_CLO", + "HEDGE_MAC", + "HEDGE_MBS", + "SER_IGSNR", + "SER_IGMEZ", + "SER_IGEQY", + "SER_IGINX", + "SER_HYSNR", + "SER_HYMEZ", + "SER_HYEQY", + "SER_HYINX", + "SER_HYCURVE", + "SER_IGCURVE", + "SER_ITRXCURVE", + "XCURVE", + "MBSCDS", + "IGOPTDEL", + "HYOPTDEL", + "HYEQY", + "HYMEZ", + "HYSNR", + "HYINX", + "IGEQY", + "IGMEZ", + "IGSNR", + "IGINX", + "XOEQY", + "XOMEZ", + "XOINX", + "EUEQY", + "EUMEZ", + "EUSNR", + "EUINX", + "BSPK", + "*", +] + + +@dataclass +class Counterparty: + name: str + + +register_adapter(Frequency, lambda f: AsIs(f.value)) + + +class Deal: + _conn: ClassVar = dbconn("dawndb") + _sql_fields: ClassVar[list[str]] = [] + _sql_insert: ClassVar[str] = "" + _sql_select: ClassVar[str] = "" + _insert_queue: ClassVar[list] = [] + + def stage(self): + self._insert_queue.append([getattr(self, f) for f in self._sql_fields]) + + @classmethod + def commit(cls): + with cls._conn.cursor() as c: + c.executemany(cls._insert_str, cls._insert_queue) + cls._conn.commit() + + @classmethod + def from_tradeid(cls, trade_id: int): + with cls._conn.cursor() as c: + c.execute(cls._sql_select, (trade_id,)) + r = c.fetchone() + return cls(*r) + + +@dataclass +class CDSDeal(Deal): + fund: Fund + account_code: str + cp_code: str + security_id: str + security_desc: str + maturity: datetime.date + currency: Ccy + protection: Literal["Buy", "Sell"] + notional: float + fixed_rate: float + upfront: float + traded_level: Decimal + effective_date: datetime.date = field(default=None) + portfolio: Portfolio = field(default=None) + folder: CdsStrat = field(default=None) + payment_rolldate: BusDayConvention = BusDayConvention.following + day_count: DayCount = "ACT/360" + frequency: Frequency = Frequency.Quarterly + trade_date: datetime.date = field(default_factory=datetime.date.today()) + upfront_settle_date: datetime.date = field( + default_factory=lambda: next_business_day(datetime.date.today()) + ) + swap_type: SwapType = "CD_INDEX" + clearing_facility: ClearingFacility = "ICE-CREDIT" + isda_definition: IsdaDoc = "ISDA2014" + + def __post_init__(self): + self.effective_date = previous_twentieth(self.trade_date) + + def credit_index(self): + index = CreditIndex( + redcode=self.security_id, + maturity=self.maturity, + notional=self.notional, + value_date=self.trade_date, + ) + index.direction = self.protection + + +CDSDeal._sql_fields = [f.name for f in fields(CDSDeal)] +place_holders = ",".join(["%s"] * len(fields(CDSDeal))) +columns = ",".join(c for c in CDSDeal._sql_fields) +CDSDeal._sql_insert = f"INSERT INTO cds({columns}) VALUES({place_holders})" +CDSDeal._sql_select = f"SELECT {columns} FROM cds WHERE id=%s" |
