debentures-dot-com 0.1.1__py3-none-any.whl
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.
- debentures_dot_com/__consulta_dados.py +4 -0
- debentures_dot_com/__init__.py +5 -0
- debentures_dot_com/__volumes.py +9 -0
- debentures_dot_com/emissoes.py +175 -0
- debentures_dot_com/estoques.py +177 -0
- debentures_dot_com/eventos_fin.py +37 -0
- debentures_dot_com/mercados.py +81 -0
- debentures_dot_com/utils/__init__.py +0 -0
- debentures_dot_com/utils/utils.py +156 -0
- debentures_dot_com-0.1.1.dist-info/METADATA +54 -0
- debentures_dot_com-0.1.1.dist-info/RECORD +14 -0
- debentures_dot_com-0.1.1.dist-info/WHEEL +5 -0
- debentures_dot_com-0.1.1.dist-info/licenses/LICENSE +21 -0
- debentures_dot_com-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
volume/volumeporperiodo_e.asp?op_exc=False&emissao=0&dt_ini=01%2F07%2F2025&dt_fim=23%2F07%2F2025&ICVM=&moeda=1
|
|
3
|
+
volume/volumeporperiodo_e.asp?op_exc=Nada&emissao=2&dt_ini=01%2F07%2F2024&dt_fim=23%2F07%2F2025&ICVM=&moeda=1
|
|
4
|
+
|
|
5
|
+
/volume/volumeporgarantia-especie_d.asp?pMes_Ini=05&pAno_Ini=2025&pMes_Fim=07&pAno_Fim=2025&moeda=1&pConsol=1&op_exc=Nada&ICVM=%20NULL
|
|
6
|
+
volume/volumeporgarantia-especie_d.asp?pMes_Ini=5&pAno_Ini=2025&pMes_Fim=5&pAno_Fim=2025&pConsol=0&moeda=1&op_exc=Nada&ICVM=%20NULL
|
|
7
|
+
volume/volumeporgarantia-especie_de.asp?pMes_Ini=05&pAno_Ini=2025&pMes_Fim=07&pAno_Fim=2025&moeda=1&pConsol=1&op_exc=Nada&ICVM
|
|
8
|
+
|
|
9
|
+
https://www.debentures.com.br/exploreosnd/consultaadados/volume/volumeporgarantia-especie_de.asp?pMes_Ini=05&pAno_Ini=2025&pMes_Fim=07&pAno_Fim=2025&moeda=1&pConsol=1&op_exc=Nada&ICVM=%20NULL&ICVM=NULL
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import io
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from bs4 import BeautifulSoup
|
|
5
|
+
from datetime import date
|
|
6
|
+
from .utils.utils import get_response_to_pd, _format_cnpj, _format_date_for_url
|
|
7
|
+
from .__consulta_dados import UrlDebentures
|
|
8
|
+
|
|
9
|
+
class EmissoesDebentures:
|
|
10
|
+
def __init__(self)->str:
|
|
11
|
+
root_url = UrlDebentures().root_url
|
|
12
|
+
self.root_url = f'{root_url}/emissoesdedebentures'
|
|
13
|
+
|
|
14
|
+
def lista_deb_publicas(self,timeout:int=None)->pd.DataFrame:
|
|
15
|
+
url = f'{self.root_url}/caracteristicas_r.asp?tip_deb=publicas&op_exc='
|
|
16
|
+
timeout = timeout if isinstance(timeout,int) else 10
|
|
17
|
+
r = requests.get(url,timeout=timeout)
|
|
18
|
+
soup = BeautifulSoup(r.text, 'html.parser')
|
|
19
|
+
table = soup.find('table', class_='Tab10333333')
|
|
20
|
+
# Check if the table exists
|
|
21
|
+
if table:
|
|
22
|
+
df = []
|
|
23
|
+
# Extract table rows
|
|
24
|
+
rows = table.find_all('tr')
|
|
25
|
+
# Loop through rows and extract data
|
|
26
|
+
for row in rows:
|
|
27
|
+
cells = row.find_all(['td', 'th']) # handles both header and data cells
|
|
28
|
+
cell_texts = [cell.get_text(strip=True) for cell in cells]
|
|
29
|
+
df.append(cell_texts[1:-1])
|
|
30
|
+
df = pd.DataFrame(df, columns = ['Ativo', 'Emissor', 'Dump', 'Situacao'])
|
|
31
|
+
df = df.drop(columns=['Dump'])
|
|
32
|
+
else:
|
|
33
|
+
df = pd.DataFrame()
|
|
34
|
+
print("Table with class 'Tab10333333' not found.")
|
|
35
|
+
return df
|
|
36
|
+
|
|
37
|
+
def lista_caracteristicas(self, ativo:str,timeout:int=None)->pd.DataFrame:
|
|
38
|
+
url = f'{self.root_url}/caracteristicas_e.asp?Ativo={ativo}'
|
|
39
|
+
timeout = timeout if isinstance(timeout,int) else 10
|
|
40
|
+
r = requests.get(url,timeout=timeout)
|
|
41
|
+
df = pd.read_csv(io.StringIO(r.text), sep='|', encoding='utf-8', names=['raw'], skiprows=2)
|
|
42
|
+
df = df[1:]['raw'].str.split('\t', expand=True).reset_index(drop=True)
|
|
43
|
+
df = df.T.reset_index(drop=True)
|
|
44
|
+
df.columns = ['Descricao', 'Valores']
|
|
45
|
+
return df
|
|
46
|
+
|
|
47
|
+
#def _dt_fim_ini_fix(self, date_):
|
|
48
|
+
# dt_par = parser.parse(date_)
|
|
49
|
+
# return f'{dt_par.day:02d}%2F{dt_par.month:02d}%2F{dt_par.year}'
|
|
50
|
+
|
|
51
|
+
def pu_historico(self, ativo:str, dt_inicio:str=None, dt_fim:str=None,timeout:int=None)->pd.DataFrame:
|
|
52
|
+
params = []
|
|
53
|
+
|
|
54
|
+
if not dt_inicio:
|
|
55
|
+
dt_inicio= '20010101'
|
|
56
|
+
|
|
57
|
+
if not dt_fim:
|
|
58
|
+
dt_fim = date.today().strftime('%Y%m%d')
|
|
59
|
+
|
|
60
|
+
dt_inicio_fmt = _format_date_for_url(dt_inicio)
|
|
61
|
+
params.append(f'dt_ini={dt_inicio_fmt}')
|
|
62
|
+
dt_fim_fmt = _format_date_for_url(dt_fim)
|
|
63
|
+
params.append(f'dt_fim={dt_fim_fmt}')
|
|
64
|
+
|
|
65
|
+
# Add conditional suffix if any date filters exist
|
|
66
|
+
add_suffix = '++++' if params else ''
|
|
67
|
+
|
|
68
|
+
query_string = '&' + '&'.join(params) if params else ''
|
|
69
|
+
url = f'{self.root_url}/puhistorico_e.asp?op_exc=False&ativo={ativo}{add_suffix}{query_string}'
|
|
70
|
+
|
|
71
|
+
return get_response_to_pd(url,timeout=timeout)
|
|
72
|
+
|
|
73
|
+
def prazo_medio(self, ativo:str = None, emissor:str = None, datacvm:str = None, dt_ini:str=None, dt_fim:str=None, anoini:str=None, anofim:str=None, repactuacao:str = None, exec:str = None,timeout:int=None)->list:
|
|
74
|
+
ativo = ativo if isinstance(ativo, str) else ''
|
|
75
|
+
emissor = _format_cnpj(emissor) if emissor else ''
|
|
76
|
+
datacvm = datacvm if isinstance(datacvm, str) else 'e'
|
|
77
|
+
dt_ini = _format_date_for_url(dt_ini)
|
|
78
|
+
dt_fim = _format_date_for_url(dt_fim)
|
|
79
|
+
repactuacao = repactuacao if isinstance(repactuacao, str) else ''
|
|
80
|
+
exec = exec if isinstance(exec, str) else 'Nada'
|
|
81
|
+
if isinstance(anoini, int):
|
|
82
|
+
anoini = str(anoini)
|
|
83
|
+
elif not isinstance(anoini, str):
|
|
84
|
+
anoini = ''
|
|
85
|
+
|
|
86
|
+
if isinstance(anofim, int):
|
|
87
|
+
anofim = str(anofim)
|
|
88
|
+
elif not isinstance(anofim, str):
|
|
89
|
+
anofim = ''
|
|
90
|
+
url = (
|
|
91
|
+
f'{self.root_url}/prazo-medio_e.asp?'
|
|
92
|
+
f'Ativo={ativo}&Emissor={emissor}&dataCVM={datacvm}&dt_ini={dt_ini}'
|
|
93
|
+
f'&dt_fim={dt_fim}&anoini={anoini}&anofim={anofim}&ComRepactuacao={repactuacao}&Op_exc={exec}'
|
|
94
|
+
)
|
|
95
|
+
df = get_response_to_pd(url,timeout)
|
|
96
|
+
df_medio = df[:2]
|
|
97
|
+
df_medio = df_medio.iloc[:, :3]
|
|
98
|
+
df_medio.columns = ['', 'Tipo Prazo', 'Prazo Medio']
|
|
99
|
+
df_medio= df_medio.drop(columns='')
|
|
100
|
+
df_data = df[2:].reset_index(drop=True)
|
|
101
|
+
df_data.columns = df_data.iloc[0]
|
|
102
|
+
df_data = df_data[1:].reset_index(drop=True)[:-2]
|
|
103
|
+
return df_medio, df_data
|
|
104
|
+
|
|
105
|
+
def conversao_permuta(self, ativo:str=None, exec:bool=None, dt_ini:str=None, dt_fim:str=None, classe:str=None,timeout:int=None)->pd.DataFrame:
|
|
106
|
+
ativo = ativo if isinstance(ativo, str) else ''
|
|
107
|
+
dt_ini = _format_date_for_url(dt_ini)
|
|
108
|
+
dt_fim = _format_date_for_url(dt_fim)
|
|
109
|
+
classe = classe if isinstance(classe, str) else ''
|
|
110
|
+
exec = exec if isinstance(exec, bool) else False
|
|
111
|
+
url = (
|
|
112
|
+
f'{self.root_url}/conversoes-permutas_e.asp?'
|
|
113
|
+
f'ativo={ativo},%20&op_exc={exec}&dt_ini={dt_ini}&dt_fim={dt_fim}&classe={classe}'
|
|
114
|
+
)
|
|
115
|
+
return get_response_to_pd(url,timeout=timeout)
|
|
116
|
+
|
|
117
|
+
def caracteristicas_debs(self, tipo:str=None,exec:bool=None,mnome:str=None,ativo:str=None,
|
|
118
|
+
ipo:str=None,icvm:str=None,escri_padro:str=None,cvm_ini:str=None,cvm_fim:str=None,
|
|
119
|
+
emis_ini:str=None,emis_fim:str=None,venc_ini:str=None,venc_fim:str=None,tpv:str=None,
|
|
120
|
+
tnv:str=None,rent_ini:str=None,rent_fim:str=None,distrib_ini:str=None,distrib_fim:str=None,
|
|
121
|
+
indice:str=None,tipo_:str=None,crit_calc:str=None,dia_ref:str=None,mult_rend:str=None,
|
|
122
|
+
limite:str=None,trat_limite:str=None,tx_spread:str=None,prazo:str=None,premio_novo:str=None,
|
|
123
|
+
premio_prazo:str=None,premio_antigo:str=None,par:str=None,amortizacao:str=None,mbanco:str=None,
|
|
124
|
+
magente:str=None,instdep:str=None,coordenador:str=None)->pd.DataFrame:
|
|
125
|
+
tipo = tipo if isinstance(tipo, str) else 'privadas'
|
|
126
|
+
exec = exec if isinstance(exec, bool) else False
|
|
127
|
+
mnome = mnome if isinstance(mnome, str) else ''
|
|
128
|
+
ativo = ativo if isinstance(ativo, str) else ''
|
|
129
|
+
ipo = ipo if isinstance(ipo, str) else ''
|
|
130
|
+
icvm = icvm if isinstance(icvm, str) else ''
|
|
131
|
+
escri_padro = escri_padro if isinstance(escri_padro, str) else ''
|
|
132
|
+
cvm_ini = cvm_ini if isinstance(cvm_ini, str) else ''
|
|
133
|
+
cvm_fim = cvm_fim if isinstance(cvm_fim, str) else ''
|
|
134
|
+
emis_ini = emis_ini if isinstance(emis_ini, str) else ''
|
|
135
|
+
emis_fim = emis_fim if isinstance(emis_fim, str) else ''
|
|
136
|
+
venc_ini = venc_ini if isinstance(venc_ini, str) else ''
|
|
137
|
+
venc_fim = venc_fim if isinstance(venc_fim, str) else ''
|
|
138
|
+
tpv = tpv if isinstance(tpv, str) else ''
|
|
139
|
+
tnv = tnv if isinstance(tnv, str) else ''
|
|
140
|
+
rent_ini = rent_ini if isinstance(rent_ini, str) else ''
|
|
141
|
+
rent_fim = rent_fim if isinstance(rent_fim, str) else ''
|
|
142
|
+
distrib_ini = distrib_ini if isinstance(distrib_ini, str) else ''
|
|
143
|
+
distrib_fim = distrib_fim if isinstance(distrib_fim, str) else ''
|
|
144
|
+
indice = indice if isinstance(indice, str) else ''
|
|
145
|
+
tipo_ = tipo_ if isinstance(tipo_, str) else ''
|
|
146
|
+
crit_calc = crit_calc if isinstance(crit_calc, str) else ''
|
|
147
|
+
dia_ref = dia_ref if isinstance(dia_ref, str) else ''
|
|
148
|
+
mult_rend = mult_rend if isinstance(mult_rend, str) else ''
|
|
149
|
+
limite = limite if isinstance(limite, str) else ''
|
|
150
|
+
trat_limite = trat_limite if isinstance(trat_limite, str) else ''
|
|
151
|
+
tx_spread = tx_spread if isinstance(tx_spread, str) else ''
|
|
152
|
+
prazo = prazo if isinstance(prazo, str) else ''
|
|
153
|
+
premio_novo = premio_novo if isinstance(premio_novo, str) else ''
|
|
154
|
+
premio_prazo = premio_prazo if isinstance(premio_prazo, str) else ''
|
|
155
|
+
premio_antigo = premio_antigo if isinstance(premio_antigo, str) else ''
|
|
156
|
+
par = par if isinstance(par, str) else ''
|
|
157
|
+
amortizacao = amortizacao if isinstance(amortizacao, str) else ''
|
|
158
|
+
mbanco = mbanco if isinstance(mbanco, str) else ''
|
|
159
|
+
magente = magente if isinstance(magente, str) else ''
|
|
160
|
+
instdep = instdep if isinstance(instdep, str) else ''
|
|
161
|
+
coordenador = coordenador if isinstance(coordenador, str) else ''
|
|
162
|
+
|
|
163
|
+
url = (
|
|
164
|
+
f'{self.root_url}/caracteristicas_e.asp?tip_deb={tipo}&'
|
|
165
|
+
f'op_exc={exec}&mnome={mnome}&ativo={ativo}&IPO={ipo}&icvm={icvm}&EscrituraPadronizada={escri_padro}&'
|
|
166
|
+
f'cvm_ini={cvm_ini}&cvm_fim={cvm_fim}&emis_ini={emis_ini}&emis_fim={emis_fim}&venc_ini={venc_ini}&venc_fim={venc_fim}&TPV={tpv}&'
|
|
167
|
+
f'TNV={tnv}&rent_ini={rent_ini}&rent_fim={rent_fim}&distrib_ini={distrib_ini}&distrib_fim={distrib_fim}&indice={indice}&'
|
|
168
|
+
f'tipo={tipo_}&crit_calc={crit_calc}&dia_ref={dia_ref}&mult_rend={mult_rend}&limite={limite}&trat_limite={trat_limite}&'
|
|
169
|
+
f'tx_spread={tx_spread}&prazo={prazo}&premio_novo={premio_novo}&premio_prazo={premio_prazo}&premio_antigo={premio_antigo}&Par={par}&'
|
|
170
|
+
f'amortizacao={amortizacao}&mbanco={mbanco}&magente={magente}&instdep={instdep}&coordenador={coordenador}'
|
|
171
|
+
)
|
|
172
|
+
df = get_response_to_pd(url)
|
|
173
|
+
df.columns = df.iloc[0]
|
|
174
|
+
df = df[1:].reset_index(drop=True)[:-2]
|
|
175
|
+
return df
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import requests
|
|
4
|
+
from dateutil import parser
|
|
5
|
+
from .utils.utils import get_response_to_pd, _format_cnpj, _format_date_for_url,simple_response_to_pd,get_soup_response_to_pd
|
|
6
|
+
from .__consulta_dados import UrlDebentures
|
|
7
|
+
|
|
8
|
+
def parse_estoque_data(data_string: str, tipo: str) -> pd.DataFrame:
|
|
9
|
+
"""
|
|
10
|
+
Parses the given string content into a pandas DataFrame,
|
|
11
|
+
now also extracting the 'Moeda' type.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
data_string: A string containing the stock data with multiple date blocks.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
A pandas DataFrame with the extracted stock information.
|
|
18
|
+
"""
|
|
19
|
+
lines = data_string.strip().split('\n')
|
|
20
|
+
parsed_data = []
|
|
21
|
+
current_date = None
|
|
22
|
+
current_moeda = None # New variable to store the currency type
|
|
23
|
+
|
|
24
|
+
for line in lines:
|
|
25
|
+
line = line.strip()
|
|
26
|
+
|
|
27
|
+
# Skip header lines that are not part of the data blocks
|
|
28
|
+
if line.startswith("Estoque SND Caracter"):
|
|
29
|
+
continue
|
|
30
|
+
|
|
31
|
+
# Extract 'Data do Estoque' and 'Moeda'
|
|
32
|
+
# Adjusted regex to capture the currency symbol (R$ or US$)
|
|
33
|
+
date_moeda_match = re.match(r'Data do Estoque (\d{2}/\d{2}/\d{4}) - Moeda (R\$|US\$)', line)
|
|
34
|
+
if date_moeda_match:
|
|
35
|
+
current_date = pd.to_datetime(date_moeda_match.group(1), format='%d/%m/%Y')
|
|
36
|
+
current_moeda = date_moeda_match.group(2) # Capture the currency type
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
# Identify header row for data blocks
|
|
40
|
+
if current_date and line.startswith(tipo):
|
|
41
|
+
headers = [h.strip() for h in line.split('\t') if h.strip()]
|
|
42
|
+
continue # Move to the next line to read data
|
|
43
|
+
|
|
44
|
+
# Read data rows (excluding "Total do dia")
|
|
45
|
+
if current_date and not line.startswith("Total do dia") and not line.startswith(tipo) and line:
|
|
46
|
+
parts = [p.strip() for p in line.split('\t') if p.strip()]
|
|
47
|
+
if parts and len(parts) == len(headers):
|
|
48
|
+
row_dict = {'Data do Estoque': current_date, 'Moeda': current_moeda} # Add 'Moeda' to the dictionary
|
|
49
|
+
for i, header in enumerate(headers):
|
|
50
|
+
value = parts[i]
|
|
51
|
+
# Clean and convert numeric values
|
|
52
|
+
if header != tipo:
|
|
53
|
+
value = value.replace('.', '').replace(',', '.') # Remove thousands separator, change decimal comma to dot
|
|
54
|
+
try:
|
|
55
|
+
value = float(value)
|
|
56
|
+
except ValueError:
|
|
57
|
+
pass # Keep as string if not a number
|
|
58
|
+
row_dict[header] = value
|
|
59
|
+
parsed_data.append(row_dict)
|
|
60
|
+
|
|
61
|
+
if not parsed_data:
|
|
62
|
+
return pd.DataFrame()
|
|
63
|
+
|
|
64
|
+
df = pd.DataFrame(parsed_data)
|
|
65
|
+
|
|
66
|
+
# Ensure correct column order and data types
|
|
67
|
+
if not df.empty:
|
|
68
|
+
df['Data do Estoque'] = pd.to_datetime(df['Data do Estoque'])
|
|
69
|
+
# Convert numeric columns, handling potential errors if any non-numeric data slipped through
|
|
70
|
+
for col in ['Mercado', 'Tesouraria', 'Total']:
|
|
71
|
+
if col in df.columns:
|
|
72
|
+
df[col] = pd.to_numeric(df[col], errors='coerce')
|
|
73
|
+
return df
|
|
74
|
+
|
|
75
|
+
def get_estoque_to_pd(url:str, tipo: str, timeout:int=None)-> pd.DataFrame:
|
|
76
|
+
timeout = timeout if isinstance(timeout, int) else 10
|
|
77
|
+
try:
|
|
78
|
+
response = requests.get(url, timeout=timeout)
|
|
79
|
+
response.encoding = 'ISO-8859-1'
|
|
80
|
+
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
|
|
81
|
+
return parse_estoque_data(response.text, tipo)
|
|
82
|
+
except requests.exceptions.ConnectionError as e:
|
|
83
|
+
print(f"Connection Error for {url}: {e}")
|
|
84
|
+
return pd.DataFrame()
|
|
85
|
+
except requests.exceptions.Timeout as e:
|
|
86
|
+
print(f"Timeout Error for {url}: {e}")
|
|
87
|
+
return pd.DataFrame()
|
|
88
|
+
except requests.exceptions.HTTPError as e:
|
|
89
|
+
print(f"HTTP Error for {url}: {e}")
|
|
90
|
+
return pd.DataFrame()
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"An unexpected error occurred for {url}: {e}")
|
|
93
|
+
return pd.DataFrame()
|
|
94
|
+
|
|
95
|
+
def _consulta_relatorio(url:str, tipo_relatorio:str, dt_ini:str=None, dt_fim:str=None, moeda:int=None,opcao:int=None,exec:str=None,timeout:int=None)->pd.DataFrame:
|
|
96
|
+
dt_ini = _format_date_for_url(dt_ini, '%d/%m/%Y') if dt_ini else '02/03/1992'
|
|
97
|
+
dt_fim = _format_date_for_url(dt_fim,'%d/%m/%Y') if dt_fim else '31/12/2029'
|
|
98
|
+
if moeda is not None and moeda not in [1, 2]:
|
|
99
|
+
raise ValueError("Parameter 'moeda' must be 1 or 2.")
|
|
100
|
+
moeda = moeda if isinstance(moeda, int) else 1
|
|
101
|
+
exec = exec if isinstance(exec, str) else 'on'
|
|
102
|
+
opcao = opcao if isinstance(opcao, int) else 100
|
|
103
|
+
url = (
|
|
104
|
+
f'{url}/estoquepor_re.asp?op_rel={tipo_relatorio}'
|
|
105
|
+
f'&Dt_ini={dt_ini}&Dt_fim={dt_fim}&op_exc={exec}&op_subInd=&Opcao={opcao}&Moeda={moeda}'
|
|
106
|
+
)
|
|
107
|
+
return get_estoque_to_pd(url, tipo_relatorio, 1000)
|
|
108
|
+
|
|
109
|
+
class EstoquesCorporativos:
|
|
110
|
+
"""
|
|
111
|
+
Consult the open data page on debentures.com,
|
|
112
|
+
specifically the tab 'estoque' (https://www.debentures.com.br/exploreosnd/consultaadados/estoque/)
|
|
113
|
+
to extract the information via Python.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def __init__(self)->str:
|
|
117
|
+
root_url = UrlDebentures().root_url
|
|
118
|
+
self.root_url = f'{root_url}/estoque'
|
|
119
|
+
|
|
120
|
+
def estoque_por_ativo(self, ativo:str=None, dt_ini:str=None, dt_fim:str=None, exec:str=None,moeda:int=None,timeout:int=None)->pd.DataFrame:
|
|
121
|
+
ativo = ativo if isinstance(ativo, str) else ''
|
|
122
|
+
exec = exec if isinstance(exec, str) else 'Nada'
|
|
123
|
+
if moeda is not None and moeda not in [1, 2]:
|
|
124
|
+
raise ValueError("Parameter 'moeda' must be 1 or 2.")
|
|
125
|
+
moeda = moeda if isinstance(moeda, int) else 1
|
|
126
|
+
dt_ini = _format_date_for_url(dt_ini, '%d/%m/%Y') if dt_ini else '02/03/1992'
|
|
127
|
+
dt_fim = _format_date_for_url(dt_fim, '%d/%m/%Y') if dt_fim else '31/12/2029'
|
|
128
|
+
url = (
|
|
129
|
+
f'{self.root_url}/estoqueporativo_e.asp?'
|
|
130
|
+
f'ativo={ativo}&dt_ini={dt_ini}&dt_fim={dt_fim}&moeda={moeda}&Op_exc={exec}'
|
|
131
|
+
)
|
|
132
|
+
if moeda == 1:
|
|
133
|
+
simb_moeda= 'R$'
|
|
134
|
+
else:
|
|
135
|
+
simb_moeda= 'USD'
|
|
136
|
+
df = get_response_to_pd(url,skiprows=4,timeout=timeout)
|
|
137
|
+
#df = df.iloc[2:]
|
|
138
|
+
df.columns = ['Data', 'Qtd Mercado', f'Volume Mercado ({simb_moeda} Mil)','Qtd Tesouraria',
|
|
139
|
+
f'Volume Tesouraria ({simb_moeda} Mil)','Qtd Total',
|
|
140
|
+
f'Volume Total ({simb_moeda} Mil)', 'Dump']
|
|
141
|
+
df = df.drop(columns=['Dump'])
|
|
142
|
+
return df
|
|
143
|
+
|
|
144
|
+
def estoque_por_periodo(self, dt_ini:str=None, dt_fim:str=None, moeda:int=None,timeout:int=None)->pd.DataFrame:
|
|
145
|
+
if moeda is not None and moeda not in [1, 2]:
|
|
146
|
+
raise ValueError("Parameter 'moeda' must be 1 or 2.")
|
|
147
|
+
moeda = moeda if isinstance(moeda, int) else 1
|
|
148
|
+
dt_ini = _format_date_for_url(dt_ini) if dt_ini else '02/03/1992'
|
|
149
|
+
dt_fim = _format_date_for_url(dt_fim) if dt_fim else '31/12/2029'
|
|
150
|
+
url = (
|
|
151
|
+
f'{self.root_url}/estoqueporperiodo_e.asp?'
|
|
152
|
+
f'dt_ini={dt_ini}&dt_fim={dt_fim}&moeda={moeda}'
|
|
153
|
+
)
|
|
154
|
+
df = get_response_to_pd(url,timeout=timeout)
|
|
155
|
+
return df.iloc[:,:-1]
|
|
156
|
+
|
|
157
|
+
def estoque_a_vencer(self, dt_ini:str=None, dt_fim:str=None, moeda:int=None,repactuacao:int=None,timeout:int=None)->pd.DataFrame:
|
|
158
|
+
dt_ini = _format_date_for_url(dt_ini) if dt_ini else '02/03/1992'
|
|
159
|
+
dt_fim = _format_date_for_url(dt_fim) if dt_fim else '31/12/2029'
|
|
160
|
+
if moeda is not None and moeda not in [1, 2]:
|
|
161
|
+
raise ValueError("Parameter 'moeda' must be 1 or 2.")
|
|
162
|
+
moeda = moeda if isinstance(moeda, int) else 1
|
|
163
|
+
if repactuacao is not None and repactuacao not in [1, 2]:
|
|
164
|
+
raise ValueError("Parameter 'moeda' must be 1 or 2.")
|
|
165
|
+
repactuacao = repactuacao if isinstance(repactuacao, int) else 1
|
|
166
|
+
url = (
|
|
167
|
+
f'{self.root_url}/estoqueavencer_e.asp?'
|
|
168
|
+
f'dt_ini={dt_ini}&dt_fim={dt_fim}&moeda={moeda}&rVen={repactuacao}'
|
|
169
|
+
)
|
|
170
|
+
df = get_response_to_pd(url,skiprows=4,timeout=timeout)
|
|
171
|
+
return df.iloc[:,:-1]
|
|
172
|
+
|
|
173
|
+
def estoque_relatorio(self, tipo:str, dt_ini:str=None, dt_fim:str=None, moeda:int=None,opcao:int=None,exec:str=None,timeout:int=None)->pd.DataFrame:
|
|
174
|
+
if tipo not in ['Indexadores', 'Tipo', 'Forma', 'Classe','Garantia','InstrucaoNormativa']:
|
|
175
|
+
raise ValueError("Parameter 'tipo' must be 'Indexadores', 'Tipo', 'Forma', 'Classe', 'Garantia' or 'InstrucaoNormativa'")
|
|
176
|
+
return _consulta_relatorio(self.root_url, tipo, dt_ini, dt_fim, moeda,opcao,exec,timeout)
|
|
177
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .utils.utils import get_response_to_pd, _format_cnpj, _format_date_for_url
|
|
2
|
+
from .__consulta_dados import UrlDebentures
|
|
3
|
+
|
|
4
|
+
class EventosFinanceiros:
|
|
5
|
+
def __init__(self)->str:
|
|
6
|
+
root_url = UrlDebentures().root_url
|
|
7
|
+
self.root_url = f'{root_url}/eventosfinanceiros'
|
|
8
|
+
|
|
9
|
+
def agenda_eventos(self, ativo:str = None, emissor:str = None, evento:str = None, dt_ini:str=None, dt_fim:str=None, dt_pgto_ini:str=None, dt_pgto_fim:str=None,timeout:int=None)->list:
|
|
10
|
+
ativo = ativo if isinstance(ativo, str) else ''
|
|
11
|
+
emissor = _format_cnpj(emissor) if emissor else ''
|
|
12
|
+
evento = evento if isinstance(evento, str) else ''
|
|
13
|
+
dt_ini = _format_date_for_url(dt_ini)
|
|
14
|
+
dt_fim = _format_date_for_url(dt_fim)
|
|
15
|
+
dt_pgto_ini = _format_date_for_url(dt_pgto_ini)
|
|
16
|
+
dt_pgto_fim = _format_date_for_url(dt_pgto_fim)
|
|
17
|
+
url = (
|
|
18
|
+
f'{self.root_url}/agenda_e.asp?'
|
|
19
|
+
f'emissor={emissor}&ativo={ativo}&evento={evento}&dt_ini={dt_ini}&dt_fim={dt_fim}'
|
|
20
|
+
f'&dt_pgto_ini={dt_pgto_ini}&dt_pgto_fim={dt_pgto_fim}'
|
|
21
|
+
)
|
|
22
|
+
df = get_response_to_pd(url,timeout=timeout)
|
|
23
|
+
return df
|
|
24
|
+
|
|
25
|
+
def pu_eventos(self, ativo:str = None, exec:str = None,emissor:str = None, evento:str = None, dt_ini:str=None, dt_fim:str=None,timeout:int=None)->list:
|
|
26
|
+
ativo = ativo if isinstance(ativo, str) else ''
|
|
27
|
+
emissor = _format_cnpj(emissor) if emissor else ''
|
|
28
|
+
exec = exec if isinstance(exec, str) else 'Nada'
|
|
29
|
+
evento = evento if isinstance(evento, str) else ''
|
|
30
|
+
dt_ini = _format_date_for_url(dt_ini)
|
|
31
|
+
dt_fim = _format_date_for_url(dt_fim)
|
|
32
|
+
url = (
|
|
33
|
+
f'{self.root_url}/pudeeventos_e.asp?'
|
|
34
|
+
f'op_exc={exec}&ativo={ativo}&evento={evento}&dt_ini={dt_ini}&dt_fim={dt_fim}&emissor={emissor}'
|
|
35
|
+
)
|
|
36
|
+
df = get_response_to_pd(url,timeout=timeout)
|
|
37
|
+
return df
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import io
|
|
3
|
+
from dateutil import parser
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from .utils.utils import get_response_to_pd, _format_cnpj, _format_date_for_url,simple_response_to_pd,get_soup_response_to_pd
|
|
6
|
+
from .__consulta_dados import UrlDebentures
|
|
7
|
+
|
|
8
|
+
class MercadoSecundario:
|
|
9
|
+
def __init__(self)->str:
|
|
10
|
+
root_url = UrlDebentures().root_url
|
|
11
|
+
self.root_url = f'https://www.anbima.com.br/informacoes/merc-sec-debentures/'
|
|
12
|
+
self.root_url_ = f'{root_url}/mercadosecundario'
|
|
13
|
+
|
|
14
|
+
def arquivo_precos_diario(self, data:str)->pd.DataFrame:
|
|
15
|
+
data_ = _format_date_for_url(data, '%y%m%d')
|
|
16
|
+
url = f'{self.root_url}/arqs/db{data_}.txt'
|
|
17
|
+
return simple_response_to_pd(url, '@')
|
|
18
|
+
|
|
19
|
+
#def vencidos_antecipadamente_diario(self, data:str)->pd.DataFrame:
|
|
20
|
+
# data_ = _format_date_for_url(data, '%d%b%Y')
|
|
21
|
+
# url = f'{self.root_url}/resultados/mdeb_{data_}_vencidos_antecipadamente.asp'
|
|
22
|
+
# df = get_response_to_pd(url)
|
|
23
|
+
# return df
|
|
24
|
+
|
|
25
|
+
#def ipca_spread_diario(self, data:str)->pd.DataFrame:
|
|
26
|
+
# data_ = _format_date_for_url(data, '%d%b%Y')
|
|
27
|
+
# url = f'{self.root_url}/resultados/mdeb_{data_}_ipca_spread.asp'
|
|
28
|
+
# df = get_response_to_pd(url)
|
|
29
|
+
# return df
|
|
30
|
+
|
|
31
|
+
#def igpm_spread_diario(self, data:str)->pd.DataFrame:
|
|
32
|
+
# data_ = _format_date_for_url(data, '%d%b%Y')
|
|
33
|
+
# url = f'{self.root_url}/resultados/mdeb_{data_}_igp-m.asp'
|
|
34
|
+
# df = get_response_to_pd(url)
|
|
35
|
+
# return df
|
|
36
|
+
|
|
37
|
+
def preco_negociacao(self, ativo:str = None, exec:str = None,emissor:str = None, dt_ini:str=None, dt_fim:str=None)->list:
|
|
38
|
+
ativo = ativo if isinstance(ativo, str) else ''
|
|
39
|
+
emissor = _format_cnpj(emissor) if emissor else ''
|
|
40
|
+
exec = exec if isinstance(exec, str) else 'Nada'
|
|
41
|
+
dt_ini = _format_date_for_url(dt_ini, '%Y%m%d') if dt_ini else '19900302'
|
|
42
|
+
dt_fim = _format_date_for_url(dt_fim, '%Y%m%d') if dt_fim else '20291231'
|
|
43
|
+
url = (
|
|
44
|
+
f'{self.root_url_}/precosdenegociacao_e.asp?'
|
|
45
|
+
f'op_exc={exec}&emissor={emissor}&ativo={ativo}&dt_ini={dt_ini}&dt_fim={dt_fim}'
|
|
46
|
+
)
|
|
47
|
+
df = get_response_to_pd(url)
|
|
48
|
+
return df
|
|
49
|
+
|
|
50
|
+
def volume_negociacao(self, dt_ini:str=None, dt_fim:str=None)->list:
|
|
51
|
+
dt_ini = _format_date_for_url(dt_ini, '%d/%m/%Y') if dt_ini else '02/03/1992'
|
|
52
|
+
dt_fim = _format_date_for_url(dt_fim, '%d/%m/%Y') if dt_fim else '31/12/2029'
|
|
53
|
+
|
|
54
|
+
url = f'{self.root_url_}/volumesnegociados_r.asp'
|
|
55
|
+
|
|
56
|
+
headers = {
|
|
57
|
+
"Host": "www.debentures.com.br",
|
|
58
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0",
|
|
59
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
60
|
+
"Accept-Language": "en-US,en;q=0.5",
|
|
61
|
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
62
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
63
|
+
"Origin": "https://www.debentures.com.br",
|
|
64
|
+
"Connection": "keep-alive",
|
|
65
|
+
"Upgrade-Insecure-Requests": "1",
|
|
66
|
+
"Sec-Fetch-Dest": "document",
|
|
67
|
+
"Sec-Fetch-Mode": "navigate",
|
|
68
|
+
"Sec-Fetch-Site": "same-origin",
|
|
69
|
+
"Sec-Fetch-User": "?1",
|
|
70
|
+
"DNT": "1",
|
|
71
|
+
"Sec-GPC": "1",
|
|
72
|
+
"Priority": "u=0, i",
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
data = {
|
|
76
|
+
"dt_ini": f"{dt_ini}",
|
|
77
|
+
"dt_fim": f"{dt_fim}",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
df = get_soup_response_to_pd(url, header_class='Ver10666666_cab', table_class='Tab10333333', headers=headers, data=data)
|
|
81
|
+
return df
|
|
File without changes
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import io
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import locale
|
|
5
|
+
from bs4 import BeautifulSoup
|
|
6
|
+
from dateutil import parser
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_response_to_pd(url: str, sep:str = None, headers:dict=None, data:dict=None,timeout:int=None,skiprows:int=None) -> pd.DataFrame:
|
|
10
|
+
if sep is None:
|
|
11
|
+
sep = '|'
|
|
12
|
+
if timeout is None:
|
|
13
|
+
timeout= 10
|
|
14
|
+
if skiprows is None:
|
|
15
|
+
skiprows = 2
|
|
16
|
+
try:
|
|
17
|
+
response = requests.get(url, headers=headers, data=data, timeout=timeout)
|
|
18
|
+
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
|
|
19
|
+
df = pd.read_csv(io.StringIO(response.text), sep=sep, encoding='utf-8', names=['raw'], skiprows=skiprows)
|
|
20
|
+
df = df['raw'].str.split('\t', expand=True).reset_index(drop=True)
|
|
21
|
+
df.columns = df.iloc[0]
|
|
22
|
+
df = df[1:].reset_index(drop=True)[:-2]
|
|
23
|
+
return df
|
|
24
|
+
except requests.exceptions.ConnectionError as e:
|
|
25
|
+
print(f"Connection Error for {url}: {e}")
|
|
26
|
+
return pd.DataFrame()
|
|
27
|
+
except requests.exceptions.Timeout as e:
|
|
28
|
+
print(f"Timeout Error for {url}: {e}")
|
|
29
|
+
return pd.DataFrame()
|
|
30
|
+
except requests.exceptions.HTTPError as e:
|
|
31
|
+
print(f"HTTP Error for {url}: {e}")
|
|
32
|
+
return pd.DataFrame()
|
|
33
|
+
except Exception as e:
|
|
34
|
+
print(f"An unexpected error occurred for {url}: {e}")
|
|
35
|
+
return pd.DataFrame()
|
|
36
|
+
|
|
37
|
+
def simple_response_to_pd(url:str, sep:str, encoding:str=None, names:list=None, skiprows:int=None) ->pd.DataFrame:
|
|
38
|
+
encoding = encoding if isinstance(encoding, str) else 'utf-8'
|
|
39
|
+
names = names if isinstance(names, list) else ['raw']
|
|
40
|
+
skiprows = skiprows if isinstance(skiprows, int) else 2
|
|
41
|
+
try:
|
|
42
|
+
response = requests.get(url, timeout=10)
|
|
43
|
+
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
|
|
44
|
+
df = pd.read_csv(io.StringIO(response.text), sep=sep, encoding=encoding, names=names, skiprows=skiprows)
|
|
45
|
+
return df
|
|
46
|
+
except requests.exceptions.ConnectionError as e:
|
|
47
|
+
print(f"Connection Error for {url}: {e}")
|
|
48
|
+
return pd.DataFrame()
|
|
49
|
+
except requests.exceptions.Timeout as e:
|
|
50
|
+
print(f"Timeout Error for {url}: {e}")
|
|
51
|
+
return pd.DataFrame()
|
|
52
|
+
except requests.exceptions.HTTPError as e:
|
|
53
|
+
print(f"HTTP Error for {url}: {e}")
|
|
54
|
+
return pd.DataFrame()
|
|
55
|
+
except Exception as e:
|
|
56
|
+
print(f"An unexpected error occurred for {url}: {e}")
|
|
57
|
+
return pd.DataFrame()
|
|
58
|
+
|
|
59
|
+
def _format_cnpj(cnpj: str) -> str:
|
|
60
|
+
"""
|
|
61
|
+
Formats a CNPJ string to be 14 digits, padding with leading zeros if necessary.
|
|
62
|
+
Returns an empty string if the input is not a valid CNPJ (e.g., non-numeric or too long).
|
|
63
|
+
"""
|
|
64
|
+
if not isinstance(cnpj, str):
|
|
65
|
+
return ''
|
|
66
|
+
|
|
67
|
+
cnpj_digits = ''.join(filter(str.isdigit, cnpj))
|
|
68
|
+
|
|
69
|
+
if len(cnpj_digits) > 14:
|
|
70
|
+
return '' # CNPJ too long
|
|
71
|
+
|
|
72
|
+
return cnpj_digits.zfill(14)
|
|
73
|
+
|
|
74
|
+
def _format_date_for_url(date_input: str, dtfmt:str = None, locale_:str = None) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Converts a date string (in various formats) to DD%2FMM%2FYYYY for URL usage.
|
|
77
|
+
Returns an empty string if the date cannot be parsed.
|
|
78
|
+
"""
|
|
79
|
+
if locale_ is None:
|
|
80
|
+
locale_ = 'pt_BR.utf8'
|
|
81
|
+
locale.setlocale(locale.LC_TIME, locale_)
|
|
82
|
+
if dtfmt is None:
|
|
83
|
+
dtfmt = '%d%%2F%m%%2F%Y'
|
|
84
|
+
if not isinstance(date_input, str) or not date_input:
|
|
85
|
+
return ''
|
|
86
|
+
try:
|
|
87
|
+
parsed_date = parser.parse(date_input)
|
|
88
|
+
return parsed_date.strftime(dtfmt)
|
|
89
|
+
except ValueError:
|
|
90
|
+
return '' # Invalid date format
|
|
91
|
+
|
|
92
|
+
def get_soup_response_to_pd(url: str, header_class:str = None, table_class:str = None, headers:dict=None, data:dict=None,timeout:int=None) ->pd.DataFrame:
|
|
93
|
+
if timeout is None:
|
|
94
|
+
timeout= 10
|
|
95
|
+
try:
|
|
96
|
+
response = requests.get(url, headers=headers, data=data, timeout=timeout)
|
|
97
|
+
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
|
|
98
|
+
soup = BeautifulSoup(response.text, 'html.parser')
|
|
99
|
+
header_table = soup.find('table', class_=f'{header_class}')
|
|
100
|
+
headers = []
|
|
101
|
+
if header_table:
|
|
102
|
+
header_tds = header_table.find_all('td')
|
|
103
|
+
for td in header_tds:
|
|
104
|
+
text = td.get_text(strip=True)
|
|
105
|
+
if text:
|
|
106
|
+
headers.append(text)
|
|
107
|
+
else:
|
|
108
|
+
print(f"Could not find the header table (class='{header_class}').")
|
|
109
|
+
headers = ["Data de Negociação", "Volume Negociado em Moeda da Época"]
|
|
110
|
+
|
|
111
|
+
data_table = soup.find('table', class_=f'{table_class}')
|
|
112
|
+
extracted_data = []
|
|
113
|
+
|
|
114
|
+
if data_table:
|
|
115
|
+
rows = data_table.find_all('tr')
|
|
116
|
+
for row in rows:
|
|
117
|
+
cols = row.find_all('td')
|
|
118
|
+
cols = [ele.get_text(strip=True) for ele in cols]
|
|
119
|
+
cleaned_row = [col for col in cols if col]
|
|
120
|
+
|
|
121
|
+
if cleaned_row:
|
|
122
|
+
if "Total:" in cleaned_row[0] or "Total:" in cleaned_row[1]:
|
|
123
|
+
if len(cleaned_row) == 1 and "Total:" in cleaned_row[0]:
|
|
124
|
+
total_value_str = cleaned_row[0].replace("Total:", "").strip()
|
|
125
|
+
extracted_data.append(["Total", total_value_str])
|
|
126
|
+
elif len(cleaned_row) == 2 and "Total:" in cleaned_row[1]:
|
|
127
|
+
total_value_str = cleaned_row[1].replace("Total:", "").strip()
|
|
128
|
+
extracted_data.append(["Total", total_value_str])
|
|
129
|
+
else:
|
|
130
|
+
extracted_data.append(cleaned_row)
|
|
131
|
+
elif len(cleaned_row) == 2:
|
|
132
|
+
extracted_data.append(cleaned_row)
|
|
133
|
+
else:
|
|
134
|
+
print(f"Could not find the data table (class='{table_class}').")
|
|
135
|
+
if extracted_data and headers:
|
|
136
|
+
df = pd.DataFrame(extracted_data, columns=headers)
|
|
137
|
+
#print("\nDataFrame created successfully:")
|
|
138
|
+
elif extracted_data:
|
|
139
|
+
df = pd.DataFrame(extracted_data)
|
|
140
|
+
print("\nDataFrame created successfully (without specific headers):")
|
|
141
|
+
else:
|
|
142
|
+
df = pd.DataFrame()
|
|
143
|
+
print("No data extracted to form a DataFrame.")
|
|
144
|
+
return df
|
|
145
|
+
except requests.exceptions.ConnectionError as e:
|
|
146
|
+
print(f"Connection Error for {url}: {e}")
|
|
147
|
+
return pd.DataFrame()
|
|
148
|
+
except requests.exceptions.Timeout as e:
|
|
149
|
+
print(f"Timeout Error for {url}: {e}")
|
|
150
|
+
return pd.DataFrame()
|
|
151
|
+
except requests.exceptions.HTTPError as e:
|
|
152
|
+
print(f"HTTP Error for {url}: {e}")
|
|
153
|
+
return pd.DataFrame()
|
|
154
|
+
except Exception as e:
|
|
155
|
+
print(f"An unexpected error occurred for {url}: {e}")
|
|
156
|
+
return pd.DataFrame()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: debentures-dot-com
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Um cliente em Python para consultar dados de debêntures do portal debentures.com.br
|
|
5
|
+
Author-email: gtazevedo <guilherme.tt.azevedo@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/gtazevedo/debentures_dot_com
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/gtazevedo/debentures_dot_com/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: pandas
|
|
20
|
+
Requires-Dist: beautifulsoup4
|
|
21
|
+
Requires-Dist: python-dateutil
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# debentures_dot_com
|
|
25
|
+
|
|
26
|
+
API para consultar dados do site [debentures.com.br](https://www.debentures.com.br/).
|
|
27
|
+
|
|
28
|
+
Esta API está atualmente em sua versão inicial; portanto, algumas funções ainda estão incompletas e nem todos os dados podem ser consultados no momento.
|
|
29
|
+
|
|
30
|
+
Atualmente, foram adicionadas consultas para os seguintes dados disponíveis na seção [Consulta a Dados](https://www.debentures.com.br/exploreosnd/consultaadados):
|
|
31
|
+
|
|
32
|
+
- **Emissões Debêntures** (acessível através da classe `EmissoesDebentures`)
|
|
33
|
+
- **Estoques Corporativos** (acessível através da classe `EstoquesCorporativos`)
|
|
34
|
+
- **Eventos Financeiros** (acessível através da classe `EventosFinanceiros`)
|
|
35
|
+
- **Mercado Secundário** (acessível através da classe `MercadoSecundario`)
|
|
36
|
+
|
|
37
|
+
## Instalação
|
|
38
|
+
O pacote pode ser instalado via pip (exemplo):
|
|
39
|
+
```bash
|
|
40
|
+
pip install debentures-dot-com
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Como Usar
|
|
44
|
+
Um exemplo rápido de como consultar emissões de debêntures públicas:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from debentures_dot_com import EmissoesDebentures
|
|
48
|
+
|
|
49
|
+
ed = EmissoesDebentures()
|
|
50
|
+
df = ed.lista_deb_publicas()
|
|
51
|
+
print(df.head())
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Para mais detalhes e testes de desenvolvimento, você pode verificar o arquivo `tests/dev.ipynb`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
debentures_dot_com/__consulta_dados.py,sha256=Zl6DnTC1bnImoUVLRAdH2S9Lo7iyKwb8gJ_mVq_-ZWA,133
|
|
2
|
+
debentures_dot_com/__init__.py,sha256=m2TmpzeSfFbkbrJqA99A7VAv94_EHF3RvLLUdImF2To,208
|
|
3
|
+
debentures_dot_com/__volumes.py,sha256=YLcgcBW6D9hKiaPy64e2YSRovaCR3xLSYw90kKvuFeU,827
|
|
4
|
+
debentures_dot_com/emissoes.py,sha256=oEQ-WX8AmsQiasTolLXZYjk6ArhlIfqa6Tb2NZdzLP8,9644
|
|
5
|
+
debentures_dot_com/estoques.py,sha256=RfyzguddQSOQU1uSkZ96sXeQvrZxelfjJltwqx5WNbo,8706
|
|
6
|
+
debentures_dot_com/eventos_fin.py,sha256=vRg7nQ6Iu0u5eM3cDfr5kVAKwHyi299REvt7s1srDGQ,1928
|
|
7
|
+
debentures_dot_com/mercados.py,sha256=ayPBsD2C94Zhn3FMYbHXSjGpz_8ArXjekDksbg17SbA,3630
|
|
8
|
+
debentures_dot_com/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
debentures_dot_com/utils/utils.py,sha256=7onBlgae5nGn1BaMDHC7SkLy8PipRnhWKuKDvtajwaw,6817
|
|
10
|
+
debentures_dot_com-0.1.1.dist-info/licenses/LICENSE,sha256=8BZPj1h3mE1GPJh9yA-zV4yHHm7fmWGKooXqRpmgZBQ,1087
|
|
11
|
+
debentures_dot_com-0.1.1.dist-info/METADATA,sha256=0C1x6XswBcocEaLu2RHh_4poiLz5gMLYOJeozchQoLo,2178
|
|
12
|
+
debentures_dot_com-0.1.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
13
|
+
debentures_dot_com-0.1.1.dist-info/top_level.txt,sha256=rsS9-rNuT6I6Lc8ye_foJB-LmFFy5kYd1KPtDrushHs,19
|
|
14
|
+
debentures_dot_com-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Guilherme
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
debentures_dot_com
|