Coverage for rivapy / pricing / fra_pricing.py: 88%
56 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
1from datetime import datetime, date
2from scipy.optimize import brentq
3from rivapy.tools.interfaces import BaseDatedCurve
4from rivapy.instruments.bond_specifications import DeterministicCashflowBondSpecification
5from rivapy.marketdata import DiscountCurveParametrized, ConstantRate, DiscountCurve
6from rivapy.pricing.bond_pricing import DeterministicCashflowPricer
7from rivapy.pricing.pricing_request import PricingRequest
8from rivapy.pricing._logger import logger
9from rivapy.instruments.deposit_specifications import DepositSpecification
10from rivapy.instruments.fra_specifications import ForwardRateAgreementSpecification
11from typing import List as _List, Union as _Union, Tuple
12from rivapy.tools.datetools import DayCounter, roll_day
15class ForwardRateAgreementPricer:
17 def __init__(
18 self,
19 val_date: _Union[date, datetime],
20 fra_spec: ForwardRateAgreementSpecification,
21 discount_curve: DiscountCurve,
22 forward_curve: DiscountCurve = None,
23 ):
24 """Initializes the FRA pricer with valuation date, FRA specification, discount curve and forward curve.
26 Args:
27 val_date (_Union[date, datetime]): specific date for which the value of the financial instrument is calculated.
28 fra_spec (ForwardRateAgreementSpecification): Specification object with FRA specific parameters.
29 discount_curve (DiscountCurve): Discount curve used for discounting.
30 forward_curve(): from underlying index...
32 """
34 self._val_date = val_date
35 self._fra_spec = fra_spec
36 self._discount_curve = discount_curve
38 if forward_curve == None:
39 # generate forward curve from given discount curve?
40 self._forward_curve = discount_curve # TODO implement functionality
41 else:
42 self._forward_curve = forward_curve
44 @staticmethod
45 def get_expected_cashflows(
46 specification: ForwardRateAgreementSpecification,
47 val_date: _Union[datetime.date, datetime],
48 fwdcurve: DiscountCurve,
49 ) -> _List[Tuple[datetime, float]]:
50 """Calculate expected cashflows for the FRA specification based on the valuation date and discount curve.
52 Args:
53 specification (ForwardRateAgreementSpecification): The FRA specification.
54 val_date (_Union[datetime.date, datetime]): The data as of which the cashflows are calculated.
55 fwdcurve (_Union[DiscountCurve, None]): The forward curve.
57 Returns:
58 List[Tuple[datetime, float]]: List of tuples containing payment dates and amounts.
59 """
61 cashflows = []
62 # using curve daycount convention to get fwd-rate data
63 dcc_rate = DayCounter(fwdcurve.daycounter)
64 fwdrateDF = fwdcurve.value_fwd(val_date, specification._rate_start_date, specification._rate_end_date)
65 dt_rate = dcc_rate.yf(specification._rate_start_date, specification._rate_end_date)
66 fwdrate = (1.0 / fwdrateDF - 1) / dt_rate
67 print(f"Day count fraction (yf): {dt_rate}, Forward rate: {fwdrate}")
69 # using instrument daycount convention to calculate delta t for cf amount calculation and discouting
70 dcc = DayCounter(specification.day_count_convention)
71 dt = dcc.yf(specification._start_date, specification._end_date)
72 amount = specification._notional * (fwdrate - specification._rate) * dt
73 print(f"dt: {dt}, Specification_Rate: {specification._rate}, Amount: {amount}")
74 cf = amount / (1 + fwdrate * dt)
75 print(f"Cashflow: {cf}")
77 payment_date = roll_day(
78 specification._start_date, specification._calendar, specification._business_day_convention, settle_days=specification._payment_days
79 )
80 cashflows.append((payment_date, cf))
82 return cashflows
84 def expected_cashflows(self):
85 """Calculate expected cashflows for the FRA specification.
87 Returns:
88 List[Tuple[datetime, float]]: List of tuples containing payment dates and amounts.
89 """
90 return ForwardRateAgreementPricer.get_expected_cashflows(self._fra_spec, self._val_date, self._forward_curve)
92 @staticmethod
93 def get_price(
94 val_date: _Union[datetime.date, datetime],
95 specification: ForwardRateAgreementSpecification,
96 discount_curve: DiscountCurve,
97 forward_curve: _Union[DiscountCurve, None] = None,
98 ) -> float:
99 """Calculate the present value of the specified FRA given a discount curve and forward curve
101 Args:
102 val_date (_Union[datetime.date, datetime]): The valuation date.
103 specification (ForwardRateAgreementSpecification): The FRA specification.
104 discount_curve (DiscountCurve): The discount curve.
105 forward_curve (_Union[DiscountCurve, None]): The forward curve.
107 Returns:
108 float: The present value of the FRA.
109 """
110 expected_cashflows = ForwardRateAgreementPricer.get_expected_cashflows(specification, val_date, forward_curve)
111 price = discount_curve.value(val_date, expected_cashflows[0][0]) * expected_cashflows[0][1]
112 # DeterministicCashflowPricer.get_pv_cashflows(val_date, specification, discount_curve, expected_cashflows)
113 return price
115 def price(self):
116 """Calculate the present value of the specified FRA given a discount curve and forward curve
118 Returns:
119 float: present value of a deposit based on simple compounding
120 """
121 price = ForwardRateAgreementPricer.get_price(self._val_date, self._fra_spec, self._discount_curve, self._forward_curve)
123 return price
125 @staticmethod
126 def compute_fair_rate(
127 val_date: _Union[datetime, date],
128 specification: ForwardRateAgreementSpecification,
129 discount_curve: DiscountCurve,
130 ):
131 """Computes the fair rate such that the when used in the specification of the FRA gives a net value of zero.
132 A discount curve is given, from which the Forward Rate is determined between the two dates.
133 Assuming simple compounding
134 Forward rate = (DF_1/DF_2 -1 )/ time_interval
135 = (1 /FWD_DF -1 )/ time_interval
137 Args:
138 val_date (_Union[datetime, date]): specific date as of which the value of the financial instrument is calculated.
139 forward_curve (DiscountCurve): Forward curve used for projecting rates
140 rate_start_date (_Union[datetime, date]): start date for the forward period
141 rate_end_date (_Union[datetime, date]): end date for the forward period
143 Returns:
144 float: _description_
145 """
147 rate_start_date = specification._rate_start_date
148 rate_end_date = specification._rate_end_date
150 dcc = DayCounter(discount_curve.daycounter)
151 yf = dcc.yf(rate_start_date, rate_end_date)
152 fwd_df = discount_curve.value_fwd(val_date, rate_start_date, rate_end_date) # REF DATE is =
154 fair_rate = (1.0 / fwd_df - 1) / yf
156 return fair_rate