aboutsummaryrefslogtreecommitdiffstats
path: root/python/innocap.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/innocap.py')
-rw-r--r--python/innocap.py112
1 files changed, 112 insertions, 0 deletions
diff --git a/python/innocap.py b/python/innocap.py
new file mode 100644
index 00000000..191901f1
--- /dev/null
+++ b/python/innocap.py
@@ -0,0 +1,112 @@
+from io import BytesIO
+from serenitas.utils.env import DAILY_DIR
+import datetime
+from serenitas.ops.citco import GIL, GTL
+from serenitas.utils.remote import Client
+from serenitas.utils.db import dbconn
+from serenitas.analytics.dates import prev_business_day, next_business_day
+from report_ops.sma import build_position_file
+from report_ops.utils import SettlementMonitor
+
+settlement_sum_query = "SELECT currency, sum(payment_amount) as payment_amount FROM payment_settlements ps2 WHERE fund=%s AND asset_class in ('BOND', 'SPOT') AND settle_date BETWEEN %s AND %s group by currency;"
+_account_fund = {"ISOS01": "ISOSEL"}
+
+
+def concat_csv(file_type, date):
+ match file_type:
+ case "trade":
+ file_tag = "innocap_serenitas_trades"
+ case "instrument":
+ file_tag = "i.innocap_serenitas"
+ fname = f"Innocap_ISOSEL_{file_type}_{date:%Y-%m-%d}.csv"
+ buf = BytesIO()
+ buf.write((",".join(GTL if file_type == "trade" else GIL) + "\n").encode())
+ for f in (DAILY_DIR / str(date)).iterdir():
+ if f.is_file() and f.name.startswith(file_tag):
+ with f.open("rb") as fh:
+ next(fh) # Don't concat headers
+ buf.write(fh.read())
+ return buf.getvalue(), fname
+
+
+def upload_citco_files(date, upload):
+ for file_type in ("trade", "instrument"):
+ buf, fname = concat_csv(file_type, date)
+ dest = DAILY_DIR / str(date) / fname
+ dest.write_bytes(buf)
+ if upload:
+ innocap_sftp = Client.from_creds("innocap", folder="Innocap")
+ innocap_sftp.put(buf, fname)
+
+
+def upload_position_files(date, fund, upload):
+ buf, dest = build_position_file(
+ date,
+ fund,
+ )
+ if upload:
+ client = Client.from_creds("innocap", folder="Innocap")
+ client.put(buf, dest.name)
+ client = Client.from_creds("citco")
+ client.put(buf, dest.name)
+
+
+def get_cash_balance(date, account, conn):
+ with conn.cursor() as c:
+ sql_str = "SELECT balance, currency_code from cash_balances WHERE account_number=%s AND date=%s"
+ c.execute(sql_str, (account, date))
+ return {row.currency_code: row.balance for row in c}
+
+
+def monitor_cash_balances(date, account, conn, upload):
+ cob = prev_business_day(date)
+ fund = _account_fund[account]
+ if cash_balances := get_cash_balance(cob, account, conn):
+ for projection_date in (date, next_business_day(date)):
+ with conn.cursor() as c:
+ c.execute(settlement_sum_query, (fund, date, projection_date))
+ for row in c:
+ projection_balance = (
+ cash_balances[row.currency] + row.payment_amount
+ )
+ if projection_balance < 0:
+ SettlementMonitor.stage(
+ {
+ "date": projection_date,
+ "account": account,
+ "currency": row.currency,
+ "projected_balance": projection_balance,
+ }
+ )
+ SettlementMonitor.email(fund)
+ SettlementMonitor._insert_queue.clear()
+
+ else:
+ raise ValueError(f"No cash balances parsed for account {account}: {cob}")
+
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "workdate",
+ nargs="?",
+ type=datetime.date.fromisoformat,
+ default=datetime.date.today(),
+ help="file transfer date",
+ )
+ parser.add_argument(
+ "--no-upload",
+ "-n",
+ action="store_true",
+ default=False,
+ help="uploads to citco and innocap",
+ )
+ args = parser.parse_args()
+ cob = prev_business_day(args.workdate)
+ conn = dbconn("dawndb")
+
+ upload_citco_files(cob, not args.no_upload)
+ upload_position_files(cob, "ISOSEL", not args.no_upload)
+ monitor_cash_balances(args.workdate, "ISOS01", conn, not args.no_upload)