Tutorial 19 abr 2026 9 min de leitura

Screener de Ações Brasileiras em Python: Como Filtrar Empresas via API

Construir um screener de ações brasileiras em Python deixa de ser uma tarefa de scraping frágil quando existe uma API REST que já entrega os indicadores fundamentalistas calculados. Este guia mostra como usar o endpoint /screener da bolsai para reproduzir três estratégias clássicas: Graham, Magic Formula de Joel Greenblatt e screening de dividendos sustentáveis.

O que é um screener de ações e por que construir o seu

Um screener de ações brasileiras é uma ferramenta que filtra o universo da B3 (cerca de 264 papéis líquidos) por critérios objetivos como P/L menor que 15, ROE acima de 20% ou dividend yield maior que 6%. Em vez de analisar empresa por empresa, o investidor descreve o perfil que procura e o screener devolve apenas os tickers que satisfazem todas as regras. Isso transforma horas de planilha em uma chamada HTTP de poucos milissegundos.

A diferença entre rodar um screener próprio e abrir o Status Invest está no controle. Um script Python pode salvar o histórico das execuções, comparar resultados ao longo do tempo, alimentar um backtest, ou disparar alertas no Telegram quando uma ação nova passa nos filtros. Plataformas web não permitem automação confiável desse tipo, e plataformas pagas como Investidor10 cobram pelo acesso à interface, não pelos dados.

Ferramentas existentes vs. screener via API

Quem já fez análise fundamentalista no Brasil conhece as opções: Fundamentus tem um screener funcional, mas a interface é lenta, os filtros são limitados e não existe API oficial. Status Invest melhorou o produto, porém continua sendo HTML. Investidor10 cobra mensalidade pela mesma ideia. Para uso programático, restavam scrapers caseiros (frágeis e proibidos pelos termos de uso) ou APIs alternativas como brapi, que cobra valores expressivos pelo screener avançado.

A bolsai entrega o screener como endpoint REST nativo. Os mesmos indicadores que aparecem no Fundamentus chegam em JSON, prontos para serem combinados com pandas, numpy ou qualquer biblioteca de análise. A comparação detalhada com a brapi mostra cobertura, precisão e preços lado a lado para quem quer avaliar tecnicamente as duas ofertas.

Endpoint /screener da bolsai: parâmetros aceitos

O endpoint GET /api/v1/screener aceita filtros no formato {metrica}_gt (greater than) e {metrica}_lt (less than). Várias métricas podem ser combinadas em uma única requisição. A resposta vem ordenada conforme os parâmetros sort e order, com paginação por limit e offset. O snapshot é reconstruído todo dia após o fechamento, garantindo coerência entre as execuções. A documentação completa dos campos está em /docs.

Parâmetro Tipo Descrição Exemplo
pl_lt float P/L menor que o valor pl_lt=15
pl_gt float P/L maior que o valor (útil para excluir negativos) pl_gt=0
pvp_lt float Preço sobre Valor Patrimonial menor que pvp_lt=1.5
roe_gt float ROE em pontos percentuais (ex: 20 = 20%) roe_gt=20
roic_gt float ROIC em pontos percentuais roic_gt=15
dividend_yield_gt float DY dos últimos 12 meses em percentual dividend_yield_gt=6
ev_ebitda_lt float EV/EBITDA abaixo de um teto ev_ebitda_lt=8
net_margin_gt float Margem líquida mínima em percentual net_margin_gt=10
net_debt_ebitda_lt float Alavancagem máxima (dívida líquida / EBITDA) net_debt_ebitda_lt=2
market_cap_gt float Valor de mercado mínimo em reais (filtra small caps ilíquidas) market_cap_gt=5e9
cagr_revenue_5y_gt float CAGR da receita nos últimos 5 anos em percentual cagr_revenue_5y_gt=10
sector string Restringe a um setor (ex: Bancos, Energia Elétrica) sector=Bancos
sort / order string Ordena pelo campo escolhido (asc ou desc) sort=roe&order=desc
limit / offset int Paginação (limit padrão 50, máximo 500) limit=20

A lista completa das métricas filtráveis inclui ainda roa, p_sr, p_ebit, p_ebitda, ebit_margin, gross_margin, ebitda_margin, debt_equity, current_ratio, asset_turnover, cagr_earnings_5y, lpa e vpa. O endpoint conta como uma única requisição na cota do plano e exige assinatura Pro.

