import datetime from exchangelib import HTMLBody from serenitas.analytics.dates import prev_business_day from serenitas.utils.db import dbconn from report_ops.utils import check_cleared_cds, Monitor from report_ops.misc import _recon_recipients, _cc_recipients class BondFactorMonitor( Monitor, headers=( "date", "citco_security_id", "security_id", "serenitas_factor", "admin_factor", "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"*ACTION REQUESTED* Incorrect Factors: {fund}", HTMLBody( f""" Hello,

We see the below factor mismatches. Could you please correct the below?

{cls.to_tabulate()} """ ), to_recipients=_recon_recipients[fund], cc_recipients=_cc_recipients[fund], ) def check_bond_factors(date, fund, conn): with conn.cursor() as c: c.execute( "SELECT citco_security_id, security_id, serenitas_factor, admin_factor, serenitas_factor-admin_factor as difference FROM compare_citco_bonds (%s, %s) WHERE abs(serenitas_factor - admin_factor) > .01;", (date, fund), ) for row in c: d = row._asdict() | {"date": date} BondFactorMonitor.stage(d) BondFactorMonitor.email(fund) if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument( "cob", nargs="?", type=datetime.date.fromisoformat, default=prev_business_day(datetime.date.today()), help="working date", ) args = parser.parse_args() conn = dbconn("dawndb") for fund in ("ISOSEL",): check_cleared_cds(args.cob, fund, conn) check_bond_factors(args.cob, fund, conn)