import datetime import argparse from serenitas.ops.funds import Service from serenitas.ops.trade_dataclasses import IAMDeal from serenitas.analytics.dates import prev_business_day from serenitas.utils.db import dbconn def cancel_old_iam_trades(fund: str, cob: datetime.date, conn) -> "Iterable": """Finds and cancels old IAM trades""" with conn.cursor() as cursor: cursor.execute( "DELETE FROM iams WHERE trade_date=%s AND fund=%s RETURNING *", (cob, fund), ) for row in cursor: trade_data = row._asdict() yield IAMDeal.from_dict(**trade_data) conn.commit() def generate_new_iam_trades(fund: str, cob: datetime.date, conn) -> "Iterable": """Generates new IAM deals""" with conn.cursor() as cursor: cursor.execute( "SELECT * FROM list_iam(%s, %s)", (cob, fund), ) for row in cursor: trade_data = row._asdict() | {"trade_date": cob} yield IAMDeal.from_dict(**trade_data) def generate_new_iam_offset_trades(fund: str, cob: datetime.date, conn) -> "Iterable": """Generates offsets if the sma has already updated these IAM deals""" _ignore = {"BOWDST": ("GS_FCM",)} with conn.cursor() as cursor: cursor.execute( "SELECT broker, currency, fund, sum(-start_money) AS start_money " "FROM list_iam(%s, %s) GROUP BY (broker, currency, fund);", (cob, fund), ) for row in cursor: if row.broker not in _ignore[fund]: trade_data = row._asdict() | { "is_offset": True, "folder": "M_CSH_CASH", "portfolio": "CASH", "trade_date": cob, } yield IAMDeal.from_dict(**trade_data) def update_matured_iam_trades(fund: str, cob: datetime.date, conn) -> "Iterable": """Sets previous days as matured""" with conn.cursor() as cursor: cursor.execute( "UPDATE iams SET maturity=%s WHERE maturity is NULL AND trade_date<=%s AND fund=%s RETURNING *", (cob, prev_business_day(cob), fund), ) for row in cursor: trade_data = row._asdict() | {} yield IAMDeal.from_dict(**trade_data) conn.commit() def build_iam(fund: str, cob: datetime.date, conn, upload: bool): """Generates IAM file for globeop""" service = Service[fund] for old_iam in cancel_old_iam_trades(fund, cob, conn): service.push_trade(old_iam, "CANCEL") for new_iam in generate_new_iam_trades(fund, cob, conn): new_iam.stage() if fund == "BOWDST": for new_iam_offset in generate_new_iam_offset_trades(fund, cob, conn): new_iam_offset.stage() for iam in IAMDeal.commit(returning=True): service.push_trade(iam, "NEW") for update_iam in update_matured_iam_trades(fund, cob, conn): service.push_trade(update_iam, "UPDATE") buf, dest = service.build_buffer(trade_type="iam") if upload: service.upload(buf, dest.name) service().clear() def parse_args(): """Parses command line arguments""" parser = argparse.ArgumentParser(description="Generate IAM file for globeop") parser.add_argument( "cob", nargs="?", type=datetime.date.fromisoformat, default=prev_business_day(datetime.date.today()), ) parser.add_argument("-n", "--no-upload", action="store_true", help="do not upload") return parser.parse_args() def main(): """Generates IAM files for globeop""" conn = dbconn("dawndb") args = parse_args() for fund in ("SERCGMAST", "BOWDST"): build_iam(fund, args.cob, conn, not args.no_upload) if __name__ == "__main__": main()