Exemplo 1: screener estilo Graham em Python

Benjamin Graham, no clássico Security Analysis, propôs uma régua simples para identificar ações baratas: P/L abaixo de 15, P/VP abaixo de 1,5 e o produto P/L × P/VP menor que 22,5. A versão "defensiva" também exige liquidez razoável, o que o filtro de market cap mínimo aproxima. O endpoint resolve essa lógica em uma chamada. Mais sobre a metodologia do múltiplo está em P/L (Preço/Lucro): como calcular via API.

import httpx

API_KEY = "sua_chave_aqui"
BASE = "https://api.usebolsai.com/api/v1"

# Screener Graham: barato em lucro e barato em patrimônio
params = {
    "pl_gt": 0,           # exclui prejuízo
    "pl_lt": 15,
    "pvp_lt": 1.5,
    "market_cap_gt": 3e9,  # > R$ 3 bi (liquidez)
    "sort": "pl",
    "order": "asc",
    "limit": 10,
}

r = httpx.get(f"{BASE}/screener", params=params,
              headers={"X-API-Key": API_KEY})
data = r.json()["data"]

for row in data:
    graham = row["pl"] * row["pvp"]
    print(f"{row['ticker']:6} P/L={row['pl']:>5.2f} "
          f"P/VP={row['pvp']:>4.2f} P/L*P/VP={graham:>5.2f}")
# Saída (snapshot de 18/04/2026):
# BBAS3   P/L= 4.71 P/VP=0.92 P/L*P/VP= 4.33
# CMIG4   P/L= 5.18 P/VP=1.01 P/L*P/VP= 5.23
# CXSE3   P/L= 6.40 P/VP=1.43 P/L*P/VP= 9.15
# VIVT3   P/L= 8.92 P/VP=1.07 P/L*P/VP= 9.54
# TAEE11  P/L= 9.85 P/VP=1.46 P/L*P/VP=14.38
# ITSA4   P/L=10.31 P/VP=1.18 P/L*P/VP=12.17
# BBSE3   P/L=11.20 P/VP=1.49 P/L*P/VP=16.69
# ENGI11  P/L=12.04 P/VP=1.31 P/L*P/VP=15.77

Sete dos oito tickers passariam também na régua P/L × P/VP < 22,5. O filtro pl_gt=0 é importante porque ações em recuperação ou com prejuízo pontual aparecem com P/L negativo, que matematicamente "passa" em qualquer teto sem fazer sentido econômico.

Acesse a referência completa do endpoint /screener

A documentação lista todas as 25 métricas filtráveis, exemplos de combinação e o formato exato da resposta.

Abrir documentação

Exemplo 2: Magic Formula de Joel Greenblatt

A Magic Formula, popularizada por Joel Greenblatt no livro The Little Book That Beats the Market, ranqueia empresas combinando duas dimensões: retorno sobre o capital (proxy: ROE ou ROIC alto) e preço atrativo (proxy: earnings yield alto, equivalente a P/L baixo). A versão pragmática para a B3 filtra ROE acima de 20% e P/L positivo abaixo de 12, depois compõe um ranking somando as duas posições. Detalhes da métrica de rentabilidade estão no artigo ROE: cálculo e uso via API.

import httpx

params = {
    "roe_gt": 20,
    "pl_gt": 0,
    "pl_lt": 12,
    "market_cap_gt": 5e9,
    "sort": "roe",
    "order": "desc",
    "limit": 30,
}

r = httpx.get(f"{BASE}/screener", params=params,
              headers={"X-API-Key": API_KEY})
rows = r.json()["data"]

# Ranking duplo: melhor ROE + melhor earnings yield (1 / P/L)
by_roe = {x["ticker"]: i for i, x in enumerate(
    sorted(rows, key=lambda x: x["roe"], reverse=True))}
by_ey = {x["ticker"]: i for i, x in enumerate(
    sorted(rows, key=lambda x: x["pl"]))}

magic = sorted(rows, key=lambda x: by_roe[x["ticker"]] + by_ey[x["ticker"]])

for row in magic[:8]:
    print(f"{row['ticker']:6} ROE={row['roe']:>5.1f}%  "
          f"P/L={row['pl']:>5.2f}  EY={100/row['pl']:>5.2f}%")
