aboutsummaryrefslogtreecommitdiffstats
path: root/python/reallocate_iam.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/reallocate_iam.py')
-rw-r--r--python/reallocate_iam.py162
1 files changed, 162 insertions, 0 deletions
diff --git a/python/reallocate_iam.py b/python/reallocate_iam.py
new file mode 100644
index 00000000..6a322754
--- /dev/null
+++ b/python/reallocate_iam.py
@@ -0,0 +1,162 @@
+from serenitas.utils.misc import rename_keys
+import datetime
+from collections import defaultdict
+from psycopg2.errors import UniqueViolation
+from serenitas.analytics.dates import bus_day
+from ops.funds import Fund
+
+_iam_brokers = {
+ "BAML_ISDA": "BOANNY",
+ "CS": "CSITLN",
+ "GS": "GOLINY",
+ "BNP": "BNPBNY",
+ "MS": "MSCILN",
+ "JPM": "JPCBNY",
+ "GS_FCM": "GOLDNY",
+}
+_custodian = {"GOLDNY": "GS"}
+_cash_account = {"GOLDNY": "057363418ICE-CDS"}
+
+
+def iam_serialize(obj, action, trade_date):
+ rename_keys(
+ obj,
+ {
+ "dealid": "Deal Id",
+ "counterparty": "Counterparty",
+ "currency": "Currency",
+ "start_money": "StartMoney",
+ "trade_date": "Trade Date",
+ },
+ )
+
+ deal_fields = {
+ "Deal Type": "IamDeal",
+ "Client": "HEDGEMARK",
+ "Fund": "BOS_PAT_BOWDOIN",
+ "Custodian": _custodian.get(obj["Counterparty"], "BNY"),
+ "Cash Account": _cash_account.get(obj["Counterparty"], 751254),
+ "State": "Valid",
+ "SettlementDate": obj["Trade Date"],
+ "Basis": "ACT/360",
+ "MarginType": "Variation",
+ "DealFunction": "OTC",
+ "Folder": "M_CSH_CASH" if obj["strategy"] == "CSH_CASH" else obj["strategy"],
+ "Action": action,
+ "TransactionIndicator": "DEPOSIT" if obj["StartMoney"] > 0 else "LOAN",
+ "ExpirationDate": trade_date
+ if action == "UPDATE"
+ else None, # We are updating old IAMDeals to expire
+ "CallNoticeIndicator": "24H" if action == "NEW" else None, # This is a new IAM
+ }
+ obj["StartMoney"] = abs(obj["StartMoney"])
+ obj.update(deal_fields)
+ return obj
+
+
+def gen_offset(totals, trade_date):
+ offsets = [
+ (trade_date, "NEW", "CSH_CASH", broker, None, -amount, "USD", True)
+ for broker, amount in totals.items()
+ ]
+ return offsets
+
+
+def gen_strat_alloc(conn, trade_date):
+ new_iam = []
+ totals = defaultdict(int) # Need to figure out how much to offset
+ with conn.cursor() as c:
+ strategy_allocation = (
+ "SELECT broker, amount, currency, strategy FROM (SELECT *, rank() "
+ "OVER(PARTITION BY broker,fund ORDER BY date desc) FROM strategy_im si "
+ "WHERE fund = 'BOWDST' AND date<=%s ORDER BY date DESC) test WHERE RANK=1 and abs(amount) >= .01;"
+ )
+ c.execute(strategy_allocation, (trade_date,))
+ for row in c:
+ new_iam.append(
+ (
+ trade_date,
+ "NEW",
+ row.strategy,
+ _iam_brokers[row.broker],
+ None,
+ row.amount,
+ row.currency,
+ False,
+ )
+ )
+ if row.broker != "GOLDNY": # HM doesn't book FCM, no need to offset
+ totals[_iam_brokers[row.broker]] += row.amount
+ new_iam += gen_offset(totals, trade_date)
+ return new_iam
+
+
+def process_trades(conn, trade_date):
+ # We will be grabbing the IAM deals from the DB for the new trades and for the updated trades
+ deals = []
+ actions = {
+ "NEW": (
+ "UPDATE iam_tickets set uploaded=True where maturity is null and trade_date =%s and trade_date =%s "
+ "and action='NEW' and not uploaded returning *"
+ ),
+ "UPDATE": (
+ "UPDATE iam_tickets set maturity=%s where trade_date != %s and maturity is null and action='NEW' returning *"
+ ),
+ }
+ for action, query in actions.items():
+ with conn.cursor() as c:
+ c.execute(query, (trade_date, trade_date))
+ for row in c:
+ deals.append(iam_serialize(row._asdict(), action, trade_date))
+ return deals
+
+
+def gen_iam_deals(conn, trade_date):
+ new_iam = gen_strat_alloc(conn, trade_date)
+ iam_deals = []
+ with conn.cursor() as c:
+ insert_query = (
+ """INSERT INTO iam_tickets(trade_date, action, strategy, counterparty, maturity, start_money, currency, "offset") """
+ """VALUES (%s, %s, %s, %s, %s, %s, %s, %s);"""
+ )
+ try:
+ c.executemany(insert_query, new_iam)
+ except UniqueViolation:
+ # We already uploaded the IAM tickets today in that case, we need to update and cancel the old uploads
+ conn.rollback()
+ c.execute(
+ "DELETE FROM iam_tickets where trade_date=%s returning *", (trade_date,)
+ )
+ cancel_iam_deals = [
+ iam_serialize(row._asdict(), "CANCEL", trade_date) for row in c
+ ]
+ iam_deals += cancel_iam_deals
+ c.executemany(insert_query, new_iam)
+ iam_deals += process_trades(conn, trade_date)
+ return iam_deals
+
+
+def process_upload(conn, trade_date, iam_deals):
+ bowdst = Fund["BOWDST"]()
+ bowdst.staging_queue.extend(iam_deals)
+ if bowdst.staging_queue:
+ buf, dest = bowdst.build_buffer("iam")
+ bowdst.upload(buf, dest.name)
+
+
+if __name__ == "__main__":
+ import argparse
+ from serenitas.utils.db import dbconn
+
+ conn = dbconn("dawndb")
+ parser = argparse.ArgumentParser(description="Generate IAM file for globeop")
+ parser.add_argument(
+ "date",
+ nargs="?",
+ type=datetime.date.fromisoformat,
+ default=(datetime.date.today() - bus_day).date(),
+ )
+ args = parser.parse_args()
+ iam_deals = gen_iam_deals(conn, args.date)
+ process_upload(conn, args.date, iam_deals)
+ conn.commit()