aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/ops/funds.py15
-rw-r--r--python/ops/trade_dataclasses.py121
2 files changed, 40 insertions, 96 deletions
diff --git a/python/ops/funds.py b/python/ops/funds.py
index 12de1110..101deea2 100644
--- a/python/ops/funds.py
+++ b/python/ops/funds.py
@@ -1,10 +1,11 @@
import csv
import datetime
import pathlib
-from csv_headers.citco import GTL
+from csv_headers.citco import GTL, GIL
from serenitas.utils.remote import FtpClient, SftpClient
from serenitas.utils.exchange import ExchangeMessage, FileAttachment
from io import StringIO
+from pickle import dumps
from typing import Tuple, Union
from serenitas.utils.env import DAILY_DIR
from .file_gen import get_headers, build_line
@@ -122,7 +123,9 @@ class Selene(Fund, fund_name="ISOSEL"):
@classmethod
def set_headers(cls, trade_type):
- pass
+ if trade_type == "product":
+ cls.headers = GIL
+ cls.filepath_pattern = "i.innocap_serenitas.{timestamp:%Y%m%d%H%M%S}.csv"
@staticmethod
def upload(buf, dest):
@@ -130,13 +133,13 @@ class Selene(Fund, fund_name="ISOSEL"):
sftp.put(buf, dest)
@classmethod
- def stage(cls, trade, *, trade_type, action="NEW", **kwargs):
+ def stage(cls, trade, *, trade_type, redis_pipeline, **kwargs):
obj = DealKind[trade_type].from_dict(**trade)
if (
(trade_type not in ("cds", "irs", "swaption", "trs"))
or (trade_type == "cds" and obj.attach is None)
- or obj.product.committed
+ or obj.product.status == "Acknowledged"
):
- cls.staging_queue.append(obj.to_citco(action))
+ cls.staging_queue.append(obj.to_citco(trade["action"]))
else:
- pass
+ redis_pipeline.rpush("product_queue", dumps((trade_type, trade)))
diff --git a/python/ops/trade_dataclasses.py b/python/ops/trade_dataclasses.py
index 220611a0..07ac69be 100644
--- a/python/ops/trade_dataclasses.py
+++ b/python/ops/trade_dataclasses.py
@@ -27,11 +27,12 @@ import warnings
logger = logging.getLogger(__name__)
-Fund = Literal["SERCGMAST", "BRINKER", "BOWDST"]
+Fund = Literal["SERCGMAST", "BRINKER", "BOWDST", "ISOSEL"]
Portfolio = Literal[
"OPTIONS", "IR", "MORTGAGES", "CURVE", "TRANCHE", "CLO", "HEDGE_MAC"
] # deprecated IG, HY, STRUCTURED
+Status = Literal["Pending", "Submitted", "Acknowledged", "Failed"]
_funds = {"BAML": "SERCGMAST", "GS": "BOWDST", "WF": "SERCGMAST"}
_fcms = {
"Bank of America, N.A.": "BAML",
@@ -188,6 +189,14 @@ class DealKind:
return SwaptionDeal
case "termination":
return TerminationDeal
+ case "irs":
+ return IRSDeal
+ case "trs":
+ return TRSDeal
+ case "spot":
+ return SpotDeal
+ case "fx_swap":
+ return FxSwapDeal
case _:
return None
@@ -431,100 +440,40 @@ class MTMDeal:
class Citco:
- _citco_headers = []
- _citco_sftp = SftpClient.from_creds("citco")
- _submission_queue = []
-
- @classmethod
- def citco_upload(cls):
- if not cls._citco_queue: # early exit
- return
- buf = StringIO()
- csvwriter = csv.writer(buf)
- csvwriter.writerow(cls._citco_headers)
- for h in cls._citco_queue:
- _citco_to_action = {"R": "UPDATE", "D": "CANCEL", "N": "NEW"}
- warnings.warn("we will get rid of overwriting")
- h["Fund"] = "ISOSEL"
- # Ensure each file is unique
- h["Comment"] = f"{datetime.datetime.now():%Y%m%d%H%M%S}"
- h["Notes"] = f"{datetime.datetime.now():%Y%m%d%H%M%S}"
- identifier = (
- "instrument" if cls.file_tag == "i.innocap_serenitas." else "trade"
- )
- unique_id = (
- h["UniqueIdentifier"]
- if cls.file_tag == "i.innocap_serenitas."
- else h["ClientOrderID"]
- )
- cls._submission_queue.append(
- [
- unique_id,
- _citco_to_action[
- h.get("OrdStatus", "N")
- ], # We only update trades, not instruments
- identifier,
- ]
- )
- csvwriter.writerows(
- [row.get(h, None) for h in cls._citco_headers] for row in cls._citco_queue
- )
- buf = buf.getvalue().encode()
- cls._citco_sftp.client.chdir("/incoming")
- cls._citco_sftp.put(buf, cls.fname())
- cls.submission_commit()
- dest = DAILY_DIR / str(datetime.date.today()) / cls.fname()
- dest.write_bytes(buf)
- cls._citco_queue.clear()
- cls._submission_queue.clear()
-
- def citco_stage(self, action="NEW"):
- self._citco_queue.append(self.to_citco(action))
-
- @classmethod
- def fname(cls):
- return f"{cls.file_tag}{datetime.datetime.now():%Y%m%d%H%M%S}.csv"
-
- @classmethod
- def submission_commit(cls):
- sql_str = "INSERT INTO citco_submission_status (serenitas_id, action, identifier_type) VALUES (%s, %s, %s) "
- with cls._conn.cursor() as c:
- c.executemany(sql_str, cls._submission_queue)
- cls._conn.commit()
+ pass
class CitcoProduct(Citco):
- _citco_queue: ClassVar[list] = []
- _citco_headers = GIL
product_key = ()
- file_tag = "i.innocap_serenitas."
def __init_subclass__(cls, product_key, **kwargs):
cls.product_key = product_key
def get_productid(self):
filter_clause = " AND ".join([f"{k}=%s" for k in self.product_key])
- sql_str = f"SELECT id, dealid, committed FROM {self._table_name} WHERE {filter_clause}"
+ sql_str = (
+ f"SELECT id, deal id, status FROM {self._table_name} WHERE {filter_clause}"
+ )
with self._conn.cursor() as c:
c.execute(
sql_str,
tuple([getattr(self, k) for k in self.product_key]),
)
if results := c.fetchone():
- (self.id, self.dealid, self.committed) = results
+ (self.id, self.dealid, self.status) = results
- def to_citco(self, action):
+ def to_citco(self):
+ if not self.id:
+ self.stage()
+ self.commit()
+ self.get_productid()
obj = self.serialize("citco")
- obj["Birth_date"] = obj["Birth_date"].strftime("%Y%m%d")
- obj["Death_date"] = obj["Death_date"].strftime("%Y%m%d")
+ for k in ["Birth_date", "Death_date"]:
+ obj[k] = obj[k].strftime("%Y%m%d")
return obj
class CitcoTrade(Citco):
- _citco_queue: ClassVar[list] = []
- _citco_headers = GTL
- file_tag = "innocap_serenitas_trades_"
-
def to_citco(self, action):
obj = self.serialize("citco")
obj["SettleCurrency"] = "USD"
@@ -1612,7 +1561,7 @@ class TrancheProduct(
underlying_id_source: str = field(
default="RED", metadata={"citco": "UnderlyingIDSource"}
)
- committed: bool = field(default=False)
+ status: Status = field(default="Pending")
id: int = field(default=None, metadata={"insert": False})
dealid: str = field(
default=None, metadata={"insert": False, "citco": "UniqueIdentifier"}
@@ -1649,12 +1598,8 @@ class TrancheProduct(
self.currency = "EUR" if index in ("XO", "EU") else "USD"
self.get_productid()
- def to_citco(self, action):
- if not self.id:
- self.stage()
- self.commit()
- self.get_productid()
- obj = super().to_citco(action)
+ def to_citco(self):
+ obj = super().to_citco()
obj["Command"] = "N"
obj["Active"] = "Y"
obj["CouponRate"] = obj["CouponRate"] / 100
@@ -1723,6 +1668,7 @@ class SwaptionProduct(
self.currency = "EUR" if index in ("XO", "EU") else "USD"
elif self.instrument_type == "SWPO":
self.security_desc = ""
+ self.underlying_id_source = "USERID"
self.get_productid()
def to_citco(self):
@@ -1731,15 +1677,14 @@ class SwaptionProduct(
self.commit()
self.get_productid()
obj = super().to_citco(action)
- if (
- self.underlying_id_source == "USERID"
- ): # Implies this is a Interest Rate Swaption
+ if self.instrument_type == "SWPO": # Implies this is a Interest Rate Swaption
irs = IRSProduct(
birth_date=self.birth_date,
death_date=self.death_date,
fixed_rate=self.strike,
float_index=self.underlying_security_id,
)
+ warnings.warn("We're just tacking on the IRS here, it's not very elegant")
irs.citco_stage()
obj["UnderlyingSecurityId"] = irs.dealid
obj["Command"] = "N"
@@ -1754,6 +1699,7 @@ _citco_frequency = {"Yearly": 1, "Daily": 9, "Quarterly": 3}
_citco_bdc = {"Modified Following": 4}
_citco_daycount = {"ACT/360": 2}
_citco_ratesource = {"SOFRRATE": 17819}
+_to_index = {"SOFRINDX": "SOFRRATE"}
_citco_cp_isda = {
"MSCSNY": "MS_IS",
"GOLDNY": "GS_IS",
@@ -1811,12 +1757,7 @@ class IRSProduct(
self.security_desc = f"SWAP IRS {self.float_index}-{self.fixed_rate}-{self.birth_date}-{self.death_date}"
def to_citco(self):
- if not self.id:
- self.stage()
- self.commit()
- self.get_productid()
-
- obj = super().to_citco(action)
+ obj = super().to_citco()
d = {
"S_P_CurrencyCode": self.currency,
"S_P_PaymentFreqID": _citco_frequency[self.fixed_payment_freq],
@@ -1880,7 +1821,7 @@ class TRSProduct(
_citco_trs = {"4J623JAA8": "IBOXHY_TRS"}
self.security_desc = f"{_citco_trs[self.underlying_security]}-{self.funding_index}-{self.birth_date}-{self.death_date}"
- def to_citco(self):
+ def to_citco(self, action):
if not self.id:
self.stage()