PYield 0.40.7__tar.gz → 0.41.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyield-0.40.7 → pyield-0.41.0}/PKG-INFO +1 -1
- pyield-0.41.0/pyield/__about__.py +1 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/__init__.py +3 -1
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/lft.py +24 -0
- pyield-0.41.0/pyield/tn/ntnb1.py +345 -0
- pyield-0.41.0/pyield/tn/ntnbprinc.py +80 -0
- pyield-0.40.7/pyield/__about__.py +0 -1
- {pyield-0.40.7 → pyield-0.41.0}/.gitignore +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/LICENSE +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/README.md +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/anbima/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/anbima/difusao.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/anbima/ettj_intraday.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/anbima/ettj_last.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/anbima/ima.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/anbima/imaq.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/anbima/tpf.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/di1.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/di_over.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/futures/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/futures/common.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/b3/futures/xml.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/auction.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/ptax_api.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/rates.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/repo.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bc/vna.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bday/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bday/core.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bday/holidays/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bday/holidays/br_holidays_new.txt +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bday/holidays/br_holidays_old.txt +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/bday/holidays/brholidays.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/config.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/conftest.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/converters.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/data_cache.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/fwd.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/interpolator.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/ipca/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/ipca/historical.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/ipca/projected.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/py.typed +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/retry.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/__init__.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/auctions.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/benchmark.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/ltn.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/ntnb.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/ntnc.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/ntnf.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/pre.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/tn/tools.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyield/types.py +0 -0
- {pyield-0.40.7 → pyield-0.41.0}/pyproject.toml +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.41.0"
|
|
@@ -5,7 +5,7 @@ from pyield.__about__ import __version__
|
|
|
5
5
|
from pyield.b3 import di1, futures
|
|
6
6
|
from pyield.fwd import forward, forwards
|
|
7
7
|
from pyield.interpolator import Interpolator
|
|
8
|
-
from pyield.tn import lft, ltn, ntnb, ntnc, ntnf, pre
|
|
8
|
+
from pyield.tn import lft, ltn, ntnb, ntnb1, ntnbprinc, ntnc, ntnf, pre
|
|
9
9
|
|
|
10
10
|
__all__ = [
|
|
11
11
|
"__version__",
|
|
@@ -23,6 +23,8 @@ __all__ = [
|
|
|
23
23
|
"lft",
|
|
24
24
|
"ltn",
|
|
25
25
|
"ntnb",
|
|
26
|
+
"ntnbprinc",
|
|
27
|
+
"ntnb1",
|
|
26
28
|
"ntnc",
|
|
27
29
|
"ntnf",
|
|
28
30
|
"pre",
|
|
@@ -146,3 +146,27 @@ def premium(lft_rate: float, di_rate: float) -> float:
|
|
|
146
146
|
ltt_factor = (lft_rate + 1) ** (1 / 252)
|
|
147
147
|
di_factor = (di_rate + 1) ** (1 / 252)
|
|
148
148
|
return (ltt_factor * di_factor - 1) / (di_factor - 1)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def price(
|
|
152
|
+
vna: float,
|
|
153
|
+
quotation: float,
|
|
154
|
+
) -> float:
|
|
155
|
+
"""
|
|
156
|
+
Calculate the LFT price using Brazilian Treasury rules.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
vna (float): The nominal value of the LFT bond.
|
|
160
|
+
quotation (float): The LFT quotation in base 100.
|
|
161
|
+
Returns:
|
|
162
|
+
float: The LFT price truncated to 6 decimal places.
|
|
163
|
+
|
|
164
|
+
References:
|
|
165
|
+
- SEI Proccess 17944.005214/2024-09
|
|
166
|
+
|
|
167
|
+
Examples:
|
|
168
|
+
>>> from pyield import lft
|
|
169
|
+
>>> lft.price(15785.324502, 99.9291)
|
|
170
|
+
15774.132706
|
|
171
|
+
"""
|
|
172
|
+
return tools.truncate(vna * quotation / 100, 6)
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import polars as pl
|
|
5
|
+
|
|
6
|
+
import pyield.converters as cv
|
|
7
|
+
import pyield.tn.tools as bt
|
|
8
|
+
from pyield import bday
|
|
9
|
+
from pyield.types import DateLike, has_nullable_args
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
Global parameters for NTN-B1 bonds calculations.
|
|
13
|
+
These parameters are used to define the cash flows and payment structure of the bonds,
|
|
14
|
+
according to Commercial Name.
|
|
15
|
+
The parameters are initialized based on the commercial name of the NTN-B1 bond.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
AMORTIZATION_PAYMENT = 0
|
|
19
|
+
FINAL_AMORTIZATION_PAYMENT = 0
|
|
20
|
+
NUMBER_OF_AMORTIZATIONS = 0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CommercialName(Enum):
|
|
24
|
+
"""
|
|
25
|
+
Commercial Name Enum used to identify the kind of used NTN-B1 in the scope of the
|
|
26
|
+
calculation (Renda+ or Educa+).
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
RENDA_MAIS = "Renda+"
|
|
30
|
+
EDUCA_MAIS = "Educa+"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Mapeamento estático do número de meses
|
|
34
|
+
# Isso é uma constante real (não muda durante a execução)
|
|
35
|
+
PARAMS_MAP = {
|
|
36
|
+
CommercialName.RENDA_MAIS: 240,
|
|
37
|
+
CommercialName.EDUCA_MAIS: 60,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _get_bond_parameters(commercial_name: CommercialName) -> tuple[float, float, int]:
|
|
42
|
+
"""
|
|
43
|
+
Returns amortization parameters based on commercial name.
|
|
44
|
+
Returns: (amortization_payment, final_amortization_payment, number_of_amortizations)
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
n_amortizations = PARAMS_MAP[commercial_name]
|
|
48
|
+
except KeyError:
|
|
49
|
+
raise ValueError(f"Invalid commercial name: {commercial_name}")
|
|
50
|
+
|
|
51
|
+
amortization_payment = 1 / n_amortizations
|
|
52
|
+
final_amortization_payment = 1 - (amortization_payment * (n_amortizations - 1))
|
|
53
|
+
|
|
54
|
+
return amortization_payment, final_amortization_payment, n_amortizations
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def payment_dates(
|
|
58
|
+
settlement: DateLike, maturity: DateLike, commercial_name: CommercialName
|
|
59
|
+
) -> pl.Series:
|
|
60
|
+
"""
|
|
61
|
+
Generate all remaining amortization dates between a given date and the maturity
|
|
62
|
+
date.
|
|
63
|
+
The dates are inclusive. Payments are made from January 15th of the year of
|
|
64
|
+
conversion to December 15 of maturity year.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
settlement (DateLike): The settlement date (exclusive) to start generating
|
|
68
|
+
the amortization dates.
|
|
69
|
+
maturity (DateLike): The maturity date.
|
|
70
|
+
commercial_name (CommercialName): The commercial name of the NTN-B1 bond
|
|
71
|
+
(Renda+ or Educa+).
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
pl.Series: Series of coupon dates within the specified range.
|
|
75
|
+
|
|
76
|
+
Examples:
|
|
77
|
+
>>> from pyield import ntnb1
|
|
78
|
+
>>> r_mais = ntnb1.CommercialName.RENDA_MAIS
|
|
79
|
+
>>> ntnb1.payment_dates("10-05-2024", "15-12-2050", r_mais)
|
|
80
|
+
shape: (240,)
|
|
81
|
+
Series: 'payment_dates' [date]
|
|
82
|
+
[
|
|
83
|
+
2031-01-15
|
|
84
|
+
2031-02-15
|
|
85
|
+
2031-03-15
|
|
86
|
+
2031-04-15
|
|
87
|
+
2031-05-15
|
|
88
|
+
…
|
|
89
|
+
2050-08-15
|
|
90
|
+
2050-09-15
|
|
91
|
+
2050-10-15
|
|
92
|
+
2050-11-15
|
|
93
|
+
2050-12-15
|
|
94
|
+
]
|
|
95
|
+
"""
|
|
96
|
+
if has_nullable_args(settlement, maturity, commercial_name):
|
|
97
|
+
return pl.Series("payment_dates", dtype=pl.Date)
|
|
98
|
+
|
|
99
|
+
# Validate and normalize dates
|
|
100
|
+
settlement = cv.convert_dates(settlement)
|
|
101
|
+
maturity = cv.convert_dates(maturity)
|
|
102
|
+
|
|
103
|
+
if maturity <= settlement:
|
|
104
|
+
raise ValueError("Maturity date must be after the settlement date.")
|
|
105
|
+
|
|
106
|
+
maturity = maturity.replace(day=15)
|
|
107
|
+
|
|
108
|
+
# Get bond parameters
|
|
109
|
+
_, _, n_amortizations = _get_bond_parameters(commercial_name)
|
|
110
|
+
|
|
111
|
+
amtz_dates = [maturity - pd.DateOffset(months=i) for i in range(n_amortizations)]
|
|
112
|
+
|
|
113
|
+
if len(amtz_dates) == 0:
|
|
114
|
+
raise ValueError("No amortization dates found after settlement date.")
|
|
115
|
+
|
|
116
|
+
s_pmt_dates = pl.Series(name="payment_dates", values=amtz_dates).cast(pl.Date)
|
|
117
|
+
|
|
118
|
+
return s_pmt_dates.filter(s_pmt_dates > settlement).sort()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def cash_flows(
|
|
122
|
+
settlement: DateLike, maturity: DateLike, commercial_name: CommercialName
|
|
123
|
+
) -> pl.DataFrame:
|
|
124
|
+
"""
|
|
125
|
+
Generate the cash flows for NTN-B1 bonds between the settlement and maturity dates.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
settlement (DateScalar): The settlement date (exclusive) to start generating
|
|
129
|
+
the cash flows.
|
|
130
|
+
maturity (DateScalar): The maturity date of the bond.
|
|
131
|
+
commercial_name (CommercialName): The commercial name of the NTN-B1 bond
|
|
132
|
+
(Renda+ or Educa+).
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
pd.DataFrame: DataFrame with columns "PaymentDate" and "CashFlow".
|
|
136
|
+
|
|
137
|
+
Returned columns:
|
|
138
|
+
- PaymentDate: The payment date of the cash flow
|
|
139
|
+
- CashFlow: Cash flow value for the bond
|
|
140
|
+
|
|
141
|
+
Examples:
|
|
142
|
+
>>> from pyield import ntnb1
|
|
143
|
+
>>> r_mais = ntnb1.CommercialName.RENDA_MAIS
|
|
144
|
+
>>> ntnb1.cash_flows("10-05-2024", "15-12-2060", r_mais)
|
|
145
|
+
shape: (240, 2)
|
|
146
|
+
┌─────────────┬──────────┐
|
|
147
|
+
│ PaymentDate ┆ CashFlow │
|
|
148
|
+
│ --- ┆ --- │
|
|
149
|
+
│ date ┆ f64 │
|
|
150
|
+
╞═════════════╪══════════╡
|
|
151
|
+
│ 2041-01-15 ┆ 0.004167 │
|
|
152
|
+
│ 2041-02-15 ┆ 0.004167 │
|
|
153
|
+
│ 2041-03-15 ┆ 0.004167 │
|
|
154
|
+
│ 2041-04-15 ┆ 0.004167 │
|
|
155
|
+
│ 2041-05-15 ┆ 0.004167 │
|
|
156
|
+
│ … ┆ … │
|
|
157
|
+
│ 2060-08-15 ┆ 0.004167 │
|
|
158
|
+
│ 2060-09-15 ┆ 0.004167 │
|
|
159
|
+
│ 2060-10-15 ┆ 0.004167 │
|
|
160
|
+
│ 2060-11-15 ┆ 0.004167 │
|
|
161
|
+
│ 2060-12-15 ┆ 0.004167 │
|
|
162
|
+
└─────────────┴──────────┘
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
if has_nullable_args(settlement, maturity, commercial_name):
|
|
166
|
+
return pl.DataFrame({"PaymentDate": [], "CashFlow": []})
|
|
167
|
+
|
|
168
|
+
# Validate and normalize dates
|
|
169
|
+
settlement = cv.convert_dates(settlement)
|
|
170
|
+
maturity = cv.convert_dates(maturity)
|
|
171
|
+
|
|
172
|
+
# Get the coupon dates between the settlement and maturity dates
|
|
173
|
+
p_dates = payment_dates(settlement, maturity, commercial_name)
|
|
174
|
+
df = pl.DataFrame({"PaymentDate": p_dates})
|
|
175
|
+
|
|
176
|
+
# Get bond parameters
|
|
177
|
+
amort_payment, final_amort_payment, _ = _get_bond_parameters(commercial_name)
|
|
178
|
+
|
|
179
|
+
# Set the cash flow at maturity to FINAL_PMT and the others to COUPON_PMT
|
|
180
|
+
df = df.with_columns(
|
|
181
|
+
pl.when(pl.col("PaymentDate") == maturity)
|
|
182
|
+
.then(final_amort_payment)
|
|
183
|
+
.otherwise(amort_payment)
|
|
184
|
+
.alias("CashFlow")
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Return a dataframe with the payment dates and cash flows
|
|
188
|
+
return df
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def quotation(
|
|
192
|
+
settlement: DateLike,
|
|
193
|
+
maturity: DateLike,
|
|
194
|
+
rate: float,
|
|
195
|
+
commercial_name: CommercialName,
|
|
196
|
+
) -> float:
|
|
197
|
+
"""
|
|
198
|
+
Calculate the NTN-B quotation in base 100 using Anbima rules.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
settlement (DateScalar): The settlement date of the operation.
|
|
202
|
+
maturity (DateScalar): The maturity date of the NTN-B bond.
|
|
203
|
+
rate (float): The discount rate used to calculate the present value of
|
|
204
|
+
the cash flows, which is the yield to maturity (YTM) of the NTN-B.
|
|
205
|
+
commercial_name (CommercialName): The commercial name of the NTN-B1 bond
|
|
206
|
+
(Renda+ or Educa+).
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
float: The NTN-B quotation truncated to 6 decimal places.
|
|
210
|
+
|
|
211
|
+
References:
|
|
212
|
+
- https://www.anbima.com.br/data/files/A0/02/CC/70/8FEFC8104606BDC8B82BA2A8/Metodologias%20ANBIMA%20de%20Precificacao%20Titulos%20Publicos.pdf
|
|
213
|
+
|
|
214
|
+
Examples:
|
|
215
|
+
>>> from pyield import ntnb1
|
|
216
|
+
>>> r_mais = ntnb1.CommercialName.RENDA_MAIS
|
|
217
|
+
>>> ntnb1.quotation("18-06-2025", "15-12-2084", 0.07010, r_mais)
|
|
218
|
+
0.038332
|
|
219
|
+
"""
|
|
220
|
+
cf_df = cash_flows(settlement, maturity, commercial_name)
|
|
221
|
+
cf_dates = cf_df["PaymentDate"]
|
|
222
|
+
cf_values = cf_df["CashFlow"]
|
|
223
|
+
|
|
224
|
+
# Calculate the number of business days between settlement and cash flow dates
|
|
225
|
+
b_days = bday.count(settlement, cf_dates)
|
|
226
|
+
|
|
227
|
+
# Calculate the number of periods truncated as per Anbima rules
|
|
228
|
+
num_of_years = bt.truncate(b_days / 252, 14)
|
|
229
|
+
|
|
230
|
+
discount_factor = (1 + rate) ** num_of_years
|
|
231
|
+
|
|
232
|
+
# Calculate the present value of each cash flow (DCF) rounded as per Anbima rules
|
|
233
|
+
cf_present_value = (cf_values / discount_factor).round(10)
|
|
234
|
+
|
|
235
|
+
# Return the quotation (the dcf sum) truncated as per Anbima rules
|
|
236
|
+
return bt.truncate(cf_present_value.sum(), 6)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def price(
|
|
240
|
+
vna: float,
|
|
241
|
+
quotation: float,
|
|
242
|
+
) -> float:
|
|
243
|
+
"""
|
|
244
|
+
Calculate the NTN-B1 price using Brazilian Treasury rules.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
vna (float): The nominal value of the NTN-B bond.
|
|
248
|
+
quotation (float): The NTN-B quotation in base 100.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
float: The NTN-B1 price truncated to 6 decimal places.
|
|
252
|
+
|
|
253
|
+
References:
|
|
254
|
+
- SEI Proccess 17944.005214/2024-09
|
|
255
|
+
|
|
256
|
+
Examples:
|
|
257
|
+
>>> from pyield import ntnb1
|
|
258
|
+
>>> ntnb1.price(4299.160173, 99.3651 / 100)
|
|
259
|
+
4271.864805
|
|
260
|
+
>>> ntnb1.price(4315.498383, 100.6409 / 100)
|
|
261
|
+
4343.156412
|
|
262
|
+
"""
|
|
263
|
+
if has_nullable_args(vna, quotation):
|
|
264
|
+
return float("nan")
|
|
265
|
+
return bt.truncate(vna * quotation, 6)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def duration(
|
|
269
|
+
settlement: DateLike,
|
|
270
|
+
maturity: DateLike,
|
|
271
|
+
rate: float,
|
|
272
|
+
commercial_name: CommercialName,
|
|
273
|
+
) -> float:
|
|
274
|
+
"""
|
|
275
|
+
Calculate the Macaulay duration of the NTN-B bond in business years.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
settlement (DateScalar): The settlement date of the operation.
|
|
279
|
+
maturity (DateScalar): The maturity date of the NTN-B bond.
|
|
280
|
+
rate (float): The discount rate used to calculate the duration.
|
|
281
|
+
commercial_name (CommercialName): The commercial name of the NTN-B1 bond
|
|
282
|
+
(Renda+ or Educa+).
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
float: The Macaulay duration of the NTN-B bond in business years.
|
|
286
|
+
|
|
287
|
+
Examples:
|
|
288
|
+
>>> from pyield import ntnb1
|
|
289
|
+
>>> r_mais = ntnb1.CommercialName.RENDA_MAIS
|
|
290
|
+
>>> ntnb1.duration("23-06-2025", "15-12-2084", 0.0686, r_mais)
|
|
291
|
+
47.10493458167134
|
|
292
|
+
"""
|
|
293
|
+
# Return NaN if any input is nullable
|
|
294
|
+
if has_nullable_args(settlement, maturity, rate, commercial_name):
|
|
295
|
+
return float("nan")
|
|
296
|
+
|
|
297
|
+
df = cash_flows(settlement, maturity, commercial_name)
|
|
298
|
+
s_byears = bday.count(settlement, df["PaymentDate"]) / 252
|
|
299
|
+
s_dcf = df["CashFlow"] / (1 + rate) ** s_byears
|
|
300
|
+
duration = (s_dcf * s_byears).sum() / s_dcf.sum()
|
|
301
|
+
|
|
302
|
+
# Truncate duration to 14 decimal places for result reproducibility
|
|
303
|
+
return bt.truncate(duration, 14)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def dv01(
|
|
307
|
+
settlement: DateLike,
|
|
308
|
+
maturity: DateLike,
|
|
309
|
+
rate: float,
|
|
310
|
+
vna: float,
|
|
311
|
+
commercial_name: CommercialName = CommercialName.RENDA_MAIS,
|
|
312
|
+
) -> float:
|
|
313
|
+
"""
|
|
314
|
+
Calculate the DV01 (Dollar Value of 01) for an NTN-B1 in R$.
|
|
315
|
+
|
|
316
|
+
Represents the price change in R$ for a 1 basis point (0.01%) increase in yield.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
settlement (DateScalar): The settlement date in 'DD-MM-YYYY' format
|
|
320
|
+
or a pandas Timestamp.
|
|
321
|
+
maturity (DateScalar): The maturity date in 'DD-MM-YYYY' format or
|
|
322
|
+
a pandas Timestamp.
|
|
323
|
+
rate (float): The discount rate used to calculate the present value of
|
|
324
|
+
the cash flows, which is the yield to maturity (YTM) of the NTN-B.
|
|
325
|
+
vna (float): The nominal value of the NTN-B bond.
|
|
326
|
+
commercial_name (CommercialName): The commercial name of the NTN-B1 bond
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
float: The DV01 value, representing the price change for a 1 basis point
|
|
330
|
+
increase in yield.
|
|
331
|
+
|
|
332
|
+
Examples:
|
|
333
|
+
>>> from pyield import ntnb1
|
|
334
|
+
>>> r_mais = ntnb1.CommercialName.RENDA_MAIS
|
|
335
|
+
>>> ntnb1.dv01("23-06-2025", "15-12-2084", 0.0686, 4299.160173, r_mais)
|
|
336
|
+
0.7738490000000127
|
|
337
|
+
"""
|
|
338
|
+
if has_nullable_args(settlement, maturity, rate, vna, commercial_name):
|
|
339
|
+
return float("nan")
|
|
340
|
+
|
|
341
|
+
quotation1 = quotation(settlement, maturity, rate, commercial_name)
|
|
342
|
+
quotation2 = quotation(settlement, maturity, rate + 0.0001, commercial_name)
|
|
343
|
+
price1 = price(vna, quotation1)
|
|
344
|
+
price2 = price(vna, quotation2)
|
|
345
|
+
return price1 - price2
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from pyield import bday
|
|
2
|
+
from pyield.tn import tools
|
|
3
|
+
from pyield.types import DateLike, has_nullable_args
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def price(
|
|
7
|
+
settlement: DateLike,
|
|
8
|
+
maturity: DateLike,
|
|
9
|
+
rate: float,
|
|
10
|
+
face_value: float,
|
|
11
|
+
) -> float:
|
|
12
|
+
"""
|
|
13
|
+
Calculate the NTN-B PRINCIPAL price using Anbima rules.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
settlement (DateScalar): The settlement date in 'DD-MM-YYYY' format
|
|
17
|
+
or a pandas Timestamp.
|
|
18
|
+
maturity (DateScalar): The maturity date in 'DD-MM-YYYY' format or
|
|
19
|
+
a pandas Timestamp.
|
|
20
|
+
rate (float): The discount rate used to calculate the present value of
|
|
21
|
+
the cash flows, which is the yield to maturity (YTM) of the NTN-F.
|
|
22
|
+
face_value (float): The face value of the bond (VNA).
|
|
23
|
+
Returns:
|
|
24
|
+
float: The NTN-B PRINCIPAL price using Anbima rules.
|
|
25
|
+
|
|
26
|
+
References:
|
|
27
|
+
- https://www.anbima.com.br/data/files/A0/02/CC/70/8FEFC8104606BDC8B82BA2A8/Metodologias%20ANBIMA%20de%20Precificacao%20Titulos%20Publicos.pdf
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
>>> from pyield import ntnbprinc
|
|
31
|
+
>>> ntnbprinc.price("02-12-2025", "15-05-2029", 0.0777, 4567.033825)
|
|
32
|
+
3537.763157
|
|
33
|
+
"""
|
|
34
|
+
if has_nullable_args(settlement, maturity, rate, face_value):
|
|
35
|
+
return float("nan")
|
|
36
|
+
|
|
37
|
+
# Calculate the number of business days between settlement and cash flow dates
|
|
38
|
+
bdays = bday.count(settlement, maturity)
|
|
39
|
+
|
|
40
|
+
# Calculate the number of periods truncated as per Anbima rule
|
|
41
|
+
num_of_years = tools.truncate(bdays / 252, 14)
|
|
42
|
+
|
|
43
|
+
discount_factor = (1 + rate) ** num_of_years
|
|
44
|
+
|
|
45
|
+
# Truncate the price to 6 decimal places as per Anbima rules
|
|
46
|
+
return tools.truncate(face_value / discount_factor, 6)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def dv01(
|
|
50
|
+
settlement: DateLike,
|
|
51
|
+
maturity: DateLike,
|
|
52
|
+
rate: float,
|
|
53
|
+
face_value: float,
|
|
54
|
+
) -> float:
|
|
55
|
+
"""
|
|
56
|
+
Calculate the DV01 (Dollar Value of 01) for an LTN in R$.
|
|
57
|
+
|
|
58
|
+
Represents the price change in R$ for a 1 basis point (0.01%) increase in yield.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
settlement (DateScalar): The settlement date in 'DD-MM-YYYY' format
|
|
62
|
+
or a pandas Timestamp.
|
|
63
|
+
maturity (DateScalar): The maturity date in 'DD-MM-YYYY' format or
|
|
64
|
+
a pandas Timestamp.
|
|
65
|
+
rate (float): The discount rate used to calculate the present value of
|
|
66
|
+
the cash flows, which is the yield to maturity (YTM) of the LTN.
|
|
67
|
+
face_value (float): The face value of the bond (VNA).
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
float: The DV01 value, representing the price change for a 1 basis point
|
|
71
|
+
increase in yield.
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
>>> from pyield import ntnbprinc as bp
|
|
75
|
+
>>> bp.dv01("02-12-2025", "15-05-2029", 0.0777, 4567.033825)
|
|
76
|
+
1.1200559999997495
|
|
77
|
+
"""
|
|
78
|
+
price1 = price(settlement, maturity, rate, face_value)
|
|
79
|
+
price2 = price(settlement, maturity, rate + 0.0001, face_value)
|
|
80
|
+
return price1 - price2
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.40.7"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|