Skip to content

Commit

Permalink
DEPR: IndexCurve depr updates (#561)
Browse files Browse the repository at this point in the history
Co-authored-by: JHM Darbyshire (win11) <[email protected]>
  • Loading branch information
attack68 and attack68 authored Dec 19, 2024
1 parent b5c5744 commit d79bae6
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 77 deletions.
47 changes: 25 additions & 22 deletions docs/source/c_curves.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,32 @@
Curves
***********

The ``rateslib.curves`` module allows the fundamental :class:`~rateslib.curves.Curve`,
:class:`~rateslib.curves.LineCurve`, or :class:`~rateslib.curves.IndexCurve` class
to be defined with parameters (for the purpose of the user guide an *IndexCurve*
can be considered a *Curve* with minor enhancements).
The ``rateslib.curves`` module allows the fundamental :class:`~rateslib.curves.Curve` or
:class:`~rateslib.curves.LineCurve` class
to be defined with parameters.
These curve objects are slightly different in what they
represent and how they operate.

This module relies on the ultility modules :ref:`splines<splines-doc>`
and :ref:`dual<dual-doc>`.

.. inheritance-diagram:: rateslib.curves.Curve rateslib.curves.LineCurve rateslib.curves.IndexCurve rateslib.curves.CompositeCurve rateslib.curves.MultiCsaCurve rateslib.curves.ProxyCurve
.. inheritance-diagram:: rateslib.curves.Curve rateslib.curves.LineCurve rateslib.curves.CompositeCurve rateslib.curves.MultiCsaCurve rateslib.curves.ProxyCurve
:private-bases:
:top-classes: rateslib.curves.Curve
:parts: 1

.. autosummary::
rateslib.curves.Curve
rateslib.curves.LineCurve
rateslib.curves.IndexCurve
rateslib.curves.CompositeCurve
rateslib.curves.ProxyCurve
rateslib.curves.MultiCsaCurve
rateslib.curves.interpolate
rateslib.curves.index_left

Each fundamental curve type has ``rate()``, ``plot()``, ``shift()``, ``roll()`` and
``translate()`` methods. :class:`~rateslib.curves.IndexCurve` can also calculate
future ``index_value()``.
``translate()`` methods. A :class:`~rateslib.curves.Curve` with included ``index_base`` and
``index_lag`` can also calculate future ``index_value()`` and ``plot_index()``.

.. autosummary::
rateslib.curves.Curve.rate
Expand All @@ -53,23 +51,23 @@ future ``index_value()``.
rateslib.curves.LineCurve.shift
rateslib.curves.LineCurve.roll
rateslib.curves.LineCurve.translate
rateslib.curves.IndexCurve.index_value
rateslib.curves.Curve.index_value
rateslib.curves.Curve.plot_index

The main parameter that must be supplied to either type of curve is its ``nodes``. This
provides the curve with its degrees of freedom and represents a dict indexed by
datetimes, each with a given value. In the case of a :class:`~rateslib.curves.Curve`
these
values are discount factors (DFs), and in the case of
a :class:`~rateslib.curves.LineCurve`
these values are discount factors (DFs) or, for credit purposes, survival probabilities,
and in the case of a :class:`~rateslib.curves.LineCurve`
these are specific values, usually rates associated with that curve.

Curve
*******

A :class:`~rateslib.curves.Curve` can only be used for **interest rates**.
It is a more specialised
object because of the way it is **defined by discount factors (DFs)**. These DFs
maintain an inherent interpolation technique, which is often log-linear or log-cubic
A :class:`~rateslib.curves.Curve` can only be used for **interest rates** (or credit
**hazard rates**). It is a more specialised
object because of the way it is **defined by discount factors (DFs)** (or survival probabilities).
These DFs maintain an inherent interpolation technique, which is often log-linear or log-cubic
spline. These are generally the most efficient
type of curve, and most easily parametrised, when working with compounded RFR rates.
The initial node on a :class:`~rateslib.curves.Curve` should always have value 1.0,
Expand Down Expand Up @@ -103,7 +101,7 @@ required.
from rateslib import dt
curve = Curve(
nodes={
dt(2022,1,1): 1.0, # <- initial DF should always be 1.0
dt(2022,1,1): 1.0, # <- initial DF (/survival probability) should always be 1.0
dt(2023,1,1): 0.99,
dt(2024,1,1): 0.979,
dt(2025,1,1): 0.967,
Expand Down Expand Up @@ -135,13 +133,18 @@ Initial Node Date
-----------------

The initial node date for either curve type is important because it is implied
to be the date of the
construction of the curve (i.e. today's date). Any net present
values (NPVs) may assume other features
from this initial node, e.g. the regular settlement date of securities or the value of
cashflows on derivatives. This is the reason the initial discount factor should also
to be the date of the construction of the curve (i.e. today's date).
When a :class:`~rateslib.curves.Curve` acts as a discount curve any net present
values (NPVs) might assume other features
from this initial node, e.g. the regular settlement date of securities.
This is the also the reason the initial discount factor should also
be exactly 1.0 on a :class:`~rateslib.curves.Curve`.

The only exception to this is when building a *Curve* used to forecast index vales, such
as inflation forecasts, it may be practical to start the curve using the most recent
inflation print which is usually assigned to the start of the month,
thus this may be before *today*.

Get Item
--------

Expand Down
5 changes: 2 additions & 3 deletions docs/source/g_curves.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@
Constructing Curves
********************

*Rateslib* has six different interest rate *Curve* classes. Three of these are fundamental base
*Rateslib* has five different interest rate *Curve* classes. Two of these are fundamental base
*Curves* of different types and for different purposes. Three are objects which are
constructed via references to other curves to allow certain combinations. *Rateslib* also
has one type of *Smile* for *FX volatility*.

The three fundamental curve classes are:
The two fundamental curve classes are:

.. autosummary::
rateslib.curves.Curve
rateslib.curves.LineCurve
rateslib.curves.IndexCurve

The remaining, more complex, combination classes are:

Expand Down
7 changes: 4 additions & 3 deletions docs/source/i_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ Defaults
:skip: Enum
:skip: read_csv
:skip: get_named_calendar
:skip: Cal
:skip: NamedCal
:skip: Series
:skip: UnionCal

Calendars
==========
Expand All @@ -59,8 +63,6 @@ Scheduling
.. automodapi:: rateslib.scheduling
:no-heading:
:no-inheritance-diagram:
:skip: Any
:skip: CustomBusinessDay
:skip: DataFrame
:skip: Iterator
:skip: datetime
Expand Down Expand Up @@ -174,7 +176,6 @@ FX Volatility
:skip: NoInput
:skip: newton_1dim
:skip: uuid4
:skip: Union
:skip: datetime
:skip: dt
:skip: timedelta
Expand Down
8 changes: 4 additions & 4 deletions docs/source/i_get_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ Can ``Curves`` be constructed and plotted in *rateslib*?
===========================================================

**Of course**. Building curves is a necessity for pricing fixed income instruments.
*Rateslib* has three primitive curve structures; :class:`~rateslib.curves.Curve` (which
is **discount factor based**), :class:`~rateslib.curves.LineCurve` (which is **purely value
based**), and :class:`~rateslib.curves.IndexCurve` (which is based on a *Curve* but also
calculates index values which is useful for inflation, for example). All *Curve* types offer
*Rateslib* has two primitive curve structures; :class:`~rateslib.curves.Curve`, which
is **discount factor, or survival probability based** and which can also calculate index values
for use with inflation products, for example, and :class:`~rateslib.curves.LineCurve`
(which is **purely value based**). All *Curve* types offer
various interpolation methods, such as log-linear or log-cubic spline and can even splice certain
interpolation types together.

Expand Down
19 changes: 10 additions & 9 deletions docs/source/i_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Let's start with some fundamental *Curve* and *Instrument* constructors.
Trivial derivatives examples
----------------------------

*Rateslib* has three fundamental :ref:`Curve types<c-curves-doc>`. All can be constructed
*Rateslib* has two fundamental :ref:`Curve types<c-curves-doc>`. Both can be constructed
independently by providing basic inputs.

.. tabs::
Expand Down Expand Up @@ -77,21 +77,23 @@ independently by providing basic inputs.
id="us_ibor_3m",
)
.. tab:: IndexCurve
.. tab:: *(IndexCurve)*

An :class:`~rateslib.curves.IndexCurve` extends a *Curve* class by allowing
an ``index_base`` argument and the calculation of index values. It is DF based.
It is required for the pricing of index-linked *Instruments*.
An *Index Curve* is required by certain products, e.g.
inflation linked bonds (:class:`~rateslib.instruments.IndexFixedRateBond`) or
zero coupon inflation swaps (:class:`~rateslib.instruments.ZCIS`). Adding ``index_base``
and ``index_lag`` argument inputs extends a DF based *Curve* to work in these cases.

.. ipython:: python
usd_cpi = IndexCurve(
usd_cpi = Curve(
nodes={
dt(2022, 1, 1): 1.00,
dt(2022, 7, 1): 0.97,
dt(2023, 1, 1): 0.955,
},
index_base=308.95,
index_lag=3,
id="us_cpi",
)
Expand Down Expand Up @@ -532,9 +534,8 @@ Calibrating curves with a solver
=================================

The guide for :ref:`Constructing Curves<curves-doc>` introduces the main
curve classes,
:class:`~rateslib.curves.Curve`, :class:`~rateslib.curves.LineCurve`, and
:class:`~rateslib.curves.IndexCurve`. It also touches on some of the more
curve classes, :class:`~rateslib.curves.Curve` and :class:`~rateslib.curves.LineCurve`.
It also touches on some of the more
advanced curves :class:`~rateslib.curves.CompositeCurve`,
:class:`~rateslib.curves.ProxyCurve`, and :class:`~rateslib.curves.MultiCsaCurve`.

Expand Down
2 changes: 1 addition & 1 deletion docs/source/i_whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ email contact, see `rateslib <https://rateslib.com>`_.
* - Dependencies
- Drop support for Python 3.9, only versions 3.10 - 3.13 now supported.
* - Refactor
:class:`~rateslib.curves.CompositeCurve` no longer requires all curves to have the same ``index_base``
- :class:`~rateslib.curves.CompositeCurve` no longer requires all curves to have the same ``index_base``
or ``index_lag``. Those values will be sampled from the first provided composited *Curve*.
* - Refactor
- :red:`Minor Breaking Change!` :meth:`~rateslib.calendars.get_calendar` has dropped the
Expand Down
2 changes: 1 addition & 1 deletion docs/source/z_amortization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ will also be indexed by the index.

.. ipython:: python
icurve = IndexCurve({dt(2000, 1, 1): 1.0, dt(2010, 1, 1): 0.75}, index_base=100.0)
icurve = Curve({dt(2000, 1, 1): 1.0, dt(2010, 1, 1): 0.75}, index_base=100.0)
il = IndexFixedLeg(
effective=dt(2000, 1, 1),
termination="1y",
Expand Down
2 changes: 1 addition & 1 deletion python/rateslib/curves/curves.py
Original file line number Diff line number Diff line change
Expand Up @@ -2037,7 +2037,7 @@ def __init__( # type: ignore[no-untyped-def]
) -> None:
warnings.warn(
"`IndexCurve` is deprecated: use a `Curve` instead and the same arguments.",
DeprecationWarning
DeprecationWarning,
)
super().__init__(*args, **{"interpolation": "linear_index", **kwargs})
if isinstance(self.index_base, NoInput):
Expand Down
4 changes: 1 addition & 3 deletions python/rateslib/instruments/generics.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from rateslib import defaults
from rateslib.calendars import dcf
from rateslib.curves import Curve, IndexCurve
from rateslib.curves import Curve
from rateslib.default import NoInput
from rateslib.dual import DualTypes, dual_log
from rateslib.fx import FXForwards, FXRates
Expand Down Expand Up @@ -123,8 +123,6 @@ def rate(
_ = (dual_log(curves[0][self.effective]) / -dcf_) * 100
return _
elif metric == "index_value":
if not isinstance(curves[0], IndexCurve):
raise TypeError("`curve` used with `metric`='index_value' must be type IndexCurve.")
_ = curves[0].index_value(self.effective)
return _
raise ValueError("`metric`must be in {'curve_value', 'cc_zero_rate', 'index_value'}.")
Expand Down
2 changes: 1 addition & 1 deletion python/rateslib/instruments/rates_derivatives.py
Original file line number Diff line number Diff line change
Expand Up @@ -1876,7 +1876,7 @@ def rate(
base,
self.leg1.currency,
)
if self.leg2_index_base is NoInput.blank:
if isinstance(self.leg2_index_base, NoInput):
# must forecast for the leg
forecast_value = curves[2].index_value(
self.leg2.schedule.effective,
Expand Down
16 changes: 8 additions & 8 deletions python/rateslib/legs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

from rateslib import defaults
from rateslib.calendars import add_tenor
from rateslib.curves import Curve, IndexCurve, index_left
from rateslib.curves import Curve, index_left
from rateslib.default import NoInput, _drb
from rateslib.dual import Dual, Dual2, DualTypes, gradient, set_order
from rateslib.fx import FXForwards, FXRates
Expand Down Expand Up @@ -1587,8 +1587,8 @@ def cashflows(
defaults.headers["type"]: type(self).__name__,
defaults.headers["stub_type"]: None,
defaults.headers["currency"]: self.currency.upper(),
defaults.headers["a_acc_start"]: self.schedule.effective,
defaults.headers["a_acc_end"]: self.schedule.termination,
defaults.headers["a_acc_start"]: self.schedule.aschedule[0],
defaults.headers["a_acc_end"]: self.schedule.aschedule[-1],
defaults.headers["payment"]: self.schedule.pschedule[-1],
defaults.headers["convention"]: self.convention,
defaults.headers["dcf"]: self.dcf,
Expand Down Expand Up @@ -1709,7 +1709,7 @@ class ZeroIndexLeg(BaseLeg, _IndexLegMixin):
--------
.. ipython:: python
index_curve = IndexCurve({dt(2022, 1, 1): 1.0, dt(2027, 1, 1): 0.95}, index_base=100.0)
index_curve = Curve({dt(2022, 1, 1): 1.0, dt(2027, 1, 1): 0.95}, index_base=100.0)
zil = ZeroIndexLeg(
effective=dt(2022, 1, 15),
termination="3Y",
Expand Down Expand Up @@ -1767,9 +1767,9 @@ def _set_periods(self):
),
]

def cashflow(self, curve: IndexCurve | None = None):
"""Aggregate the cashflows on the *IndexFixedPeriod* and *Cashflow* period using an
*IndexCurve*."""
def cashflow(self, curve: Curve | None = None):
"""Aggregate the cashflows on the *IndexFixedPeriod* and *Cashflow* period using a
*Curve*."""
_ = self.periods[0].cashflow(curve) + self.periods[1].cashflow
return _

Expand Down Expand Up @@ -2159,7 +2159,7 @@ class IndexFixedLeg(_IndexLegMixin, _FixedLegMixin, BaseLeg):
.. ipython:: python
curve = Curve({dt(2022, 1, 1): 1.0, dt(2023, 1, 1): 0.98})
index_curve = IndexCurve({dt(2022, 1, 1): 1.0, dt(2023, 1, 1): 0.99}, index_base=100.0)
index_curve = Curve({dt(2022, 1, 1): 1.0, dt(2023, 1, 1): 0.99}, index_base=100.0)
index_leg_exch = IndexFixedLeg(
dt(2022, 1, 1), "9M", "Q",
notional=1000000,
Expand Down
Loading

0 comments on commit d79bae6

Please sign in to comment.