aboutsummaryrefslogtreecommitdiffstats
path: root/python/report_ops
diff options
context:
space:
mode:
Diffstat (limited to 'python/report_ops')
-rw-r--r--python/report_ops/__main__.py17
-rw-r--r--python/report_ops/misc.py10
-rw-r--r--python/report_ops/utils.py38
-rw-r--r--python/report_ops/wires.py39
4 files changed, 92 insertions, 12 deletions
diff --git a/python/report_ops/__main__.py b/python/report_ops/__main__.py
index a5172a24..856fe928 100644
--- a/python/report_ops/__main__.py
+++ b/python/report_ops/__main__.py
@@ -97,11 +97,18 @@ if args.isosel_reports:
logger.warning(e)
if args.wire_reports:
- for fund in ("BOWDST", "ISOSEL"):
- try:
- Wire[fund].to_db(args.date)
- except ValueError as e:
- logger.warning(e)
+ for fund, custodians in _fund_custodians.items():
+ for custodian in custodians:
+ report = Wire[
+ (
+ fund,
+ custodian,
+ )
+ ]
+ try:
+ report.to_db(args.date)
+ except ValueError as e:
+ logger.warning(e)
if args.send_to_custodians:
for account in (
diff --git a/python/report_ops/misc.py b/python/report_ops/misc.py
index 3492baf1..684ea6dd 100644
--- a/python/report_ops/misc.py
+++ b/python/report_ops/misc.py
@@ -43,6 +43,16 @@ _sma_recipients = {
"BRINKER": ("CSG.Team.Armata@bbh.com",),
}
+_monthend_nav_recipients = {
+ "BOWDST": _recipients["BOWDST"]
+ + (
+ "Hedgemark.FA@sscinc.com",
+ "HM-acctgprim@bnymellon.com",
+ "catherine.porter@bnymellon.com",
+ "Meghana.shroff@bnymellon.com",
+ ),
+}
+
_settlement_recipients = {
"BOWDST": _sma_recipients["BOWDST"],
"SERCGMAST": (
diff --git a/python/report_ops/utils.py b/python/report_ops/utils.py
index 80bc72d5..035b2e13 100644
--- a/python/report_ops/utils.py
+++ b/python/report_ops/utils.py
@@ -102,7 +102,7 @@ def check_cleared_cds(date, fund, conn):
_tolerance = {"IG": 0.10, "HY": 0.20, "EU": 0.20, "XO": 0.30}
with conn.cursor() as c:
c.execute(
- "SELECT *, abs(price-globeop_price) AS difference FROM list_cds_marks(%s, NULL, %s)",
+ "SELECT *, abs(price-globeop_price) AS difference FROM list_cds_marks(%s, NULL, %s) WHERE abs((notional * factor) - globeop_notional) < 100;",
(date, fund),
)
for row in c:
@@ -350,6 +350,42 @@ class CDXQuoteMonitor(
)
+class CDXNotionalMonitor(
+ Monitor,
+ headers=(
+ "security_desc",
+ "security_id",
+ "maturity",
+ "admin_notional",
+ "serenitas_notional",
+ "difference",
+ ),
+ num_format=[("{0:,.2f}", 3), ("{0:,.2f}", 4), ("{0:,.2f}", 5)],
+):
+ @classmethod
+ def email(cls, fund):
+ if not cls._staging_queue:
+ return
+ cls._em.send_email(
+ f"CDX Notional Mismatches: {fund}",
+ HTMLBody(
+ f"""
+<html>
+ <head>
+ <style>
+ table, th, td {{ border: 1px solid black; border-collapse: collapse;}}
+ th, td {{ padding: 5px; }}
+ </style>
+ </head>
+ <body>
+ Good morning,<br><br>Mismatched cleared cds notional mismatches below:<br><br>{cls.to_tabulate()}
+ </body>
+</html>"""
+ ),
+ to_recipients=_cc_recipients[fund],
+ )
+
+
class SettlementMonitor(
Monitor,
headers=("date", "account", "currency", "projected_balance"),
diff --git a/python/report_ops/wires.py b/python/report_ops/wires.py
index 50f8284d..a2f5ce1d 100644
--- a/python/report_ops/wires.py
+++ b/python/report_ops/wires.py
@@ -1,8 +1,9 @@
from dataclasses import dataclass
+from typing import Literal
import datetime
from serenitas.ops.trade_dataclasses import Deal, Ccy
from typing import ClassVar
-from .custodians import NT, BNY
+from .custodians import NT, BNY, UMB
from .misc import get_dir, dt_from_fname
from dataclasses import field
from csv import DictReader
@@ -10,11 +11,14 @@ from functools import partial
_nt_to_currency = {"EURO - EUR": "EUR", "U.S. DOLLARS - USD": "USD"}
+CUSTODIAN = Literal["UMB", "NT", "BNY"]
+
@dataclass
class Wire(Deal, table_name="custodian_wires", deal_type="custodian_wires"):
date: datetime.date
- fund: ClassVar[str]
+ fund: ClassVar[CUSTODIAN]
+ custodian: ClassVar[str]
entry_date: datetime.date
value_date: datetime.date
pay_date: datetime.date
@@ -24,13 +28,19 @@ class Wire(Deal, table_name="custodian_wires", deal_type="custodian_wires"):
unique_ref: str
dtkey: ClassVar = field(metadata={"insert": False, "select": False})
- def __init_subclass__(cls, fund, dtkey, **kwargs):
+ def __init_subclass__(cls, fund, custodian, dtkey, **kwargs):
cls._sql_insert = (
cls._sql_insert.removesuffix("RETURNING *")
+ "ON CONFLICT (unique_ref) DO NOTHING RETURNING *"
)
cls.fund = fund
- cls._registry[fund] = cls
+ cls.custodian = custodian
+ cls._registry[
+ (
+ fund,
+ custodian,
+ )
+ ] = cls
cls.dtkey = dtkey
def __post_init__(self):
@@ -53,7 +63,7 @@ class Wire(Deal, table_name="custodian_wires", deal_type="custodian_wires"):
return p
-class BowdstWire(Wire, BNY, fund="BOWDST", dtkey="%Y%m%d%H%M%S"):
+class BowdstBNYWire(Wire, BNY, fund="BOWDST", custodian="BNY", dtkey="%Y%m%d%H%M%S"):
@classmethod
def from_report_line(cls, line: dict):
return cls(
@@ -79,7 +89,7 @@ class BowdstWire(Wire, BNY, fund="BOWDST", dtkey="%Y%m%d%H%M%S"):
cls.commit()
-class SeleneWire(Wire, NT, fund="ISOSEL", dtkey="%Y%m%d%H%M"):
+class SeleneNTWire(Wire, NT, fund="ISOSEL", custodian="NT", dtkey="%Y%m%d%H%M"):
@classmethod
def from_report_line(cls, line: dict):
return cls(
@@ -102,3 +112,20 @@ class SeleneWire(Wire, NT, fund="ISOSEL", dtkey="%Y%m%d%H%M"):
if "sponsor" in line["narrative"].lower():
cls.from_report_line(line).stage()
cls.commit()
+
+
+class SerenitasUMBWire(
+ Wire, UMB, fund="SERCGMAST", custodian="UMB", dtkey="%Y%m%d%H%M"
+):
+ @classmethod
+ def from_report_line(cls, line: dict):
+ return
+
+ @classmethod
+ def to_db(cls, date):
+ # conn = cls._conn
+ # with conn.cursor() as c:
+ # c.execute("DELETE FROM custodian_wires WHERE date=%s AND fund=%s AND custodian=%s", (date, cls.fund, cls.custodian,))
+ # conn.commit()
+ # the unique ref will be generated from the row + the date and reports will only be delivered at 7pm daily
+ pass