pyield 0.44.2__tar.gz → 0.44.4__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 (68) hide show
  1. {pyield-0.44.2 → pyield-0.44.4}/PKG-INFO +1 -1
  2. pyield-0.44.4/pyield/__about__.py +1 -0
  3. {pyield-0.44.2 → pyield-0.44.4}/pyield/_internal/retry.py +0 -4
  4. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/futures/__init__.py +17 -43
  5. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/futures/historical.py +3 -6
  6. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/futures/intraday.py +19 -4
  7. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/price_report.py +6 -7
  8. {pyield-0.44.2 → pyield-0.44.4}/pyield/selic/cpm.py +4 -5
  9. pyield-0.44.2/pyield/__about__.py +0 -1
  10. {pyield-0.44.2 → pyield-0.44.4}/.gitignore +0 -0
  11. {pyield-0.44.2 → pyield-0.44.4}/LICENSE +0 -0
  12. {pyield-0.44.2 → pyield-0.44.4}/README.md +0 -0
  13. {pyield-0.44.2 → pyield-0.44.4}/pyield/__init__.py +0 -0
  14. {pyield-0.44.2 → pyield-0.44.4}/pyield/_internal/__init__.py +0 -0
  15. {pyield-0.44.2 → pyield-0.44.4}/pyield/_internal/converters.py +0 -0
  16. {pyield-0.44.2 → pyield-0.44.4}/pyield/_internal/data_cache.py +0 -0
  17. {pyield-0.44.2 → pyield-0.44.4}/pyield/_internal/types.py +0 -0
  18. {pyield-0.44.2 → pyield-0.44.4}/pyield/anbima/__init__.py +0 -0
  19. {pyield-0.44.2 → pyield-0.44.4}/pyield/anbima/difusao.py +0 -0
  20. {pyield-0.44.2 → pyield-0.44.4}/pyield/anbima/ettj_intraday.py +0 -0
  21. {pyield-0.44.2 → pyield-0.44.4}/pyield/anbima/ettj_last.py +0 -0
  22. {pyield-0.44.2 → pyield-0.44.4}/pyield/anbima/ima.py +0 -0
  23. {pyield-0.44.2 → pyield-0.44.4}/pyield/anbima/imaq.py +0 -0
  24. {pyield-0.44.2 → pyield-0.44.4}/pyield/anbima/tpf.py +0 -0
  25. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/__init__.py +0 -0
  26. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/_contracts.py +0 -0
  27. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/_validar_pregao.py +0 -0
  28. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/di1.py +0 -0
  29. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/di_over.py +0 -0
  30. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/futures/common.py +0 -0
  31. {pyield-0.44.2 → pyield-0.44.4}/pyield/b3/intraday_derivatives.py +0 -0
  32. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/__init__.py +0 -0
  33. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/auction.py +0 -0
  34. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/copom.py +0 -0
  35. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/ptax_api.py +0 -0
  36. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/rates.py +0 -0
  37. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/repo.py +0 -0
  38. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/trades_intraday.py +0 -0
  39. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/trades_monthly.py +0 -0
  40. {pyield-0.44.2 → pyield-0.44.4}/pyield/bc/vna.py +0 -0
  41. {pyield-0.44.2 → pyield-0.44.4}/pyield/bday/__init__.py +0 -0
  42. {pyield-0.44.2 → pyield-0.44.4}/pyield/bday/core.py +0 -0
  43. {pyield-0.44.2 → pyield-0.44.4}/pyield/bday/holidays/br_holidays_new.txt +0 -0
  44. {pyield-0.44.2 → pyield-0.44.4}/pyield/bday/holidays/br_holidays_old.txt +0 -0
  45. {pyield-0.44.2 → pyield-0.44.4}/pyield/bday/holidays/brholidays.py +0 -0
  46. {pyield-0.44.2 → pyield-0.44.4}/pyield/clock.py +0 -0
  47. {pyield-0.44.2 → pyield-0.44.4}/pyield/fwd.py +0 -0
  48. {pyield-0.44.2 → pyield-0.44.4}/pyield/interpolator.py +0 -0
  49. {pyield-0.44.2 → pyield-0.44.4}/pyield/ipca/__init__.py +0 -0
  50. {pyield-0.44.2 → pyield-0.44.4}/pyield/ipca/historical.py +0 -0
  51. {pyield-0.44.2 → pyield-0.44.4}/pyield/ipca/projected.py +0 -0
  52. {pyield-0.44.2 → pyield-0.44.4}/pyield/py.typed +0 -0
  53. {pyield-0.44.2 → pyield-0.44.4}/pyield/rmd.py +0 -0
  54. {pyield-0.44.2 → pyield-0.44.4}/pyield/selic/__init__.py +0 -0
  55. {pyield-0.44.2 → pyield-0.44.4}/pyield/selic/probabilities.py +0 -0
  56. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/__init__.py +0 -0
  57. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/auctions.py +0 -0
  58. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/benchmark.py +0 -0
  59. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/lft.py +0 -0
  60. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/ltn.py +0 -0
  61. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/ntnb.py +0 -0
  62. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/ntnb1.py +0 -0
  63. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/ntnbprinc.py +0 -0
  64. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/ntnc.py +0 -0
  65. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/ntnf.py +0 -0
  66. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/pre.py +0 -0
  67. {pyield-0.44.2 → pyield-0.44.4}/pyield/tn/tools.py +0 -0
  68. {pyield-0.44.2 → pyield-0.44.4}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyield
