R Mercado financeiro

Introdução

Em economia e finanças, mercado financeiro é como se denomina todo o universo que envolve as operações de compra e venda de ativos financeiros, tais como valores mobiliários (ações, obrigações, etc.), mercadorias (pedras preciosas, commodities, etc.) e câmbio. É todo o ambiente em que ocorrem as operações de investimentos financeiros. (Wikipédia)

Dados

As cotações das ações negociadas em bolsa podem obtidas na página Séries Históricas da B3 S.A. – Bolsa, Brasil Balcão (ex BM&F BOVESPA), nos sites InfoMoney e yahoo! finance, ou em diversas outras fontes.

Banco de Dados

As séries históricas da B3 são carregadas e ajustadas em um banco de dados SQLite, conforme o exemplo mostrado abaixo para a série histórica das ações do Bradesco (BBDC4):

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
B3 série histórica das ações do Bradesco (BBDC4)

http://www.b3.com.br/pt_br/market-data-e-indices/servicos-de-dados/market-data/historico/mercado-a-vista/series-historicas/

Programa para ler arquivos de séries históricas da B3,
gerar para o ativo especificado um arquivo delimitado
por ';' e um banco de dados com uma tabela contendo os
dados lidos, e ajustar o histórico das ações na tabela
do banco de dados.

Criado em 2021-01-28

