aboutsummaryrefslogtreecommitdiffstats
path: root/python/report_ops/cash.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/report_ops/cash.py')
-rw-r--r--python/report_ops/cash.py129
1 files changed, 129 insertions, 0 deletions
diff --git a/python/report_ops/cash.py b/python/report_ops/cash.py
new file mode 100644
index 00000000..092dbb7d
--- /dev/null
+++ b/python/report_ops/cash.py
@@ -0,0 +1,129 @@
+from dataclasses import field, dataclass
+from serenitas.ops.trade_dataclasses import Deal, Fund
+from serenitas.analytics.dates import prev_business_day, next_business_day
+import datetime
+from serenitas.utils.exchange import ExchangeMessage
+from serenitas.utils.env import DAILY_DIR
+import pandas as pd
+from serenitas.utils.db import dbconn, dawn_engine
+from typing import ClassVar
+from .misc import get_dir, dt_from_fname
+from .custodians import NT, UMB
+
+
+@dataclass
+class IAMDeal(Deal, deal_type=None, table_name="iam_tickets"):
+ trade_date: datetime.date = field(metadata={"globeop": "SettlementDate"})
+ action: str = field(metadata={"globeop": "Action"})
+ strategy: str = field(metadata={"globeop": "Folder"})
+ counterparty: str = field(metadata={"globeop": "Counterparty"})
+ maturity: datetime.date
+ start_money: float = field(metadata={"globeop": "StartMoney"})
+ currency: str = field(metadata={"globeop": "Currency"})
+ booked_offset: bool
+ uploaded: bool
+ fund: Fund
+ dealid: str = field(metadata={"insert": False})
+ id: int = field(metadata={"insert": False})
+
+ def to_globeop(self, action):
+ obj = super().to_globeop(action)
+ obj["Deal Type"] = "IamDeal"
+ obj["ExpirationDate"] = self.trade_date if self.action == "UPDATE" else None
+ obj["CallNoticeIndicator"] = "24H" if self.action == "NEW" else None
+ obj["TransactionIndicator"] = ("DEPOSIT" if obj["StartMoney"] > 0 else "LOAN",)
+ obj["StartMoney"] = abs(obj["StartMoney"])
+ obj["Folder"] = (
+ "M_CSH_CASH" if obj["strategy"] == "CSH_CASH" else obj["strategy"]
+ )
+ obj["DealFunction"] = "OTC"
+ obj["MarginType"] = "Variation"
+ obj["Basis"] = "ACT/360"
+ return obj
+
+
+@dataclass
+class CashReport:
+ fund: ClassVar[str]
+ account_number: ClassVar[str]
+ date: datetime.date
+ _conn: ClassVar[dbconn] = dbconn("dawndb")
+ _staging_queue: ClassVar[set] = set()
+ _insert_sql = "INSERT INTO cash_balances VALUES (%s, %s, %s, %s, %s, %s) ON CONFLICT DO NOTHING"
+
+ def __init_subclass__(cls, fund, account_number):
+ cls.fund = fund
+ cls.account_number = account_number
+
+ def to_db(self, report_name):
+ self.download_reports(self.date)
+ report_dir = get_dir(self.date)
+ report_dir.mkdir(exist_ok=True, parents=True)
+ p = max(
+ [f for f in get_dir(self.date).iterdir() if f.name.startswith(report_name)],
+ key=dt_from_fname,
+ default=None,
+ )
+ if not p:
+ raise ValueError(
+ f"No reports found for fund: {self.fund} date: {self.date}"
+ )
+ return p
+
+ @classmethod
+ def commit(cls):
+ with cls._conn.cursor() as c:
+ c.executemany(cls._insert_sql, cls._staging_queue)
+ cls._conn.commit()
+
+
+class NTCashReport(CashReport, NT, fund="ISOSEL", account_number="ISOS01"):
+ def to_db(self):
+ p = super().to_db("cash_")
+ df = pd.read_csv(p, on_bad_lines="warn")
+ df = df[df["T-NARR-LONG"] == "CLOSING BALANCE"]
+ df = df[["Consolidation", "Currency code", "A-TRAN-AMT"]]
+ df.columns = df.columns.str.replace(" |-|_", "", regex=True).str.lower()
+ df = df.set_index(["consolidation", "currencycode"])
+ for row in df.itertuples():
+ self.stage_from_row(row)
+ self.commit()
+ self._staging_queue.clear()
+
+ def stage_from_row(self, row):
+ (account, currency), amount = row
+ self._staging_queue.add(
+ (
+ prev_business_day(self.date),
+ self.fund,
+ f"NT Custody Account {self.fund}",
+ account,
+ currency,
+ amount,
+ )
+ )
+
+
+class UMBCashReport(CashReport, UMB, fund="SERCGMAST", account_number="159260.1"):
+ def to_db(self):
+ p = super().to_db("umb_")
+ df = pd.read_excel(p, skiprows=3)
+ for row in (
+ df.groupby(["Portfolio #", "Currency"]).sum()["Current Balance"].items()
+ ):
+ self.stage_from_row(row)
+ self.commit()
+ self._staging_queue.clear()
+
+ def stage_from_row(self, row):
+ (account, currency), amount = row
+ self._staging_queue.add(
+ (
+ prev_business_day(self.date),
+ self.fund,
+ f"UMB Custody Account {self.fund}",
+ account,
+ currency,
+ amount,
+ )
+ )