from serenitas.utils.env import DAILY_DIR from serenitas.utils.exchange import ExchangeMessage import datetime import logging import argparse from collateral.common import load_pdf from pathlib import Path import pandas as pd from collections import defaultdict from interest_statement import export_data from dateutil.relativedelta import relativedelta logger = logging.getLogger(__name__) def get_fpath(counterparty, save=False): if save: return ( DAILY_DIR / "Serenitas" / f"{counterparty}_reports" / "Interest Statements" ) else: return DAILY_DIR / "Serenitas" / "MonthlyInterest" / f"{counterparty}_reports" def download_messages(em, counterparty, start, end, save=False): for msg in em.get_msgs( 20, path=["Interest", counterparty], start_date=start, end_date=end ): base_dir = get_fpath(counterparty, save) for attach in msg.attachments: fname = attach.name if (counterparty == "CS") and not ("Interest" in fname): continue p = base_dir / fname if not p.parent.exists(): p.parent.mkdir(parents=True) if not p.exists(): p.write_bytes(attach.content) def get_CS(g): for e in g[-1]: if "This interest, margin" in e.text: if value == "No Accruals to Report": return 0 return float(value) value = e.text def get_BNP(l): for e, n in zip(l, l[1:]): if "Due to" in e.text: value = n.text.replace(",", "") return -float(value) def get_CITI(path): df = pd.read_excel(path) for row in df.itertuples(): if "Net Interest Due To CP" in row or "Net Interest Due to Citi" in row: return -row._6 def get_GS(l): for e, n in zip(l, l[1:]): if "due to" in e.text: return float(n.text.replace("USD", "").replace(",", "")) def get_MS(path): df = pd.read_excel(path) return -round(df["LOCAL_ACCRUAL"].sum(), 2) def get_BoA(l): for e, n in zip(l, l[1:]): if "Net interest Amount" in e.text: return -float(n.text.replace("(", "-").replace(")", "").replace(",", "")) def get_JPM(g): for e in g: if "Page" in e.text: return float(value.replace(",", "")) value = e.text def get_BARCLAYS(l): for e, n in zip(l, l[1:]): if "Accrued" in e.text: return float(n.text.replace("(", "-").replace(")", "").replace(",", "")) def start_end(date): date = date - relativedelta(months=1) start = datetime.date(date.year, date.month, 1) end = start + relativedelta(months=1) end -= datetime.timedelta(days=1) return start, end def get_interest(counterparties, save=False): interest_amounts = defaultdict(float) for cp in counterparties: try: func = globals()[f"get_{cp}"] except KeyError: print(f"Missing cp {cp}") base_path = Path("/home/serenitas/Daily/Serenitas/MonthlyInterest/") if cp in ("CITI", "MS"): for p in (base_path / f"{cp}_reports").glob("*.xls*"): if p.name.startswith("~"): continue amount = func(p) interest_amounts[cp] = interest_amounts[cp] + amount else: for p in (base_path / f"{cp}_reports").glob("*.pdf"): amount = func(load_pdf(p, pages=True if cp == "CS" else False)) interest_amounts[cp] = interest_amounts[cp] + amount return pd.DataFrame(interest_amounts, index=[0]).T.rename( index={"BoA": "BAML_ISDA"}, columns={0: "monthly_statement"} ) if __name__ == "__main__": em = ExchangeMessage() counterparties = ["BNP", "CITI", "GS", "MS", "BoA", "JPM", "BARCLAYS"] # First run --save, then run --accept if it looks good parser = argparse.ArgumentParser(description="Save, accept within tolerances") parser.add_argument( "date", type=datetime.date.fromisoformat, nargs="?", default=datetime.date.today(), ) parser.add_argument( "--save", "-s", action="store_true", default=False, help="store in proper folders", ) parser.add_argument( "--accept", "-a", action="store_true", default=False, help="accept the differences are within tolerance and edit the csv accordingly", ) args = parser.parse_args() start = datetime.date(args.date.year, args.date.month, 1) for cp in counterparties: download_messages(em, cp, start, args.date, args.save) interest_amounts = get_interest(counterparties, save=args.save) start, end = start_end(args.date) global df df = pd.merge( export_data(start, end).groupby("broker").sum(), interest_amounts, how="outer", left_index=True, right_index=True, ) df = df.fillna(0) df["difference"] = round(df["amount"] - df["monthly_statement"], 2) if args.accept: ssnc_df = export_data(start, end) for k, v in df["difference"].items(): ssnc_df.loc[k].loc["CSH_CASH"] -= v from io import StringIO from serenitas.utils.exchange import ExchangeMessage, FileAttachment buf = StringIO() ssnc_df.to_csv(buf) attach = [ FileAttachment( name=f"{start:%b}.csv", content=buf.getvalue().encode(), ) ] em = ExchangeMessage() em.send_email( subject=f"Allocation of Interest for {start:%b}", body="Please see attached", to_recipients=("serenitas.otc@sscinc.com", "SERENITAS.ops@sscinc.com"), cc_recipients=("nyops@lmcg.com",), attach=attach, )