aboutsummaryrefslogtreecommitdiffstats
path: root/python/monthend_interest_recon.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/monthend_interest_recon.py')
-rw-r--r--python/monthend_interest_recon.py200
1 files changed, 200 insertions, 0 deletions
diff --git a/python/monthend_interest_recon.py b/python/monthend_interest_recon.py
new file mode 100644
index 00000000..93844d14
--- /dev/null
+++ b/python/monthend_interest_recon.py
@@ -0,0 +1,200 @@
+from serenitas.utils.env import DAILY_DIR
+from serenitas.utils.exchange import ExchangeMessage
+import datetime
+from collateral.baml_isda import download_from_secure_id
+from bs4 import BeautifulSoup
+from urllib.parse import urlsplit, parse_qs, urlunsplit
+import logging
+import argparse
+
+from collateral.common import load_pdf
+from pathlib import Path
+import pandas as pd
+from collections import defaultdict
+import shutil
+
+from interest_statement import export_data
+from dateutil.relativedelta import relativedelta
+
+logger = logging.getLogger(__name__)
+
+
+def download_messages(em, counterparty, start, end, recon=False):
+ for msg in em.get_msgs(
+ 20,
+ path=["Interest", counterparty],
+ ):
+ if recon:
+ base_dir = (
+ DAILY_DIR / "Serenitas" / "MonthlyInterest" / f"{counterparty}_reports"
+ )
+ else:
+ if counterparty == "CITI":
+ base_dir = DAILY_DIR / f"{counterparty}_reports" / "Interest Statements"
+ elif counterparty == "BAML":
+ base_dir = (
+ DAILY_DIR / "Serenitas" / f"BoA_reports" / "Interest Statements"
+ )
+ else:
+ base_dir = (
+ DAILY_DIR
+ / "Serenitas"
+ / f"{counterparty}_reports"
+ / "Interest Statements"
+ )
+ if (msg.datetime_sent.date() >= datetime.date.fromisoformat(start)) and (
+ msg.datetime_sent.date() <= datetime.date.fromisoformat(end)
+ ):
+ if counterparty == "BAML":
+ soup = BeautifulSoup(msg.body, features="lxml")
+ a = soup.find("a")
+ url = urlsplit(a["href"])
+ query = parse_qs(url.query)
+ base_url = urlunsplit(url[:2] + ("",) * 3)
+ try:
+ download_from_secure_id(
+ query["id"][0], query["brand"][0], base_dir, base_url
+ )
+ except ValueError as e:
+ logging.error(e)
+ continue
+ continue
+ 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:
+ if "This interest, margin" in e.text:
+ return float(value)
+ value = e.text
+
+
+def get_BNP(g):
+ for e in g:
+ if "Due to" in e.text:
+ value = next(g).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:
+ return -row._6
+
+
+def get_GS(g):
+ for e in g:
+ if "due to" in e.text:
+ return float(next(g).text.replace("USD", "").replace(",", ""))
+
+
+def get_MS(path):
+ df = pd.read_excel(path)
+ return -round(df["LOCAL_ACCRUAL"].sum(), 2)
+
+
+def get_BAML(g):
+ for e in g:
+ if "Net interest Amount" in e.text:
+ return -float(next(g).text.replace("(", "-").replace(")", ""))
+
+
+def get_JPM(g):
+ for e in g:
+ if "Page" in e.text:
+ return float(value.replace(",", ""))
+ value = e.text
+
+
+def start_end(year, month):
+ start = datetime.date(year, 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}")
+ if cp in ("CITI", "MS"):
+ for file in Path(
+ f"/home/serenitas/Daily/Serenitas/MonthlyInterest/{cp}_reports"
+ ).glob("*.xls*"):
+ amount = func(file)
+ interest_amounts[cp] = interest_amounts[cp] + amount
+ else:
+ for file in Path(
+ f"/home/serenitas/Daily/Serenitas/MonthlyInterest/{cp}_reports"
+ ).glob("*.pdf"):
+ g = iter(load_pdf(file))
+ amount = func(g)
+ interest_amounts[cp] = interest_amounts[cp] + amount
+ if not save:
+ try:
+ shutil.rmtree(
+ f"/home/serenitas/Daily/Serenitas/MonthlyInterest/{cp}_reports"
+ )
+ except FileNotFoundError:
+ pass
+ return pd.DataFrame(interest_amounts, index=[0]).T.rename(
+ index={"BAML": "BAML_ISDA"}, columns={0: "monthly_statement"}
+ )
+
+
+def main():
+ em = ExchangeMessage()
+ counterparties = ["BNP", "CITI", "CS", "GS", "MS", "BAML", "JPM"]
+
+ parser = argparse.ArgumentParser(description="determine sender destination")
+ parser.add_argument("start")
+ parser.add_argument("end", default=datetime.date.today())
+ parser.add_argument(
+ "--recon",
+ action="store_true",
+ default=False,
+ help="for automation or for monthly",
+ )
+ parser.add_argument(
+ "--save",
+ action="store_true",
+ default=False,
+ help="for automation or for monthly",
+ )
+ args = parser.parse_args()
+
+ for cp in counterparties:
+ download_messages(em, cp, args.start, args.end, recon=args.recon)
+
+ if args.recon:
+ df = get_interest(counterparties, save=args.save)
+ start, end = start_end(
+ datetime.datetime.today().year, datetime.datetime.today().month - 1
+ )
+ global interest_recon
+ interest_recon = pd.merge(
+ export_data(start, end).groupby("broker").sum(),
+ df,
+ how="outer",
+ left_index=True,
+ right_index=True,
+ )
+ interest_recon["difference"] = (
+ interest_recon["amount"] - interest_recon["monthly_statement"]
+ )
+
+
+if __name__ == "__main__":
+ main()