aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/citco_ops/utils.py54
-rw-r--r--python/innocap_bond_setts.py29
2 files changed, 70 insertions, 13 deletions
diff --git a/python/citco_ops/utils.py b/python/citco_ops/utils.py
index 450b2204..0c42306b 100644
--- a/python/citco_ops/utils.py
+++ b/python/citco_ops/utils.py
@@ -10,10 +10,19 @@ from psycopg.errors import UniqueViolation
from exchangelib import HTMLBody
from tabulate import tabulate
from functools import lru_cache
+from serenitas.analytics.dates import next_business_day
+from decimal import Decimal
+import math
logger = logging.getLogger(__name__)
+def next_business_days(date, offset):
+ for i in range(offset):
+ date = next_business_day(date)
+ return date
+
+
def get_file_status(s):
is_processed, fname_short = s.rsplit("_", 1)
is_processed = is_processed.rsplit("-")[1] == "PROCESSED"
@@ -58,6 +67,11 @@ def instrument_table(instrument_id):
return "citco_trs"
+def round_up(n, decimals=0):
+ multiplier = 10**decimals
+ return math.ceil(n * multiplier) / multiplier
+
+
@dataclass
class CitcoSubmission(Deal, deal_type=None, table_name="citco_submission"):
fname: str = field()
@@ -218,19 +232,47 @@ class Payment:
class PaymentSettlement(Payment):
@classmethod
- def email_innocap(cls, date):
+ def email_innocap(cls, date, account_balance):
if not cls._insert_queue:
return
+ cls.subtract_cash_balance(account_balance)
+ move_cash = ""
+ for currency in ("USD", "EUR"):
+ biggest_deficit = min(
+ list(
+ map(
+ lambda x: int(x.amount) if x.currency == currency else 0,
+ cls._insert_queue,
+ )
+ )
+ )
+ if biggest_deficit < 0:
+ move_cash += f"\n\n***Please move ${round_up(abs(biggest_deficit), -6):,.2f} {currency} to Northern Trust from Scotia and confirm when done.***"
em = ExchangeMessage()
em.send_email(
- f"Payment Settlements Bond/FX NT: ISOSEL {date}",
- "Good morning, \n\nWe have the following amounts settling in the next 4 calendar days at Northern Trust: (Positive Amounts = Receive, Negative Amounts=Pay)\n\n"
+ f"{'*ACTION REQUESTED* ' if move_cash else ''}Payment Settlements Bond/FX NT: ISOSEL {date}",
+ "Good morning, \n\nProjected Balances at Northern Trust: (Positive Amounts = Positive Balance, Negative Amounts = Negative Balance)\n\n"
+ "\n".join(
settlement.to_email_format() for settlement in cls._insert_queue
- ),
- to_recipients=_recipients["ISOSEL"],
- cc_recipients=("Selene-Ops@lmcg.com",),
+ )
+ + move_cash,
+ to_recipients=("fyu@lmcg.com",),
+ # cc_recipients=("Selene-Ops@lmcg.com",),
)
+ cls._insert_queue.clear()
+
+ @classmethod
+ def stage_payment(cls, settlements, date):
+ for row in settlements:
+ cls._insert_queue.append(cls(date, row.currency, row.payment_amount))
+
+ @classmethod
+ def subtract_cash_balance(cls, account_balance):
+ overdraft = []
+ for settlement in cls._insert_queue:
+ settlement.amount = Decimal(account_balance[settlement.currency]) - (
+ -settlement.amount
+ )
class GFSMonitor(Payment):
diff --git a/python/innocap_bond_setts.py b/python/innocap_bond_setts.py
index 37101b80..8fd10db2 100644
--- a/python/innocap_bond_setts.py
+++ b/python/innocap_bond_setts.py
@@ -1,6 +1,15 @@
import datetime
from serenitas.utils.db import dbconn
-from citco_ops.utils import PaymentSettlement
+from citco_ops.utils import PaymentSettlement, next_business_days
+from serenitas.analytics.dates import prev_business_day
+
+
+def get_cash_balance(account_number, date, 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_number, date))
+ return {row.currency_code: row.balance for row in c}
+
if __name__ == "__main__":
import argparse
@@ -15,11 +24,17 @@ if __name__ == "__main__":
)
args = parser.parse_args()
conn = dbconn("dawndb")
- sql_str = "SELECT settle_date, 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 settle_date, currency;"
+ sql_str = "SELECT settle_date, 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 AND currency=%s group by settle_date, currency;"
+ cash_balances = get_cash_balance("ISOS01", prev_business_day(args.date), conn)
with conn.cursor() as c:
for fund in ("ISOSEL",):
- c.execute(
- sql_str, (fund, args.date, args.date + datetime.timedelta(days=4))
- )
- PaymentSettlement.stage_payment(c)
- PaymentSettlement.email_innocap(args.date)
+ for date in (
+ args.date,
+ next_business_days(args.date, 1),
+ next_business_days(args.date, 2),
+ ):
+ for currency in ("USD", "EUR"):
+ params = (fund, args.date, date, currency)
+ c.execute(sql_str, params)
+ PaymentSettlement.stage_payment(c, date)
+ PaymentSettlement.email_innocap(args.date, cash_balances)