3
- Version: 0.44.2
3
+ Version: 0.44.4
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.44.4"
@@ -11,10 +11,6 @@ _HTTP_MUITAS_REQUISICOES = 429
11
11
  _HTTP_ERRO_SERVIDOR_MINIMO = 500
12
12
 
13
13
 
14
- class DadoIndisponivelError(Exception):
15
- """Levantada quando o dado baixado for considerado inválido (dado vazio/pequeno)."""
16
-
17
-
18
14
  _EXCECOES_TRANSITORIAS = (
19
15
  rex.Timeout,
20
16
  rex.ConnectionError,
@@ -4,7 +4,6 @@ import polars as pl
4
4
 
5
5
  import pyield._internal.converters as cv
6
6
  from pyield import clock
7
- from pyield._internal.retry import DadoIndisponivelError
8
7
  from pyield._internal.types import DateLike, any_is_empty
9
8
  from pyield.b3._contracts import normalizar_codigos_contrato
10
9
  from pyield.b3._validar_pregao import data_negociacao_valida
@@ -13,41 +12,10 @@ from pyield.b3.futures import historical, intraday
13
12
  logger = logging.getLogger(__name__)
14
13
 
15
14
 
16
- def _buscar_intraday_ou_historico(
17
- data_negociacao,
18
- codigos_contrato: list[str],
19
- full_report: bool,
20
- ) -> pl.DataFrame:
21
- horario_atual = clock.now().time()
22
- if horario_atual < intraday.HORA_INICIO_INTRADAY:
23
- return pl.DataFrame()
24
-
25
- if horario_atual >= intraday.HORA_FIM_INTRADAY:
26
- for tentativa_full_report in (full_report, not full_report):
27
- try:
28
- df_historico = historical.historical(
29
- data_negociacao, codigos_contrato, tentativa_full_report
30
- )
31
- except DadoIndisponivelError:
32
- continue
33
- if not df_historico.is_empty():
34
- logger.info("Dados consolidados disponíveis. Usando histórico.")
35
- return df_historico
36
- logger.info("Histórico consolidado indisponível. Tentando intraday.")
37
-
38
- dataframes_intraday = [intraday.intraday(codigo) for codigo in codigos_contrato]
39
- dataframes_intraday = [df for df in dataframes_intraday if not df.is_empty()]
40
- if not dataframes_intraday:
41
- return pl.DataFrame()
42
- if len(dataframes_intraday) == 1:
43
- return dataframes_intraday[0]
44
- return pl.concat(dataframes_intraday, how="diagonal_relaxed").sort("TickerSymbol")
45
-
46
-
47
15
  def futures(
48
16
  date: DateLike,
49
17
  contract_code: str | list[str],
50
- full_report: bool = False,
18
+ full_report: bool | None = None,
51
19
  ) -> pl.DataFrame:
52
20
  """Busca dados de um contrato futuro da B3 para a data de referência.
53
21
 
@@ -59,10 +27,12 @@ def futures(
59
27
  - Moedas: DOL, WDO, EUR, GBR, JAP, CNY
60
28
  - Índices: IND, WIN, ISP, WSP
61
29
  - Commodities: BGI, CCM, ICF, CNL, SJC, SOY, ETH, GLD
62
- full_report: Se False (padrão), usa o simplified price report (SPR),
63
- arquivo leve (~2 KB) com apenas preços de ajuste. Se True, usa o
64
- price report completo (PR, ~2 MB) com todos os dados de negociação.
65
- Relevante apenas quando o dado não está no cache.
30
+ full_report: Controla a fonte de dados quando o dado não está no cache.
31
+ Se None (padrão), prioriza dados intraday (para data de hoje) e
32
+ usa SPR como fallback ideal para uso interativo.
33
+ Se False, usa o simplified price report (SPR, ~2 KB).
34
+ Se True, usa apenas o price report completo (PR, ~2 MB) —
35
+ indicado para processos batch noturnos.
66
36
 
67
37
  Returns:
68
38
  DataFrame Polars com os dados do contrato informado.
@@ -105,12 +75,16 @@ def futures(
105
75
  if not data_negociacao_valida(data_negociacao):
106
76
  return pl.DataFrame()
107
77
 
108
- if intraday.data_intraday_valida(data_negociacao):
109
- return _buscar_intraday_ou_historico(
110
- data_negociacao=data_negociacao,
111
- codigos_contrato=codigos_contrato,
112
- full_report=full_report,
113
- )
78
+ # None: tenta intraday primeiro (só hoje + horário ok)
79
+ if full_report is None:
80
+ eh_hoje = intraday.data_intraday_valida(data_negociacao)
81
+ if eh_hoje:
82
+ horario = clock.now().time()
83
+ if horario >= intraday.HORA_INICIO_INTRADAY:
84
+ df = intraday.intraday(codigos_contrato)
85
+ if not df.is_empty():
86
+ return df
87
+ full_report = False
114
88
 
115
89
  return historical.historical(data_negociacao, codigos_contrato, full_report)
116
90
 
@@ -24,9 +24,8 @@ def historical(
24
24
  Args:
25
25
  data: Data de negociação.
26
26
  codigo_contrato: Código(s) do contrato futuro na B3.
27
- full_report: Se False (padrão), usa o simplified price report (SPR),
28
- arquivo leve (~2 KB) com apenas preços de ajuste. Se True, usa o
29
- price report completo (PR, ~2 MB) com todos os dados de negociação.
27
+ full_report: Se False (padrão), usa o simplified price report
28
+ (SPR, ~2 KB). Se True, usa o price report completo (PR, ~2 MB).
30
29
 
31
30
  Returns:
32
31
  DataFrame Polars com dados históricos de futuros.
@@ -88,9 +87,7 @@ def historical(
88
87
  if codigos_sem_cache:
89
88
  for codigo in codigos_sem_cache:
90
89
  df_bruto = fetch_price_report(
91
- date=data,
92
- contract_code=codigo,
93
- full_report=full_report,
90
+ date=data, contract_code=codigo, full_report=full_report
94
91
  )
95
92
  if df_bruto.is_empty():
96
93
  continue
@@ -5,6 +5,7 @@ import polars as pl
5
5
  import polars.selectors as cs
6
6
 
7
7
  from pyield import bday, clock
8
+ from pyield.b3._contracts import normalizar_codigos_contrato
8
9
  from pyield.b3._validar_pregao import data_negociacao_valida
9
10
  from pyield.b3.futures.common import expr_dv01
10
11
  from pyield.b3.intraday_derivatives import fetch_intraday_derivatives
@@ -13,8 +14,6 @@ from pyield.fwd import forwards
13
14
  # Pregão abre às 9:00, porém os dados têm atraso de 15 minutos.
14
15
  # Esperar 1 minuto adicional para garantir que estejam disponíveis (9:16h).
15
16
  HORA_INICIO_INTRADAY = dt.time(9, 16)
16
- # Pregão fecha às 18:00h, momento em que os dados consolidados começam a ser preparados.
17
- HORA_FIM_INTRADAY = dt.time(18, 30)
18
17
 
19
18
  logger = logging.getLogger(__name__)
20
19
 
@@ -27,7 +26,7 @@ def data_intraday_valida(data_verificacao: dt.date) -> bool:
27
26
  return data_verificacao == clock.today()
28
27
 
29
28
 
30
- def intraday(codigo_contrato: str) -> pl.DataFrame:
29
+ def intraday(codigo_contrato: str | list[str]) -> pl.DataFrame:
31
30
  """Busca os dados intraday mais recentes da B3.
32
31
 
33
32
  Os dados intraday da fonte possuem atraso aproximado de 15 minutos.
@@ -35,7 +34,8 @@ def intraday(codigo_contrato: str) -> pl.DataFrame:
35
34
  menos 15 minutos.
36
35
 
37
36
  Args:
38
- codigo_contrato: Código base do contrato futuro na B3.
37
+ codigo_contrato: Código base do contrato futuro na B3, ou lista de
38
+ códigos.
39
39
 
40
40
  Returns:
41
41
  DataFrame Polars com dados intraday processados.
@@ -65,6 +65,21 @@ def intraday(codigo_contrato: str) -> pl.DataFrame:
65
65
  - LastRate (Float64): Última taxa negociada.
66
66
  - ForwardRate (Float64): Taxa a termo (apenas DI1/DAP).
67
67
  """
68
+ codigos = normalizar_codigos_contrato(codigo_contrato)
69
+ if not codigos:
70
+ return pl.DataFrame()
71
+
72
+ dfs = [_intraday_contrato(c) for c in codigos]
73
+ dfs = [df for df in dfs if not df.is_empty()]
74
+ if not dfs:
75
+ return pl.DataFrame()
76
+ if len(dfs) == 1:
77
+ return dfs[0]
78
+ return pl.concat(dfs, how="diagonal_relaxed").sort("TickerSymbol")
79
+
80
+
81
+ def _intraday_contrato(codigo_contrato: str) -> pl.DataFrame:
82
+ """Busca e processa dados intraday de um único contrato."""
68
83
  try:
69
84
  df_bruto = fetch_intraday_derivatives(codigo_contrato)
70
85
  if df_bruto.is_empty():
@@ -10,7 +10,7 @@ from lxml import etree
10
10
  from lxml.etree import _Element
11
11
 
12
12
  import pyield._internal.converters as cv
13
- from pyield._internal.retry import DadoIndisponivelError, retry_padrao
13
+ from pyield._internal.retry import retry_padrao
14
14
  from pyield._internal.types import DateLike, any_is_empty
15
15
  from pyield.b3._contracts import normalizar_codigos_contrato
16
16
  from pyield.b3._validar_pregao import data_negociacao_valida
@@ -112,8 +112,7 @@ def _baixar_zip_url(data: dt.date, relatorio_completo: bool) -> bytes:
112
112
  resposta.raise_for_status()
113
113
 
114
114
  if len(resposta.content) < MIN_TAMANHO_ZIP_BYTES:
115
- data_str_formatada = data.strftime("%Y-%m-%d")
116
- raise DadoIndisponivelError(f"Sem dados disponíveis para {data_str_formatada}.")
115
+ return bytes()
117
116
  return resposta.content
118
117
 
119
118
 
@@ -231,6 +230,8 @@ def _processar_xml_extraido(xml_bytes: bytes, codigo_contrato: str) -> pl.DataFr
231
230
  @lru_cache(maxsize=64)
232
231
  def _obter_xml_price_report(data: dt.date, relatorio_completo: bool) -> bytes:
233
232
  dados_zip = _baixar_zip_url(data, relatorio_completo)
233
+ if not dados_zip:
234
+ return bytes()
234
235
  return _extrair_xml_zip_aninhado(dados_zip)
235
236
 
236
237
 
@@ -311,8 +312,6 @@ def fetch_price_report(
311
312
  - MinLimitValue (Float64): Limite mínimo de variação.
312
313
 
313
314
  Raises:
314
- DadoIndisponivelError: Se a data for válida, mas o endpoint não fornecer
315
- arquivo para a data consultada.
316
315
  requests.HTTPError: Se a requisição HTTP ao endpoint falhar.
317
316
  zipfile.BadZipFile: Se o arquivo ZIP recebido estiver corrompido.
318
317
  etree.XMLSyntaxError: Se o XML recebido estiver malformado.
@@ -348,7 +347,7 @@ def fetch_price_report(
348
347
  dataframes.append(df)
349
348
  if not dataframes:
350
349
  return pl.DataFrame()
351
- return pl.concat(dataframes).sort("TickerSymbol")
350
+ return pl.concat(dataframes, how="diagonal").sort("TickerSymbol")
352
351
  except (zipfile.BadZipFile, etree.XMLSyntaxError):
353
352
  registro.exception(f"Falha ao parsear o price report de {contratos} em {date}.")
354
353
  raise
@@ -433,4 +432,4 @@ def read_price_report(
433
432
  dataframes.append(df)
434
433
  if not dataframes:
435
434
  return pl.DataFrame()
436
- return pl.concat(dataframes).sort("TickerSymbol")
435
+ return pl.concat(dataframes, how="diagonal").sort("TickerSymbol")
@@ -39,7 +39,7 @@ import requests
39
39
 
40
40
  import pyield._internal.converters as cv
41
41
  from pyield import bday
42
- from pyield._internal.retry import DadoIndisponivelError, retry_padrao
42
+ from pyield._internal.retry import retry_padrao
43
43
  from pyield._internal.types import DateLike
44
44
  from pyield.b3._validar_pregao import data_negociacao_valida
45
45
  from pyield.b3.price_report import (
@@ -284,12 +284,11 @@ def data(date: DateLike) -> pl.DataFrame:
284
284
  return _empty_schema()
285
285
 
286
286
  try:
287
- zip_data = _baixar_zip_url(trade_date, "SPR")
287
+ zip_data = _baixar_zip_url(trade_date, relatorio_completo=False)
288
+ if not zip_data:
289
+ return _empty_schema()
288
290
  xml_bytes = _extrair_xml_zip_aninhado(zip_data)
289
291
  records = _parsear_xml_registros(xml_bytes, "CPM")
290
- except DadoIndisponivelError:
291
- logger.warning("CPM: dados SPR indisponíveis para %s.", trade_date)
292
- return _empty_schema()
293
292
  except Exception:
294
293
  logger.exception("CPM: falha ao baixar SPR para %s.", trade_date)
295
294
  return _empty_schema()
@@ -1 +0,0 @@
1
- __version__ = "0.44.2"
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