pyield 0.48.4__tar.gz → 0.48.6__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.
Files changed (71) hide show
  1. {pyield-0.48.4 → pyield-0.48.6}/PKG-INFO +1 -1
  2. pyield-0.48.6/pyield/__about__.py +1 -0
  3. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/di_over.py +40 -26
  4. {pyield-0.48.4 → pyield-0.48.6}/pyield/bc/__init__.py +3 -6
  5. {pyield-0.48.4 → pyield-0.48.6}/pyield/bc/leiloes.py +3 -3
  6. pyield-0.48.6/pyield/bc/sgs.py +386 -0
  7. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/leiloes.py +2 -2
  8. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/utils.py +1 -1
  9. pyield-0.48.4/pyield/__about__.py +0 -1
  10. pyield-0.48.4/pyield/bc/ptax.py +0 -196
  11. pyield-0.48.4/pyield/bc/taxas.py +0 -317
  12. {pyield-0.48.4 → pyield-0.48.6}/.gitignore +0 -0
  13. {pyield-0.48.4 → pyield-0.48.6}/LICENSE +0 -0
  14. {pyield-0.48.4 → pyield-0.48.6}/README.md +0 -0
  15. {pyield-0.48.4 → pyield-0.48.6}/pyield/__init__.py +0 -0
  16. {pyield-0.48.4 → pyield-0.48.6}/pyield/_internal/__init__.py +0 -0
  17. {pyield-0.48.4 → pyield-0.48.6}/pyield/_internal/br_numbers.py +0 -0
  18. {pyield-0.48.4 → pyield-0.48.6}/pyield/_internal/cache.py +0 -0
  19. {pyield-0.48.4 → pyield-0.48.6}/pyield/_internal/converters.py +0 -0
  20. {pyield-0.48.4 → pyield-0.48.6}/pyield/_internal/data_cache.py +0 -0
  21. {pyield-0.48.4 → pyield-0.48.6}/pyield/_internal/retry.py +0 -0
  22. {pyield-0.48.4 → pyield-0.48.6}/pyield/_internal/types.py +0 -0
  23. {pyield-0.48.4 → pyield-0.48.6}/pyield/anbima/__init__.py +0 -0
  24. {pyield-0.48.4 → pyield-0.48.6}/pyield/anbima/ettj_intradia.py +0 -0
  25. {pyield-0.48.4 → pyield-0.48.6}/pyield/anbima/ettj_ultima.py +0 -0
  26. {pyield-0.48.4 → pyield-0.48.6}/pyield/anbima/ima_ultimo.py +0 -0
  27. {pyield-0.48.4 → pyield-0.48.6}/pyield/anbima/imaq.py +0 -0
  28. {pyield-0.48.4 → pyield-0.48.6}/pyield/anbima/tpf.py +0 -0
  29. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/__init__.py +0 -0
  30. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/_contratos.py +0 -0
  31. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/_validar_pregao.py +0 -0
  32. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/boletim.py +0 -0
  33. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/derivativos_intradia.py +0 -0
  34. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/di1.py +0 -0
  35. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/futuro/__init__.py +0 -0
  36. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/futuro/contratos.py +0 -0
  37. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/futuro/historico.py +0 -0
  38. {pyield-0.48.4 → pyield-0.48.6}/pyield/b3/futuro/intradia.py +0 -0
  39. {pyield-0.48.4 → pyield-0.48.6}/pyield/bc/compromissada.py +0 -0
  40. {pyield-0.48.4 → pyield-0.48.6}/pyield/bc/copom.py +0 -0
  41. {pyield-0.48.4 → pyield-0.48.6}/pyield/bc/tpf_intradia.py +0 -0
  42. {pyield-0.48.4 → pyield-0.48.6}/pyield/bc/tpf_mensal.py +0 -0
  43. {pyield-0.48.4 → pyield-0.48.6}/pyield/bc/vna.py +0 -0
  44. {pyield-0.48.4 → pyield-0.48.6}/pyield/du/__init__.py +0 -0
  45. {pyield-0.48.4 → pyield-0.48.6}/pyield/du/core.py +0 -0
  46. {pyield-0.48.4 → pyield-0.48.6}/pyield/du/feriados/__init__.py +0 -0
  47. {pyield-0.48.4 → pyield-0.48.6}/pyield/du/feriados/feriados_antigos_br.txt +0 -0
  48. {pyield-0.48.4 → pyield-0.48.6}/pyield/du/feriados/feriados_br.py +0 -0
  49. {pyield-0.48.4 → pyield-0.48.6}/pyield/du/feriados/feriados_novos_br.txt +0 -0
  50. {pyield-0.48.4 → pyield-0.48.6}/pyield/fwd.py +0 -0
  51. {pyield-0.48.4 → pyield-0.48.6}/pyield/interpolador.py +0 -0
  52. {pyield-0.48.4 → pyield-0.48.6}/pyield/ipca/__init__.py +0 -0
  53. {pyield-0.48.4 → pyield-0.48.6}/pyield/ipca/historico.py +0 -0
  54. {pyield-0.48.4 → pyield-0.48.6}/pyield/ipca/projetado.py +0 -0
  55. {pyield-0.48.4 → pyield-0.48.6}/pyield/py.typed +0 -0
  56. {pyield-0.48.4 → pyield-0.48.6}/pyield/relogio.py +0 -0
  57. {pyield-0.48.4 → pyield-0.48.6}/pyield/selic/__init__.py +0 -0
  58. {pyield-0.48.4 → pyield-0.48.6}/pyield/selic/cpm.py +0 -0
  59. {pyield-0.48.4 → pyield-0.48.6}/pyield/selic/probabilities.py +0 -0
  60. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/__init__.py +0 -0
  61. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/benchmark.py +0 -0
  62. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/lft.py +0 -0
  63. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/ltn.py +0 -0
  64. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/ntnb.py +0 -0
  65. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/ntnb1.py +0 -0
  66. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/ntnbprinc.py +0 -0
  67. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/ntnc.py +0 -0
  68. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/ntnf.py +0 -0
  69. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/pre.py +0 -0
  70. {pyield-0.48.4 → pyield-0.48.6}/pyield/tn/rmd.py +0 -0
  71. {pyield-0.48.4 → pyield-0.48.6}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyield
