pyield 0.53.0__tar.gz → 0.53.1__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.53.0 → pyield-0.53.1}/PKG-INFO +1 -1
- pyield-0.53.1/pyield/tpf/secundario/__init__.py +19 -0
- pyield-0.53.1/pyield/tpf/secundario/_intradia.py +139 -0
- pyield-0.53.0/pyield/tpf/secundario.py → pyield-0.53.1/pyield/tpf/secundario/_mensal.py +46 -146
- {pyield-0.53.0 → pyield-0.53.1}/pyproject.toml +1 -1
- {pyield-0.53.0 → pyield-0.53.1}/LICENSE +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/README.md +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/_internal/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/_internal/br_numbers.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/_internal/cache.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/_internal/converters.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/_internal/data_cache.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/_internal/retry.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/_internal/types.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/anbima/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/anbima/imaq.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/anbima/mercado_secundario.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/b3/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/b3/_contratos.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/b3/_validar_pregao.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/b3/boletim.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/b3/derivativos_intradia.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/b3/di_over.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/bc/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/bc/_olinda.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/bc/leiloes.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/bc/lft.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/bc/sgs.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/du/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/du/core.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/du/feriados/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/du/feriados/feriados_antigos_br.txt +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/du/feriados/feriados_br.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/du/feriados/feriados_novos_br.txt +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/futuro/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/futuro/contratos.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/futuro/di1.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/futuro/historico.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/futuro/intradia.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/fwd.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/interpolador.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/ipca/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/ipca/historico.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/ipca/projetado.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/py.typed +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/relogio.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/selic/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/selic/compromissada.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/selic/copom.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/selic/cpm.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/selic/probabilities.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/lft.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/ltn.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/ntnb.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/ntnb1.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/ntnbprinc.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/ntnc.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/_titulos/ntnf.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/benchmark.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/leiloes.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/pre.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/rmd/__init__.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/rmd/_aba_1_3.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/rmd/_aba_2_1.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/rmd/_common.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/rmd/_download.py +0 -0
- {pyield-0.53.0 → pyield-0.53.1}/pyield/tpf/utils.py +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Negociações do mercado secundário de TPFs no sistema Selic do BCB."""
|
|
2
|
+
|
|
3
|
+
from pyield.tpf.secundario._intradia import intradia as intradia
|
|
4
|
+
from pyield.tpf.secundario._mensal import baixar_zip as baixar_zip
|
|
5
|
+
from pyield.tpf.secundario._mensal import ler_zip as ler_zip
|
|
6
|
+
from pyield.tpf.secundario._mensal import mensal as mensal
|
|
7
|
+
from pyield.tpf.secundario._mensal import (
|
|
8
|
+
nome_arquivo_mensal as nome_arquivo_mensal,
|
|
9
|
+
)
|
|
10
|
+
from pyield.tpf.secundario._mensal import zip_para_silver as zip_para_silver
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"baixar_zip",
|
|
14
|
+
"intradia",
|
|
15
|
+
"ler_zip",
|
|
16
|
+
"mensal",
|
|
17
|
+
"nome_arquivo_mensal",
|
|
18
|
+
"zip_para_silver",
|
|
19
|
+
]
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Dados intradia do mercado secundário de TPFs no sistema Selic do BCB."""
|
|
2
|
+
|
|
3
|
+
import datetime as dt
|
|
4
|
+
|
|
5
|
+
import polars as pl
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from pyield import du, relogio
|
|
9
|
+
from pyield._internal.br_numbers import float_br, inteiro_br, taxa_br
|
|
10
|
+
from pyield._internal.cache import ttl_cache
|
|
11
|
+
from pyield._internal.retry import retry_padrao
|
|
12
|
+
|
|
13
|
+
URL_BASE_TEMPO_REAL = (
|
|
14
|
+
"https://www3.bcb.gov.br/novoselic/rest/precosNegociacao/pub/download/estatisticas/"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
HORA_INICIO_TEMPO_REAL = dt.time(9, 0, 0)
|
|
18
|
+
HORA_FIM_TEMPO_REAL = dt.time(22, 0, 0)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@ttl_cache()
|
|
22
|
+
@retry_padrao
|
|
23
|
+
def _buscar_csv_intradia() -> bytes:
|
|
24
|
+
hoje = relogio.hoje()
|
|
25
|
+
data_formatada = hoje.strftime("%d-%m-%Y")
|
|
26
|
+
url = f"{URL_BASE_TEMPO_REAL}{data_formatada}"
|
|
27
|
+
resposta = requests.get(url, timeout=30) # API costuma levar ~10s
|
|
28
|
+
resposta.raise_for_status()
|
|
29
|
+
return resposta.content
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _parsear_csv_intradia(dados: bytes) -> pl.DataFrame:
|
|
33
|
+
return pl.read_csv(
|
|
34
|
+
dados,
|
|
35
|
+
separator=";",
|
|
36
|
+
infer_schema=False,
|
|
37
|
+
null_values="-",
|
|
38
|
+
).rename(lambda c: c.strip())
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _processar_df_intradia(df: pl.DataFrame) -> pl.DataFrame:
|
|
42
|
+
agora = relogio.agora()
|
|
43
|
+
return df.filter(pl.col("//1") == "1").select(
|
|
44
|
+
data_hora_consulta=agora,
|
|
45
|
+
data_liquidacao=agora.date(),
|
|
46
|
+
titulo=pl.col("sigla").str.strip_chars(),
|
|
47
|
+
codigo_selic=inteiro_br("código título"),
|
|
48
|
+
data_vencimento=pl.col("data vencimento").str.to_date("%d/%m/%Y"),
|
|
49
|
+
pu_minimo=float_br("pu mínimo"),
|
|
50
|
+
pu_medio=float_br("pu médio"),
|
|
51
|
+
pu_maximo=float_br("pu máximo"),
|
|
52
|
+
pu_ultimo=float_br("mercado à vista pu último"),
|
|
53
|
+
taxa_minima=taxa_br("tx mínimo"),
|
|
54
|
+
taxa_media=taxa_br("tx médio"),
|
|
55
|
+
taxa_maxima=taxa_br("tx máximo"),
|
|
56
|
+
taxa_ultima=taxa_br("tx último"),
|
|
57
|
+
operacoes=inteiro_br("totais liquidados operações"),
|
|
58
|
+
quantidade=inteiro_br("títulos"),
|
|
59
|
+
financeiro=float_br("financeiro"),
|
|
60
|
+
operacoes_corretagem=inteiro_br("corretagem liquidados operações"),
|
|
61
|
+
quantidade_corretagem=inteiro_br("corretagem títulos"),
|
|
62
|
+
termo_pu_minimo=float_br("pu mínimo_duplicated_0"),
|
|
63
|
+
termo_pu_medio=float_br("pu médio_duplicated_0"),
|
|
64
|
+
termo_pu_ultimo=float_br("mercado a termo pu último"),
|
|
65
|
+
termo_pu_maximo=float_br("pu máximo_duplicated_0"),
|
|
66
|
+
termo_taxa_ultima=taxa_br("tx último_duplicated_0"),
|
|
67
|
+
termo_taxa_minima=taxa_br("tx mínimo_duplicated_0"),
|
|
68
|
+
termo_taxa_media=taxa_br("tx médio_duplicated_0"),
|
|
69
|
+
termo_taxa_maxima=taxa_br("tx máximo_duplicated_0"),
|
|
70
|
+
termo_operacoes=inteiro_br("totais contratados operações"),
|
|
71
|
+
termo_quantidade=inteiro_br("títulos_duplicated_0"),
|
|
72
|
+
termo_financeiro=float_br("financeiro_duplicated_0"),
|
|
73
|
+
termo_operacoes_corretagem=inteiro_br("corretagem contratados operações"),
|
|
74
|
+
termo_quantidade_corretagem=inteiro_br("corretagem títulos_duplicated_0"),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _mercado_selic_aberto() -> bool:
|
|
79
|
+
agora = relogio.agora()
|
|
80
|
+
hoje = agora.date()
|
|
81
|
+
hora = agora.time()
|
|
82
|
+
eh_dia_util = du.eh_dia_util(hoje)
|
|
83
|
+
eh_horario = HORA_INICIO_TEMPO_REAL <= hora <= HORA_FIM_TEMPO_REAL
|
|
84
|
+
|
|
85
|
+
return eh_dia_util and eh_horario
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def intradia() -> pl.DataFrame:
|
|
89
|
+
"""Busca dados intradia do mercado secundário de TPFs.
|
|
90
|
+
|
|
91
|
+
Fonte: Banco Central do Brasil, sistema SELIC. Os dados ficam disponíveis
|
|
92
|
+
apenas durante o horário do SELIC (09:00-22:00 BRT) em dias úteis.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
DataFrame Polars com negociações intradia do mercado secundário.
|
|
96
|
+
Retorna DataFrame vazio fora do horário do SELIC.
|
|
97
|
+
|
|
98
|
+
Output Columns:
|
|
99
|
+
* data_hora_consulta (Datetime): data e hora da consulta.
|
|
100
|
+
* data_liquidacao (Date): data de liquidação à vista.
|
|
101
|
+
* titulo (String): sigla do título público.
|
|
102
|
+
* codigo_selic (Int64): código SELIC do título.
|
|
103
|
+
* data_vencimento (Date): data de vencimento do título.
|
|
104
|
+
* pu_minimo (Float64): menor preço negociado.
|
|
105
|
+
* pu_medio (Float64): preço médio negociado.
|
|
106
|
+
* pu_maximo (Float64): maior preço negociado.
|
|
107
|
+
* pu_ultimo (Float64): último preço negociado.
|
|
108
|
+
* taxa_minima (Float64): menor taxa negociada.
|
|
109
|
+
* taxa_media (Float64): taxa média negociada.
|
|
110
|
+
* taxa_maxima (Float64): maior taxa negociada.
|
|
111
|
+
* taxa_ultima (Float64): última taxa negociada.
|
|
112
|
+
* operacoes (Int64): total de operações liquidadas.
|
|
113
|
+
* quantidade (Int64): quantidade total de títulos negociados.
|
|
114
|
+
* financeiro (Float64): valor financeiro total negociado.
|
|
115
|
+
* operacoes_corretagem (Int64): operações via corretagem.
|
|
116
|
+
* quantidade_corretagem (Int64): títulos via corretagem.
|
|
117
|
+
* termo_pu_minimo (Float64): menor preço a termo negociado.
|
|
118
|
+
* termo_pu_medio (Float64): preço médio a termo negociado.
|
|
119
|
+
* termo_pu_ultimo (Float64): último preço a termo negociado.
|
|
120
|
+
* termo_pu_maximo (Float64): maior preço a termo negociado.
|
|
121
|
+
* termo_taxa_ultima (Float64): última taxa a termo negociada.
|
|
122
|
+
* termo_taxa_minima (Float64): menor taxa a termo negociada.
|
|
123
|
+
* termo_taxa_media (Float64): taxa média a termo negociada.
|
|
124
|
+
* termo_taxa_maxima (Float64): maior taxa a termo negociada.
|
|
125
|
+
* termo_operacoes (Int64): total de operações a termo.
|
|
126
|
+
* termo_quantidade (Int64): total de títulos a termo negociados.
|
|
127
|
+
* termo_financeiro (Float64): valor financeiro total a termo.
|
|
128
|
+
* termo_operacoes_corretagem (Int64): operações a termo via corretagem.
|
|
129
|
+
* termo_quantidade_corretagem (Int64): títulos a termo via corretagem.
|
|
130
|
+
|
|
131
|
+
Examples:
|
|
132
|
+
>>> df = yd.tpf.secundario.intradia() # doctest: +SKIP
|
|
133
|
+
"""
|
|
134
|
+
if not _mercado_selic_aberto():
|
|
135
|
+
return pl.DataFrame()
|
|
136
|
+
|
|
137
|
+
texto_bruto = _buscar_csv_intradia()
|
|
138
|
+
df = _parsear_csv_intradia(texto_bruto)
|
|
139
|
+
return _processar_df_intradia(df)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Dados mensais do mercado secundário de TPFs no sistema Selic do BCB."""
|
|
2
2
|
|
|
3
3
|
import datetime as dt
|
|
4
4
|
import io
|
|
@@ -10,33 +10,19 @@ import polars as pl
|
|
|
10
10
|
import polars.selectors as ps
|
|
11
11
|
import requests
|
|
12
12
|
|
|
13
|
-
from pyield import
|
|
14
|
-
from pyield._internal.br_numbers import float_br
|
|
13
|
+
from pyield import relogio
|
|
14
|
+
from pyield._internal.br_numbers import float_br
|
|
15
15
|
from pyield._internal.cache import ttl_cache
|
|
16
16
|
from pyield._internal.converters import converter_datas
|
|
17
17
|
from pyield._internal.retry import retry_padrao
|
|
18
18
|
from pyield._internal.types import DateLike, any_is_empty
|
|
19
19
|
|
|
20
20
|
URL_BASE_MENSAL = "https://www4.bcb.gov.br/pom/demab/negociacoes/download"
|
|
21
|
-
URL_BASE_TEMPO_REAL = (
|
|
22
|
-
"https://www3.bcb.gov.br/novoselic/rest/precosNegociacao/pub/download/estatisticas/"
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
HORA_INICIO_TEMPO_REAL = dt.time(9, 0, 0)
|
|
26
|
-
HORA_FIM_TEMPO_REAL = dt.time(22, 0, 0)
|
|
27
21
|
CHAVES_ORDENACAO = ["data_liquidacao", "titulo", "data_vencimento"]
|
|
28
22
|
COLUNAS_MINIMAS_CSV = 2
|
|
29
23
|
|
|
30
24
|
type CaminhoArquivo = str | os.PathLike[str]
|
|
31
25
|
|
|
32
|
-
__all__ = [
|
|
33
|
-
"baixar_zip",
|
|
34
|
-
"intradia",
|
|
35
|
-
"ler_zip",
|
|
36
|
-
"mensal",
|
|
37
|
-
"zip_para_silver",
|
|
38
|
-
]
|
|
39
|
-
|
|
40
26
|
|
|
41
27
|
def _tipo_arquivo(extragrupo: bool) -> str:
|
|
42
28
|
return "E" if extragrupo else "T"
|
|
@@ -50,7 +36,22 @@ def _data_mensal(data: DateLike) -> dt.date:
|
|
|
50
36
|
return data_alvo
|
|
51
37
|
|
|
52
38
|
|
|
53
|
-
def
|
|
39
|
+
def nome_arquivo_mensal(data: DateLike, extragrupo: bool = False) -> str:
|
|
40
|
+
"""Retorna o nome do arquivo ZIP mensal do secundário no BCB/SELIC.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
data: Data de referência. Apenas ano e mês definem o arquivo.
|
|
44
|
+
extragrupo: Se verdadeiro, retorna o nome do arquivo extragrupo.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Nome do arquivo ZIP mensal publicado pelo BCB.
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
>>> yd.tpf.secundario.nome_arquivo_mensal("07-06-2026")
|
|
51
|
+
'NegT202606.ZIP'
|
|
52
|
+
>>> yd.tpf.secundario.nome_arquivo_mensal("07-01-2025", extragrupo=True)
|
|
53
|
+
'NegE202501.ZIP'
|
|
54
|
+
"""
|
|
54
55
|
data_alvo = _data_mensal(data)
|
|
55
56
|
return f"Neg{_tipo_arquivo(extragrupo)}{data_alvo:%Y%m}.ZIP"
|
|
56
57
|
|
|
@@ -88,7 +89,7 @@ def baixar_zip(data: DateLike, extragrupo: bool = False) -> bytes:
|
|
|
88
89
|
Examples:
|
|
89
90
|
>>> conteudo = yd.tpf.secundario.baixar_zip("07-01-2025") # doctest: +SKIP
|
|
90
91
|
"""
|
|
91
|
-
arquivo =
|
|
92
|
+
arquivo = nome_arquivo_mensal(data, extragrupo)
|
|
92
93
|
conteudo_zip = _baixar_url_zip(f"{URL_BASE_MENSAL}/{arquivo}")
|
|
93
94
|
_validar_zip(conteudo_zip, arquivo)
|
|
94
95
|
return conteudo_zip
|
|
@@ -147,6 +148,17 @@ def _parsear_csv_mensal(conteudo_csv: bytes) -> pl.DataFrame:
|
|
|
147
148
|
|
|
148
149
|
|
|
149
150
|
def _processar_df_mensal(df: pl.DataFrame) -> pl.DataFrame:
|
|
151
|
+
operacoes_corretagem = (
|
|
152
|
+
pl.col("NUM OPER COM CORRETAGEM").cast(pl.Int64)
|
|
153
|
+
if "NUM OPER COM CORRETAGEM" in df.columns
|
|
154
|
+
else pl.lit(None, dtype=pl.Int64)
|
|
155
|
+
)
|
|
156
|
+
quantidade_corretagem = (
|
|
157
|
+
pl.col("QUANT NEG COM CORRETAGEM").cast(pl.Int64)
|
|
158
|
+
if "QUANT NEG COM CORRETAGEM" in df.columns
|
|
159
|
+
else pl.lit(None, dtype=pl.Int64)
|
|
160
|
+
)
|
|
161
|
+
|
|
150
162
|
return (
|
|
151
163
|
df.with_columns(ps.string().str.strip_chars())
|
|
152
164
|
.with_columns(
|
|
@@ -162,7 +174,6 @@ def _processar_df_mensal(df: pl.DataFrame) -> pl.DataFrame:
|
|
|
162
174
|
data_vencimento=pl.col("VENCIMENTO").str.to_date("%d/%m/%Y", strict=False),
|
|
163
175
|
operacoes=pl.col("NUM DE OPER").cast(pl.Int64),
|
|
164
176
|
quantidade=pl.col("quantidade"),
|
|
165
|
-
financeiro=(pl.col("quantidade") * pl.col("pu_medio")).round(2),
|
|
166
177
|
pu_minimo=float_br("PU MIN"),
|
|
167
178
|
pu_medio=pl.col("pu_medio"),
|
|
168
179
|
pu_maximo=float_br("PU MAX"),
|
|
@@ -171,8 +182,8 @@ def _processar_df_mensal(df: pl.DataFrame) -> pl.DataFrame:
|
|
|
171
182
|
taxa_minima=float_br("TAXA MIN"),
|
|
172
183
|
taxa_media=float_br("TAXA MED"),
|
|
173
184
|
taxa_maxima=float_br("TAXA MAX"),
|
|
174
|
-
operacoes_corretagem=
|
|
175
|
-
quantidade_corretagem=
|
|
185
|
+
operacoes_corretagem=operacoes_corretagem,
|
|
186
|
+
quantidade_corretagem=quantidade_corretagem,
|
|
176
187
|
)
|
|
177
188
|
.sort(CHAVES_ORDENACAO)
|
|
178
189
|
)
|
|
@@ -201,7 +212,6 @@ def zip_para_silver(conteudo_zip: bytes) -> pl.DataFrame:
|
|
|
201
212
|
* data_vencimento (Date): data de vencimento do título.
|
|
202
213
|
* operacoes (Int64): número total de operações.
|
|
203
214
|
* quantidade (Int64): quantidade total negociada.
|
|
204
|
-
* financeiro (Float64): valor financeiro negociado.
|
|
205
215
|
* pu_minimo (Float64): preço unitário mínimo.
|
|
206
216
|
* pu_medio (Float64): preço unitário médio.
|
|
207
217
|
* pu_maximo (Float64): preço unitário máximo.
|
|
@@ -213,6 +223,11 @@ def zip_para_silver(conteudo_zip: bytes) -> pl.DataFrame:
|
|
|
213
223
|
* operacoes_corretagem (Int64): operações com corretagem.
|
|
214
224
|
* quantidade_corretagem (Int64): quantidade com corretagem.
|
|
215
225
|
|
|
226
|
+
Notes:
|
|
227
|
+
O schema silver é estável para concatenação entre meses. Em layouts
|
|
228
|
+
antigos da fonte que não trazem corretagem, ``operacoes_corretagem`` e
|
|
229
|
+
``quantidade_corretagem`` são retornadas como nulas.
|
|
230
|
+
|
|
216
231
|
Examples:
|
|
217
232
|
>>> conteudo = yd.tpf.secundario.baixar_zip("07-01-2025") # doctest: +SKIP
|
|
218
233
|
>>> df = yd.tpf.secundario.zip_para_silver(conteudo) # doctest: +SKIP
|
|
@@ -244,7 +259,7 @@ def mensal(data: DateLike, extragrupo: bool = False) -> pl.DataFrame:
|
|
|
244
259
|
"""Busca dados mensais do mercado secundário de TPFs.
|
|
245
260
|
|
|
246
261
|
Fonte: Banco Central do Brasil, sistema SELIC. Baixa o ZIP mensal de
|
|
247
|
-
negociações secundárias, valida o bronze bruto e retorna o DataFrame
|
|
262
|
+
negociações secundárias, valida o bronze bruto e retorna o DataFrame ouro.
|
|
248
263
|
Apenas o ano e o mês de ``data`` são usados para identificar o arquivo.
|
|
249
264
|
|
|
250
265
|
Args:
|
|
@@ -263,7 +278,6 @@ def mensal(data: DateLike, extragrupo: bool = False) -> pl.DataFrame:
|
|
|
263
278
|
* data_vencimento (Date): data de vencimento do título.
|
|
264
279
|
* operacoes (Int64): número total de operações.
|
|
265
280
|
* quantidade (Int64): quantidade total negociada.
|
|
266
|
-
* financeiro (Float64): valor financeiro negociado.
|
|
267
281
|
* pu_minimo (Float64): preço unitário mínimo.
|
|
268
282
|
* pu_medio (Float64): preço unitário médio.
|
|
269
283
|
* pu_maximo (Float64): preço unitário máximo.
|
|
@@ -274,6 +288,11 @@ def mensal(data: DateLike, extragrupo: bool = False) -> pl.DataFrame:
|
|
|
274
288
|
* taxa_maxima (Float64): taxa máxima.
|
|
275
289
|
* operacoes_corretagem (Int64): operações com corretagem.
|
|
276
290
|
* quantidade_corretagem (Int64): quantidade com corretagem.
|
|
291
|
+
* financeiro (Float64): valor financeiro negociado.
|
|
292
|
+
|
|
293
|
+
Notes:
|
|
294
|
+
Esta é a camada ouro mensal: retorna o schema de ``zip_para_silver``
|
|
295
|
+
acrescido de ``financeiro = quantidade * pu_medio``.
|
|
277
296
|
|
|
278
297
|
Examples:
|
|
279
298
|
>>> df = yd.tpf.secundario.mensal("07-01-2025", extragrupo=True)
|
|
@@ -286,125 +305,6 @@ def mensal(data: DateLike, extragrupo: bool = False) -> pl.DataFrame:
|
|
|
286
305
|
if (data_alvo.year, data_alvo.month) > (hoje.year, hoje.month):
|
|
287
306
|
return pl.DataFrame()
|
|
288
307
|
|
|
289
|
-
return zip_para_silver(baixar_zip(data_alvo, extragrupo))
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
@ttl_cache()
|
|
293
|
-
@retry_padrao
|
|
294
|
-
def _buscar_csv_intradia() -> bytes:
|
|
295
|
-
hoje = relogio.hoje()
|
|
296
|
-
data_formatada = hoje.strftime("%d-%m-%Y")
|
|
297
|
-
url = f"{URL_BASE_TEMPO_REAL}{data_formatada}"
|
|
298
|
-
resposta = requests.get(url, timeout=30) # API costuma levar ~10s
|
|
299
|
-
resposta.raise_for_status()
|
|
300
|
-
return resposta.content
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
def _parsear_csv_intradia(dados: bytes) -> pl.DataFrame:
|
|
304
|
-
return pl.read_csv(
|
|
305
|
-
dados,
|
|
306
|
-
separator=";",
|
|
307
|
-
infer_schema=False,
|
|
308
|
-
null_values="-",
|
|
309
|
-
).rename(lambda c: c.strip())
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
def _processar_df_intradia(df: pl.DataFrame) -> pl.DataFrame:
|
|
313
|
-
agora = relogio.agora()
|
|
314
|
-
return df.filter(pl.col("//1") == "1").select(
|
|
315
|
-
data_hora_consulta=agora,
|
|
316
|
-
data_liquidacao=agora.date(),
|
|
317
|
-
titulo=pl.col("sigla").str.strip_chars(),
|
|
318
|
-
codigo_selic=inteiro_br("código título"),
|
|
319
|
-
data_vencimento=pl.col("data vencimento").str.to_date("%d/%m/%Y"),
|
|
320
|
-
pu_minimo=float_br("pu mínimo"),
|
|
321
|
-
pu_medio=float_br("pu médio"),
|
|
322
|
-
pu_maximo=float_br("pu máximo"),
|
|
323
|
-
pu_ultimo=float_br("mercado à vista pu último"),
|
|
324
|
-
taxa_minima=taxa_br("tx mínimo"),
|
|
325
|
-
taxa_media=taxa_br("tx médio"),
|
|
326
|
-
taxa_maxima=taxa_br("tx máximo"),
|
|
327
|
-
taxa_ultima=taxa_br("tx último"),
|
|
328
|
-
operacoes=inteiro_br("totais liquidados operações"),
|
|
329
|
-
quantidade=inteiro_br("títulos"),
|
|
330
|
-
financeiro=float_br("financeiro"),
|
|
331
|
-
operacoes_corretagem=inteiro_br("corretagem liquidados operações"),
|
|
332
|
-
quantidade_corretagem=inteiro_br("corretagem títulos"),
|
|
333
|
-
termo_pu_minimo=float_br("pu mínimo_duplicated_0"),
|
|
334
|
-
termo_pu_medio=float_br("pu médio_duplicated_0"),
|
|
335
|
-
termo_pu_ultimo=float_br("mercado a termo pu último"),
|
|
336
|
-
termo_pu_maximo=float_br("pu máximo_duplicated_0"),
|
|
337
|
-
termo_taxa_ultima=taxa_br("tx último_duplicated_0"),
|
|
338
|
-
termo_taxa_minima=taxa_br("tx mínimo_duplicated_0"),
|
|
339
|
-
termo_taxa_media=taxa_br("tx médio_duplicated_0"),
|
|
340
|
-
termo_taxa_maxima=taxa_br("tx máximo_duplicated_0"),
|
|
341
|
-
termo_operacoes=inteiro_br("totais contratados operações"),
|
|
342
|
-
termo_quantidade=inteiro_br("títulos_duplicated_0"),
|
|
343
|
-
termo_financeiro=float_br("financeiro_duplicated_0"),
|
|
344
|
-
termo_operacoes_corretagem=inteiro_br("corretagem contratados operações"),
|
|
345
|
-
termo_quantidade_corretagem=inteiro_br("corretagem títulos_duplicated_0"),
|
|
308
|
+
return zip_para_silver(baixar_zip(data_alvo, extragrupo)).with_columns(
|
|
309
|
+
financeiro=(pl.col("quantidade") * pl.col("pu_medio")).round(2),
|
|
346
310
|
)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
def _mercado_selic_aberto() -> bool:
|
|
350
|
-
agora = relogio.agora()
|
|
351
|
-
hoje = agora.date()
|
|
352
|
-
hora = agora.time()
|
|
353
|
-
eh_dia_util = du.eh_dia_util(hoje)
|
|
354
|
-
eh_horario = HORA_INICIO_TEMPO_REAL <= hora <= HORA_FIM_TEMPO_REAL
|
|
355
|
-
|
|
356
|
-
return eh_dia_util and eh_horario
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
def intradia() -> pl.DataFrame:
|
|
360
|
-
"""Busca dados intradia do mercado secundário de TPFs.
|
|
361
|
-
|
|
362
|
-
Fonte: Banco Central do Brasil, sistema SELIC. Os dados ficam disponíveis
|
|
363
|
-
apenas durante o horário do SELIC (09:00-22:00 BRT) em dias úteis.
|
|
364
|
-
|
|
365
|
-
Returns:
|
|
366
|
-
DataFrame Polars com negociações intradia do mercado secundário.
|
|
367
|
-
Retorna DataFrame vazio fora do horário do SELIC.
|
|
368
|
-
|
|
369
|
-
Output Columns:
|
|
370
|
-
* data_hora_consulta (Datetime): data e hora da consulta.
|
|
371
|
-
* data_liquidacao (Date): data de liquidação à vista.
|
|
372
|
-
* titulo (String): sigla do título público.
|
|
373
|
-
* codigo_selic (Int64): código SELIC do título.
|
|
374
|
-
* data_vencimento (Date): data de vencimento do título.
|
|
375
|
-
* pu_minimo (Float64): menor preço negociado.
|
|
376
|
-
* pu_medio (Float64): preço médio negociado.
|
|
377
|
-
* pu_maximo (Float64): maior preço negociado.
|
|
378
|
-
* pu_ultimo (Float64): último preço negociado.
|
|
379
|
-
* taxa_minima (Float64): menor taxa negociada.
|
|
380
|
-
* taxa_media (Float64): taxa média negociada.
|
|
381
|
-
* taxa_maxima (Float64): maior taxa negociada.
|
|
382
|
-
* taxa_ultima (Float64): última taxa negociada.
|
|
383
|
-
* operacoes (Int64): total de operações liquidadas.
|
|
384
|
-
* quantidade (Int64): quantidade total de títulos negociados.
|
|
385
|
-
* financeiro (Float64): valor financeiro total negociado.
|
|
386
|
-
* operacoes_corretagem (Int64): operações via corretagem.
|
|
387
|
-
* quantidade_corretagem (Int64): títulos via corretagem.
|
|
388
|
-
* termo_pu_minimo (Float64): menor preço a termo negociado.
|
|
389
|
-
* termo_pu_medio (Float64): preço médio a termo negociado.
|
|
390
|
-
* termo_pu_ultimo (Float64): último preço a termo negociado.
|
|
391
|
-
* termo_pu_maximo (Float64): maior preço a termo negociado.
|
|
392
|
-
* termo_taxa_ultima (Float64): última taxa a termo negociada.
|
|
393
|
-
* termo_taxa_minima (Float64): menor taxa a termo negociada.
|
|
394
|
-
* termo_taxa_media (Float64): taxa média a termo negociada.
|
|
395
|
-
* termo_taxa_maxima (Float64): maior taxa a termo negociada.
|
|
396
|
-
* termo_operacoes (Int64): total de operações a termo.
|
|
397
|
-
* termo_quantidade (Int64): total de títulos a termo negociados.
|
|
398
|
-
* termo_financeiro (Float64): valor financeiro total a termo.
|
|
399
|
-
* termo_operacoes_corretagem (Int64): operações a termo via corretagem.
|
|
400
|
-
* termo_quantidade_corretagem (Int64): títulos a termo via corretagem.
|
|
401
|
-
|
|
402
|
-
Examples:
|
|
403
|
-
>>> df = yd.tpf.secundario.intradia() # doctest: +SKIP
|
|
404
|
-
"""
|
|
405
|
-
if not _mercado_selic_aberto():
|
|
406
|
-
return pl.DataFrame()
|
|
407
|
-
|
|
408
|
-
texto_bruto = _buscar_csv_intradia()
|
|
409
|
-
df = _parsear_csv_intradia(texto_bruto)
|
|
410
|
-
return _processar_df_intradia(df)
|
|
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
|
|
File without changes
|