Análisando Empresas do Mercado Financeiro com RAG: Uma Abordagem Baseada em IA Generativa e Dados Fundamentalistas
Introdução
Imagine fazer análises comparativas de empresas com dados financeiros atualizados, acessando-os de forma rápida e com informações reais e atualizadas de uma fonte segura. ⏱️Hoje, quando precisamos avaliar uma empresa, precisamos abrir uma planilha, analisar valores, ver indicadores e acaba sendo uma tarefa bastante trabalhosa.
💡 Quando colocamos na equação os modelos LLMs e a técnica RAG, esse trabalho fica muito mais suave, produtivo e, o melhor, mais confiável.
Pretendo mostrar neste artigo como usar LLMs para análise de empresas do mercado financeiro, tornando-a mais simples, rápida e confiável, usando RAGs.
🔩 O que iremos desenvolver é um assistente de análises com base no LlamaIndex, e o modelo LLM que usarei será o Gemini Pro, e a fonte de dados será o site Fundamentus.com.br .
Alinhando alguns conceitos
O projeto baseia-se em um conjunto de tecnologias; irei detalhar cada uma antes de entrarmos na codificação.
⚙️LlamaIndex: Para aqueles que não conhecem, o LlamaIndex é um framework de orquestração que simplifica a integração de dados para a construção de aplicativos usando LLMs.
⚙️LLMs (Large Language Models): São modelos de aprendizado de máquina treinados em grandes quantidades de texto, capazes de gerar e processar linguagem natural de forma impressionante.
Usaremos o “Gemini Pro” para processar consultas em linguagem natural e compreender nuances contextuais, tornando nosso mecanismo de pesquisa mais intuitivo.
⚙️ RAG (Retrieval-Augmented Generation): É uma técnica de IA que combina geração de texto com recuperação de informações para produzir conteúdos mais precisos.
O site Fundamentus.com.br é uma plataforma que fornece dados fundamentalistas e informações financeiras de empresas listadas na bolsa de valores, auxiliando investidores na análise de ações e tomada de decisões no mercado financeiro.
Vamos iniciar e pôr a mão na massa! 🖖🤓🤚
Instalação
Usando as seguintes bibliotecas:
!pip install llama-index -q
!pip install pandas -q
!pip install llama-index-core -q
!pip install llama-index-llms-gemini -q
!pip install llama-index-experimental -q
Codificação
Após a instalação das bibliotecas, vamos criar um script para baixar a página de empresas e transformá-la em um DataFrame no pandas.Para simplificar o artigo e torná-lo mais acessível, vamos utilizar apenas algumas colunas.
Nesse caso, usaremos apenas algumas colunas:
- P/L = Preço da ação dividido pelo lucro por ação. O P/L é o número de anos que se levaria para reaver o capital aplicado na compra de uma ação, através do recebimento do lucro gerado pela empresa, considerando que esses lucros permaneçam constantes.
- P/VP = Preço da ação dividido pelo Valor Patrimonial por ação. Informa quanto o mercado está disposto a pagar sobre o Patrimônio Líquido da empresa
- PSR = Price Sales Ratio: Preço da ação dividido pela Receita Líquida por ação
- Dividend Yield = Dividendo pago por ação dividido pelo preço da ação. É o rendimento gerado para o dono da ação pelo pagamento de dividendos.
- ROE = Retorno sobre o Patrimônio Líquido: Lucro líquido dividido pelo Patrimônio Líquido
- Patrim. Líq = O patrimônio líquido representa os valores que os sócios ou acionistas têm na empresa em um determinado momento. No balanço patrimonial, a diferença entre o valor dos ativos e dos passivos e resultado de exercícios futuros representa o PL (Patrimônio Líquido), que é o valor contábil devido pela pessoa jurídica aos sócios ou acionistas.
- Liq. Corr. = Ativo Circulante dividido pelo Passivo Circulante: Reflete a capacidade de pagamento da empresa no curto prazo.
- P/Ativo = Preço da ação dividido pelos Ativos totais por ação.
🔗Criação do Pipeline de Consulta
📌 Pergunta do Usuário: O nosso primeiro bloco será um componente de entrada (InputComponent) utilizado para capturar as perguntas do usuário.
📌 Identificação de Tickers: Agora, iremos criar as instruções para identificar, no questionamento do usuário, qual empresa ou empresas ele está falando e assim, identificar seus respectivos tickers.
📌 Instruções com Pandas: Após identificar quais tickers fazem parte da intenção do usuário, utilizaremos essas informações para criar uma nova consulta mais direcionada utilizando pandas.
📌 Síntese da Resposta: Por último, reunimos todas as informações catalogadas nas etapas anteriores para gerar um prompt mais refinado e adepto ao contexto.
Código da criação do Pipeline:
🧩 Juntanto todos os blocos usando QueryPipeline
p = QueryPipeline(
modules={
"Pergunta_do_Usuario": pergunta_do_usuario,
"Prompt_IdentificarTickers": prompt_identificar_tickers,
"LLM_Query_IdentificarTickers": llm, #" usaremos nossa LLM Gemini Pro
"Parser_RespostaQuery_IdentificarTickers":output_pandas_parser,
"Prompt_InstruçõesPandas":prompt_instrucoes_pandas,
"LLM_Query_InstruçõesPandas": llm,
"Parser_RespostaQuery_InstruçõesPandas": output_pandas_parser,
"Prompt_SínteseResposta": prompt_sintese_resposta,
"LLM_SínteseResposta": llm,
},
verbose=True,
)
p.add_chain([ "Pergunta_do_Usuario","Prompt_IdentificarTickers", "LLM_Query_IdentificarTickers", "Parser_RespostaQuery_IdentificarTickers" ])
p.add_chain(["Pergunta_do_Usuario", "Prompt_InstruçõesPandas","LLM_Query_InstruçõesPandas","Parser_RespostaQuery_InstruçõesPandas" ])
p.add_links([
Link("Parser_RespostaQuery_IdentificarTickers", "Prompt_InstruçõesPandas", dest_key="resultado_parse_tickers"),
Link("Pergunta_do_Usuario", "Prompt_SínteseResposta", dest_key="query_str"),
Link("LLM_Query_InstruçõesPandas", "Prompt_SínteseResposta", dest_key="resposta_instrucoes_pandas"),
Link("Parser_RespostaQuery_InstruçõesPandas", "Prompt_SínteseResposta", dest_key="resultado_parse_pandas"),
Link("Parser_RespostaQuery_IdentificarTickers", "Prompt_SínteseResposta", dest_key="resultado_parse_tickers"),
])
p.add_link("Prompt_SínteseResposta", "LLM_SínteseResposta")
Com nosso pipeline contruido, agora podemos iniciar nosso primeiro teste:
pergunta = """
me diga o ROE e cotacao além da oscilacao nos ultimos anos
da vale e americanas
"""
resposta = p.run(query_str=pergunta)
display(Markdown(resposta.message.content))
Resposta:
Cotação e ROE
VALE3 (Vale):
Cotação: R$ 64,29
ROE: 20,68%
AMER3 (Americanas):
Cotação: R$ 0,53
ROE: 54,76%
Oscilação nos Últimos Anos Infelizmente, a saída do Pandas não contém informações sobre a oscilação nos últimos anos.
A Vale (VALE3) tem uma cotação mais alta e um ROE menor do que a Americanas (AMER3).
A Americanas tem uma cotação mais baixa e um ROE maior do que a Vale.
A saída do Pandas não fornece informações sobre a oscilação nos últimos anos.
🛑 As oscilações nos últimos anos não estão disponíveis na saída do Pandas.
Observe que a análise foi quase perfeita, pois utilizamos apenas uma fonte de dados local, que em nosso caso é o dataframe Pandas.
Com isso, o sistema não foi capaz de nos fornecer informações sobre a oscilação das ações. Isso é algo positivo, pois a IA generativa não inventou valores para a oscilação com base nas demais colunas, mantendo a integridade dos dados.
🧲 Adicionando Retriver ao Pipeline
Para superar essa limitação, vamos adicionar um módulo com conectividade à internet em nosso diagrama. Para isso, utilizaremos o módulo Retriever para estabelecermos acesso ao Fundamentus. Para obter mais informações sobre Retrievers, acesse: Documentação dos Retriever.
Mais o que é esse Retriever ? 🤔
O Retriever é um módulo do LlamaIndex, que permite acessar e consultar fontes de dados externas, como APIs e bancos de dados, para enriquecer as respostas geradas por nosso LLM Gemini-Pro!
from typing import Optional,Dict,List
from llama_index.core.retrievers import BaseRetriever
from llama_index.core.schema import NodeWithScore, QueryBundle, TextNode
from llama_index.core.query_engine import RetrieverQueryEngine
class FundamentusRetriever(BaseRetriever):
"""Fundamentus Pesquisar mais detalhada em função dos tickers"""
...
# Após criarmos nosso Retriever FundamentusRetriever,
# iremos testalo antes de adicionar em nosso pipeline! :)
fundamentus_retriever = FundamentusRetriever()
query_engine = RetrieverQueryEngine.from_args(fundamentus_retriever, llm=llm)
response = query_engine.query("['PETR4','VALE3','PETR3']")
print(response)
Output:
- PETR4: 106,66%
- VALE3: 0,31%
- PETR3: 93,68%
🔗 Atualizando Pipeline
Ao integrar o Retriever, teremos a capacidade de extrair dados externos do site fundamentus.com.br, utilizando os tickers identificados nas perguntas dos usuários. Essa inclusão no QueryPipeline aprimorará significativamente as respostas do nosso RAG, tornando-as mais eficazes e completas.
🧰 Após recriar nosso pipeline iremos testar com a mesma pergunta!
pergunta = """
me diga o ROE e cotacao além da oscilacao nos ultimos anos
da vale e americanas
"""
resposta = p.run(query_str=pergunta)
display(Markdown(resposta.message.content))
VALE3
ROE: 20,68%
Cotação: R$ 64,29
Oscilação:
No dia: -0,34%
No mês: 0,61%
Em 30 dias: 2,78%
Em 12 meses: 0,31%
AMER3
ROE: 54,76%
Cotação: R$ 0,53
Oscilação:
No dia: 0,00%
No mês: -3,64%
Em 30 dias: -8,62%
Em 12 meses: -52,68%
Resumo:
A VALE3 tem um ROE maior que a AMER3, indicando maior rentabilidade.
A cotação da VALE3 é significativamente maior que a da AMER3.
A AMER3 tem apresentado uma oscilação negativa mais acentuada nos últimos anos em comparação com a VALE3.
📡Note que agora a resposta veio completa!
Para conferir, basta acessar os links do Fundamentus com seus respectivos tickers:
https://fundamentus.com.br/detalhes.php?papel=AMER3
https://fundamentus.com.br/detalhes.php?papel=VALE3
🖖 Na análise realizada neste artigo, foram selecionadas algumas colunas do dataframe para avaliação:
Durante a análise no site Fundamentus, foram utilizados dados de oscilação para simplificar o escopo e facilitar a compreensão do artigo. O código completo está disponível em meu repositório no GitHub, pois alguns passos foram simplificados ao longo do artigo, focando nos aspectos mais essenciais.
O objetivo principal foi demonstrar a facilidade de criar um sistema de análise de empresas com o uso do LLM sem custos adicionais.
Colab — IA Generativa e Dados Fundamentalistas
Referencias: