pyield 0.47.2__tar.gz → 0.47.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.
- {pyield-0.47.2 → pyield-0.47.4}/PKG-INFO +9 -10
- {pyield-0.47.2 → pyield-0.47.4}/README.md +8 -9
- pyield-0.47.4/pyield/__about__.py +1 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/price_report.py +138 -114
- pyield-0.47.2/pyield/__about__.py +0 -1
- {pyield-0.47.2 → pyield-0.47.4}/.gitignore +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/LICENSE +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/_internal/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/_internal/br_numbers.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/_internal/cache.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/_internal/converters.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/_internal/data_cache.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/_internal/retry.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/_internal/types.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/anbima/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/anbima/ettj_intraday.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/anbima/ettj_last.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/anbima/ima.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/anbima/imaq.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/anbima/tpf.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/_contracts.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/_validar_pregao.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/derivatives_intraday.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/di1.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/di_over.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/futures/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/futures/common.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/auction.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/copom.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/ptax_api.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/rates.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/repo.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bc/vna.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bday/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bday/core.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bday/holidays/br_holidays_new.txt +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bday/holidays/br_holidays_old.txt +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/bday/holidays/brholidays.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/clock.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/fwd.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/interpolator.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/ipca/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/ipca/historical.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/ipca/projected.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/py.typed +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/rmd.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/selic/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/selic/cpm.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/selic/probabilities.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/__init__.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/auctions.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/benchmark.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/lft.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/ltn.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/ntnb.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/ntnb1.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/ntnbprinc.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/ntnc.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/ntnf.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/pre.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyield/tn/utils.py +0 -0
- {pyield-0.47.2 → pyield-0.47.4}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyield
|
|
3
|
-
Version: 0.47.
|
|
3
|
+
Version: 0.47.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
|
|
@@ -206,23 +206,22 @@ ntnf.di_spreads("30-05-2025", bps=True)
|
|
|
206
206
|
## Dados de Futuros
|
|
207
207
|
|
|
208
208
|
```python
|
|
209
|
-
from pyield import futures
|
|
209
|
+
from pyield import futures, futures_intraday
|
|
210
210
|
|
|
211
211
|
# DI1 (Futuro de Depósito Interfinanceiro)
|
|
212
212
|
futures("31-05-2024", "DI1")
|
|
213
213
|
|
|
214
|
-
# Outros contratos disponíveis:
|
|
215
|
-
# - Juros: DI1, DDI,
|
|
216
|
-
# - Moedas: DOL, WDO
|
|
217
|
-
# - Índices: IND, WIN
|
|
218
|
-
# - Commodities: BGI, CCM, ICF, CNL, SJC, SOY, ETH, GLD
|
|
214
|
+
# Outros contratos disponíveis no cache histórico:
|
|
215
|
+
# - Juros: DI1, DDI, FRC, FRO, DAP
|
|
216
|
+
# - Moedas: DOL, WDO
|
|
217
|
+
# - Índices: IND, WIN
|
|
219
218
|
futures("31-05-2024", "DAP")
|
|
220
219
|
|
|
221
|
-
#
|
|
222
|
-
futures("
|
|
220
|
+
# Múltiplas datas de uma vez
|
|
221
|
+
futures(["29-05-2024", "31-05-2024"], "DI1")
|
|
223
222
|
|
|
224
223
|
# Dados intradiários (quando o mercado estiver aberto)
|
|
225
|
-
|
|
224
|
+
futures_intraday("DI1") # Retorna dados ao vivo durante o horário de negociação
|
|
226
225
|
```
|
|
227
226
|
|
|
228
227
|
## Tratamento de Datas
|
|
@@ -162,23 +162,22 @@ ntnf.di_spreads("30-05-2025", bps=True)
|
|
|
162
162
|
## Dados de Futuros
|
|
163
163
|
|
|
164
164
|
```python
|
|
165
|
-
from pyield import futures
|
|
165
|
+
from pyield import futures, futures_intraday
|
|
166
166
|
|
|
167
167
|
# DI1 (Futuro de Depósito Interfinanceiro)
|
|
168
168
|
futures("31-05-2024", "DI1")
|
|
169
169
|
|
|
170
|
-
# Outros contratos disponíveis:
|
|
171
|
-
# - Juros: DI1, DDI,
|
|
172
|
-
# - Moedas: DOL, WDO
|
|
173
|
-
# - Índices: IND, WIN
|
|
174
|
-
# - Commodities: BGI, CCM, ICF, CNL, SJC, SOY, ETH, GLD
|
|
170
|
+
# Outros contratos disponíveis no cache histórico:
|
|
171
|
+
# - Juros: DI1, DDI, FRC, FRO, DAP
|
|
172
|
+
# - Moedas: DOL, WDO
|
|
173
|
+
# - Índices: IND, WIN
|
|
175
174
|
futures("31-05-2024", "DAP")
|
|
176
175
|
|
|
177
|
-
#
|
|
178
|
-
futures("
|
|
176
|
+
# Múltiplas datas de uma vez
|
|
177
|
+
futures(["29-05-2024", "31-05-2024"], "DI1")
|
|
179
178
|
|
|
180
179
|
# Dados intradiários (quando o mercado estiver aberto)
|
|
181
|
-
|
|
180
|
+
futures_intraday("DI1") # Retorna dados ao vivo durante o horário de negociação
|
|
182
181
|
```
|
|
183
182
|
|
|
184
183
|
## Tratamento de Datas
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.47.4"
|
|
@@ -1,34 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exemplo de trecho do XML bruto da B3:
|
|
3
|
+
<PricRpt>
|
|
4
|
+
<TradDt>
|
|
5
|
+
<Dt>2026-04-01</Dt>
|
|
6
|
+
</TradDt>
|
|
7
|
+
<SctyId>
|
|
8
|
+
<TckrSymb>DI1F31</TckrSymb>
|
|
9
|
+
</SctyId>
|
|
10
|
+
<FinInstrmId>
|
|
11
|
+
<OthrId>
|
|
12
|
+
<Id>200000235664</Id>
|
|
13
|
+
<Tp>
|
|
14
|
+
<Prtry>8</Prtry>
|
|
15
|
+
</Tp>
|
|
16
|
+
</OthrId>
|
|
17
|
+
<PlcOfListg>
|
|
18
|
+
<MktIdrCd>BVMF</MktIdrCd>
|
|
19
|
+
</PlcOfListg>
|
|
20
|
+
</FinInstrmId>
|
|
21
|
+
<TradDtls>
|
|
22
|
+
<TradQty>29880</TradQty>
|
|
23
|
+
</TradDtls>
|
|
24
|
+
<FinInstrmAttrbts>
|
|
25
|
+
<MktDataStrmId>E</MktDataStrmId>
|
|
26
|
+
...
|
|
27
|
+
<MinTradLmt Ccy="BRL">12.87</MinTradLmt>
|
|
28
|
+
</FinInstrmAttrbts>
|
|
29
|
+
</PricRpt>
|
|
30
|
+
"""
|
|
31
|
+
|
|
1
32
|
import datetime as dt
|
|
2
33
|
import io
|
|
3
|
-
import
|
|
34
|
+
import re
|
|
4
35
|
import zipfile
|
|
5
|
-
from functools import lru_cache
|
|
6
36
|
|
|
7
37
|
import polars as pl
|
|
8
38
|
import requests
|
|
9
39
|
from lxml import etree
|
|
10
|
-
from lxml.etree import _Element
|
|
11
40
|
|
|
12
41
|
import pyield._internal.converters as cv
|
|
42
|
+
from pyield._internal.cache import ttl_cache
|
|
13
43
|
from pyield._internal.retry import retry_padrao
|
|
14
44
|
from pyield._internal.types import DateLike, any_is_empty
|
|
15
45
|
from pyield.b3._contracts import normalizar_codigos_contrato
|
|
16
46
|
from pyield.b3._validar_pregao import data_negociacao_valida
|
|
17
47
|
|
|
18
|
-
registro = logging.getLogger(__name__)
|
|
19
|
-
|
|
20
48
|
# --- Constantes de Processamento XML ---
|
|
21
49
|
NAMESPACE_B3 = "urn:bvmf.217.01.xsd"
|
|
22
50
|
NAMESPACES = {"ns": NAMESPACE_B3}
|
|
23
51
|
# ZIP válido do price report ~2KB; 1KB detecta arquivos "sem dados"
|
|
24
52
|
MIN_TAMANHO_ZIP_BYTES = 1024
|
|
25
|
-
|
|
26
|
-
XPATH_DATA_NEGOCIACAO = ".//ns:TradDt/ns:Dt"
|
|
27
|
-
XPATH_ATRIBUTOS_INSTRUMENTO = ".//ns:FinInstrmAttrbts"
|
|
28
|
-
XPATH_DETALHES_NEGOCIO = ".//ns:TradDtls"
|
|
53
|
+
XPATH_PRICE_REPORT = "//ns:PricRpt"
|
|
29
54
|
|
|
30
55
|
# --- Mapeamento de Colunas ---
|
|
31
|
-
|
|
32
56
|
# Estrutura: (id_pdf, nome_xml, tipo_polars)
|
|
33
57
|
# Esta camada base preserva os nomes originais do XML da B3.
|
|
34
58
|
# https://www.b3.com.br/data/files/16/70/29/9C/6219D710C8F297D7AC094EA8/Catalogo_precos_v1.3.pdf
|
|
@@ -74,10 +98,11 @@ COLUNAS_PRICE_REPORT: list[tuple[str, str, type[pl.DataType]]] = [
|
|
|
74
98
|
("5.32", "MinTradLmt", pl.Float64),
|
|
75
99
|
]
|
|
76
100
|
|
|
77
|
-
#
|
|
78
|
-
|
|
101
|
+
# Schema completo: nome_xml → tipo_polars. Garante ordem e tipagem constante.
|
|
102
|
+
SCHEMA_PRICE_REPORT = {nome: tipo for _, nome, tipo in COLUNAS_PRICE_REPORT}
|
|
79
103
|
|
|
80
104
|
|
|
105
|
+
@ttl_cache()
|
|
81
106
|
@retry_padrao
|
|
82
107
|
def _baixar_zip_url(data: dt.date, relatorio_completo: bool) -> bytes:
|
|
83
108
|
data_str = data.strftime("%y%m%d")
|
|
@@ -124,42 +149,51 @@ def price_report_extract(conteudo_zip: bytes) -> bytes:
|
|
|
124
149
|
return zip_interno.read(nomes_xml[-1])
|
|
125
150
|
|
|
126
151
|
|
|
127
|
-
def _extrair_dados_contrato(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if pai is None:
|
|
132
|
-
return None
|
|
133
|
-
registro_pregao = pai.getparent()
|
|
134
|
-
if registro_pregao is None:
|
|
135
|
-
return None
|
|
136
|
-
elemento_data = registro_pregao.find(XPATH_DATA_NEGOCIACAO, NAMESPACES)
|
|
137
|
-
if elemento_data is None:
|
|
138
|
-
return None
|
|
152
|
+
def _extrair_dados_contrato(pric_rpt: etree._Element) -> dict | None:
|
|
153
|
+
dados = {}
|
|
154
|
+
tem_ticker = False
|
|
155
|
+
tem_data = False
|
|
139
156
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
157
|
+
for elem in pric_rpt.iter():
|
|
158
|
+
text = elem.text
|
|
159
|
+
if not text:
|
|
160
|
+
continue
|
|
144
161
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
tag = elem.tag
|
|
163
|
+
if tag[0] == "{":
|
|
164
|
+
tag = tag[tag.find("}") + 1 :]
|
|
148
165
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
# 🔑 obrigatórios primeiro
|
|
167
|
+
if tag == "TckrSymb":
|
|
168
|
+
dados["TckrSymb"] = text
|
|
169
|
+
tem_ticker = True
|
|
170
|
+
continue
|
|
154
171
|
|
|
155
|
-
|
|
172
|
+
if tag == "Dt":
|
|
173
|
+
pai = elem.getparent()
|
|
174
|
+
if pai is None:
|
|
175
|
+
continue
|
|
156
176
|
|
|
177
|
+
parent = pai.tag
|
|
178
|
+
if parent[0] == "{":
|
|
179
|
+
parent = parent[parent.find("}") + 1 :]
|
|
157
180
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
181
|
+
if parent == "TradDt":
|
|
182
|
+
dados["TradDt"] = text
|
|
183
|
+
tem_data = True
|
|
184
|
+
continue
|
|
185
|
+
|
|
186
|
+
# ⚡ resto
|
|
187
|
+
if tag in SCHEMA_PRICE_REPORT:
|
|
188
|
+
dados[tag] = text
|
|
189
|
+
|
|
190
|
+
if not tem_ticker or not tem_data:
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
return dados
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _parsear_xml_registros(xml_bytes: bytes) -> list[dict]:
|
|
163
197
|
analisador = etree.XMLParser(
|
|
164
198
|
ns_clean=True,
|
|
165
199
|
remove_blank_text=True,
|
|
@@ -169,72 +203,65 @@ def _parsear_xml_registros(
|
|
|
169
203
|
no_network=True,
|
|
170
204
|
load_dtd=False,
|
|
171
205
|
)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if not elementos_ticker:
|
|
182
|
-
return []
|
|
183
|
-
|
|
184
|
-
registros = []
|
|
185
|
-
for elemento in elementos_ticker:
|
|
186
|
-
if not isinstance(elemento, etree._Element):
|
|
187
|
-
continue
|
|
188
|
-
dados_contrato = _extrair_dados_contrato(elemento)
|
|
189
|
-
if dados_contrato is not None:
|
|
190
|
-
ticker = dados_contrato["TckrSymb"]
|
|
191
|
-
if comprimento_ticker is None or len(ticker) == comprimento_ticker:
|
|
192
|
-
registros.append(dados_contrato)
|
|
206
|
+
arvore = etree.parse(io.BytesIO(xml_bytes), parser=analisador)
|
|
207
|
+
resultado = arvore.xpath(XPATH_PRICE_REPORT, namespaces=NAMESPACES)
|
|
208
|
+
elementos: list[etree._Element] = resultado # type: ignore[assignment]
|
|
209
|
+
registros = [
|
|
210
|
+
dados
|
|
211
|
+
for pric_rpt in elementos
|
|
212
|
+
if (dados := _extrair_dados_contrato(pric_rpt)) is not None
|
|
213
|
+
]
|
|
193
214
|
return registros
|
|
194
215
|
|
|
195
216
|
|
|
196
217
|
def _converter_para_df(registros: list[dict]) -> pl.DataFrame:
|
|
197
218
|
df = pl.DataFrame(registros)
|
|
198
219
|
# Casting usa os nomes originais do XML, que são constantes
|
|
199
|
-
tipos_coluna = {k: v for k, v in
|
|
200
|
-
|
|
220
|
+
tipos_coluna = {k: v for k, v in SCHEMA_PRICE_REPORT.items() if k in df.columns}
|
|
221
|
+
df = df.cast(tipos_coluna, strict=False) # type: ignore
|
|
222
|
+
# Adiciona colunas ausentes com null e garante ordem/schema constante
|
|
223
|
+
colunas_faltantes = {
|
|
224
|
+
nome: pl.lit(None).cast(tipo)
|
|
225
|
+
for nome, tipo in SCHEMA_PRICE_REPORT.items()
|
|
226
|
+
if nome not in df.columns
|
|
227
|
+
}
|
|
228
|
+
if colunas_faltantes:
|
|
229
|
+
df = df.with_columns(**colunas_faltantes)
|
|
230
|
+
return df.select(SCHEMA_PRICE_REPORT.keys())
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _processar_xml_extraido(xml_bytes: bytes) -> pl.DataFrame:
|
|
234
|
+
registros = _parsear_xml_registros(xml_bytes)
|
|
235
|
+
if not registros:
|
|
236
|
+
return pl.DataFrame()
|
|
237
|
+
return _converter_para_df(registros).sort("TckrSymb")
|
|
201
238
|
|
|
202
239
|
|
|
203
|
-
def
|
|
204
|
-
|
|
205
|
-
|
|
240
|
+
def _filtrar_df(
|
|
241
|
+
df: pl.DataFrame,
|
|
242
|
+
prefixos: list[str],
|
|
206
243
|
comprimento_ticker: int | None = None,
|
|
207
244
|
) -> pl.DataFrame:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return pl.DataFrame()
|
|
215
|
-
|
|
216
|
-
df = _converter_para_df(registros)
|
|
245
|
+
ticker = pl.col("TckrSymb")
|
|
246
|
+
if comprimento_ticker:
|
|
247
|
+
df = df.filter(ticker.str.len_chars() == comprimento_ticker)
|
|
248
|
+
if prefixos:
|
|
249
|
+
padrao = f"^({'|'.join(re.escape(prefixo) for prefixo in prefixos)})"
|
|
250
|
+
df = df.filter(ticker.str.contains(padrao))
|
|
217
251
|
return df.sort("TckrSymb")
|
|
218
252
|
|
|
219
253
|
|
|
220
|
-
|
|
221
|
-
def _obter_xml_price_report(data: dt.date, relatorio_completo: bool) -> bytes:
|
|
254
|
+
def _obter_df_price_report(data: dt.date, relatorio_completo: bool) -> pl.DataFrame:
|
|
222
255
|
dados_zip = _baixar_zip_url(data, relatorio_completo)
|
|
223
256
|
if not dados_zip:
|
|
224
|
-
return
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
except zipfile.BadZipFile:
|
|
228
|
-
registro.warning("ZIP corrompido na transmissão, re-baixando...")
|
|
229
|
-
dados_zip = _baixar_zip_url(data, relatorio_completo)
|
|
230
|
-
if not dados_zip:
|
|
231
|
-
return bytes()
|
|
232
|
-
return price_report_extract(dados_zip)
|
|
257
|
+
return pl.DataFrame()
|
|
258
|
+
xml_bytes = price_report_extract(dados_zip)
|
|
259
|
+
return _processar_xml_extraido(xml_bytes)
|
|
233
260
|
|
|
234
261
|
|
|
235
262
|
def price_report_fetch(
|
|
236
263
|
date: DateLike,
|
|
237
|
-
ticker_prefix: str | list[str],
|
|
264
|
+
ticker_prefix: str | list[str] | None = None,
|
|
238
265
|
ticker_length: int | None = None,
|
|
239
266
|
full_report: bool = False,
|
|
240
267
|
) -> pl.DataFrame:
|
|
@@ -259,7 +286,8 @@ def price_report_fetch(
|
|
|
259
286
|
'YYYY-MM-DD' ou objeto datetime.date.
|
|
260
287
|
ticker_prefix: Prefixo do ticker B3 (ex.: 'DI1', 'DOL',
|
|
261
288
|
'CPM') ou lista de prefixos (ex.: ['DI1', 'DAP']).
|
|
262
|
-
Usado como filtro starts-with no XML.
|
|
289
|
+
Usado como filtro starts-with no XML. Se None (padrão),
|
|
290
|
+
retorna todos os ativos sem filtro.
|
|
263
291
|
ticker_length: Comprimento exato do ticker para filtrar registros.
|
|
264
292
|
Se None (padrão), retorna todos os tickers que casam com o
|
|
265
293
|
prefixo (ex.: 6 para futuros, 13 para opções).
|
|
@@ -286,10 +314,8 @@ def price_report_fetch(
|
|
|
286
314
|
* IntlFinVol (Float64): volume financeiro internacional.
|
|
287
315
|
* OpnIntrst (Int64): contratos em aberto.
|
|
288
316
|
* FinInstrmQty (Int64): quantidade negociada de instrumentos financeiros.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
* BestAskPric (Float64): ultima melhor oferta de venda no snapshot
|
|
292
|
-
diario; pode ser nulo.
|
|
317
|
+
* BestBidPric (Float64): ultima melhor oferta de compra no snapshot diario; pode ser nulo.
|
|
318
|
+
* BestAskPric (Float64): ultima melhor oferta de venda no snapshot diario; pode ser nulo. diario; pode ser nulo.
|
|
293
319
|
* FrstPric (Float64): preço de abertura.
|
|
294
320
|
* MinPric (Float64): preço mínimo negociado.
|
|
295
321
|
* MaxPric (Float64): preço máximo negociado.
|
|
@@ -333,8 +359,7 @@ def price_report_fetch(
|
|
|
333
359
|
>>> df.is_empty()
|
|
334
360
|
True
|
|
335
361
|
"""
|
|
336
|
-
|
|
337
|
-
if any_is_empty(date) or not prefixos:
|
|
362
|
+
if any_is_empty(date):
|
|
338
363
|
return pl.DataFrame()
|
|
339
364
|
|
|
340
365
|
date = cv.converter_datas(date)
|
|
@@ -342,20 +367,19 @@ def price_report_fetch(
|
|
|
342
367
|
if not data_negociacao_valida(date):
|
|
343
368
|
return pl.DataFrame()
|
|
344
369
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if not dataframes:
|
|
370
|
+
df = _obter_df_price_report(date, full_report)
|
|
371
|
+
if df.is_empty() or ticker_prefix is None:
|
|
372
|
+
return df
|
|
373
|
+
|
|
374
|
+
prefixos = normalizar_codigos_contrato(ticker_prefix)
|
|
375
|
+
if not prefixos:
|
|
352
376
|
return pl.DataFrame()
|
|
353
|
-
return
|
|
377
|
+
return _filtrar_df(df, prefixos, ticker_length)
|
|
354
378
|
|
|
355
379
|
|
|
356
380
|
def price_report_read(
|
|
357
381
|
xml_bytes: bytes,
|
|
358
|
-
ticker_prefix: str | list[str],
|
|
382
|
+
ticker_prefix: str | list[str] | None = None,
|
|
359
383
|
ticker_length: int | None = None,
|
|
360
384
|
) -> pl.DataFrame:
|
|
361
385
|
"""Lê e processa o price report da B3 a partir do conteúdo XML bruto.
|
|
@@ -367,6 +391,7 @@ def price_report_read(
|
|
|
367
391
|
xml_bytes: Conteúdo do XML em bytes (já descomprimido).
|
|
368
392
|
ticker_prefix: Prefixo do ticker B3 (ex.: 'DI1', 'DOL',
|
|
369
393
|
'CPM') ou lista de prefixos (ex.: ['DI1', 'DAP']).
|
|
394
|
+
Se None (padrão), retorna todos os ativos sem filtro.
|
|
370
395
|
ticker_length: Comprimento exato do ticker para filtrar registros.
|
|
371
396
|
Se None (padrão), retorna todos os tickers que casam com o
|
|
372
397
|
prefixo.
|
|
@@ -375,15 +400,14 @@ def price_report_read(
|
|
|
375
400
|
pl.DataFrame: DataFrame com as mesmas colunas documentadas em
|
|
376
401
|
:func:`price_report_fetch`.
|
|
377
402
|
"""
|
|
378
|
-
|
|
379
|
-
if any_is_empty(xml_bytes) or not prefixos:
|
|
403
|
+
if any_is_empty(xml_bytes):
|
|
380
404
|
return pl.DataFrame()
|
|
381
405
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
df
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if not
|
|
406
|
+
df = _processar_xml_extraido(xml_bytes)
|
|
407
|
+
if df.is_empty() or ticker_prefix is None:
|
|
408
|
+
return df
|
|
409
|
+
|
|
410
|
+
prefixos = normalizar_codigos_contrato(ticker_prefix)
|
|
411
|
+
if not prefixos:
|
|
388
412
|
return pl.DataFrame()
|
|
389
|
-
return
|
|
413
|
+
return _filtrar_df(df, prefixos, ticker_length)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.47.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
|
|
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
|