3
- Version: 0.48.4
3
+ Version: 0.48.6
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
@@ -0,0 +1 @@
1
+ __version__ = "0.48.6"
@@ -9,46 +9,29 @@ Formato do arquivo (ex.: 20250228.txt):
9
9
  Notas de implementação:
10
10
  - O valor "00001315" representa 1315 / 10^4 = 0.1315 (13,15% a.a.).
11
11
  - Arquivos ausentes (feriados/fins de semana) retornam erro FTP 550.
12
+ - Série disponível a partir de 20/08/2012 (primeiro arquivo no FTP).
12
13
  """
13
14
 
15
+ import datetime as dt
14
16
  import ftplib
15
17
  import logging
16
18
 
19
+ from pyield._internal.cache import ttl_cache
17
20
  from pyield._internal.converters import converter_datas
18
21
  from pyield._internal.types import DateLike, any_is_empty
19
22
 
20
23
  registro = logging.getLogger(__name__)
21
24
 
25
+ # Primeiro arquivo disponível no FTP da CETIP
26
+ DATA_INICIO = dt.date(2012, 8, 20)
27
+
22
28
  # 4 casas decimais na taxa = 2 casas decimais em percentual
23
29
  CASAS_DECIMAIS_DI_OVER = 4
24
30
 
25
31
 
26
- def di_over(data: DateLike) -> float:
27
- """Obtém a taxa DI over via FTP da B3/CETIP.
28
-
29
- Busca o arquivo de taxa DI (Depósito Interfinanceiro) no servidor
30
- FTP da CETIP para a data informada.
31
-
32
- Args:
33
- data: data da consulta para buscar a taxa DI.
34
-
35
- Returns:
36
- Taxa DI para a data especificada (ex: 0.1315 para 13,15%).
37
- Retorna ``nan`` se a data for feriado ou fim de semana.
38
-
39
- Examples:
40
- >>> di_over("28/02/2025")
41
- 0.1315
42
- >>> di_over("01/01/2025") # Feriado
43
- nan
44
- """
45
- if any_is_empty(data):
46
- return float("nan")
47
-
48
- # Converte a data para o formato esperado do arquivo: YYYYMMDD.txt
49
- data_ref = converter_datas(data)
50
- nome_arquivo = data_ref.strftime("%Y%m%d.txt")
51
-
32
+ @ttl_cache()
33
+ def _buscar_taxa(nome_arquivo: str) -> float:
34
+ """Busca a taxa DI no FTP da CETIP para o arquivo informado."""
52
35
  try:
53
36
  with ftplib.FTP("ftp.cetip.com.br", timeout=10) as ftp:
54
37
  ftp.login()
@@ -75,3 +58,34 @@ def di_over(data: DateLike) -> float:
75
58
  except ftplib.all_errors as e:
76
59
  registro.error("Erro de conexão ou transferência FTP: %s", e)
77
60
  raise ConnectionError(f"Falha ao buscar taxa DI via FTP: {e}") from e
61
+
62
+
63
+ def di_over(data: DateLike) -> float:
64
+ """Obtém a taxa DI over via FTP da B3/CETIP.
65
+
66
+ Busca o arquivo de taxa DI (Depósito Interfinanceiro) no servidor
67
+ FTP da CETIP para a data informada.
68
+
69
+ Args:
70
+ data: data da consulta para buscar a taxa DI.
71
+
72
+ Returns:
73
+ Taxa DI para a data especificada (ex: 0.1315 para 13,15%).
74
+ Retorna ``nan`` se a data for feriado, fim de semana ou
75
+ anterior a 20/08/2012 (início da série no FTP).
76
+
77
+ Examples:
78
+ >>> di_over("28/02/2025")
79
+ 0.1315
80
+ >>> di_over("01/01/2025") # Feriado
81
+ nan
82
+ """
83
+ if any_is_empty(data):
84
+ return float("nan")
85
+
86
+ data_ref = converter_datas(data)
87
+ if data_ref < DATA_INICIO:
88
+ return float("nan")
89
+
90
+ nome_arquivo = data_ref.strftime("%Y%m%d.txt")
91
+ return _buscar_taxa(nome_arquivo)
@@ -1,10 +1,9 @@
1
1
  from pyield.bc import compromissada, copom
2
2
  from pyield.bc.compromissada import compromissadas
3
3
  from pyield.bc.leiloes import leiloes
4
- from pyield.bc.ptax import ptax, ptax_serie
5
- from pyield.bc.taxas import (
6
- di_over,
7
- di_over_serie,
4
+ from pyield.bc.sgs import (
5
+ ptax,
6
+ ptax_serie,
8
7
  selic_meta,
9
8
  selic_meta_serie,
10
9
  selic_over,
@@ -17,8 +16,6 @@ from pyield.bc.vna import vna_lft
17
16
  __all__ = [
18
17
  "copom",
19
18
  "compromissada",
20
- "di_over",
21
- "di_over_serie",
22
19
  "leiloes",
23
20
  "ptax_serie",
24
21
  "compromissadas",
@@ -19,7 +19,7 @@ from pyield import du
19
19
  from pyield._internal.br_numbers import float_br, taxa_br
20
20
  from pyield._internal.retry import retry_padrao
21
21
  from pyield._internal.types import DateLike
22
- from pyield.bc.ptax import ptax_serie
22
+ from pyield.bc.sgs import ptax_serie
23
23
  from pyield.tn.ntnb import duration as duration_b
24
24
  from pyield.tn.ntnf import duration as duration_f
25
25
 
@@ -240,8 +240,8 @@ def _buscar_ptax(df: pl.DataFrame) -> pl.DataFrame:
240
240
  return pl.DataFrame()
241
241
 
242
242
  return (
243
- df_ptax.select("data", "cotacao_media")
244
- .rename({"data": "data_ref", "cotacao_media": "ptax"})
243
+ df_ptax.select("data", "cotacao")
244
+ .rename({"data": "data_ref", "cotacao": "ptax"})
245
245
  .sort("data_ref")
246
246
  )
247
247
 
@@ -0,0 +1,386 @@
1
+ """Séries do Sistema Gerenciador de Séries (SGS) do Banco Central.
2
+
3
+ Séries disponíveis:
4
+ - PTAX Venda (SGS 1)
5
+ - SELIC Meta (SGS 432)
6
+ - SELIC Over (SGS 1178)
7
+
8
+ Exemplos de chamada à API:
9
+ https://api.bcb.gov.br/dados/serie/bcdata.sgs.1178/dados?formato=json&dataInicial=29/01/2025&dataFinal=31/01/2025
10
+ https://api.bcb.gov.br/dados/serie/bcdata.sgs.1178/dados/ultimos/5?formato=json
11
+
12
+ Exemplo de resposta JSON da API do BCB:
13
+ [{"data":"29/01/2025","valor":"12.15"},
14
+ {"data":"30/01/2025","valor":"13.15"},
15
+ {"data":"31/01/2025","valor":"13.15"}]
16
+
17
+ Notas de implementação:
18
+ - Intervalos > 10 anos são divididos automaticamente em blocos.
19
+ - SELIC Over e Meta: valores percentuais convertidos para decimal
20
+ (divididos por 100) e arredondados para 4 casas decimais.
21
+ - PTAX Venda: valor absoluto em R$ arredondado para 4 casas.
22
+ """
23
+
24
+ import datetime as dt
25
+ from enum import Enum
26
+
27
+ import polars as pl
28
+ import requests
29
+
30
+ from pyield import relogio
31
+ from pyield._internal.cache import ttl_cache
32
+ from pyield._internal.converters import converter_datas
33
+ from pyield._internal.retry import retry_padrao
34
+ from pyield._internal.types import DateLike, any_is_empty
35
+
36
+ URL_BASE = "https://api.bcb.gov.br/dados/serie/bcdata.sgs."
37
+
38
+ ESQUEMA_BRUTO = {"data": pl.Date, "valor": pl.Float64}
39
+
40
+ # Limite de segurança em dias, correspondendo a ~9.5 anos.
41
+ # Evita a complexidade do cálculo exato de 10 anos-calendário.
42
+ LIMITE_DIAS_SEGURO = 3500 # aprox 365 * 9.5
43
+
44
+ CASAS_DECIMAIS_TAXA = 4 # Selic: 2 casas no formato percentual → 4 em decimal
45
+ CASAS_DECIMAIS_PTAX = 4
46
+
47
+
48
+ class SerieSGS(Enum):
49
+ """Enum para as séries disponíveis no SGS do Banco Central."""
50
+
51
+ PTAX_VENDA = 1
52
+ SELIC_META = 432
53
+ SELIC_OVER = 1178
54
+
55
+
56
+ # ── Infraestrutura de acesso à API SGS ──────────────────────────────
57
+
58
+
59
+ @ttl_cache()
60
+ @retry_padrao
61
+ def _chamar_api(url_api: str) -> list[dict[str, str]]:
62
+ resposta = requests.get(url_api, timeout=10)
63
+ resposta.raise_for_status()
64
+ return resposta.json()
65
+
66
+
67
+ def _montar_url_intervalo(
68
+ serie: SerieSGS, inicio: dt.date, fim: dt.date | None = None
69
+ ) -> str:
70
+ inicio_str = inicio.strftime("%d/%m/%Y")
71
+ url = f"{URL_BASE}{serie.value}/dados?formato=json&dataInicial={inicio_str}"
72
+ if fim:
73
+ url += f"&dataFinal={fim.strftime('%d/%m/%Y')}"
74
+ return url
75
+
76
+
77
+ def _montar_url_ultimos(serie: SerieSGS, n: int) -> str:
78
+ return f"{URL_BASE}{serie.value}/dados/ultimos/{n}?formato=json"
79
+
80
+
81
+ def _buscar_api(url_api: str) -> pl.DataFrame:
82
+ """Busca dados da API e retorna DataFrame bruto {data, valor}."""
83
+ try:
84
+ dados = _chamar_api(url_api)
85
+ except requests.exceptions.HTTPError as e:
86
+ if e.response.status_code == 404: # noqa
87
+ return pl.DataFrame(schema=ESQUEMA_BRUTO)
88
+ raise
89
+
90
+ if not dados:
91
+ return pl.DataFrame(schema=ESQUEMA_BRUTO)
92
+
93
+ return pl.from_dicts(dados).select(
94
+ pl.col("data").str.to_date("%d/%m/%Y"),
95
+ pl.col("valor").cast(pl.Float64),
96
+ )
97
+
98
+
99
+ def _buscar_dados_url(
100
+ serie: SerieSGS,
101
+ inicio: DateLike,
102
+ fim: DateLike | None = None,
103
+ ) -> pl.DataFrame:
104
+ """Orquestra a busca, dividindo intervalos > 10 anos em blocos."""
105
+ data_inicio = converter_datas(inicio)
106
+ data_fim = converter_datas(fim) if fim else relogio.hoje()
107
+
108
+ if (data_fim - data_inicio).days < LIMITE_DIAS_SEGURO:
109
+ return _buscar_api(_montar_url_intervalo(serie, data_inicio, data_fim))
110
+
111
+ inicios = pl.date_range(start=data_inicio, end=data_fim, interval="10y", eager=True)
112
+ fins = inicios.dt.offset_by("10y").clip(upper_bound=data_fim)
113
+
114
+ todos_dfs = [
115
+ _buscar_api(_montar_url_intervalo(serie, ini, fim))
116
+ for ini, fim in zip(inicios, fins)
117
+ ]
118
+
119
+ todos_dfs = [df for df in todos_dfs if not df.is_empty()]
120
+
121
+ if not todos_dfs:
122
+ return pl.DataFrame(schema=ESQUEMA_BRUTO)
123
+
124
+ return pl.concat(todos_dfs).unique(subset=["data"], keep="first").sort("data")
125
+
126
+
127
+ def _buscar_serie(
128
+ serie: SerieSGS,
129
+ inicio: DateLike | None,
130
+ fim: DateLike | None,
131
+ ultimos: int | None,
132
+ ) -> pl.DataFrame:
133
+ """Busca genérica para qualquer série SGS."""
134
+ if ultimos is not None:
135
+ return _buscar_api(_montar_url_ultimos(serie, ultimos))
136
+ if inicio is not None:
137
+ return _buscar_dados_url(serie, inicio, fim)
138
+ raise ValueError("Informe 'inicio' ou 'ultimos'.")
139
+
140
+
141
+ # ── Helpers de transformação ─────────────────────────────────────────
142
+
143
+ ESQUEMA_TAXA = {"data": pl.Date, "taxa": pl.Float64}
144
+ ESQUEMA_PTAX = {"data": pl.Date, "cotacao": pl.Float64}
145
+
146
+
147
+ def _converter_para_taxa(df: pl.DataFrame) -> pl.DataFrame:
148
+ """Converte valor percentual para decimal e renomeia para 'taxa'."""
149
+ if df.is_empty():
150
+ return pl.DataFrame(schema=ESQUEMA_TAXA)
151
+ return df.select(
152
+ "data",
153
+ taxa=pl.col("valor").truediv(100).round(CASAS_DECIMAIS_TAXA),
154
+ )
155
+
156
+
157
+ def _extrair_escalar(df: pl.DataFrame, coluna: str) -> float:
158
+ """Extrai um valor escalar de um DataFrame ou retorna nan se vazio."""
159
+ if df.is_empty():
160
+ return float("nan")
161
+ return df[coluna].item(0)
162
+
163
+
164
+ # ── SELIC Over ───────────────────────────────────────────────────────
165
+
166
+
167
+ def selic_over_serie(
168
+ inicio: DateLike | None = None,
169
+ fim: DateLike | None = None,
170
+ *,
171
+ ultimos: int | None = None,
172
+ ) -> pl.DataFrame:
173
+ """Taxa SELIC Over (série SGS 1178).
174
+
175
+ Taxa de juros média diária praticada no mercado interbancário,
176
+ com títulos públicos como garantia.
177
+
178
+ Args:
179
+ inicio: Data inicial.
180
+ fim: Data final. Se ``None``, usa a data mais recente.
181
+ ultimos: Número de registros mais recentes a retornar.
182
+ Mutuamente exclusivo com ``inicio``/``fim``.
183
+
184
+ Returns:
185
+ DataFrame com colunas data e taxa, ou DataFrame vazio.
186
+
187
+ Examples:
188
+ >>> from pyield import bc
189
+ >>> # Sem dados em 26-01-2025 (domingo). Selic mudou por reunião do Copom.
190
+ >>> bc.selic_over_serie("26-01-2025").head(5) # Primeiras 5 linhas
191
+ shape: (5, 2)
192
+ ┌────────────┬────────┐
193
+ │ data ┆ taxa │
194
+ │ --- ┆ --- │
195
+ │ date ┆ f64 │
196
+ ╞════════════╪════════╡
197
+ │ 2025-01-27 ┆ 0.1215 │
198
+ │ 2025-01-28 ┆ 0.1215 │
199
+ │ 2025-01-29 ┆ 0.1215 │
200
+ │ 2025-01-30 ┆ 0.1315 │
201
+ │ 2025-01-31 ┆ 0.1315 │
202
+ └────────────┴────────┘
203
+
204
+ >>> # Buscando dados para um intervalo específico
205
+ >>> bc.selic_over_serie("14-09-2025", "17-09-2025")
206
+ shape: (3, 2)
207
+ ┌────────────┬───────┐
208
+ │ data ┆ taxa │
209
+ │ --- ┆ --- │
210
+ │ date ┆ f64 │
211
+ ╞════════════╪═══════╡
212
+ │ 2025-09-15 ┆ 0.149 │
213
+ │ 2025-09-16 ┆ 0.149 │
214
+ │ 2025-09-17 ┆ 0.149 │
215
+ └────────────┴───────┘
216
+ """
217
+ return _converter_para_taxa(
218
+ _buscar_serie(SerieSGS.SELIC_OVER, inicio, fim, ultimos)
219
+ )
220
+
221
+
222
+ def selic_over(data: DateLike) -> float:
223
+ """Taxa SELIC Over para uma data específica.
224
+
225
+ Args:
226
+ data: Data da consulta.
227
+
228
+ Returns:
229
+ Taxa SELIC Over ou ``nan`` se não disponível.
230
+
231
+ Examples:
232
+ >>> from pyield import bc
233
+ >>> bc.selic_over("31-05-2024")
234
+ 0.104
235
+ """
236
+ if any_is_empty(data):
237
+ return float("nan")
238
+ return _extrair_escalar(selic_over_serie(data, data), "taxa")
239
+
240
+
241
+ # ── SELIC Meta ───────────────────────────────────────────────────────
242
+
243
+
244
+ def selic_meta_serie(
245
+ inicio: DateLike | None = None,
246
+ fim: DateLike | None = None,
247
+ *,
248
+ ultimos: int | None = None,
249
+ ) -> pl.DataFrame:
250
+ """Taxa SELIC Meta (série SGS 432).
251
+
252
+ Taxa de juros oficial definida pelo COPOM.
253
+
254
+ Args:
255
+ inicio: Data inicial.
256
+ fim: Data final. Se ``None``, usa a data mais recente.
257
+ ultimos: Número de registros mais recentes a retornar.
258
+ Mutuamente exclusivo com ``inicio``/``fim``.
259
+
260
+ Returns:
261
+ DataFrame com colunas data e taxa, ou DataFrame vazio.
262
+
263
+ Examples:
264
+ >>> from pyield import bc
265
+ >>> bc.selic_meta_serie("31-05-2024", "31-05-2024")
266
+ shape: (1, 2)
267
+ ┌────────────┬───────┐
268
+ │ data ┆ taxa │
269
+ │ --- ┆ --- │
270
+ │ date ┆ f64 │
271
+ ╞════════════╪═══════╡
272
+ │ 2024-05-31 ┆ 0.105 │
273
+ └────────────┴───────┘
274
+ """
275
+ return _converter_para_taxa(
276
+ _buscar_serie(SerieSGS.SELIC_META, inicio, fim, ultimos)
277
+ )
278
+
279
+
280
+ def selic_meta(data: DateLike) -> float:
281
+ """Taxa SELIC Meta para uma data específica.
282
+
283
+ Args:
284
+ data: Data da consulta.
285
+
286
+ Returns:
287
+ Taxa SELIC Meta ou ``nan`` se não disponível.
288
+
289
+ Examples:
290
+ >>> from pyield import bc
291
+ >>> bc.selic_meta("31-05-2024")
292
+ 0.105
293
+ """
294
+ if any_is_empty(data):
295
+ return float("nan")
296
+ return _extrair_escalar(selic_meta_serie(data, data), "taxa")
297
+
298
+
299
+ # ── PTAX ─────────────────────────────────────────────────────────────
300
+
301
+
302
+ def ptax_serie(
303
+ inicio: DateLike | None = None,
304
+ fim: DateLike | None = None,
305
+ *,
306
+ ultimos: int | None = None,
307
+ ) -> pl.DataFrame:
308
+ """Cotação PTAX de venda do dólar (série SGS 1).
309
+
310
+ Fonte: Banco Central do Brasil (BCB). Frequência diária.
311
+
312
+ A cotação retornada é a PTAX de **venda**, a taxa de câmbio
313
+ oficial do dólar no Brasil, usada como referência para
314
+ liquidação de contratos, marcação a mercado de derivativos,
315
+ conversão de DV01 e índices de fundos cambiais.
316
+
317
+ Args:
318
+ inicio: Data inicial.
319
+ fim: Data final. Se ``None``, usa a data mais recente.
320
+ ultimos: Número de registros mais recentes a retornar.
321
+ Mutuamente exclusivo com ``inicio``/``fim``.
322
+
323
+ Returns:
324
+ DataFrame com colunas data e cotacao, ou DataFrame vazio
325
+ se não houver dados.
326
+
327
+ Output Columns:
328
+ * data (Date): data da cotação.
329
+ * cotacao (Float64): cotação PTAX de venda em R$/US$.
330
+
331
+ Notes:
332
+ Disponível desde 28.11.1984. Refere-se às taxas administradas até
333
+ março de 1990 e às taxas livres a partir de então (Resolução 1690,
334
+ de 18.3.1990). A partir de março de 1992, essa taxa recebeu a
335
+ denominação PTAX. Desde 1 de julho de 2011 (Circular 3506), a PTAX
336
+ corresponde à média aritmética das taxas obtidas em quatro consultas
337
+ diárias aos dealers de câmbio.
338
+
339
+ Examples:
340
+ >>> from pyield import bc
341
+ >>> bc.ptax_serie("20-04-2025", "25-04-2025")
342
+ shape: (4, 2)
343
+ ┌────────────┬─────────┐
344
+ │ data ┆ cotacao │
345
+ │ --- ┆ --- │
346
+ │ date ┆ f64 │
347
+ ╞════════════╪═════════╡
348
+ │ 2025-04-22 ┆ 5.7496 │
349
+ │ 2025-04-23 ┆ 5.688 │
350
+ │ 2025-04-24 ┆ 5.6738 │
351
+ │ 2025-04-25 ┆ 5.6846 │
352
+ └────────────┴─────────┘
353
+ """
354
+ df = _buscar_serie(SerieSGS.PTAX_VENDA, inicio, fim, ultimos)
355
+ if df.is_empty():
356
+ return pl.DataFrame(schema=ESQUEMA_PTAX)
357
+ return df.select(
358
+ "data",
359
+ cotacao=pl.col("valor").round(CASAS_DECIMAIS_PTAX),
360
+ )
361
+
362
+
363
+ def ptax(data: DateLike) -> float:
364
+ """Cotação PTAX de venda para uma data específica.
365
+
366
+ Retorna a PTAX de venda, taxa de câmbio oficial do dólar no
367
+ Brasil.
368
+
369
+ Args:
370
+ data: Data desejada.
371
+
372
+ Returns:
373
+ Cotação PTAX de venda em R$/US$, ou ``nan`` se não houver
374
+ cotação (feriado, fim de semana ou data futura).
375
+
376
+ Examples:
377
+ >>> from pyield import bc
378
+ >>> bc.ptax("22-04-2025")
379
+ 5.7496
380
+
381
+ >>> bc.ptax("20-04-2025")
382
+ nan
383
+ """
384
+ if any_is_empty(data):
385
+ return float("nan")
386
+ return _extrair_escalar(ptax_serie(data, data), "cotacao")
@@ -292,8 +292,8 @@ def _buscar_ptax(data_leilao: dt.date) -> pl.DataFrame:
292
292
  return pl.DataFrame()
293
293
 
294
294
  return (
295
- df.select("data", "cotacao_media")
296
- .rename({"data": "data_ref", "cotacao_media": "ptax"})
295
+ df.select("data", "cotacao")
296
+ .rename({"data": "data_ref", "cotacao": "ptax"})
297
297
  .sort("data_ref")
298
298
  )
299
299
 
@@ -80,7 +80,7 @@ def adicionar_duration(
80
80
 
81
81
  def adicionar_dv01(df: pl.DataFrame, data_ref: dt.date) -> pl.DataFrame:
82
82
  """Adiciona `dv01` e `dv01_usd` ao DataFrame. Requer coluna `duration`."""
83
- from pyield.bc.ptax import ptax # noqa: PLC0415
83
+ from pyield.bc.sgs import ptax # noqa: PLC0415
84
84
 
85
85
  expr_duracao_mod = pl.col("duration") / (1 + pl.col("taxa_indicativa"))
86
86
  df = df.with_columns(dv01=0.0001 * expr_duracao_mod * pl.col("pu"))
@@ -1 +0,0 @@
1
- __version__ = "0.48.4"
@@ -1,196 +0,0 @@
1
- """
2
- Módulo para acessar a API de cotações PTAX do Banco Central do Brasil (BCB)
3
-
4
- Exemplo de chamada à API:
5
- https://olinda.bcb.gov.br/olinda/servico/PTAX/versao/v1/odata/CotacaoDolarPeriodo(dataInicial=@dataInicial,dataFinalCotacao=@dataFinalCotacao)?@dataInicial='09-01-2025'&@dataFinalCotacao='09-10-2025'&$format=text/csv
6
-
7
- Exemplo de resposta CSV da API do BCB:
8
- cotacaoCompra, cotacaoVenda, dataHoraCotacao
9
- 2814 , 2828 , 1984-12-03 11:29:00.0
10
- 2814 , 2828 , 1984-12-03 16:38:00.0
11
- 2867 , 2881 , 1984-12-04 11:17:00.0
12
- "0,843" , "0,845" , 1995-01-02 18:20:00.0
13
- ...
14
- "5,4272" , "5,4278" , 2025-09-08 13:09:40.608
15
- "5,4272" , "5,4278" , 2025-09-09 13:07:27.786
16
- "5,4117" , "5,4123" , 2025-09-10 13:06:29.196
17
-
18
- ATENÇÃO: a fração de segundo varia entre .0 (datas antigas) e .608
19
- (datas recentes). Usar %.f (variável) no parsing, nunca %.3f (fixo).
20
- """
21
-
22
- import datetime as dt
23
-
24
- import polars as pl
25
- import requests
26
-
27
- import pyield._internal.converters as cv
28
- from pyield import relogio
29
- from pyield._internal.br_numbers import float_br
30
- from pyield._internal.cache import ttl_cache
31
- from pyield._internal.retry import retry_padrao
32
- from pyield._internal.types import DateLike
33
-
34
- URL_API_PTAX = "https://olinda.bcb.gov.br/olinda/servico/PTAX/versao/v1/odata/CotacaoDolarPeriodo(dataInicial=@dataInicial,dataFinalCotacao=@dataFinalCotacao)?"
35
-
36
-
37
- def _montar_url_api(inicio: dt.date, fim: dt.date) -> str:
38
- inicio_str = inicio.strftime("%m-%d-%Y")
39
- fim_str = fim.strftime("%m-%d-%Y")
40
- return (
41
- f"{URL_API_PTAX}"
42
- f"@dataInicial='{inicio_str}'"
43
- f"&@dataFinalCotacao='{fim_str}'"
44
- f"&$format=text/csv"
45
- )
46
-
47
-
48
- @ttl_cache()
49
- @retry_padrao
50
- def _buscar_texto_api(url: str) -> bytes:
51
- resposta = requests.get(url, timeout=10)
52
- resposta.raise_for_status()
53
- return resposta.content
54
-
55
-
56
- def _parsear_df(conteudo_csv: bytes) -> pl.DataFrame:
57
- """Lê o CSV bruto da API PTAX em DataFrame com todas as colunas como string."""
58
- return pl.read_csv(conteudo_csv, infer_schema=False)
59
-
60
-
61
- def _processar_df(df: pl.DataFrame) -> pl.DataFrame:
62
- return (
63
- df.with_columns(
64
- cotacao_compra=float_br("cotacaoCompra"),
65
- cotacao_venda=float_br("cotacaoVenda"),
66
- data_hora=pl.col("dataHoraCotacao").str.to_datetime(
67
- format="%Y-%m-%d %H:%M:%S%.f", strict=False
68
- ),
69
- )
70
- .with_columns(
71
- data=pl.col("data_hora").cast(pl.Date),
72
- hora=pl.col("data_hora").dt.time(),
73
- cotacao_media=pl.mean_horizontal("cotacao_compra", "cotacao_venda").round(
74
- 5
75
- ),
76
- )
77
- .sort("data_hora")
78
- .unique(subset=["data"], keep="last")
79
- .select("data", "hora", "cotacao_compra", "cotacao_venda", "cotacao_media")
80
- .sort("data")
81
- )
82
-
83
-
84
- def ptax_serie(
85
- inicio: DateLike | None = None,
86
- fim: DateLike | None = None,
87
- ) -> pl.DataFrame:
88
- """Cotações de fechamento do Dólar PTAX (taxa de câmbio).
89
-
90
- Fonte: Banco Central do Brasil (BCB). Frequência diária.
91
-
92
- Se `inicio` não for informada, usa 28.11.1984 (primeira data
93
- disponível). Se `fim` não for informada, usa a data de hoje.
94
-
95
- Args:
96
- inicio: Data de início da consulta. Padrão é ``None``.
97
- fim: Data de fim da consulta. Padrão é ``None``.
98
-
99
- Returns:
100
- DataFrame com as cotações do período, ou DataFrame vazio
101
- se não houver dados.
102
-
103
- Output Columns:
104
- * data (Date): data da cotação.
105
- * hora (Time): hora da cotação.
106
- * cotacao_compra (Float64): taxa de compra em R$.
107
- * cotacao_venda (Float64): taxa de venda em R$.
108
- * cotacao_media (Float64): média de compra/venda (5 casas).
109
-
110
- Notes:
111
- Disponível desde 28.11.1984; refere-se às taxas
112
- administradas até março de 1990 e às taxas livres a
113
- partir de então (Resolução 1690, de 18.3.1990). A
114
- partir de março de 1992, essa taxa recebeu a
115
- denominação PTAX. Desde 1 de julho de 2011 (Circular
116
- 3506), a PTAX corresponde à média aritmética das
117
- taxas obtidas em quatro consultas diárias aos dealers
118
- de câmbio.
119
-
120
- Documentação da API:
121
- https://olinda.bcb.gov.br/olinda/servico/PTAX/versao/v1/documentacao
122
-
123
- Examples:
124
- >>> from pyield import bc
125
- >>> bc.ptax_serie(inicio="20-04-2025", fim="25-04-2025")
126
- shape: (4, 5)
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
- └────────────┴──────────────┴────────────────┴───────────────┴───────────────┘
137
-
138
- >>> bc.ptax_serie(inicio="02-01-1995", fim="06-01-1995")
139
- shape: (5, 5)
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
- └────────────┴──────────┴────────────────┴───────────────┴───────────────┘
151
- """
152
- if inicio:
153
- inicio = cv.converter_datas(inicio)
154
- else:
155
- inicio = dt.date(1984, 11, 28)
156
-
157
- if fim:
158
- fim = cv.converter_datas(fim)
159
- else:
160
- fim = relogio.hoje()
161
-
162
- url = _montar_url_api(inicio, fim)
163
- texto = _buscar_texto_api(url)
164
- df = _parsear_df(texto)
165
- if df.is_empty():
166
- return pl.DataFrame()
167
- return _processar_df(df)
168
-
169
-
170
- def ptax(data: DateLike) -> float:
171
- """Cotação PTAX média de fechamento para uma data específica.
172
-
173
- Args:
174
- data: Data desejada.
175
-
176
- Returns:
177
- Taxa média (cotacao_media) do dia, ou ``nan`` se não
178
- houver cotação (feriado, fim de semana ou data futura).
179
-
180
- Examples:
181
- >>> from pyield import bc
182
- >>> # Busca a PTAX para um dia útil
183
- >>> bc.ptax("22-08-2025")
184
- 5.4389
185
-
186
- >>> # Busca a PTAX para um fim de semana (sem dados)
187
- >>> bc.ptax("23-08-2025")
188
- nan
189
- """
190
- dados_ptax = ptax_serie(
191
- inicio=data,
192
- fim=data,
193
- )
194
- if dados_ptax.is_empty():
195
- return float("nan")
196
- return dados_ptax["cotacao_media"].item(0)
@@ -1,317 +0,0 @@
1
- """Taxas de juros do Banco Central do Brasil (séries SGS).
2
-
3
- Séries disponíveis:
4
- - SELIC Over (SGS 1178)
5
- - SELIC Meta (SGS 432)
6
- - DI Over (SGS 11)
7
-
8
- Exemplo de chamada à API:
9
- https://api.bcb.gov.br/dados/serie/bcdata.sgs.1178/dados?formato=json&dataInicial=29/01/2025&dataFinal=31/01/2025
10
-
11
- Exemplo de resposta JSON da API do BCB (valores em percentual):
12
- [{"data":"29/01/2025","valor":"12.15"},
13
- {"data":"30/01/2025","valor":"13.15"},
14
- {"data":"31/01/2025","valor":"13.15"}]
15
-
16
- Notas de implementação:
17
- - Valores percentuais são convertidos para decimal (divididos por 100).
18
- - SELIC Over e Meta: arredondadas para 4 casas decimais.
19
- - DI Over diária: 8 casas decimais; anualizada: 4 casas decimais.
20
- - Intervalos > 10 anos são divididos automaticamente em blocos.
21
- """
22
-
23
- import datetime as dt
24
- from enum import Enum
25
-
26
- import polars as pl
27
- import requests
28
-
29
- from pyield import relogio
30
- from pyield._internal.cache import ttl_cache
31
- from pyield._internal.converters import converter_datas
32
- from pyield._internal.retry import retry_padrao
33
- from pyield._internal.types import DateLike, any_is_empty
34
-
35
-
36
- def _extrair_taxa(df: pl.DataFrame) -> float:
37
- """Extrai a taxa escalar de um DataFrame ou retorna nan se vazio."""
38
- if df.is_empty():
39
- return float("nan")
40
- return df["taxa"].item(0)
41
-
42
-
43
- URL_BASE = "https://api.bcb.gov.br/dados/serie/bcdata.sgs."
44
- CASAS_DECIMAIS_ANUALIZADA = 4 # 2 casas no formato percentual
45
- CASAS_DECIMAIS_DIARIA = 8 # 6 casas no formato percentual
46
-
47
- # Limite de segurança em dias, correspondendo a ~9.5 anos.
48
- # Evita a complexidade do cálculo exato de 10 anos-calendário.
49
- LIMITE_DIAS_SEGURO = 3500 # aprox 365 * 9.5
50
-
51
-
52
- class SerieBC(Enum):
53
- """Enum para as séries disponíveis no Banco Central."""
54
-
55
- SELIC_OVER = 1178
56
- SELIC_META = 432
57
- DI_OVER = 11
58
-
59
-
60
- @ttl_cache()
61
- @retry_padrao
62
- def _chamar_api(url_api: str) -> list[dict[str, str]]:
63
- resposta = requests.get(url_api, timeout=10)
64
- resposta.raise_for_status()
65
- return resposta.json()
66
-
67
-
68
- def _montar_url_download(
69
- serie: SerieBC, inicio: dt.date, fim: dt.date | None = None
70
- ) -> str:
71
- inicio_str = inicio.strftime("%d/%m/%Y")
72
- url = f"{URL_BASE}{serie.value}/dados?formato=json&dataInicial={inicio_str}"
73
- if fim:
74
- url += f"&dataFinal={fim.strftime('%d/%m/%Y')}"
75
- return url
76
-
77
-
78
- def _buscar_requisicao(
79
- serie: SerieBC,
80
- inicio: dt.date,
81
- fim: dt.date | None,
82
- ) -> pl.DataFrame:
83
- """Busca dados da API para um intervalo."""
84
- esquema_esperado = {"data": pl.Date, "taxa": pl.Float64}
85
- url_api = _montar_url_download(serie, inicio, fim)
86
-
87
- try:
88
- dados = _chamar_api(url_api)
89
- except requests.exceptions.HTTPError as e:
90
- if e.response.status_code == 404: # noqa
91
- return pl.DataFrame(schema=esquema_esperado)
92
- raise
93
-
94
- if not dados:
95
- return pl.DataFrame(schema=esquema_esperado)
96
-
97
- return pl.from_dicts(dados).select(
98
- pl.col("data").str.to_date("%d/%m/%Y"),
99
- taxa=pl.col("valor").cast(pl.Float64) / 100,
100
- )
101
-
102
-
103
- def _buscar_dados_url(
104
- serie: SerieBC,
105
- inicio: DateLike,
106
- fim: DateLike | None = None,
107
- ) -> pl.DataFrame:
108
- """Orquestra a busca, dividindo intervalos > 10 anos em blocos."""
109
- data_inicio = converter_datas(inicio)
110
- data_fim = converter_datas(fim) if fim else relogio.hoje()
111
-
112
- if (data_fim - data_inicio).days < LIMITE_DIAS_SEGURO:
113
- return _buscar_requisicao(serie, data_inicio, data_fim)
114
-
115
- inicios = pl.date_range(start=data_inicio, end=data_fim, interval="10y", eager=True)
116
- fins = inicios.dt.offset_by("10y").clip(upper_bound=data_fim)
117
-
118
- todos_dfs = [_buscar_requisicao(serie, ini, fim) for ini, fim in zip(inicios, fins)]
119
-
120
- todos_dfs = [df for df in todos_dfs if not df.is_empty()]
121
-
122
- if not todos_dfs:
123
- return pl.DataFrame()
124
-
125
- return pl.concat(todos_dfs).unique(subset=["data"], keep="first").sort("data")
126
-
127
-
128
- def selic_over_serie(
129
- inicio: DateLike,
130
- fim: DateLike | None = None,
131
- ) -> pl.DataFrame:
132
- """Taxa SELIC Over (série SGS 1178).
133
-
134
- Taxa de juros média diária praticada no mercado interbancário,
135
- com títulos públicos como garantia.
136
-
137
- Args:
138
- inicio: Data inicial.
139
- fim: Data final. Se ``None``, usa a data mais recente.
140
-
141
- Returns:
142
- DataFrame com colunas data e taxa, ou DataFrame vazio.
143
-
144
- Examples:
145
- >>> from pyield import bc
146
- >>> # Sem dados em 26-01-2025 (domingo). Selic mudou por reunião do Copom.
147
- >>> bc.selic_over_serie("26-01-2025").head(5) # Primeiras 5 linhas
148
- shape: (5, 2)
149
- ┌────────────┬────────┐
150
- │ data ┆ taxa │
151
- │ --- ┆ --- │
152
- │ date ┆ f64 │
153
- ╞════════════╪════════╡
154
- │ 2025-01-27 ┆ 0.1215 │
155
- │ 2025-01-28 ┆ 0.1215 │
156
- │ 2025-01-29 ┆ 0.1215 │
157
- │ 2025-01-30 ┆ 0.1315 │
158
- │ 2025-01-31 ┆ 0.1315 │
159
- └────────────┴────────┘
160
-
161
- >>> # Buscando dados para um intervalo específico
162
- >>> bc.selic_over_serie("14-09-2025", "17-09-2025")
163
- shape: (3, 2)
164
- ┌────────────┬───────┐
165
- │ data ┆ taxa │
166
- │ --- ┆ --- │
167
- │ date ┆ f64 │
168
- ╞════════════╪═══════╡
169
- │ 2025-09-15 ┆ 0.149 │
170
- │ 2025-09-16 ┆ 0.149 │
171
- │ 2025-09-17 ┆ 0.149 │
172
- └────────────┴───────┘
173
- """
174
- if any_is_empty(inicio):
175
- return pl.DataFrame()
176
- df = _buscar_dados_url(SerieBC.SELIC_OVER, inicio, fim)
177
- return df.with_columns(pl.col("taxa").round(CASAS_DECIMAIS_ANUALIZADA))
178
-
179
-
180
- def selic_over(data: DateLike) -> float:
181
- """Taxa SELIC Over para uma data específica.
182
-
183
- Args:
184
- data: Data da consulta.
185
-
186
- Returns:
187
- Taxa SELIC Over ou ``nan`` se não disponível.
188
-
189
- Examples:
190
- >>> from pyield import bc
191
- >>> bc.selic_over("31-05-2024")
192
- 0.104
193
- """
194
- if any_is_empty(data):
195
- return float("nan")
196
- return _extrair_taxa(selic_over_serie(data, data))
197
-
198
-
199
- def selic_meta_serie(
200
- inicio: DateLike,
201
- fim: DateLike | None = None,
202
- ) -> pl.DataFrame:
203
- """Taxa SELIC Meta (série SGS 432).
204
-
205
- Taxa de juros oficial definida pelo COPOM.
206
-
207
- Args:
208
- inicio: Data inicial.
209
- fim: Data final. Se ``None``, usa a data mais recente.
210
-
211
- Returns:
212
- DataFrame com colunas data e taxa, ou DataFrame vazio.
213
-
214
- Examples:
215
- >>> from pyield import bc
216
- >>> bc.selic_meta_serie("31-05-2024", "31-05-2024")
217
- shape: (1, 2)
218
- ┌────────────┬───────┐
219
- │ data ┆ taxa │
220
- │ --- ┆ --- │
221
- │ date ┆ f64 │
222
- ╞════════════╪═══════╡
223
- │ 2024-05-31 ┆ 0.105 │
224
- └────────────┴───────┘
225
- """
226
- if any_is_empty(inicio):
227
- return pl.DataFrame()
228
- df = _buscar_dados_url(SerieBC.SELIC_META, inicio, fim)
229
- return df.with_columns(pl.col("taxa").round(CASAS_DECIMAIS_ANUALIZADA))
230
-
231
-
232
- def selic_meta(data: DateLike) -> float:
233
- """Taxa SELIC Meta para uma data específica.
234
-
235
- Args:
236
- data: Data da consulta.
237
-
238
- Returns:
239
- Taxa SELIC Meta ou ``nan`` se não disponível.
240
-
241
- Examples:
242
- >>> from pyield import bc
243
- >>> bc.selic_meta("31-05-2024")
244
- 0.105
245
- """
246
- if any_is_empty(data):
247
- return float("nan")
248
- return _extrair_taxa(selic_meta_serie(data, data))
249
-
250
-
251
- def di_over_serie(
252
- inicio: DateLike,
253
- fim: DateLike | None = None,
254
- anualizada: bool = True,
255
- ) -> pl.DataFrame:
256
- """Taxa DI Over (série SGS 11).
257
-
258
- Taxa de juros média dos empréstimos interbancários.
259
-
260
- Args:
261
- inicio: Data inicial.
262
- fim: Data final. Se ``None``, usa a data mais recente.
263
- anualizada: Se ``True``, retorna a taxa anualizada (base
264
- 252 d.u.). Caso contrário, retorna a taxa diária.
265
-
266
- Returns:
267
- DataFrame com colunas data e taxa, ou DataFrame vazio.
268
-
269
- Examples:
270
- >>> from pyield import bc
271
- >>> # Retorna todos os dados desde 29-01-2025
272
- >>> bc.di_over_serie("29-01-2025").head(5) # Primeiras 5 linhas
273
- shape: (5, 2)
274
- ┌────────────┬────────┐
275
- │ data ┆ taxa │
276
- │ --- ┆ --- │
277
- │ date ┆ f64 │
278
- ╞════════════╪════════╡
279
- │ 2025-01-29 ┆ 0.1215 │
280
- │ 2025-01-30 ┆ 0.1315 │
281
- │ 2025-01-31 ┆ 0.1315 │
282
- │ 2025-02-03 ┆ 0.1315 │
283
- │ 2025-02-04 ┆ 0.1315 │
284
- └────────────┴────────┘
285
- """
286
- if any_is_empty(inicio):
287
- return pl.DataFrame()
288
- df = _buscar_dados_url(SerieBC.DI_OVER, inicio, fim)
289
- if anualizada:
290
- return df.with_columns(
291
- taxa=(((pl.col("taxa") + 1).pow(252)) - 1).round(CASAS_DECIMAIS_ANUALIZADA)
292
- )
293
- return df.with_columns(taxa=pl.col("taxa").round(CASAS_DECIMAIS_DIARIA))
294
-
295
-
296
- def di_over(data: DateLike, anualizada: bool = True) -> float:
297
- """Taxa DI Over para uma data específica.
298
-
299
- Args:
300
- data: Data da consulta.
301
- anualizada: Se ``True``, retorna a taxa anualizada (base
302
- 252 d.u.). Caso contrário, retorna a taxa diária.
303
-
304
- Returns:
305
- Taxa DI Over ou ``nan`` se não disponível.
306
-
307
- Examples:
308
- >>> from pyield import bc
309
- >>> bc.di_over("31-05-2024")
310
- 0.104
311
-
312
- >>> bc.di_over("28-01-2025", anualizada=False)
313
- 0.00045513
314
- """
315
- if any_is_empty(data):
316
- return float("nan")
317
- return _extrair_taxa(di_over_serie(data, data, anualizada))
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