Coverage for rivapy / tools / interfaces.py: 65%
79 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-27 14:36 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-27 14:36 +0000
1import abc
2import enum
3from typing import List, Tuple
4import datetime as dt
5import numpy as np
6import json
7import hashlib
8from rivapy.tools.datetime_grid import DateTimeGrid
9from rivapy.tools.holidays_compat import ECB, UnitedStates, Germany
12class DateTimeFunction(abc.ABC):
13 @abc.abstractmethod
14 def compute(self, ref_date: dt.datetime, dt_grid: DateTimeGrid) -> np.ndarray:
15 pass
18class _JSONDecoder(json.JSONDecoder):
19 def __init__(self, *args, **kwargs):
20 json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)
22 def object_hook(self, obj):
23 ret = {}
24 for key, value in obj.items():
25 if key in {"timestamp", "whatever"}:
26 ret[key] = dt.fromisoformat(value)
27 else:
28 ret[key] = value
29 return ret
32class _JSONEncoder(json.JSONEncoder):
33 def default(self, obj):
34 if isinstance(obj, (dt.date, dt.datetime)): # , pd.Timestamp)):
35 return obj.isoformat()
36 if isinstance(obj, enum.Enum):
37 return obj.value
38 # return json.JSONEncoder.default(obj)
39 return super().default(obj)
42class FactoryObject(abc.ABC):
44 def to_dict(self):
45 result = self._to_dict()
46 result["cls"] = type(self).__name__
47 return result
49 def to_json(self):
50 return json.dumps(self.to_dict(), cls=_JSONEncoder).encode()
52 @classmethod
53 def from_json(cls, json_str: str):
54 tmp = json.loads(json_str, cls=_JSONDecoder)
55 return cls.from_dict(tmp)
57 @staticmethod
58 def hash_for_dict(data: dict):
59 return hashlib.sha1(json.dumps(data, cls=_JSONEncoder).encode()).hexdigest()
61 def hash(self):
62 return FactoryObject.hash_for_dict(self.to_dict())
64 @abc.abstractmethod
65 def _to_dict(self) -> dict:
66 pass
68 @classmethod
69 def from_dict(cls, data: dict) -> object:
70 from datetime import datetime, date
72 def parse_date(val):
73 if isinstance(val, str):
74 try:
75 # Try parsing as datetime first
76 return datetime.fromisoformat(val)
77 except ValueError:
78 return val
79 return val
81 CALENDAR_REGISTRY = {
82 "ECB": ECB,
83 "UnitedStates": UnitedStates,
84 "Germany": Germany,
85 # Add more as needed
86 }
88 def calendar_from_name(name):
89 cls = CALENDAR_REGISTRY.get(name)
90 if cls:
91 return cls()
92 raise ValueError(f"Unknown calendar: {name}")
94 # List of keys that may be date/datetime fields (customize as needed)
95 date_keys = ["issue_date", "trade_date", "maturity_date", "start_date", "end_date", "rate_start_date", "rate_end_date", "fixing_date"]
96 parsed_data = {}
97 for k, v in data.items():
98 if k != "cls" and k in date_keys:
99 parsed_data[k] = parse_date(v)
100 elif k == "calendar":
101 parsed_data[k] = calendar_from_name(v)
102 elif k != "cls":
103 parsed_data[k] = v
104 return cls(**parsed_data)
107class BaseDatedCurve(abc.ABC):
108 @abc.abstractmethod
109 def value(self, ref_date: dt.datetime, d: dt.datetime) -> np.ndarray: # , dt_grid: DateTimeGrid)->np.ndarray:
110 pass