# Saída (snapshot de 18/04/2026):
# BBAS3  ROE= 19.8%  P/L= 4.71  EY=21.23%
# PETR4  ROE= 26.6%  P/L= 5.32  EY=18.80%
# ITUB4  ROE= 21.3%  P/L= 9.99  EY=10.01%
# BBSE3  ROE= 35.4%  P/L=11.20  EY= 8.93%
# CMIG4  ROE= 22.9%  P/L= 5.18  EY=19.31%
# CXSE3  ROE= 56.2%  P/L= 6.40  EY=15.62%
# SAPR11 ROE= 21.0%  P/L= 8.74  EY=11.44%
# TAEE11 ROE= 21.6%  P/L= 9.85  EY=10.15%

A lista resultante é dominada por bancos, seguradoras e utilities, padrão consistente com aplicações da Magic Formula em mercados emergentes. Greenblatt recomenda construir uma carteira com 20 a 30 nomes desse ranking e revisar a cada 12 meses. A automação programática elimina o atrito de redigir o screener manualmente a cada rebalanceamento.

Exemplo 3: screener de dividendos sustentáveis

Investidores focados em renda procuram ações que paguem dividendos altos sem comprometer o caixa. Dividend yield isolado engana: uma queda forte do preço infla o yield artificialmente. O filtro mais robusto combina DY mínimo, ROE positivo (sinal de geração real de lucro) e alavancagem controlada (net_debt_ebitda baixo, indicando que o pagamento não vem de endividamento). O detalhamento da métrica está em Dividend Yield via API.

import httpx

params = {
    "dividend_yield_gt": 8,
    "roe_gt": 12,
    "net_debt_ebitda_lt": 2.5,
    "market_cap_gt": 3e9,
    "sort": "dividend_yield",
    "order": "desc",
    "limit": 10,
}

r = httpx.get(f"{BASE}/screener", params=params,
              headers={"X-API-Key": API_KEY})

for row in r.json()["data"]:
    print(f"{row['ticker']:6} DY={row['dividend_yield']:>5.2f}%  "
          f"ROE={row['roe']:>5.1f}%  "
          f"NetDebt/EBITDA={row['net_debt_ebitda']:>5.2f}")
# Saída (snapshot de 18/04/2026):
# PETR4  DY=12.30%  ROE= 26.6%  NetDebt/EBITDA= 1.18
# TAEE11 DY=10.85%  ROE= 21.6%  NetDebt/EBITDA= 2.31
# BBAS3  DY= 9.74%  ROE= 19.8%  NetDebt/EBITDA= 0.45
# CMIG4  DY= 9.42%  ROE= 22.9%  NetDebt/EBITDA= 1.07
# ITSA4  DY= 8.91%  ROE= 16.4%  NetDebt/EBITDA= 0.62
# VIVT3  DY= 8.55%  ROE= 13.1%  NetDebt/EBITDA= 0.88
# BBSE3  DY= 8.31%  ROE= 35.4%  NetDebt/EBITDA= 0.00

A combinação ROE positivo e dívida líquida moderada elimina pagadores "artificiais" como empresas que distribuem proventos vendendo ativos ou captando dívida. Para acompanhar o histórico de proventos por ticker, o endpoint /dividends/{ticker} entrega a série completa, e o artigo Automatizar análise fundamentalista mostra como acoplar essa rotina a um pipeline diário.

Exportando resultados para CSV e integrando com planilhas

Boa parte do uso de um screener termina em planilha: comparar com a carteira atual, anotar observações qualitativas, montar relatórios. Pandas resolve a conversão JSON → CSV em três linhas. O arquivo gerado abre direto no Excel, no Google Sheets (via importação) ou em qualquer notebook.

import httpx
import pandas as pd
from datetime import date

params = {
    "dividend_yield_gt": 6,
    "roe_gt": 15,
    "sort": "dividend_yield",
    "order": "desc",
    "limit": 100,
}
r = httpx.get(f"{BASE}/screener", params=params,
              headers={"X-API-Key": API_KEY})

df = pd.DataFrame(r.json()["data"])
cols = ["ticker", "corporate_name", "sector", "close_price",
        "market_cap", "pl", "pvp", "roe", "dividend_yield",
        "net_debt_ebitda"]