@author: halley
"""

import sys
import os
import re
import sqlite3
from sqlite3 import Error

# Constantes
ATIVO = "BBDC4"
ativo = "bbdc4"


# Funções
def proventos(conn, data, valor):
    """Aplicar os ajustes devido aos proventos (juros e dividendos)"""
    cur = conn.cursor()
    cur.execute("SELECT PREULT FROM {} WHERE DATAPREG = '{}'".format(ativo, data))
    row = cur.fetchone()
    preult = row[0]
    fator = (preult - valor) / preult
    comando = (
        "UPDATE {} SET "
        +"PREABE = PREABE * "
        +str(fator)
        +","
        +"PREULT = PREULT * "
        +str(fator)
        +","
        +"PREMIN = PREMIN * "
        +str(fator)
        +","
        +"PREMAX = PREMAX * "
        +str(fator)
        +","
        +"PREMED = PREMED * "
        +str(fator)
        +" "
        +"WHERE DATAPREG <= '{}'"
    )
    conn.execute(comando.format(ativo, data))


def bonific(conn, data, fator):
    """Aplicar os ajustes devido às bonificações"""
    comando = (
        "UPDATE {} SET "
        +"PREABE = PREABE * "
        +str(fator)
        +","
        +"PREULT = PREULT * "
        +str(fator)
        +","
        +"PREMIN = PREMIN * "
        +str(fator)
        +","
        +"PREMAX = PREMAX * "
        +str(fator)
        +","
        +"PREMED = PREMED * "
        +str(fator)
        +" "
        +"WHERE DATAPREG <= '{}'"
    )
    conn.execute(comando.format(ativo, data))


# Diretório de trabalho
os.chdir("/home/halley/R/mercado/B3/")

# Criar, se não existir, ou se conectar com o banco de dados
try:
    conn = sqlite3.connect("{}.sqlite".format(ativo))
    conn.isolation_level = None
    cur = conn.cursor()
except Error as e:
    print(e)
    sys.exit()

# Criar a tabela no banco de dados se não existir
conn.execute("DROP TABLE IF EXISTS {}".format(ativo))
conn.execute(
    """CREATE TABLE IF NOT EXISTS {} (
    TIPREG VARCHAR(2),
    DATAPREG DATE,
    CODBDI VARCHAR(2),
    CODNEG VARCHAR(12),
    TPMERC NUMERIC(3,0),
    NOMRES VARCHAR(12),
    ESPECI VARCHAR(10),
    PRAZOT INT,
    MODREF VARCHAR(4),
    PREABE NUMERIC(13,2),
    PREMAX NUMERIC(13,2),
    PREMIN NUMERIC(13,2),
    PREMED NUMERIC(13,2),
    PREULT NUMERIC(13,2),
    PREFEC NUMERIC(13,2),
    PREOFC NUMERIC(13,2),
    PREOFV NUMERIC(13,2),
    TOTNEG NUMERIC(5,0),
    QUATOT NUMERIC(18,0),
    VOLTOT NUMERIC(18,2),
    PREEXE NUMERIC(13,2),
    INDOPC NUMERIC(1,0),
    DATVEN DATE,
    FATCOT NUMERIC(7,0),
    PTOEXE NUMERIC(13,6),
    CODISI VARCHAR(12),
    DISMES NUMERIC(3,0)
)""".format(
        ativo
    )
)

# Esvaziar a tabela se já contiver dados
conn.execute("DELETE FROM {}".format(ativo))

# Lista de arquivos a serem carregados no banco de dados
entradas = ["COTAHIST_A2020.TXT", "COTAHIST_A2021.TXT"]

# Arquivo delimitado gerado
saida = open("{}.csv".format(ativo), "w")
saida.write(
    "TIPREG;DATAPREG;CODBDI;CODNEG;TPMERC;"
    +"NOMRES;ESPECI;PRAZOT;MODREF;PREABE;PREMAX;"
    +"PREMIN;PREMED;PREULT;PREOFC;PREOFV;TOTNEG;"
    +"QUATOT;VOLTOT;PREEXE;INDOPC;DATVEN;FATCOT;"
    +"PTOEXE;CODISI;DISMES\n"
)

# Carregar as cotações presentes nos arquivos lidos
# no banco de dados escrever no arquivo delimitado
for entrada in entradas:
    with open(entrada, "r") as linhas:
        # Ler todas as linhas uma a uma
        for linha in linhas:
            # Linhas de cotações históricas
            if linha.startswith("01") and linha[12:24].strip() == ATIVO:
                TIPREG = linha[0:2]
                DATAPREG = linha[2:6] + "-" + linha[6:8] + "-" + linha[8:10]
                CODBDI = linha[10:12]
                CODNEG = linha[12:24].strip()
                TPMERC = int(linha[24:27])
                NOMRES = re.sub("\s+", " ", linha[27:39].strip())
                ESPECI = re.sub("\s+", " ", linha[39:49].strip())
                try:
                    PRAZOT = int(linha[49:52])
                except:
                    PRAZOT = 0
                MODREF = linha[52:56].strip()
                PREABE = float(linha[56:69]) / 100.0
                PREMAX = float(linha[69:82]) / 100.0
                PREMIN = float(linha[82:95]) / 100.0
                PREMED = float(linha[95:108]) / 100.0
                PREULT = float(linha[108:121]) / 100.0
                PREOFC = float(linha[121:134]) / 100.0
                PREOFV = float(linha[134:147]) / 100.0
                TOTNEG = int(linha[147:152])
                QUATOT = int(linha[152:170])
                VOLTOT = float(linha[170:188]) / 100.0
                PREEXE = float(linha[188:201]) / 100.0
                INDOPC = int(linha[201:202])
                DATVEN = 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()
                DISMES = int(linha[242:245])
                # Gerar um registro delimitado por ";"
                delim = (
                    TIPREG
                    +";"
                    +DATAPREG
                    +";"
                    +CODBDI
                    +";"
                    +CODNEG
                    +";"
                    +str(TPMERC)
                    +";"
                    +NOMRES
                    +";"
                    +ESPECI
                    +";"
                    +str(PRAZOT)
                    +";"
                    +MODREF
                    +";"
                    +str(PREABE)
                    +";"
                    +str(PREMAX)
                    +";"
                    +str(PREMIN)
                    +";"
                    +str(PREMED)
                    +";"
                    +str(PREULT)
                    +";"
                    +str(PREOFC)
                    +";"
                    +str(PREOFV)
                    +";"
                    +str(TOTNEG)
                    +";"
                    +str(QUATOT)
                    +";"
                    +str(VOLTOT)
                    +";"
                    +str(PREEXE)
                    +";"
                    +str(INDOPC)
                    +";"
                    +DATVEN
                    +";"
                    +str(FATCOT)
                    +";"
                    +str(PTOEXE)
                    +";"
                    +CODISI
                    +";"
                    +str(DISMES)
                    +"\n"
                )
                saida.write(delim)
                # Dados a serem inseridos no banco de dados
                v = [
                    TIPREG,
                    DATAPREG,
                    CODBDI,
                    CODNEG,
                    TPMERC,
                    NOMRES,
                    ESPECI,
                    PRAZOT,
                    MODREF,
                    PREABE,
                    PREMAX,
                    PREMIN,
                    PREMED,
                    PREULT,
                    PREULT,
                    PREOFC,
                    PREOFV,
                    TOTNEG,
                    QUATOT,
                    VOLTOT,
                    PREEXE,
                    INDOPC,
                    DATVEN,
                    FATCOT,
                    PTOEXE,
                    CODISI,
                    DISMES,
                ]
                c = """INSERT INTO {} VALUES
                (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"""
                conn.execute(c.format(ativo), v)

# Efetivar as transações
conn.commit()

# Ajustes devido aos proventos e bonificações (2020/2021)
proventos(conn, "2020-01-02", 0.01897481)
proventos(conn, "2020-02-03", 0.01897481)
proventos(conn, "2020-02-17", 0.06403536)
proventos(conn, "2020-03-02", 0.01897481)
proventos(conn, "2020-04-01", 0.01897481)
bonific(conn, "2020-04-13", 100.0 / 110.0)
proventos(conn, "2020-05-04", 0.01897481)
proventos(conn, "2020-06-01", 0.01897481)
proventos(conn, "2020-07-01", 0.01897481)
proventos(conn, "2020-08-03", 0.01897481)
proventos(conn, "2020-09-01", 0.01897481)
proventos(conn, "2020-10-01", 0.01897481)
proventos(conn, "2020-11-03", 0.01897481)
proventos(conn, "2020-12-01", 0.01897481)
proventos(conn, "2020-12-28", 0.41527335)
proventos(conn, "2021-01-04", 0.01897481)
proventos(conn, "2021-02-01", 0.01897481)
proventos(conn, "2021-02-17", 0.02182128)
proventos(conn, "2021-03-01", 0.018974809)
proventos(conn, "2021-03-30", 0.018974809)
bonific(conn, "2021-04-16", 100.0 / 110.0)
proventos(conn, "2021-05-03", 0.018974809)
proventos(conn, "2021-06-01", 0.018974809)
proventos(conn, "2021-07-01", 0.018974809)
proventos(conn, "2021-07-02", 0.539008031)
proventos(conn, "2021-08-02", 0.018974809)
proventos(conn, "2021-09-01", 0.018974809)

# Efetivar as transações
conn.commit()

# Número de linhas carregadas na tabela
cur.execute("SELECT COUNT(*) FROM {}".format(ativo))
row = cur.fetchone()
print("{} Linhas: {}".format(ATIVO, str(row[0])))

# Fechar a conexão com o banco de dados e o arquivo delimitado
conn.close()
saida.close()
Referências