diff options
Diffstat (limited to 'python/reallocate_iam.py')
| -rw-r--r-- | python/reallocate_iam.py | 162 |
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() |