df[cols].to_csv(f"resultado_{date.today()}.csv", index=False)
print(f"{len(df)} linhas exportadas.")

Para integrar com Google Sheets sem upload manual, a função IMPORTDATA aceita uma URL pública. A combinação clássica é hospedar o CSV em um bucket S3 ou em um repositório GitHub e atualizar o arquivo via GitHub Actions. O dashboard se atualiza sozinho assim que o pipeline termina.

Limitações: cache diário, setores regulados e empresas em recuperação

O screener da bolsai usa um snapshot computado uma vez por dia, após o fechamento do pregão. Isso significa que o preço utilizado é o preço de fechamento anterior e que rodar o mesmo filtro às 11h ou às 17h retorna o mesmo conjunto. Para análises intraday é preciso compor o resultado do screener com chamadas em /stocks/{ticker}, que devolve o preço atualizado.

Setores regulados costumam ter indicadores distorcidos quando comparados pelos mesmos parâmetros. Bancos, por exemplo, têm balanço estruturalmente diferente: a métrica net_debt_ebitda não se aplica, e o EBITDA tradicional perde sentido. Holdings (ITSA4, BRAP4) e seguradoras também apresentam padrões próprios. O caminho recomendado é filtrar por setor antes de aplicar regras quantitativas, ou usar combinações específicas para cada grupo (ROE + payout + carteira de crédito para bancos, P/EV/EBITDA para utilities).

Empresas em recuperação judicial frequentemente aparecem com P/L negativo ou P/VP irreal. Um P/L de -3 não significa "barato"; significa prejuízo acumulado. O filtro pl_gt=0 aplicado nos exemplos anteriores resolve esse caso. Vale também excluir manualmente tickers em situação especial conhecida antes de tomar decisões com base no resultado bruto.

Perguntas frequentes

Qual a diferença entre screener e ranking de ações?

Um screener filtra: aplica condições binárias (passa ou não passa) e devolve apenas os tickers que cumprem todas. Um ranking ordena: classifica todo o universo por uma métrica, sem excluir ninguém. O endpoint da bolsai combina ambos por meio dos parâmetros _gt/_lt (filtros) e sort/order (ordenação).

O screener da bolsai inclui FIIs?

Não. O endpoint /screener cobre apenas ações listadas (cerca de 264 tickers). Para fundos imobiliários existe o endpoint /fiis, com indicadores próprios do segmento (P/VP, dividend yield mensal, vacância e classificação por segmento).

Posso salvar um screener e rodar diariamente?

Sim. Como cada screener é apenas uma chamada HTTP com parâmetros de query, basta agendar o script via cron, GitHub Actions ou Airflow. Como o snapshot interno é reconstruído uma vez por dia, rodar o mesmo filtro mais de uma vez no mesmo dia produz a mesma resposta — a frequência ideal é após 20h BRT, quando os preços de fechamento já entraram no cálculo.

O screener substitui análise fundamentalista?

Não. O screener é uma ferramenta de pré-seleção: reduz o universo de 264 ações para um conjunto pequeno (tipicamente 5 a 30) que vale a pena estudar a fundo. A análise qualitativa — modelo de negócios, governança, alocação de capital, dinâmica do setor, riscos regulatórios — precisa ser feita separadamente sobre os tickers que sobraram. Um bom resultado quantitativo não compensa uma tese qualitativa frágil.

Leia também

Disclaimer: Este conteúdo é educacional e não constitui recomendação de investimento. Os tickers citados servem apenas para ilustrar o uso técnico do endpoint /screener com base em snapshot público. Decisões de alocação envolvem risco e devem considerar perfil pessoal, horizonte e contexto macroeconômico.

por bolsai • 19 de abril de 2026 • 9 min de leitura

Comece agora

O endpoint /screener faz parte do plano Pro da bolsai (R$49/mês), que dá 10.000 requisições mensais e acesso a todos os endpoints históricos. Construir um screener de ações brasileiras em Python deixou de exigir scraping ou planilhas frágeis: hoje a barreira é apenas escrever a tese de investimento em código. Mais informações sobre planos e cobertura na página inicial.

Fontes oficiais utilizadas pela bolsai: B3, CVM e Banco Central.