Skip to content

Interest Rates

quantflow.rates.interest_rate.Rate pydantic-model

Bases: BaseModel

Class representing an interest rate with optional compounding frequency

Fields:

rate pydantic-field

rate = ZERO

Interest rate as a decimal (e.g. 0.05 for 5%)

day_counter pydantic-field

day_counter = ACTACT

Day count convention to use when calculating time to maturity

frequency pydantic-field

frequency = None

Compounding frequency, when None it is considered as continuous compounding

percent property

percent

Interest rate as a percentage

bps property

bps

Interest rate as basis points, 1 bps = 0.01% = 0.0001 in decimal

from_number classmethod

from_number(rate, *, frequency=None, day_counter=ACTACT)

Create a Rate instance from a Number

PARAMETER DESCRIPTION
rate

interest rate as a decimal (e.g. 0.05 for 5%)

TYPE: Number

frequency

Compounding frequency, when None it is considered as continuous compounding

TYPE: Period | None DEFAULT: None

day_counter

Day count convention to use

TYPE: DayCounter DEFAULT: ACTACT

Source code in quantflow/rates/interest_rate.py
@classmethod
def from_number(
    cls,
    rate: Annotated[Number, Doc("interest rate as a decimal (e.g. 0.05 for 5%)")],
    *,
    frequency: Annotated[
        Period | None,
        Doc(
            "Compounding frequency, when None it is considered as "
            "continuous compounding"
        ),
    ] = None,
    day_counter: Annotated[
        DayCounter, Doc("Day count convention to use")
    ] = DayCounter.ACTACT,
) -> Self:
    """Create a Rate instance from a Number"""
    return cls(
        rate=round(to_decimal(rate), ROUND_RATE),
        frequency=frequency,
        day_counter=day_counter,
    )

from_spot_and_forward classmethod

from_spot_and_forward(spot, forward, ref_date, maturity_date, *, frequency=None, day_counter=ACTACT)

Calculate rate from spot and forward

PARAMETER DESCRIPTION
spot

Spot price of the underlying asset

TYPE: Decimal

forward

Forward price of the underlying asset

TYPE: Decimal

ref_date

Reference date for the calculation

TYPE: datetime

maturity_date

Maturity date for the calculation

TYPE: datetime

frequency

Compounding frequency, when None it is considered as continuous compounding

TYPE: Period | None DEFAULT: None

day_counter

Day count convention to use

TYPE: DayCounter DEFAULT: ACTACT

Source code in quantflow/rates/interest_rate.py
@classmethod
def from_spot_and_forward(
    cls,
    spot: Annotated[Decimal, Doc("Spot price of the underlying asset")],
    forward: Annotated[Decimal, Doc("Forward price of the underlying asset")],
    ref_date: Annotated[datetime, Doc("Reference date for the calculation")],
    maturity_date: Annotated[datetime, Doc("Maturity date for the calculation")],
    *,
    frequency: Annotated[
        Period | None,
        Doc(
            "Compounding frequency, when None it is considered as "
            "continuous compounding"
        ),
    ] = None,
    day_counter: Annotated[
        DayCounter, Doc("Day count convention to use")
    ] = DayCounter.ACTACT,
) -> Self:
    """Calculate rate from spot and forward"""
    # use Act/365 for now
    ttm = day_counter.dcf(ref_date, maturity_date)
    if ttm <= 0:
        return cls(frequency=frequency, day_counter=day_counter)
    if frequency is None:
        return cls.from_number(
            rate=math.log(float(forward / spot)) / ttm,
            day_counter=day_counter,
            frequency=frequency,
        )
    else:
        # TODO: implement this
        raise NotImplementedError("Discrete compounding is not implemented yet")

discount_factor

discount_factor(ref_date, maturity_date)

Calculate discount factor from the rate

Source code in quantflow/rates/interest_rate.py
def discount_factor(self, ref_date: datetime, maturity_date: datetime) -> Decimal:
    """Calculate discount factor from the rate"""
    ttm = self.day_counter.dcf(ref_date, maturity_date)
    if ttm <= 0:
        return ONE
    if self.frequency is None:
        return Decimal(math.exp(-float(self.rate) * ttm))
    else:
        raise NotImplementedError("Discrete compounding is not implemented yet")