|
import os |
|
import sqlite3 |
|
from zipfile import ZipFile |
|
from datetime import datetime |
|
|
|
############################################### |
|
def existe_negociacao(cursor, data_pregao, codigo_negociacao, prazo_termo): |
|
""" |
|
Verifica se uma determinada negociação já existe no banco de dados com base na Data do Pregão, o Código de Negociação e o Prazo a Termo |
|
|
|
É preciso informar o cursor de uma conexão aberta. |
|
|
|
Parametros: |
|
cursor: Cursor da Conexão com o banco de dados |
|
data_pregao, data do pregão no formato YYYY-mm-aa |
|
codigo_negociacao, código da negociação com letras maiúscula |
|
prazo_termo, prazo da negociação a termo |
|
retorno |
|
Contagem de registros encontrados |
|
""" |
|
result = cursor.execute("select count(*) from cotacoes where DATA_PREGAO = ? and CODIGO_NEGOCIACAO = ? and PRAZO_TERMO = ?",(data_pregao, codigo_negociacao, prazo_termo)).fetchone() |
|
return result[0] |
|
|
|
############################################### |
|
def processa_cotacoes(ano, mes=None, dia=None, |
|
sqlite_file='db.sqlite', |
|
path='./downloads'): |
|
""" |
|
Processa cada registro do arquivo de histórico da B3, verificando se o registro já existe com base em DATA_PREGAO, CODIGO_NEGOCIACAO e PRAZO_TERMO |
|
|
|
Parametros: |
|
"ano" no formato de quatro digitos |
|
"mês" no formato númerico |
|
"dia" no formato númerico |
|
Retorno |
|
Retorna uma tupla com código de resultado da operação, a quantidade de registros processados e o nome do arquivo processado. |
|
|
|
Lança uma exeption caso o arquivo não tenha o número de registro coerentes |
|
""" |
|
|
|
if dia and mes: |
|
file_name = "COTAHIST_D{:0>2}{:0>2}{:0>4}".format(dia,mes,ano) |
|
elif mes: |
|
file_name = "COTAHIST_M{:0>2}{:0>4}".format(mes,ano) |
|
else: |
|
file_name = "COTAHIST_A{:0>4}".format(ano) |
|
# |
|
zip_file_name = path + '/' + file_name + ".ZIP" |
|
print('#', end='') |
|
# |
|
conn = sqlite3.connect(sqlite_file, |
|
detect_types=sqlite3.PARSE_DECLTYPES) |
|
cursor = conn.cursor() |
|
# |
|
count = 0 |
|
# |
|
if not os.path.isfile(zip_file_name): |
|
return (404, 0, zip_file_name) |
|
with ZipFile(zip_file_name, 'r') as zip: |
|
arq_cotacoes = zip.filelist[0] |
|
print('#', end='') |
|
with zip.open(arq_cotacoes) as path: |
|
print('#', end='') |
|
# |
|
for linha in path: |
|
count = count + 1 |
|
dic = {} |
|
linha = linha.decode("iso-8859-1") |
|
if linha[0:2] == '01': # registro de dados |
|
# |
|
data_pregao = "" + linha[2:6] + "-" + linha[6:8] + "-" + linha[8:10] |
|
codigo_negociacao = linha[12:24].strip() |
|
# converte para inteiro, se vazio prenche com 0 |
|
prazo_a_termo = int(linha[49:52].strip()) if linha[49:52].strip() else 0 |
|
if not existe_negociacao(cursor, data_pregao, codigo_negociacao, prazo_a_termo): |
|
codigo_bdi = linha[10:12].strip() |
|
tipo_mercado = int(linha[24:27]) |
|
nome_resumido = linha[27:39].strip() |
|
# Remove espaços extras |
|
especificacao = " ".join(linha[39:49].split()) |
|
moeda_referencia = linha[52:56].strip() |
|
preco_abertura = float(linha[56:69])/100 |
|
preco_maximo = float(linha[69:82])/100 |
|
preco_minimo = float(linha[82:95])/100 |
|
preco_medio = float(linha[95:108])/100 |
|
preco_de_fechamento = float(linha[108:121])/100 |
|
melhor_oferta_compra = float(linha[121:134])/100 |
|
melhor_oferta_venda = float(linha[134:147])/100 |
|
total_de_negociado = int(linha[147:152]) |
|
total_de_titulos = int(linha[152:170]) |
|
volume_total = float(linha[170:188])/100 |
|
preco_executado = float(linha[188:201])/100 |
|
#indopc |
|
indicador_de_correcao = int(linha[201:202]) |
|
data_vencimento = linha[202:206] + "-" + linha[206:208] + "-" + linha[208:210] |
|
fatcot = int(linha[210:217]) |
|
ptoexe = float(linha[217:230])/1000000 |
|
codisi = linha[230:242].strip() |
|
dismis = int(linha[242:245]) |
|
# |
|
cursor.execute("insert into cotacoes (DATA_PREGAO, CODBDI, CODIGO_NEGOCIACAO, TIPO_MERCADO, NOME_RESUMIDO, ESPECI, PRAZO_TERMO, MOEDA_REFERENCIA, PRECO_ABERTURA, PRECO_MAXIMO, PRECO_MINIMO, PRECO_MEDIO, PRECO_FECHAMENTO, MELHOR_OFERTA_COMPRA, MELHOR_OFERTA_VENDA, TOTAL_NEGOCIADO, TOTAL_DE_TITULOS, VOLUME_TOTAL, PREEXE, INDOPC, DATVEN, FATCOT, PTOEXE, CODISI, DISMES) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", |
|
( |
|
data_pregao, |
|
codigo_bdi, |
|
codigo_negociacao, |
|
tipo_mercado, |
|
nome_resumido, |
|
especificacao, |
|
prazo_a_termo, |
|
moeda_referencia, |
|
preco_abertura, |
|
preco_maximo, |
|
preco_minimo, |
|
preco_medio, |
|
preco_de_fechamento, |
|
melhor_oferta_compra, |
|
melhor_oferta_venda, |
|
total_de_negociado, |
|
total_de_titulos, |
|
volume_total, |
|
preco_executado, |
|
indicador_de_correcao, |
|
data_vencimento, |
|
fatcot, |
|
ptoexe, |
|
codisi, |
|
dismis |
|
)) |
|
print('.', end='') |
|
else: |
|
print('*', end='') |
|
# |
|
elif linha[0:2] == '00': # registro de metadados |
|
print('_', end='') |
|
print("Arquivo criado em {}".format(datetime.strptime(linha[23:31], '%Y%m%d'))) |
|
elif linha[0:2] == '99': # registro de metadados |
|
size = int(linha[31:42]) |
|
print('_', end='') |
|
if count != size: |
|
raise Exception("Arquivo Invalido, número de linhas diferente: foram processadas {}, mas era esperado {}".format(count, size)) |
|
# |
|
# |
|
|
|
if not count % 40: |
|
print(" " + str(count)) |
|
zip.close() |
|
# |
|
print("# total: {}".format(count)) |
|
conn.commit() |
|
cursor.close() |
|
conn.close() |
|
return (0, count, zip_file_name) |
|
|