aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/trade_dataclasses.py83
1 files changed, 79 insertions, 4 deletions
diff --git a/python/trade_dataclasses.py b/python/trade_dataclasses.py
index dabfe05f..7b80a103 100644
--- a/python/trade_dataclasses.py
+++ b/python/trade_dataclasses.py
@@ -1,8 +1,8 @@
from dataclasses import dataclass, field, fields, Field
from enum import Enum
from io import StringIO
-from headers import DealType, MTM_HEADERS
-from typing import ClassVar
+from headers import DealType, MTM_HEADERS, HEADERS
+from typing import ClassVar, Tuple, Union
from decimal import Decimal
from typing import Literal
import csv
@@ -21,6 +21,8 @@ from serenitas.utils.remote import SftpClient
from lru import LRU
from psycopg.errors import UniqueViolation
import logging
+from serenitas.utils.remote import FtpClient, SftpClient
+
logger = logging.getLogger(__name__)
Fund = Literal["SERCGMAST", "BRINKER", "BOWDST"]
@@ -191,6 +193,56 @@ class DealKind:
return None
+def get_admin_headers(fund, trade_type):
+ if fund in ("SERCGMAST", "BOWDST", "BRINKER"):
+ return HEADERS[trade_type]
+
+
+def get_fname(
+ trade_type: Union[str, Tuple[str, str]],
+ fund: str = "SERCGMAST",
+):
+ d = {
+ "bond": "Mortgages",
+ "cds": "CreditDefaultSwapDeal",
+ "swaption": "SwaptionDeal",
+ "future": "Future",
+ "wire": "CashFlowDeal",
+ "spot": "SpotDeal",
+ "fx_swap": "FxSwapDeal",
+ "capfloor": "CapFloor",
+ "repo": "RepoDeal",
+ "termination": "Termination",
+ }
+ trade_tag: str
+ if isinstance(trade_type, tuple):
+ trade_tag = d[trade_type[0]] + trade_type[1]
+ else:
+ trade_tag = d[trade_type]
+
+ timestamp = datetime.datetime.now()
+ if fund == "BRINKER":
+ return f"LMCG_BBH_SWAP_TRADES_P.{timestamp:%Y%m%d%H%M%S}.csv"
+ elif fund == "SERCGMAST":
+ return f"Serenitas.ALL.{timestamp:%Y%m%d.%H%M%S}.{trade_tag}.csv"
+ elif fund == "BOWDST":
+ return f"Bowdst.ALL.{timestamp:%Y%m%d.%H%M%S}.{trade_tag}.csv"
+
+
+def upload_buf(buf, dest, fund):
+ match fund:
+ case "SERCGMAST":
+ ftp = FtpClient.from_creds("globeop")
+ ftp.client.cwd("incoming")
+ ftp.put(buf, dest)
+ case "BOWDST":
+ sftp = SftpClient.from_creds("hm_globeop")
+ sftp.put(buf, dest)
+ case "BRINKER":
+ sftp = SftpClient.from_creds("bbh")
+ sftp.put(buf, dest)
+
+
class Deal:
_conn: ClassVar = dbconn("dawndb", application_name="autobooker")
_registry = {}
@@ -199,6 +251,7 @@ class Deal:
_sql_insert: ClassVar[str]
_sql_select: ClassVar[str]
_insert_queue: ClassVar[list] = []
+ _admin_queue: ClassVar[list] = []
def __class_getitem__(cls, deal_type: DealType):
return cls._registry[deal_type]
@@ -228,6 +281,28 @@ class Deal:
)
@classmethod
+ def admin_upload(cls, fund, trade_type, upload):
+ if not cls._admin_queue: # early exit
+ return
+ buf = StringIO()
+ csvwriter = csv.writer(buf)
+ headers = get_admin_headers(fund, trade_type)
+ csvwriter.writerow(headers)
+ csvwriter.writerows(
+ [row.get(h, None) for h in headers] for row in cls._admin_queue
+ )
+ buf = buf.getvalue().encode()
+ fname = get_fname(trade_type, fund)
+ dest = DAILY_DIR / str(datetime.date.today()) / fname
+ dest.parent.mkdir(exist_ok=True)
+ dest.write_bytes(buf)
+ if upload:
+ upload_buf(buf, fname, fund)
+
+ def admin_stage(self):
+ self._admin_queue.append(self.to_admin())
+
+ @classmethod
def commit(cls):
with cls._conn.cursor() as c:
c.executemany(cls._sql_insert, cls._insert_queue)
@@ -588,7 +663,7 @@ class TerminationDeal(
)
id: int = field(default=None, metadata={"insert": False})
dealid: str = field(default=None, metadata={"insert": False, "mtm": "Swap ID"})
- factor: float = field(default=1, metadata={"insert": False})
+ factor: float = field(init=False, default=1, metadata={"insert": False})
orig_cp: str = field(
init=False,
metadata={"mtm": "Remaining Party", "insert": False},
@@ -662,7 +737,7 @@ class TerminationDeal(
obj["Product Type"] = obj["product_type"]
return obj
- def to_globeop(self):
+ def to_admin(self):
obj = self.serialize("globeop")
obj["TerminationAmount"] *= self.factor
obj["FeesPaid"] = (