diff options
Diffstat (limited to 'python/notify_bowdst.py')
| -rw-r--r-- | python/notify_bowdst.py | 201 |
1 files changed, 106 insertions, 95 deletions
diff --git a/python/notify_bowdst.py b/python/notify_bowdst.py index 76d6d0f4..ca987a03 100644 --- a/python/notify_bowdst.py +++ b/python/notify_bowdst.py @@ -12,109 +12,120 @@ import argparse import numpy as np import sys -parser = argparse.ArgumentParser(description="determine sender destination") -parser.add_argument("--globeop", action="store_true", help="send to globeop") -parser.add_argument( - "--debug", "-d", action="store_true", default=False, help="log to the console" -) -args = parser.parse_args() +def send_email(inaccurate_balances, accurate_balances, logger, conn, cob, args): + for row in inaccurate_balances.itertuples(): + subject = f"ACTION REQUESTED: Missing Trades {row.Index} RED: {row.security_id}" + try: + last_date = accurate_balances.xs(row.Index, level="security_desc").index[-1] -if args.debug: - logging.basicConfig() - -logger = logging.getLogger(__name__) -if not logger.handlers: - fh = SerenitasFileHandler("mismatched_trades.log") - logger.addHandler(fh) -logger.setLevel(logging.INFO) - -conn = dbconn("dawndb") -cob = (datetime.date.today() - BDay(1)).date() -dates = pd.date_range(end=cob, periods=50) -df = pd.concat( - [ - pd.read_sql_query( - "SELECT *, notional * factor AS db_notional " - "FROM list_cds_marks(%s, NULL, 'BOWDST')", + except IndexError: + logger.warning(f"No matches for {row.security_desc}") + continue + buf = StringIO() + output = pd.read_sql_query( + "SELECT * FROM cds WHERE trade_date > %s and trade_date <= %s " + "AND fund = 'BOWDST' AND security_desc = %s " + "AND orig_detach IS NULL AND orig_attach IS NULL ORDER BY trade_date DESC", conn, - params=(d,), - index_col=["security_desc"], + params=(last_date, cob, row.Index), ) - for d in dates.date - ], - keys=dates, -) - -mask = np.isclose(df.globeop_notional, df.db_notional, atol=1e-2, rtol=0.0) + if not output[output.trade_date >= cob - BDay(1)].empty: + logger.warning( + f"Mismatch balance {row.Index} {row.globeop_notional} :{row.db_notional} Trades Recently" + ) + continue + output.to_csv(buf, index=False) + attachments = [ + FileAttachment(name=f"{row.Index}.csv", content=buf.getvalue().encode()) + ] + buf.close() + msg = ( + "Good morning,\n\n" + f"We notice a difference in our notional ({row.db_notional:,.2f}) versus yours ({row.globeop_notional:,.2f}) " + f"for security {row.Index} RED: {row.security_id}.\n" + f"Our notionals last matched on {last_date} for ${row.globeop_notional:,.2f}.\n\n" + "Please see attached all the trades since we last matched. Please ensure they match your data.\n\n" + "Thanks for your help!\n\n" + "Flint" + ) + em = ExchangeMessage() + if args.globeop: + recipients = ( + "caagtradecapture@bnymellon.com", + "hm-operations@bnymellon.com", + "caagprim@bnymellon.com", + "julie.picariello@bnymellon.com", + "sa1futures.optionsprocessing@bnymellon.com", + ) + cc_recipients = ( + "fyu@lmcg.com", + "Bowdoin-Ops@LMCG.com", + ) + else: + recipients = ("fyu@lmcg.com",) + cc_recipients = () -try: - inaccurate_balances = df[~mask].loc[ - pd.Timestamp(cob), ["tenor", "security_id", "globeop_notional", "db_notional"] - ] -except KeyError: - logger.info("All Balances Matching") - sys.exit() -accurate_balances = df[mask] + em.send_email( + subject, + msg, + to_recipients=recipients, + cc_recipients=cc_recipients, + attach=attachments, + ) -for row in inaccurate_balances.itertuples(): - subject = f"ACTION REQUESTED: Missing Trades {row.Index} RED: {row.security_id}" - try: - last_date = accurate_balances.xs(row.Index, level="security_desc").index[-1] - except IndexError: - logger.warning(f"No matches for {row.security_desc}") - continue - buf = StringIO() - output = pd.read_sql_query( - "SELECT * FROM cds WHERE trade_date > %s and trade_date <= %s " - "AND fund = 'BOWDST' AND security_desc = %s " - "AND orig_detach IS NULL AND orig_attach IS NULL ORDER BY trade_date DESC", - conn, - params=(last_date, cob, row.Index), - ) - if not output[output.trade_date >= cob - BDay(1)].empty: - logger.warning( - f"Mismatch balance {row.Index} {row.globeop_notional} :{row.db_notional} Trades Recently" - ) - continue - output.to_csv(buf, index=False) - attachments = [ - FileAttachment(name=f"{row.Index}.csv", content=buf.getvalue().encode()) - ] - buf.close() - msg = ( - "Good morning,\n\n" - f"We notice a difference in our notional ({row.db_notional:,.2f}) versus yours ({row.globeop_notional:,.2f}) " - f"for security {row.Index} RED: {row.security_id}.\n" - f"Our notionals last matched on {last_date} for ${row.globeop_notional:,.2f}.\n\n" - "Please see attached all the trades since we last matched. Please ensure they match your data.\n\n" - "Thanks for your help!\n\n" - "Flint" +def main(): + parser = argparse.ArgumentParser(description="determine sender destination") + parser.add_argument("--globeop", action="store_true", help="send to globeop") + parser.add_argument( + "--debug", "-d", action="store_true", default=False, help="log to the console" ) - em = ExchangeMessage() - if args.globeop: - recipients = ( - "caagtradecapture@bnymellon.com", - "hm-operations@bnymellon.com", - "caagprim@bnymellon.com", - "julie.picariello@bnymellon.com", - "sa1futures.optionsprocessing@bnymellon.com", - ) - cc_recipients = ( - "fyu@lmcg.com", - "Bowdoin-Ops@LMCG.com", - ) - else: - recipients = ("fyu@lmcg.com",) - cc_recipients = () - em.send_email( - subject, - msg, - to_recipients=recipients, - cc_recipients=cc_recipients, - attach=attachments, + args = parser.parse_args() + + if args.debug: + logging.basicConfig() + + logger = logging.getLogger(__name__) + if not logger.handlers: + fh = SerenitasFileHandler("mismatched_trades.log") + logger.addHandler(fh) + logger.setLevel(logging.INFO) + + conn = dbconn("dawndb") + cob = (datetime.date.today() - BDay(1)).date() + dates = pd.date_range(end=cob, periods=50) + df = pd.concat( + [ + pd.read_sql_query( + "SELECT *, notional * factor AS db_notional " + "FROM list_cds_marks(%s, NULL, 'BOWDST')", + conn, + params=(d.date(),), + index_col=["security_desc"], + ) + for d in dates + ], + keys=dates, ) -logger.info("Program executed.") + mask = np.isclose(df.globeop_notional, df.db_notional, atol=1e-2, rtol=0.0) + + try: + inaccurate_balances = df[~mask].loc[ + pd.Timestamp(cob), + ["tenor", "security_id", "globeop_notional", "db_notional"], + ] + except KeyError: + logger.info("All Balances Matching") + sys.exit() + accurate_balances = df[mask] + + send_email(inaccurate_balances, accurate_balances, logger, conn, cob, args) + + logger.info("Program executed.") + + +if __name__ == "__main__": + main() |
