PYield 0.46.1__tar.gz → 0.46.2__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.46.1 → pyield-0.46.2}/PKG-INFO +12 -1
- {pyield-0.46.1 → pyield-0.46.2}/README.md +11 -0
- pyield-0.46.2/pyield/__about__.py +1 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/_validar_pregao.py +4 -12
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/ptax_api.py +26 -24
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/trades_monthly.py +3 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/fwd.py +1 -1
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/lft.py +34 -36
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/ltn.py +94 -94
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/ntnb.py +209 -205
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/ntnb1.py +30 -30
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/ntnc.py +71 -67
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/ntnf.py +188 -181
- pyield-0.46.2/pyield/tn/pre.py +203 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/utils.py +52 -13
- pyield-0.46.1/pyield/__about__.py +0 -1
- pyield-0.46.1/pyield/tn/pre.py +0 -198
- {pyield-0.46.1 → pyield-0.46.2}/.gitignore +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/LICENSE +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/_internal/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/_internal/br_numbers.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/_internal/cache.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/_internal/converters.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/_internal/data_cache.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/_internal/retry.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/_internal/types.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/anbima/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/anbima/difusao.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/anbima/ettj_intraday.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/anbima/ettj_last.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/anbima/ima.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/anbima/imaq.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/anbima/tpf.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/_contracts.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/di1.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/di_over.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/futures/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/futures/common.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/intraday_derivatives.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/b3/price_report.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/auction.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/copom.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/rates.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/repo.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bc/vna.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bday/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bday/core.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bday/holidays/br_holidays_new.txt +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bday/holidays/br_holidays_old.txt +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/bday/holidays/brholidays.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/clock.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/interpolator.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/ipca/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/ipca/historical.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/ipca/projected.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/py.typed +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/rmd.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/selic/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/selic/cpm.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/selic/probabilities.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/__init__.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/auctions.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/benchmark.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyield/tn/ntnbprinc.py +0 -0
- {pyield-0.46.1 → pyield-0.46.2}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyield
|
|
3
|
-
Version: 0.46.
|
|
3
|
+
Version: 0.46.2
|
|
4
4
|
Summary: A Python library for analysis of fixed income instruments in Brazil
|
|
5
5
|
Project-URL: Homepage, https://github.com/crdcj/PYield
|
|
6
6
|
Project-URL: Documentation, https://crdcj.github.io/PYield
|
|
@@ -247,6 +247,17 @@ ntnb.quotation(None, "15-05-2035", 0.06149) # -> nan
|
|
|
247
247
|
bday.count(["01-01-2024", None], "01-02-2024") # -> Series: [22, null]
|
|
248
248
|
```
|
|
249
249
|
|
|
250
|
+
Consultas sem dados disponíveis (data futura, feriado, fim de semana ou
|
|
251
|
+
fonte indisponível) retornam DataFrame vazio ou `nan`, sem lançar exceção:
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from pyield import bc, futures
|
|
255
|
+
|
|
256
|
+
futures("01-01-2030", "DI1").is_empty() # -> True (data futura)
|
|
257
|
+
bc.tpf_monthly_trades("01-01-2030").is_empty() # -> True (mês futuro)
|
|
258
|
+
bc.ptax("25-12-2025") # -> nan (feriado)
|
|
259
|
+
```
|
|
260
|
+
|
|
250
261
|
## Migração para Polars (v0.40.0+)
|
|
251
262
|
|
|
252
263
|
A partir da versão 0.40.0, todas as saídas tabulares passaram de Pandas para **Polars**. Entradas vetoriais que antes aceitavam `pd.Series` e `np.ndarray` agora aceitam apenas listas, tuplas ou `pl.Series`. Para converter:
|
|
@@ -203,6 +203,17 @@ ntnb.quotation(None, "15-05-2035", 0.06149) # -> nan
|
|
|
203
203
|
bday.count(["01-01-2024", None], "01-02-2024") # -> Series: [22, null]
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
+
Consultas sem dados disponíveis (data futura, feriado, fim de semana ou
|
|
207
|
+
fonte indisponível) retornam DataFrame vazio ou `nan`, sem lançar exceção:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from pyield import bc, futures
|
|
211
|
+
|
|
212
|
+
futures("01-01-2030", "DI1").is_empty() # -> True (data futura)
|
|
213
|
+
bc.tpf_monthly_trades("01-01-2030").is_empty() # -> True (mês futuro)
|
|
214
|
+
bc.ptax("25-12-2025") # -> nan (feriado)
|
|
215
|
+
```
|
|
216
|
+
|
|
206
217
|
## Migração para Polars (v0.40.0+)
|
|
207
218
|
|
|
208
219
|
A partir da versão 0.40.0, todas as saídas tabulares passaram de Pandas para **Polars**. Entradas vetoriais que antes aceitavam `pd.Series` e `np.ndarray` agora aceitam apenas listas, tuplas ou `pl.Series`. Para converter:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.46.2"
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import datetime as dt
|
|
2
|
-
import logging
|
|
3
2
|
|
|
4
3
|
from pyield import bday, clock
|
|
5
4
|
|
|
6
|
-
registro = logging.getLogger(__name__)
|
|
7
|
-
|
|
8
5
|
|
|
9
6
|
def data_negociacao_valida(data_negociacao: dt.date) -> bool:
|
|
10
7
|
"""Valida se a data de referência é utilizável para consulta.
|
|
@@ -13,24 +10,19 @@ def data_negociacao_valida(data_negociacao: dt.date) -> bool:
|
|
|
13
10
|
- Deve ser um dia útil brasileiro.
|
|
14
11
|
- Não pode estar no futuro (maior que a data corrente no Brasil).
|
|
15
12
|
|
|
16
|
-
Retorna True se válida, False caso contrário
|
|
13
|
+
Retorna True se válida, False caso contrário.
|
|
17
14
|
"""
|
|
18
15
|
if data_negociacao > clock.today():
|
|
19
|
-
registro.warning(f"A data informada {data_negociacao} está no futuro.")
|
|
20
16
|
return False
|
|
21
17
|
if not bday.is_business_day(data_negociacao):
|
|
22
|
-
registro.warning(f"A data informada {data_negociacao} não é dia útil.")
|
|
23
18
|
return False
|
|
24
19
|
|
|
25
20
|
# Não tem pregão na véspera de Natal e Ano Novo
|
|
26
|
-
datas_fechadas_especiais = {
|
|
27
|
-
dt.date(data_negociacao.year, 12, 24),
|
|
28
|
-
dt.date(data_negociacao.year, 12, 31),
|
|
21
|
+
datas_fechadas_especiais = {
|
|
22
|
+
dt.date(data_negociacao.year, 12, 24),
|
|
23
|
+
dt.date(data_negociacao.year, 12, 31),
|
|
29
24
|
}
|
|
30
25
|
if data_negociacao in datas_fechadas_especiais:
|
|
31
|
-
registro.warning(
|
|
32
|
-
f"Não há pregão na véspera de Natal e de Ano Novo: {data_negociacao}"
|
|
33
|
-
)
|
|
34
26
|
return False
|
|
35
27
|
|
|
36
28
|
return True
|
|
@@ -69,13 +69,15 @@ def _processar_df(df: pl.DataFrame) -> pl.DataFrame:
|
|
|
69
69
|
)
|
|
70
70
|
.with_columns(
|
|
71
71
|
data=pl.col("data_hora").cast(pl.Date),
|
|
72
|
+
hora=pl.col("data_hora").dt.time(),
|
|
72
73
|
cotacao_media=pl.mean_horizontal("cotacao_compra", "cotacao_venda").round(
|
|
73
74
|
5
|
|
74
75
|
),
|
|
75
76
|
)
|
|
76
|
-
.unique(subset=["data"], keep="last")
|
|
77
|
-
.select("data", "data_hora", "cotacao_compra", "cotacao_venda", "cotacao_media")
|
|
78
77
|
.sort("data_hora")
|
|
78
|
+
.unique(subset=["data"], keep="last")
|
|
79
|
+
.select("data", "hora", "cotacao_compra", "cotacao_venda", "cotacao_media")
|
|
80
|
+
.sort("data")
|
|
79
81
|
)
|
|
80
82
|
|
|
81
83
|
|
|
@@ -100,7 +102,7 @@ def ptax_series(
|
|
|
100
102
|
|
|
101
103
|
Output Columns:
|
|
102
104
|
* data (Date): data da cotação.
|
|
103
|
-
*
|
|
105
|
+
* hora (Time): hora da cotação.
|
|
104
106
|
* cotacao_compra (Float64): taxa de compra em R$.
|
|
105
107
|
* cotacao_venda (Float64): taxa de venda em R$.
|
|
106
108
|
* cotacao_media (Float64): média de compra/venda (5 casas).
|
|
@@ -122,30 +124,30 @@ def ptax_series(
|
|
|
122
124
|
>>> from pyield import bc
|
|
123
125
|
>>> bc.ptax_series(start="20-04-2025", end="25-04-2025")
|
|
124
126
|
shape: (4, 5)
|
|
125
|
-
|
|
126
|
-
│ data ┆
|
|
127
|
-
│ --- ┆ ---
|
|
128
|
-
│ date ┆
|
|
129
|
-
|
|
130
|
-
│ 2025-04-22 ┆
|
|
131
|
-
│ 2025-04-23 ┆
|
|
132
|
-
│ 2025-04-24 ┆
|
|
133
|
-
│ 2025-04-25 ┆
|
|
134
|
-
|
|
127
|
+
┌────────────┬──────────────┬────────────────┬───────────────┬───────────────┐
|
|
128
|
+
│ data ┆ hora ┆ cotacao_compra ┆ cotacao_venda ┆ cotacao_media │
|
|
129
|
+
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
|
|
130
|
+
│ date ┆ time ┆ f64 ┆ f64 ┆ f64 │
|
|
131
|
+
╞════════════╪══════════════╪════════════════╪═══════════════╪═══════════════╡
|
|
132
|
+
│ 2025-04-22 ┆ 13:09:35.629 ┆ 5.749 ┆ 5.7496 ┆ 5.7493 │
|
|
133
|
+
│ 2025-04-23 ┆ 13:06:30.443 ┆ 5.6874 ┆ 5.688 ┆ 5.6877 │
|
|
134
|
+
│ 2025-04-24 ┆ 13:04:29.639 ┆ 5.6732 ┆ 5.6738 ┆ 5.6735 │
|
|
135
|
+
│ 2025-04-25 ┆ 13:09:26.592 ┆ 5.684 ┆ 5.6846 ┆ 5.6843 │
|
|
136
|
+
└────────────┴──────────────┴────────────────┴───────────────┴───────────────┘
|
|
135
137
|
|
|
136
138
|
>>> bc.ptax_series(start="02-01-1995", end="06-01-1995")
|
|
137
139
|
shape: (5, 5)
|
|
138
|
-
|
|
139
|
-
│ data ┆
|
|
140
|
-
│ --- ┆ ---
|
|
141
|
-
│ date ┆
|
|
142
|
-
|
|
143
|
-
│ 1995-01-02 ┆
|
|
144
|
-
│ 1995-01-03 ┆
|
|
145
|
-
│ 1995-01-04 ┆
|
|
146
|
-
│ 1995-01-05 ┆
|
|
147
|
-
│ 1995-01-06 ┆
|
|
148
|
-
|
|
140
|
+
┌────────────┬──────────┬────────────────┬───────────────┬───────────────┐
|
|
141
|
+
│ data ┆ hora ┆ cotacao_compra ┆ cotacao_venda ┆ cotacao_media │
|
|
142
|
+
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
|
|
143
|
+
│ date ┆ time ┆ f64 ┆ f64 ┆ f64 │
|
|
144
|
+
╞════════════╪══════════╪════════════════╪═══════════════╪═══════════════╡
|
|
145
|
+
│ 1995-01-02 ┆ 18:20:00 ┆ 0.843 ┆ 0.845 ┆ 0.844 │
|
|
146
|
+
│ 1995-01-03 ┆ 18:25:00 ┆ 0.844 ┆ 0.846 ┆ 0.845 │
|
|
147
|
+
│ 1995-01-04 ┆ 18:12:00 ┆ 0.844 ┆ 0.846 ┆ 0.845 │
|
|
148
|
+
│ 1995-01-05 ┆ 18:07:00 ┆ 0.842 ┆ 0.844 ┆ 0.843 │
|
|
149
|
+
│ 1995-01-06 ┆ 18:12:00 ┆ 0.839 ┆ 0.841 ┆ 0.84 │
|
|
150
|
+
└────────────┴──────────┴────────────────┴───────────────┴───────────────┘
|
|
149
151
|
"""
|
|
150
152
|
if start:
|
|
151
153
|
start = cv.converter_datas(start)
|
|
@@ -23,6 +23,7 @@ from pyield._internal.cache import ttl_cache
|
|
|
23
23
|
from pyield._internal.converters import converter_datas
|
|
24
24
|
from pyield._internal.retry import retry_padrao
|
|
25
25
|
from pyield._internal.types import DateLike, any_is_empty
|
|
26
|
+
from pyield.clock import today
|
|
26
27
|
|
|
27
28
|
URL_BASE = "https://www4.bcb.gov.br/pom/demab/negociacoes/download"
|
|
28
29
|
|
|
@@ -148,6 +149,8 @@ def tpf_monthly_trades(target_date: DateLike, extragroup: bool = False) -> pl.Da
|
|
|
148
149
|
if any_is_empty(target_date):
|
|
149
150
|
return pl.DataFrame()
|
|
150
151
|
data_alvo = converter_datas(target_date)
|
|
152
|
+
if (data_alvo.year, data_alvo.month) > (today().year, today().month):
|
|
153
|
+
return pl.DataFrame()
|
|
151
154
|
url = _montar_url(data_alvo, extragroup)
|
|
152
155
|
conteudo_zip = _baixar_zip(url)
|
|
153
156
|
arquivo_extraido = _descompactar_zip(conteudo_zip)
|
|
@@ -103,7 +103,7 @@ def forwards(
|
|
|
103
103
|
>>> # Exemplo com taxas indicativas de NTN-B em 16-09-2025
|
|
104
104
|
>>> from pyield import ntnb
|
|
105
105
|
>>> df = ntnb.data("16-09-2025")
|
|
106
|
-
>>> yd.forwards(df["
|
|
106
|
+
>>> yd.forwards(df["dias_uteis"], df["taxa_indicativa"])
|
|
107
107
|
shape: (13,)
|
|
108
108
|
Series: 'fwd' [f64]
|
|
109
109
|
[
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import polars as pl
|
|
2
2
|
|
|
3
3
|
import pyield._internal.converters as cv
|
|
4
|
-
from pyield import
|
|
4
|
+
from pyield import bday
|
|
5
5
|
from pyield._internal.types import DateLike, any_is_empty
|
|
6
6
|
from pyield.tn import utils
|
|
7
7
|
|
|
@@ -17,62 +17,60 @@ def data(date: DateLike) -> pl.DataFrame:
|
|
|
17
17
|
pl.DataFrame: DataFrame Polars com os dados de LFT.
|
|
18
18
|
|
|
19
19
|
Output Columns:
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
20
|
+
- data_referencia (Date): Data de referência dos dados.
|
|
21
|
+
- titulo (String): Tipo do título (ex.: "LFT").
|
|
22
|
+
- codigo_selic (Int64): Código do título no SELIC.
|
|
23
|
+
- data_base (Date): Data base/emissão do título.
|
|
24
|
+
- data_vencimento (Date): Data de vencimento do título.
|
|
25
|
+
- dias_uteis (Int64): Dias úteis entre referência e vencimento.
|
|
26
|
+
- prazo_medio (Float64): Prazo médio do título em anos.
|
|
27
|
+
- pu (Float64): Preço unitário (PU).
|
|
28
|
+
- taxa_compra (Float64): Taxa de compra (decimal).
|
|
29
|
+
- taxa_venda (Float64): Taxa de venda (decimal).
|
|
30
|
+
- taxa_indicativa (Float64): Taxa indicativa (decimal).
|
|
31
|
+
- taxa_di (Float64): Taxa DI interpolada pelo método flat forward.
|
|
32
|
+
- rentabilidade (Float64): Rentabilidade da LFT sobre o DI.
|
|
33
33
|
|
|
34
34
|
Examples:
|
|
35
35
|
>>> from pyield import lft
|
|
36
36
|
>>> df_lft = lft.data("23-08-2024") # doctest: +SKIP
|
|
37
37
|
"""
|
|
38
|
-
df =
|
|
38
|
+
df = utils.obter_tpf(date, "LFT")
|
|
39
39
|
if df.is_empty():
|
|
40
40
|
return df
|
|
41
41
|
|
|
42
42
|
data_ref = cv.converter_datas(date)
|
|
43
43
|
|
|
44
|
-
# Adiciona BDToMat (dado derivado, não vem da ANBIMA)
|
|
45
44
|
df = df.with_columns(
|
|
46
|
-
|
|
45
|
+
dias_uteis=bday.count_expr("data_referencia", "data_vencimento"),
|
|
47
46
|
)
|
|
48
47
|
|
|
49
|
-
# Adiciona AvgMaturity e DIRate
|
|
50
48
|
df = df.with_columns(
|
|
51
|
-
|
|
49
|
+
prazo_medio=pl.col("dias_uteis") / 252,
|
|
52
50
|
)
|
|
53
51
|
df = utils.adicionar_taxa_di(df, data_ref)
|
|
54
52
|
|
|
55
53
|
df = df.with_columns(
|
|
56
|
-
|
|
57
|
-
lambda s: premium(s["
|
|
54
|
+
rentabilidade=pl.struct("taxa_indicativa", "taxa_di").map_elements(
|
|
55
|
+
lambda s: premium(s["taxa_indicativa"], s["taxa_di"]),
|
|
58
56
|
return_dtype=pl.Float64,
|
|
59
57
|
)
|
|
60
58
|
)
|
|
61
59
|
|
|
62
60
|
return df.select(
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
61
|
+
"data_referencia",
|
|
62
|
+
"titulo",
|
|
63
|
+
"codigo_selic",
|
|
64
|
+
"data_base",
|
|
65
|
+
"data_vencimento",
|
|
66
|
+
"dias_uteis",
|
|
67
|
+
"prazo_medio",
|
|
68
|
+
"pu",
|
|
69
|
+
"taxa_compra",
|
|
70
|
+
"taxa_venda",
|
|
71
|
+
"taxa_indicativa",
|
|
72
|
+
"taxa_di",
|
|
73
|
+
"rentabilidade",
|
|
76
74
|
)
|
|
77
75
|
|
|
78
76
|
|
|
@@ -90,7 +88,7 @@ def maturities(date: DateLike) -> pl.Series:
|
|
|
90
88
|
>>> from pyield import lft
|
|
91
89
|
>>> lft.maturities("22-08-2024")
|
|
92
90
|
shape: (14,)
|
|
93
|
-
Series: '
|
|
91
|
+
Series: 'data_vencimento' [date]
|
|
94
92
|
[
|
|
95
93
|
2024-09-01
|
|
96
94
|
2025-03-01
|
|
@@ -105,7 +103,7 @@ def maturities(date: DateLike) -> pl.Series:
|
|
|
105
103
|
2030-09-01
|
|
106
104
|
]
|
|
107
105
|
"""
|
|
108
|
-
return data(date)["
|
|
106
|
+
return data(date)["data_vencimento"]
|
|
109
107
|
|
|
110
108
|
|
|
111
109
|
def quotation(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import polars as pl
|
|
2
2
|
|
|
3
3
|
import pyield._internal.converters as cv
|
|
4
|
-
from pyield import
|
|
4
|
+
from pyield import bday, fwd
|
|
5
5
|
from pyield._internal.types import DateLike, any_is_empty
|
|
6
6
|
from pyield.tn import utils
|
|
7
7
|
from pyield.tn.pre import di_spreads as pre_di_spreads
|
|
@@ -20,72 +20,71 @@ def data(date: DateLike) -> pl.DataFrame:
|
|
|
20
20
|
pl.DataFrame: DataFrame Polars com os dados de LTN.
|
|
21
21
|
|
|
22
22
|
Output Columns:
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
|
|
23
|
+
- data_referencia (Date): Data de referência dos dados.
|
|
24
|
+
- titulo (String): Tipo do título (ex.: "LTN").
|
|
25
|
+
- codigo_selic (Int64): Código do título no SELIC.
|
|
26
|
+
- data_base (Date): Data base/emissão do título.
|
|
27
|
+
- data_vencimento (Date): Data de vencimento do título.
|
|
28
|
+
- dias_uteis (Int64): Dias úteis entre referência e vencimento.
|
|
29
|
+
- duration (Float64): Macaulay Duration do título (anos).
|
|
30
|
+
- prazo_medio (Float64): Prazo médio do título (anos).
|
|
31
|
+
- dv01 (Float64): Variação no preço para 1bp de taxa.
|
|
32
|
+
- dv01_usd (Float64): DV01 convertido para USD pela PTAX do dia.
|
|
33
|
+
- pu (Float64): Preço unitário (PU).
|
|
34
|
+
- taxa_compra (Float64): Taxa de compra (decimal).
|
|
35
|
+
- taxa_venda (Float64): Taxa de venda (decimal).
|
|
36
|
+
- taxa_indicativa (Float64): Taxa indicativa (decimal).
|
|
37
|
+
- taxa_di (Float64): Taxa DI interpolada pelo método flat forward.
|
|
38
|
+
- spread_di (Float64): Spread sobre o DI (também conhecido como
|
|
39
|
+
prêmio).
|
|
40
|
+
- rentabilidade (Float64): Rentabilidade diária da LTN sobre o DI.
|
|
40
41
|
|
|
41
42
|
Examples:
|
|
42
43
|
>>> from pyield import ltn
|
|
43
44
|
>>> df_ltn = ltn.data("23-08-2024") # doctest: +SKIP
|
|
44
45
|
"""
|
|
45
|
-
df =
|
|
46
|
+
df = utils.obter_tpf(date, "LTN")
|
|
46
47
|
if df.is_empty():
|
|
47
48
|
return df
|
|
48
49
|
|
|
49
50
|
data_ref = cv.converter_datas(date)
|
|
50
51
|
|
|
51
|
-
# Adiciona BDToMat (dado derivado, não vem da ANBIMA)
|
|
52
52
|
df = df.with_columns(
|
|
53
|
-
|
|
53
|
+
dias_uteis=bday.count_expr("data_referencia", "data_vencimento"),
|
|
54
54
|
)
|
|
55
55
|
|
|
56
|
-
# Adiciona Duration, AvgMaturity, DV01, DV01USD e DIRate
|
|
57
56
|
df = df.with_columns(
|
|
58
|
-
|
|
59
|
-
).with_columns(
|
|
57
|
+
duration=pl.col("dias_uteis") / 252,
|
|
58
|
+
).with_columns(prazo_medio=pl.col("duration"))
|
|
60
59
|
df = utils.adicionar_dv01(df, data_ref)
|
|
61
60
|
df = utils.adicionar_taxa_di(df, data_ref)
|
|
62
61
|
|
|
63
62
|
df = df.with_columns(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
lambda s: premium(s["
|
|
63
|
+
spread_di=pl.col("taxa_indicativa") - pl.col("taxa_di"),
|
|
64
|
+
rentabilidade=pl.struct("taxa_indicativa", "taxa_di").map_elements(
|
|
65
|
+
lambda s: premium(s["taxa_indicativa"], s["taxa_di"]),
|
|
67
66
|
return_dtype=pl.Float64,
|
|
68
67
|
),
|
|
69
68
|
)
|
|
70
69
|
|
|
71
70
|
return df.select(
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
71
|
+
"data_referencia",
|
|
72
|
+
"titulo",
|
|
73
|
+
"codigo_selic",
|
|
74
|
+
"data_base",
|
|
75
|
+
"data_vencimento",
|
|
76
|
+
"dias_uteis",
|
|
77
|
+
"duration",
|
|
78
|
+
"prazo_medio",
|
|
79
|
+
"dv01",
|
|
80
|
+
"dv01_usd",
|
|
81
|
+
"pu",
|
|
82
|
+
"taxa_compra",
|
|
83
|
+
"taxa_venda",
|
|
84
|
+
"taxa_indicativa",
|
|
85
|
+
"taxa_di",
|
|
86
|
+
"spread_di",
|
|
87
|
+
"rentabilidade",
|
|
89
88
|
)
|
|
90
89
|
|
|
91
90
|
|
|
@@ -103,7 +102,7 @@ def maturities(date: DateLike) -> pl.Series:
|
|
|
103
102
|
>>> from pyield import ltn
|
|
104
103
|
>>> ltn.maturities("22-08-2024")
|
|
105
104
|
shape: (13,)
|
|
106
|
-
Series: '
|
|
105
|
+
Series: 'data_vencimento' [date]
|
|
107
106
|
[
|
|
108
107
|
2024-10-01
|
|
109
108
|
2025-01-01
|
|
@@ -118,7 +117,7 @@ def maturities(date: DateLike) -> pl.Series:
|
|
|
118
117
|
2030-01-01
|
|
119
118
|
]
|
|
120
119
|
"""
|
|
121
|
-
return data(date)["
|
|
120
|
+
return data(date)["data_vencimento"]
|
|
122
121
|
|
|
123
122
|
|
|
124
123
|
def price(
|
|
@@ -224,7 +223,7 @@ def premium(ltn_rate: float, di_rate: float) -> float:
|
|
|
224
223
|
taxa_diaria_ltn = (1 + ltn_rate) ** (1 / 252) - 1
|
|
225
224
|
taxa_diaria_di = (1 + di_rate) ** (1 / 252) - 1
|
|
226
225
|
|
|
227
|
-
# Retorno do cálculo
|
|
226
|
+
# Retorno do cálculo da rentabilidade
|
|
228
227
|
return taxa_diaria_ltn / taxa_diaria_di
|
|
229
228
|
|
|
230
229
|
|
|
@@ -264,7 +263,7 @@ def di_spreads(date: DateLike, bps: bool = False) -> pl.DataFrame:
|
|
|
264
263
|
Calcula o DI Spread para títulos prefixados (LTN e NTN-F) em uma data de referência.
|
|
265
264
|
|
|
266
265
|
Definição do spread (forma bruta):
|
|
267
|
-
|
|
266
|
+
spread_di = taxa_indicativa - taxa de ajuste do DI
|
|
268
267
|
|
|
269
268
|
Quando ``bps=False`` a coluna retorna essa diferença em formato decimal
|
|
270
269
|
(ex: 0.000439 ≈ 4.39 bps). Quando ``bps=True`` o valor é automaticamente
|
|
@@ -272,16 +271,17 @@ def di_spreads(date: DateLike, bps: bool = False) -> pl.DataFrame:
|
|
|
272
271
|
|
|
273
272
|
Args:
|
|
274
273
|
date (DateLike): Data de referência para buscar as taxas.
|
|
275
|
-
bps (bool): Se True, retorna
|
|
274
|
+
bps (bool): Se True, retorna spread_di já convertido em basis points.
|
|
276
275
|
Padrão False.
|
|
277
276
|
|
|
278
277
|
Returns:
|
|
279
278
|
pl.DataFrame: DataFrame com as colunas do spread.
|
|
280
279
|
|
|
281
280
|
Output Columns:
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
281
|
+
- titulo (String): Tipo do título.
|
|
282
|
+
- data_vencimento (Date): Data de vencimento.
|
|
283
|
+
- spread_di (Float64): Spread em decimal ou bps conforme parâmetro
|
|
284
|
+
(também conhecido como prêmio).
|
|
285
285
|
|
|
286
286
|
Raises:
|
|
287
287
|
ValueError: Se os dados de DI não possuem 'SettlementRate' ou estão vazios.
|
|
@@ -290,25 +290,25 @@ def di_spreads(date: DateLike, bps: bool = False) -> pl.DataFrame:
|
|
|
290
290
|
>>> from pyield import ltn
|
|
291
291
|
>>> ltn.di_spreads("30-05-2025", bps=True)
|
|
292
292
|
shape: (13, 3)
|
|
293
|
-
|
|
294
|
-
│
|
|
295
|
-
│ ---
|
|
296
|
-
│ str
|
|
297
|
-
|
|
298
|
-
│ LTN
|
|
299
|
-
│ LTN
|
|
300
|
-
│ LTN
|
|
301
|
-
│ LTN
|
|
302
|
-
│ LTN
|
|
303
|
-
│ …
|
|
304
|
-
│ LTN
|
|
305
|
-
│ LTN
|
|
306
|
-
│ LTN
|
|
307
|
-
│ LTN
|
|
308
|
-
│ LTN
|
|
309
|
-
|
|
293
|
+
┌────────┬─────────────────┬───────────┐
|
|
294
|
+
│ titulo ┆ data_vencimento ┆ spread_di │
|
|
295
|
+
│ --- ┆ --- ┆ --- │
|
|
296
|
+
│ str ┆ date ┆ f64 │
|
|
297
|
+
╞════════╪═════════════════╪═══════════╡
|
|
298
|
+
│ LTN ┆ 2025-07-01 ┆ 4.39 │
|
|
299
|
+
│ LTN ┆ 2025-10-01 ┆ -9.0 │
|
|
300
|
+
│ LTN ┆ 2026-01-01 ┆ -4.88 │
|
|
301
|
+
│ LTN ┆ 2026-04-01 ┆ -4.45 │
|
|
302
|
+
│ LTN ┆ 2026-07-01 ┆ 0.81 │
|
|
303
|
+
│ … ┆ … ┆ … │
|
|
304
|
+
│ LTN ┆ 2028-01-01 ┆ 0.55 │
|
|
305
|
+
│ LTN ┆ 2028-07-01 ┆ 1.5 │
|
|
306
|
+
│ LTN ┆ 2029-01-01 ┆ 10.77 │
|
|
307
|
+
│ LTN ┆ 2030-01-01 ┆ 11.0 │
|
|
308
|
+
│ LTN ┆ 2032-01-01 ┆ 11.24 │
|
|
309
|
+
└────────┴─────────────────┴───────────┘
|
|
310
310
|
"""
|
|
311
|
-
return pre_di_spreads(date, bps=bps).filter(pl.col("
|
|
311
|
+
return pre_di_spreads(date, bps=bps).filter(pl.col("titulo") == "LTN")
|
|
312
312
|
|
|
313
313
|
|
|
314
314
|
def forwards(date: DateLike) -> pl.DataFrame:
|
|
@@ -325,35 +325,35 @@ def forwards(date: DateLike) -> pl.DataFrame:
|
|
|
325
325
|
pl.DataFrame: DataFrame com as taxas forward.
|
|
326
326
|
|
|
327
327
|
Output Columns:
|
|
328
|
-
-
|
|
329
|
-
-
|
|
330
|
-
-
|
|
331
|
-
-
|
|
328
|
+
- data_vencimento (Date): Data de vencimento.
|
|
329
|
+
- dias_uteis (Int64): Dias úteis entre referência e vencimento.
|
|
330
|
+
- taxa_indicativa (Float64): Taxa spot (zero cupom).
|
|
331
|
+
- taxa_forward (Float64): Taxa forward.
|
|
332
332
|
|
|
333
333
|
Examples:
|
|
334
334
|
>>> from pyield import ltn
|
|
335
335
|
>>> ltn.forwards("17-10-2025")
|
|
336
336
|
shape: (13, 4)
|
|
337
|
-
|
|
338
|
-
│
|
|
339
|
-
│ ---
|
|
340
|
-
│ date
|
|
341
|
-
|
|
342
|
-
│ 2026-01-01
|
|
343
|
-
│ 2026-04-01
|
|
344
|
-
│ 2026-07-01
|
|
345
|
-
│ 2026-10-01
|
|
346
|
-
│ 2027-04-01
|
|
347
|
-
│ …
|
|
348
|
-
│ 2028-07-01
|
|
349
|
-
│ 2029-01-01
|
|
350
|
-
│ 2029-07-01
|
|
351
|
-
│ 2030-01-01
|
|
352
|
-
│ 2032-01-01
|
|
353
|
-
|
|
337
|
+
┌─────────────────┬────────────┬─────────────────┬──────────────┐
|
|
338
|
+
│ data_vencimento ┆ dias_uteis ┆ taxa_indicativa ┆ taxa_forward │
|
|
339
|
+
│ --- ┆ --- ┆ --- ┆ --- │
|
|
340
|
+
│ date ┆ i64 ┆ f64 ┆ f64 │
|
|
341
|
+
╞═════════════════╪════════════╪═════════════════╪══════════════╡
|
|
342
|
+
│ 2026-01-01 ┆ 52 ┆ 0.148307 ┆ 0.148307 │
|
|
343
|
+
│ 2026-04-01 ┆ 113 ┆ 0.147173 ┆ 0.146207 │
|
|
344
|
+
│ 2026-07-01 ┆ 174 ┆ 0.145206 ┆ 0.141571 │
|
|
345
|
+
│ 2026-10-01 ┆ 239 ┆ 0.142424 ┆ 0.13501 │
|
|
346
|
+
│ 2027-04-01 ┆ 361 ┆ 0.138155 ┆ 0.129838 │
|
|
347
|
+
│ … ┆ … ┆ … ┆ … │
|
|
348
|
+
│ 2028-07-01 ┆ 676 ┆ 0.133411 ┆ 0.131654 │
|
|
349
|
+
│ 2029-01-01 ┆ 800 ┆ 0.134254 ┆ 0.138861 │
|
|
350
|
+
│ 2029-07-01 ┆ 924 ┆ 0.135264 ┆ 0.141802 │
|
|
351
|
+
│ 2030-01-01 ┆ 1049 ┆ 0.135967 ┆ 0.141177 │
|
|
352
|
+
│ 2032-01-01 ┆ 1553 ┆ 0.13883 ┆ 0.144812 │
|
|
353
|
+
└─────────────────┴────────────┴─────────────────┴──────────────┘
|
|
354
354
|
"""
|
|
355
355
|
if any_is_empty(date):
|
|
356
356
|
return pl.DataFrame()
|
|
357
|
-
df = data(date).select("
|
|
358
|
-
taxas_forward = fwd.forwards(bdays=df["
|
|
359
|
-
return df.with_columns(
|
|
357
|
+
df = data(date).select("data_vencimento", "dias_uteis", "taxa_indicativa")
|
|
358
|
+
taxas_forward = fwd.forwards(bdays=df["dias_uteis"], rates=df["taxa_indicativa"])
|
|
359
|
+
return df.with_columns(taxa_forward=taxas_forward).sort("data_vencimento")
|