Skip to content

Commit 6ae3e3c

Browse files
attack68mikelync
andauthored
ENH: add Value component (#148) (#1073)
Co-authored-by: mikelync <[email protected]> Co-authored-by: Mike Lync <[email protected]> Co-authored-by: JHM Darbyshire (M1) <[email protected]>
1 parent ef3752c commit 6ae3e3c

File tree

22 files changed

+957
-300
lines changed

22 files changed

+957
-300
lines changed

python/rateslib/curves/_parsers.py

Lines changed: 0 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -308,138 +308,3 @@ def _maybe_set_ad_order(
308308
# Curve has no method (possibly a custom curve and not a subclass of _BaseCurve)
309309
return None
310310
return original_order
311-
312-
313-
def _to_six_curve_dict(
314-
curves: CurveOption | list[CurveOption] | dict[str, CurveOption],
315-
) -> dict[str, CurveOption_]:
316-
if isinstance(curves, list | tuple):
317-
if len(curves) == 1:
318-
return dict(
319-
rate=curves[0],
320-
disc=curves[0],
321-
index=NoInput(0),
322-
rate2=curves[0],
323-
disc2=curves[0],
324-
index2=NoInput(0),
325-
)
326-
if len(curves) == 2:
327-
return dict(
328-
rate=curves[0],
329-
disc=curves[1],
330-
index=NoInput(0),
331-
rate2=curves[0],
332-
disc2=curves[1],
333-
index2=NoInput(0),
334-
)
335-
if len(curves) == 3:
336-
return dict(
337-
rate=curves[0],
338-
disc=curves[1],
339-
index=curves[2],
340-
rate2=curves[0],
341-
disc2=curves[1],
342-
index2=curves[2],
343-
)
344-
if len(curves) == 4:
345-
return dict(
346-
rate=curves[0],
347-
disc=curves[1],
348-
index=NoInput(0),
349-
rate2=curves[2],
350-
disc2=curves[3],
351-
index2=NoInput(0),
352-
)
353-
if len(curves) == 5:
354-
return dict(
355-
rate=curves[0],
356-
disc=curves[1],
357-
index=curves[2],
358-
rate2=curves[3],
359-
disc2=curves[4],
360-
index2=curves[2],
361-
)
362-
if len(curves) == 6:
363-
return dict(
364-
rate=curves[0],
365-
disc=curves[1],
366-
index=curves[2],
367-
rate2=curves[3],
368-
disc2=curves[4],
369-
index2=curves[5],
370-
)
371-
else:
372-
raise ValueError(
373-
f"`curves` as sequence must not be greater than 6 in length, got: {len(curves)}."
374-
)
375-
elif isinstance(curves, dict):
376-
return dict(
377-
rate=curves.get("rate", None) or NoInput(0),
378-
disc=curves.get("disc", None) or curves.get("rate", None) or NoInput(0),
379-
index=curves.get("index", None) or NoInput(0),
380-
rate2=curves.get("rate2", None) or curves.get("rate", None) or NoInput(0),
381-
disc2=curves.get("disc2", None) or curves.get("disc", None) or NoInput(0),
382-
index2=curves.get("index2", None) or curves.get("index", None) or NoInput(0),
383-
)
384-
else:
385-
return dict(
386-
rate=curves,
387-
disc=curves,
388-
index=NoInput(0),
389-
rate2=curves,
390-
disc2=curves,
391-
index2=NoInput(0),
392-
)
393-
394-
395-
class _Curves:
396-
"""
397-
Container for a pricing object providing a mapping for curves.
398-
"""
399-
400-
def __init__(
401-
self,
402-
*,
403-
rate_curve: CurveOption_ = NoInput(0),
404-
disc_curve: CurveOption_ = NoInput(0),
405-
index_curve: CurveOption_ = NoInput(0),
406-
leg2_rate_curve: CurveOption_ = NoInput(0),
407-
leg2_disc_curve: CurveOption_ = NoInput(0),
408-
leg2_index_curve: CurveOption_ = NoInput(0),
409-
):
410-
self._rate_curve = rate_curve
411-
self._disc_curve = disc_curve
412-
self._index_curve = index_curve
413-
self._leg2_rate_curve = leg2_rate_curve
414-
self._leg2_disc_curve = leg2_disc_curve
415-
self._leg2_index_curve = leg2_index_curve
416-
417-
@property
418-
def rate_curve(self) -> CurveOption_:
419-
"""The curve used for floating rate or hazard rate forecasting on leg1."""
420-
return self._rate_curve
421-
422-
@property
423-
def disc_curve(self) -> CurveOption_:
424-
"""The curve used for discounting on leg1."""
425-
return self._disc_curve
426-
427-
@property
428-
def index_curve(self) -> CurveOption_:
429-
"""The index curve used for forecasting index values on leg1."""
430-
return self._index_curve
431-
432-
@property
433-
def leg2_rate_curve(self) -> CurveOption_:
434-
"""The curve used for floating rate or hazard rate forecasting on leg2."""
435-
return self._leg2_rate_curve
436-
437-
@property
438-
def leg2_disc_curve(self) -> CurveOption_:
439-
"""The curve used for discounting on leg2."""
440-
return self._leg2_disc_curve
441-
442-
@property
443-
def leg2_index_curve(self) -> CurveOption_:
444-
"""The index curve used for forecasting index values on leg2."""
445-
return self._leg2_index_curve

python/rateslib/instruments/components/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from rateslib.instruments.components.portfolio import Portfolio
55
from rateslib.instruments.components.sbs import SBS
66
from rateslib.instruments.components.spread import Spread
7+
from rateslib.instruments.components.value import Value
78

89
__all__ = [
910
"IRS",
@@ -12,4 +13,5 @@
1213
"Portfolio",
1314
"Fly",
1415
"Spread",
16+
"Value",
1517
]

python/rateslib/instruments/components/cds.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
from typing import TYPE_CHECKING
44

55
from rateslib import defaults
6-
from rateslib.curves._parsers import _Curves
76
from rateslib.dual.utils import _dual_float
87
from rateslib.enums.generics import NoInput, _drb
98
from rateslib.instruments.components.protocols import _BaseInstrument
109
from rateslib.instruments.components.protocols.kwargs import _convert_to_schedule_kwargs, _KWArgs
11-
from rateslib.instruments.components.protocols.utils import _get_curve_maybe_from_solver
10+
from rateslib.instruments.components.protocols.pricing import (
11+
_Curves,
12+
_get_maybe_curve_maybe_from_solver,
13+
)
1214
from rateslib.legs.components import CreditPremiumLeg, CreditProtectionLeg
1315
from rateslib.scheduling import Frequency
1416

@@ -168,12 +170,12 @@ def rate(
168170
metric: str_ = NoInput(0),
169171
) -> DualTypes:
170172
_curves = self._parse_curves(curves)
171-
disc_curve = _get_curve_maybe_from_solver(
173+
disc_curve = _get_maybe_curve_maybe_from_solver(
172174
self.kwargs.meta["curves"], _curves, "disc_curve", solver
173175
)
174176

175177
leg2_npv: DualTypes = self.leg2.local_npv(
176-
rate_curve=_get_curve_maybe_from_solver(
178+
rate_curve=_get_maybe_curve_maybe_from_solver(
177179
self.kwargs.meta["curves"], _curves, "leg2_rate_curve", solver
178180
),
179181
disc_curve=disc_curve,
@@ -184,7 +186,7 @@ def rate(
184186
return (
185187
self.leg1.spread(
186188
target_npv=-leg2_npv,
187-
rate_curve=_get_curve_maybe_from_solver(
189+
rate_curve=_get_maybe_curve_maybe_from_solver(
188190
self.kwargs.meta["curves"], _curves, "rate_curve", solver
189191
),
190192
disc_curve=disc_curve,

python/rateslib/instruments/components/fly.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from rateslib.enums.generics import NoInput
99
from rateslib.instruments.components.protocols import _BaseInstrument
10-
from rateslib.instruments.components.protocols.utils import (
10+
from rateslib.instruments.components.protocols.pricing import (
1111
_get_fx_maybe_from_solver,
1212
)
1313
from rateslib.periods.components.utils import _maybe_fx_converted

python/rateslib/instruments/components/irs.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
from typing import TYPE_CHECKING, NoReturn
44

55
from rateslib import defaults
6-
from rateslib.curves._parsers import _Curves
76
from rateslib.dual.utils import _dual_float
87
from rateslib.enums.generics import NoInput, _drb
98
from rateslib.instruments.components.protocols import _BaseInstrument
109
from rateslib.instruments.components.protocols.kwargs import _convert_to_schedule_kwargs, _KWArgs
11-
from rateslib.instruments.components.protocols.utils import _get_curve_maybe_from_solver
10+
from rateslib.instruments.components.protocols.pricing import (
11+
_Curves,
12+
_get_maybe_curve_maybe_from_solver,
13+
)
1214
from rateslib.legs.components import FixedLeg, FloatLeg
1315

1416
if TYPE_CHECKING:
@@ -187,10 +189,10 @@ def rate(
187189
metric: str_ = NoInput(0),
188190
) -> DualTypes_:
189191
_curves = self._parse_curves(curves)
190-
leg2_rate_curve = _get_curve_maybe_from_solver(
192+
leg2_rate_curve = _get_maybe_curve_maybe_from_solver(
191193
self.kwargs.meta["curves"], _curves, "leg2_rate_curve", solver
192194
)
193-
disc_curve = _get_curve_maybe_from_solver(
195+
disc_curve = _get_maybe_curve_maybe_from_solver(
194196
self.kwargs.meta["curves"], _curves, "disc_curve", solver
195197
)
196198

@@ -223,10 +225,10 @@ def spread(
223225
forward: datetime_ = NoInput(0),
224226
) -> DualTypes:
225227
_curves = self._parse_curves(curves)
226-
leg2_rate_curve = _get_curve_maybe_from_solver(
228+
leg2_rate_curve = _get_maybe_curve_maybe_from_solver(
227229
self.kwargs.meta["curves"], _curves, "leg2_rate_curve", solver
228230
)
229-
disc_curve = _get_curve_maybe_from_solver(
231+
disc_curve = _get_maybe_curve_maybe_from_solver(
230232
self.kwargs.meta["curves"], _curves, "disc_curve", solver
231233
)
232234
leg1_npv: DualTypes = self.leg1.local_npv(

python/rateslib/instruments/components/portfolio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from rateslib import defaults
99
from rateslib.enums.generics import NoInput
1010
from rateslib.instruments.components.protocols import _BaseInstrument
11-
from rateslib.instruments.components.protocols.utils import (
11+
from rateslib.instruments.components.protocols.pricing import (
1212
_get_fx_maybe_from_solver,
1313
)
1414
from rateslib.periods.components.utils import _maybe_fx_converted

python/rateslib/instruments/components/protocols/analytic_delta.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
from typing import TYPE_CHECKING, Protocol
44

55
from rateslib.enums.generics import NoInput
6-
from rateslib.instruments.components.protocols.curves import _WithCurves
76
from rateslib.instruments.components.protocols.kwargs import _KWArgs
8-
from rateslib.instruments.components.protocols.utils import (
9-
_get_curve_maybe_from_solver,
7+
from rateslib.instruments.components.protocols.pricing import (
108
_get_fx_maybe_from_solver,
9+
_get_maybe_curve_maybe_from_solver,
10+
_WithPricingObjs,
1111
)
1212

1313
if TYPE_CHECKING:
@@ -24,7 +24,7 @@
2424
)
2525

2626

27-
class _WithAnalyticDelta(_WithCurves, Protocol):
27+
class _WithAnalyticDelta(_WithPricingObjs, Protocol):
2828
"""
2929
Protocol to determine the *analytic rate delta* of a particular *Leg* of an *Instrument*.
3030
"""
@@ -104,17 +104,17 @@ def analytic_delta(
104104
prefix = "" if leg == 1 else "leg2_"
105105

106106
return self.legs[leg - 1].analytic_delta(
107-
rate_curve=_get_curve_maybe_from_solver(
107+
rate_curve=_get_maybe_curve_maybe_from_solver(
108108
_curves_meta, _curves, f"{prefix}rate_curve", solver
109109
),
110-
disc_curve=_get_curve_maybe_from_solver(
110+
disc_curve=_get_maybe_curve_maybe_from_solver(
111111
_curves_meta, _curves, f"{prefix}disc_curve", solver
112112
),
113-
index_curve=_get_curve_maybe_from_solver(
113+
index_curve=_get_maybe_curve_maybe_from_solver(
114114
_curves_meta, _curves, f"{prefix}index_curve", solver
115115
),
116116
fx_vol=fx_vol,
117-
fx=_get_fx_maybe_from_solver(fx, solver),
117+
fx=_get_fx_maybe_from_solver(fx=fx, solver=solver),
118118
base=base,
119119
local=local,
120120
settlement=settlement,

python/rateslib/instruments/components/protocols/analytic_fixings.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
from pandas import DataFrame, DatetimeIndex, concat
77

88
from rateslib.enums.generics import NoInput
9-
from rateslib.instruments.components.protocols.curves import _WithCurves
10-
from rateslib.instruments.components.protocols.utils import (
11-
_get_curve_maybe_from_solver,
9+
from rateslib.instruments.components.protocols.pricing import (
1210
_get_fx_maybe_from_solver,
11+
_get_maybe_curve_maybe_from_solver,
12+
_WithPricingObjs,
1313
)
1414

1515
if TYPE_CHECKING:
@@ -60,7 +60,7 @@ def _composit_fixings_table(df_result: DataFrame, df: DataFrame) -> DataFrame:
6060
return df_result
6161

6262

63-
class _WithAnalyticRateFixings(_WithCurves, Protocol):
63+
class _WithAnalyticRateFixings(_WithPricingObjs, Protocol):
6464
def local_analytic_rate_fixings(
6565
self,
6666
*,
@@ -121,18 +121,18 @@ def _local_analytic_rate_fixings_from_legs(
121121
# this is a generic implementation to handle 2 legs.
122122
_curves: _Curves = self._parse_curves(curves)
123123
_curves_meta: _Curves = self.kwargs.meta["curves"]
124-
_fx_maybe_from_solver = _get_fx_maybe_from_solver(fx, solver)
124+
_fx_maybe_from_solver = _get_fx_maybe_from_solver(fx=fx, solver=solver)
125125

126126
dfs = []
127127
dfs.append(
128128
self.legs[0].local_analytic_rate_fixings(
129-
rate_curve=_get_curve_maybe_from_solver(
129+
rate_curve=_get_maybe_curve_maybe_from_solver(
130130
_curves_meta, _curves, "rate_curve", solver
131131
),
132-
disc_curve=_get_curve_maybe_from_solver(
132+
disc_curve=_get_maybe_curve_maybe_from_solver(
133133
_curves_meta, _curves, "disc_curve", solver
134134
),
135-
index_curve=_get_curve_maybe_from_solver(
135+
index_curve=_get_maybe_curve_maybe_from_solver(
136136
_curves_meta, _curves, "index_curve", solver
137137
),
138138
fx=_fx_maybe_from_solver,
@@ -143,13 +143,13 @@ def _local_analytic_rate_fixings_from_legs(
143143
)
144144
dfs.append(
145145
self.legs[1].local_analytic_rate_fixings(
146-
rate_curve=_get_curve_maybe_from_solver(
146+
rate_curve=_get_maybe_curve_maybe_from_solver(
147147
_curves_meta, _curves, "leg2_rate_curve", solver
148148
),
149-
disc_curve=_get_curve_maybe_from_solver(
149+
disc_curve=_get_maybe_curve_maybe_from_solver(
150150
_curves_meta, _curves, "leg2_disc_curve", solver
151151
),
152-
index_curve=_get_curve_maybe_from_solver(
152+
index_curve=_get_maybe_curve_maybe_from_solver(
153153
_curves_meta, _curves, "leg2_index_curve", solver
154154
),
155155
fx=_fx_maybe_from_solver,

0 commit comments

Comments
 (0)