PYield 0.46.7__tar.gz → 0.47.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.46.7 → pyield-0.47.0}/PKG-INFO +1 -1
- pyield-0.47.0/pyield/__about__.py +1 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/__init__.py +2 -1
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/__init__.py +2 -1
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/di1.py +2 -2
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/futures/__init__.py +62 -75
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/futures/historical.py +9 -53
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/price_report.py +9 -21
- pyield-0.46.7/pyield/__about__.py +0 -1
- {pyield-0.46.7 → pyield-0.47.0}/.gitignore +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/LICENSE +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/README.md +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/_internal/__init__.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/_internal/br_numbers.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/_internal/cache.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/_internal/converters.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/_internal/data_cache.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/_internal/retry.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/_internal/types.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/anbima/__init__.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/anbima/ettj_intraday.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/anbima/ettj_last.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/anbima/ima.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/anbima/imaq.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/anbima/tpf.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/_contracts.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/_validar_pregao.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/di_over.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/futures/common.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/b3/intraday_derivatives.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/__init__.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/auction.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/copom.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/ptax_api.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/rates.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/repo.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bc/vna.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bday/__init__.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bday/core.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bday/holidays/br_holidays_new.txt +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bday/holidays/br_holidays_old.txt +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/bday/holidays/brholidays.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/clock.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/fwd.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/interpolator.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/ipca/__init__.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/ipca/historical.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/ipca/projected.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/py.typed +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/rmd.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/selic/__init__.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/selic/cpm.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/selic/probabilities.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/__init__.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/auctions.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/benchmark.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/lft.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/ltn.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/ntnb.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/ntnb1.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/ntnbprinc.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/ntnc.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/ntnf.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/pre.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyield/tn/utils.py +0 -0
- {pyield-0.46.7 → pyield-0.47.0}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyield
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.47.0
|
|
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.47.0"
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
from pyield import anbima, b3, bc, bday, ipca, selic, tn
|
|
4
4
|
from pyield.__about__ import __version__
|
|
5
|
-
from pyield.b3 import di1, futures
|
|
5
|
+
from pyield.b3 import di1, futures, futures_intraday
|
|
6
6
|
from pyield.clock import now, today
|
|
7
7
|
from pyield.fwd import forward, forwards
|
|
8
8
|
from pyield.interpolator import Interpolator
|
|
@@ -37,6 +37,7 @@ __all__ = [
|
|
|
37
37
|
"rmd",
|
|
38
38
|
"bday",
|
|
39
39
|
"selic",
|
|
40
|
+
"futures_intraday",
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
# Configura o logger do pacote principal com um NullHandler
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from pyield.b3 import di1
|
|
2
2
|
from pyield.b3.di_over import di_over
|
|
3
|
-
from pyield.b3.futures import futures
|
|
3
|
+
from pyield.b3.futures import futures, futures_intraday
|
|
4
4
|
from pyield.b3.intraday_derivatives import fetch_intraday_derivatives
|
|
5
5
|
from pyield.b3.price_report import fetch_price_report, read_price_report
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@ __all__ = [
|
|
|
8
8
|
"fetch_intraday_derivatives",
|
|
9
9
|
"di_over",
|
|
10
10
|
"futures",
|
|
11
|
+
"futures_intraday",
|
|
11
12
|
"fetch_price_report",
|
|
12
13
|
"read_price_report",
|
|
13
14
|
"di1",
|
|
@@ -62,7 +62,7 @@ def data(
|
|
|
62
62
|
else:
|
|
63
63
|
datas_lista = [datas_convertidas]
|
|
64
64
|
|
|
65
|
-
df = b3.futures(date=datas_lista, contract_code="DI1"
|
|
65
|
+
df = b3.futures(date=datas_lista, contract_code="DI1")
|
|
66
66
|
if df.is_empty():
|
|
67
67
|
return df
|
|
68
68
|
|
|
@@ -195,7 +195,7 @@ def interpolate_rates(
|
|
|
195
195
|
|
|
196
196
|
# Carrega dataset de taxas DI usando datas já convertidas do df_entrada
|
|
197
197
|
datas_unicas = df_entrada["data_referencia"].drop_nulls().unique().sort().to_list()
|
|
198
|
-
df_ref = b3.futures(date=datas_unicas, contract_code="DI1"
|
|
198
|
+
df_ref = b3.futures(date=datas_unicas, contract_code="DI1")
|
|
199
199
|
# Retorna Series vazia se nenhuma taxa for encontrada
|
|
200
200
|
if df_ref.is_empty():
|
|
201
201
|
return pl.Series(dtype=pl.Float64)
|
|
@@ -1,56 +1,37 @@
|
|
|
1
1
|
import datetime as dt
|
|
2
|
-
import logging
|
|
3
2
|
|
|
4
3
|
import polars as pl
|
|
5
4
|
|
|
6
5
|
import pyield._internal.converters as cv
|
|
7
|
-
from pyield import clock
|
|
8
6
|
from pyield._internal.types import ArrayLike, DateLike, any_is_empty, is_collection
|
|
9
7
|
from pyield.b3._contracts import normalizar_codigos_contrato
|
|
10
|
-
from pyield.b3._validar_pregao import
|
|
8
|
+
from pyield.b3._validar_pregao import data_negociacao_valida
|
|
11
9
|
from pyield.b3.futures import historical, intraday
|
|
12
10
|
|
|
13
|
-
# A partir desse horário, os dados consolidados (SPR/PR) já estão disponíveis.
|
|
14
|
-
HORA_INICIO_CONSOLIDADO = dt.time(19, 0)
|
|
15
|
-
|
|
16
|
-
logger = logging.getLogger(__name__)
|
|
17
|
-
|
|
18
11
|
|
|
19
12
|
def futures(
|
|
20
13
|
date: DateLike | ArrayLike,
|
|
21
14
|
contract_code: str | list[str],
|
|
22
|
-
full_report: bool | None = None,
|
|
23
15
|
) -> pl.DataFrame:
|
|
24
16
|
"""Busca dados de um contrato futuro da B3 para a data de referência.
|
|
25
17
|
|
|
18
|
+
Dados obtidos do dataset PR cacheado no GitHub (disponível desde 2018).
|
|
19
|
+
Para dados do pregão corrente, use ``futures_intraday``.
|
|
20
|
+
|
|
26
21
|
Args:
|
|
27
22
|
date: Data de referência para consulta ou coleção de datas.
|
|
28
23
|
Quando uma coleção é fornecida, os dados são buscados para cada
|
|
29
24
|
data individualmente e concatenados. Datas inválidas (feriados,
|
|
30
25
|
fins de semana, futuras) são silenciosamente ignoradas.
|
|
31
|
-
contract_code: Código do contrato futuro na B3 ou coleção de
|
|
32
|
-
|
|
33
|
-
- Juros: DI1, DDI,
|
|
34
|
-
- Moedas: DOL, WDO
|
|
35
|
-
- Índices: IND, WIN
|
|
36
|
-
- Commodities: BGI, CCM, ICF, CNL, SJC, SOY, ETH, GLD
|
|
37
|
-
full_report: Controla a fonte de dados quando o dado não está no cache.
|
|
38
|
-
Se None (padrão) e a data é hoje: entre 09:16 e 19:00 prioriza
|
|
39
|
-
dados intraday; a partir das 19:00 prioriza os dados consolidados
|
|
40
|
-
(SPR → PR) com intraday como fallback.
|
|
41
|
-
Se False, usa o simplified price report (SPR, ~2 KB).
|
|
42
|
-
Se True, usa apenas o price report completo (PR, ~2 MB) —
|
|
43
|
-
indicado para processos batch noturnos.
|
|
26
|
+
contract_code: Código do contrato futuro na B3 ou coleção de
|
|
27
|
+
códigos. Contratos disponíveis no cache histórico:
|
|
28
|
+
- Juros: DI1, DDI, FRC, FRO, DAP
|
|
29
|
+
- Moedas: DOL, WDO
|
|
30
|
+
- Índices: IND, WIN
|
|
44
31
|
|
|
45
32
|
Returns:
|
|
46
33
|
DataFrame Polars com os dados do contrato informado.
|
|
47
34
|
|
|
48
|
-
Notes:
|
|
49
|
-
Os contratos DI1, DDI, FRC, FRO, DAP, DOL, WDO, IND e WIN possuem
|
|
50
|
-
histórico pré-cacheado (desde 2018) e são retornados instantaneamente.
|
|
51
|
-
Para os demais contratos, os dados são baixados diretamente da B3 a
|
|
52
|
-
cada chamada, o que pode ser mais lento.
|
|
53
|
-
|
|
54
35
|
Examples:
|
|
55
36
|
>>> df = futures("31-05-2024", "DI1")
|
|
56
37
|
>>> df = futures("31-05-2024", "DAP")
|
|
@@ -88,26 +69,21 @@ def futures(
|
|
|
88
69
|
if is_collection(date):
|
|
89
70
|
# date é ArrayLike neste branch
|
|
90
71
|
datas: ArrayLike = date # type: ignore[assignment]
|
|
91
|
-
return _buscar_varias_datas(datas, codigos_contrato
|
|
72
|
+
return _buscar_varias_datas(datas, codigos_contrato)
|
|
92
73
|
|
|
93
74
|
# date é escalar (DateLike) neste branch
|
|
94
75
|
data_negociacao: dt.date = cv.converter_datas(date) # type: ignore[assignment]
|
|
95
76
|
if not data_negociacao_valida(data_negociacao):
|
|
96
77
|
return pl.DataFrame()
|
|
97
78
|
|
|
98
|
-
return
|
|
79
|
+
return historical.historical(data_negociacao, codigos_contrato)
|
|
99
80
|
|
|
100
81
|
|
|
101
82
|
def _buscar_varias_datas(
|
|
102
83
|
datas: ArrayLike,
|
|
103
84
|
codigos: list[str],
|
|
104
|
-
full_report: bool | None,
|
|
105
85
|
) -> pl.DataFrame:
|
|
106
|
-
"""Busca dados para múltiplas datas
|
|
107
|
-
|
|
108
|
-
Prioriza o dataset PR cacheado (bulk). Para datas ausentes no cache,
|
|
109
|
-
busca individualmente via _buscar_por_fonte.
|
|
110
|
-
"""
|
|
86
|
+
"""Busca dados para múltiplas datas do dataset PR cacheado."""
|
|
111
87
|
serie_datas = cv.converter_datas(datas)
|
|
112
88
|
datas_validas = [
|
|
113
89
|
d for d in serie_datas if d is not None and data_negociacao_valida(d)
|
|
@@ -115,54 +91,65 @@ def _buscar_varias_datas(
|
|
|
115
91
|
if not datas_validas:
|
|
116
92
|
return pl.DataFrame()
|
|
117
93
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
resultados.append(df_cache)
|
|
124
|
-
|
|
125
|
-
# Identifica datas que não vieram do cache
|
|
126
|
-
datas_no_cache: set[dt.date] = set()
|
|
127
|
-
for df in resultados:
|
|
128
|
-
datas_no_cache.update(df["data_referencia"].unique().to_list())
|
|
129
|
-
datas_faltantes = [d for d in datas_validas if d not in datas_no_cache]
|
|
130
|
-
|
|
131
|
-
# Fallback individual apenas para datas faltantes
|
|
132
|
-
for data in datas_faltantes:
|
|
133
|
-
df = _buscar_por_fonte(data, codigos, full_report)
|
|
134
|
-
if not df.is_empty():
|
|
135
|
-
resultados.append(df)
|
|
94
|
+
resultados = [
|
|
95
|
+
df
|
|
96
|
+
for codigo in codigos
|
|
97
|
+
if not (df := historical._obter_futuros_pr(datas_validas, codigo)).is_empty()
|
|
98
|
+
]
|
|
136
99
|
|
|
137
100
|
if not resultados:
|
|
138
101
|
return pl.DataFrame()
|
|
139
102
|
return pl.concat(resultados, how="diagonal_relaxed")
|
|
140
103
|
|
|
141
104
|
|
|
142
|
-
def
|
|
143
|
-
|
|
144
|
-
codigos: list[str],
|
|
145
|
-
full_report: bool | None,
|
|
105
|
+
def futures_intraday(
|
|
106
|
+
contract_code: str | list[str],
|
|
146
107
|
) -> pl.DataFrame:
|
|
147
|
-
"""
|
|
148
|
-
if full_report is not None or data != clock.today():
|
|
149
|
-
return historical.historical(data, codigos, full_report)
|
|
108
|
+
"""Busca dados intraday de contratos futuros da B3.
|
|
150
109
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
110
|
+
Retorna os dados mais recentes do pregão corrente, com atraso
|
|
111
|
+
aproximado de 15 minutos. Para dados históricos consolidados,
|
|
112
|
+
use ``futures``.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
contract_code: Código do contrato futuro na B3 ou lista de
|
|
116
|
+
códigos (ex.: 'DI1', ['DI1', 'DAP']).
|
|
158
117
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
118
|
+
Returns:
|
|
119
|
+
DataFrame Polars com dados intraday. Retorna DataFrame vazio
|
|
120
|
+
fora do horário de pregão.
|
|
121
|
+
|
|
122
|
+
Output Columns:
|
|
123
|
+
* data_referencia (Date): data de negociação.
|
|
124
|
+
* atualizado_as (Datetime): horário a que o dado se refere
|
|
125
|
+
(com atraso de ~15 min).
|
|
126
|
+
* codigo_negociacao (String): código de negociação na B3.
|
|
127
|
+
* data_vencimento (Date): data de vencimento do contrato.
|
|
128
|
+
* dias_uteis (Int64): dias úteis até o vencimento.
|
|
129
|
+
* dias_corridos (Int64): dias corridos até o vencimento.
|
|
130
|
+
* contratos_abertos (Int64): contratos em aberto.
|
|
131
|
+
* numero_negocios (Int64): número de negócios.
|
|
132
|
+
* volume_negociado (Int64): quantidade de contratos negociados.
|
|
133
|
+
* volume_financeiro (Float64): volume financeiro bruto.
|
|
134
|
+
* dv01 (Float64): variação no preço para 1bp (apenas DI1).
|
|
135
|
+
* preco_ultimo (Float64): último preço (apenas DI1/DAP).
|
|
136
|
+
* taxa_ajuste_anterior (Float64): taxa de ajuste do dia anterior.
|
|
137
|
+
* taxa_limite_minimo (Float64): limite mínimo de variação.
|
|
138
|
+
* taxa_limite_maximo (Float64): limite máximo de variação.
|
|
139
|
+
* taxa_abertura (Float64): taxa de abertura.
|
|
140
|
+
* taxa_minima (Float64): taxa mínima negociada.
|
|
141
|
+
* taxa_media (Float64): taxa média negociada.
|
|
142
|
+
* taxa_maxima (Float64): taxa máxima negociada.
|
|
143
|
+
* taxa_oferta_compra (Float64): melhor oferta de compra.
|
|
144
|
+
* taxa_oferta_venda (Float64): melhor oferta de venda.
|
|
145
|
+
* taxa_ultima (Float64): última taxa negociada.
|
|
146
|
+
* taxa_forward (Float64): taxa a termo (apenas DI1/DAP).
|
|
147
|
+
"""
|
|
148
|
+
codigos = normalizar_codigos_contrato(contract_code)
|
|
149
|
+
if not codigos:
|
|
150
|
+
return pl.DataFrame()
|
|
164
151
|
|
|
165
|
-
return
|
|
152
|
+
return intraday.intraday(codigos)
|
|
166
153
|
|
|
167
154
|
|
|
168
155
|
def available_dates(contract_code: str) -> pl.Series:
|
|
@@ -188,4 +175,4 @@ def available_dates(contract_code: str) -> pl.Series:
|
|
|
188
175
|
return historical.listar_datas_disponiveis(contract_code)
|
|
189
176
|
|
|
190
177
|
|
|
191
|
-
__all__ = ["available_dates", "futures"]
|
|
178
|
+
__all__ = ["available_dates", "futures", "futures_intraday"]
|
|
@@ -6,7 +6,6 @@ from pyield import bday
|
|
|
6
6
|
from pyield._internal.data_cache import obter_dataset_cacheado
|
|
7
7
|
from pyield.b3._contracts import normalizar_codigos_contrato
|
|
8
8
|
from pyield.b3.futures.common import adicionar_vencimento, expr_dv01
|
|
9
|
-
from pyield.b3.price_report import fetch_price_report
|
|
10
9
|
from pyield.fwd import forwards
|
|
11
10
|
|
|
12
11
|
# Lista de contratos que negociam por taxa (juros/cupom).
|
|
@@ -63,16 +62,12 @@ def _obter_pr_normalizado() -> pl.DataFrame:
|
|
|
63
62
|
def historical(
|
|
64
63
|
data: dt.date,
|
|
65
64
|
codigo_contrato: str | list[str],
|
|
66
|
-
full_report: bool | None = None,
|
|
67
65
|
) -> pl.DataFrame:
|
|
68
|
-
"""Busca histórico de futuros
|
|
66
|
+
"""Busca histórico de futuros no dataset PR cacheado.
|
|
69
67
|
|
|
70
68
|
Args:
|
|
71
69
|
data: Data de negociação.
|
|
72
70
|
codigo_contrato: Código(s) do contrato futuro na B3.
|
|
73
|
-
full_report: Se None (padrão), tenta SPR primeiro e PR como fallback.
|
|
74
|
-
Se False, usa o simplified price report (SPR, ~2 KB).
|
|
75
|
-
Se True, usa o price report completo (PR, ~2 MB).
|
|
76
71
|
|
|
77
72
|
Returns:
|
|
78
73
|
DataFrame Polars com dados históricos de futuros.
|
|
@@ -115,6 +110,9 @@ def historical(
|
|
|
115
110
|
* taxa_forward (Float64): taxa a termo (apenas DI1/DAP).
|
|
116
111
|
|
|
117
112
|
Notes:
|
|
113
|
+
Usa exclusivamente o dataset PR cacheado no GitHub. Contratos
|
|
114
|
+
disponíveis: DI1, DDI, FRC, FRO, DAP, DOL, WDO, IND, WIN.
|
|
115
|
+
|
|
118
116
|
As colunas com prefixo ``preco_`` aparecem para contratos cotados por
|
|
119
117
|
preço (ex.: DOL, IND). As com prefixo ``taxa_`` aparecem para contratos
|
|
120
118
|
cotados por taxa (ex.: DI1, DAP, DDI, FRC, FRO). Nem todas as colunas
|
|
@@ -131,28 +129,11 @@ def historical(
|
|
|
131
129
|
if not codigos:
|
|
132
130
|
return pl.DataFrame()
|
|
133
131
|
|
|
134
|
-
dataframes
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if df_cache.is_empty():
|
|
140
|
-
codigos_sem_cache.append(codigo)
|
|
141
|
-
else:
|
|
142
|
-
dataframes.append(df_cache)
|
|
143
|
-
|
|
144
|
-
if codigos_sem_cache:
|
|
145
|
-
for codigo in codigos_sem_cache:
|
|
146
|
-
df_bruto = _buscar_price_report(data, codigo, full_report)
|
|
147
|
-
if df_bruto.is_empty():
|
|
148
|
-
continue
|
|
149
|
-
|
|
150
|
-
df_bruto = adicionar_vencimento(df_bruto, codigo, "codigo_negociacao")
|
|
151
|
-
df = _enriquecer_dados(df_bruto, codigo)
|
|
152
|
-
df_saida = _selecionar_colunas_saida(df)
|
|
153
|
-
if "data_vencimento" in df_saida.columns:
|
|
154
|
-
df_saida = df_saida.sort("data_vencimento")
|
|
155
|
-
dataframes.append(df_saida)
|
|
132
|
+
dataframes = [
|
|
133
|
+
df
|
|
134
|
+
for codigo in codigos
|
|
135
|
+
if not (df := _obter_futuros_pr([data], codigo)).is_empty()
|
|
136
|
+
]
|
|
156
137
|
|
|
157
138
|
if not dataframes:
|
|
158
139
|
return pl.DataFrame()
|
|
@@ -202,31 +183,6 @@ def listar_datas_disponiveis(codigo_contrato: str) -> pl.Series:
|
|
|
202
183
|
)
|
|
203
184
|
|
|
204
185
|
|
|
205
|
-
def _buscar_price_report(
|
|
206
|
-
data: dt.date, codigo: str, full_report: bool | None
|
|
207
|
-
) -> pl.DataFrame:
|
|
208
|
-
"""Busca o price report da B3, com fallback SPR→PR.
|
|
209
|
-
|
|
210
|
-
Quando full_report é True, usa apenas o PR (completo).
|
|
211
|
-
Nos demais casos (None ou False), tenta o SPR (leve) primeiro
|
|
212
|
-
e faz fallback para o PR se o SPR estiver vazio.
|
|
213
|
-
"""
|
|
214
|
-
if full_report is True:
|
|
215
|
-
return _normalizar_colunas_pr(
|
|
216
|
-
fetch_price_report(date=data, contract_code=codigo, full_report=True)
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
# SPR (leve) primeiro; PR (pesado) como fallback
|
|
220
|
-
df = _normalizar_colunas_pr(
|
|
221
|
-
fetch_price_report(date=data, contract_code=codigo, full_report=False)
|
|
222
|
-
)
|
|
223
|
-
if not df.is_empty():
|
|
224
|
-
return df
|
|
225
|
-
return _normalizar_colunas_pr(
|
|
226
|
-
fetch_price_report(date=data, contract_code=codigo, full_report=True)
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
|
|
230
186
|
def _filtrar_e_renomear(
|
|
231
187
|
df: pl.DataFrame, datas: list[dt.date], codigo_contrato: str
|
|
232
188
|
) -> pl.DataFrame:
|
|
@@ -102,30 +102,18 @@ def _baixar_zip_url(data: dt.date, relatorio_completo: bool) -> bytes:
|
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
def _extrair_xml_de_zip(conteudo_zip: bytes) -> bytes:
|
|
105
|
-
"""Extrai o XML
|
|
105
|
+
"""Extrai o XML do ZIP aninhado da B3 (ZIP externo → ZIP interno → XML)."""
|
|
106
106
|
with zipfile.ZipFile(io.BytesIO(conteudo_zip), "r") as zip_externo:
|
|
107
|
-
|
|
108
|
-
if not
|
|
107
|
+
nomes = zip_externo.namelist()
|
|
108
|
+
if not nomes:
|
|
109
109
|
raise ValueError("ZIP externo está vazio")
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
for nome in nomes_externos:
|
|
118
|
-
conteudo_interno = zip_externo.read(nome)
|
|
119
|
-
if conteudo_interno[:4] != b"PK\x03\x04":
|
|
120
|
-
continue
|
|
121
|
-
with zipfile.ZipFile(io.BytesIO(conteudo_interno), "r") as zip_interno:
|
|
122
|
-
nomes_xml = sorted(
|
|
123
|
-
n for n in zip_interno.namelist() if n.endswith(".xml")
|
|
124
|
-
)
|
|
125
|
-
if nomes_xml:
|
|
126
|
-
return zip_interno.read(nomes_xml[-1])
|
|
127
|
-
|
|
128
|
-
raise ValueError("Nenhum XML encontrado no ZIP")
|
|
111
|
+
conteudo_interno = zip_externo.read(nomes[0])
|
|
112
|
+
with zipfile.ZipFile(io.BytesIO(conteudo_interno), "r") as zip_interno:
|
|
113
|
+
nomes_xml = sorted(n for n in zip_interno.namelist() if n.endswith(".xml"))
|
|
114
|
+
if not nomes_xml:
|
|
115
|
+
raise ValueError("Nenhum XML encontrado no ZIP interno")
|
|
116
|
+
return zip_interno.read(nomes_xml[-1])
|
|
129
117
|
|
|
130
118
|
|
|
131
119
|
def _ticker_valido_para_contrato(ticker: str, codigo_contrato: str) -> bool:
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.46.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|