Em meio a um devaneio, solicitei a IA que tentasse analisar os ativos que representassem 50% da carteira de um ETF para obter a media ponderada de alguns dados de valuation, como são muitos ativos ela bugou, mas me forneceu o código em Python que permitiria fazer a análise, testei e deu certo, os dados obtidos realmente batem com os contidos no site.
Os dados solicitados foram:
ROE
ROIC
ROA
DIV LIQ/EBITDA
P/EBIT
P/EBITDA
LIQUIDEZ CORRENTE
LIQUIDEZ SECA
LIQUIDEZ IMEDIATA
PAS/ATIV
Caso alguém tenha interesse aqui vai o passo a passo
Baixar as planilhas das holdings do ETF no site do gestor, abrir o arquivo no excel e deixar apenas as colunas de ticker e Weight, salvar o arquivo como no formato CSV
Acessar o colab.research.google.com
Abrir um novo notebook
Digitar na caixa de texto do código "!pip install yfinance pandas" e apertar o play do lado esquerdo
Nos ícones a esquerda o penúltimo item (ícone com formato de pasta) faça o upload do arquivo CSV
Clique na caixa do primero comando e logo acima dela ele te dará a opção "+código"clique nela e insira esse prompt"
import yfinance as yf
import pandas as pd
import numpy as np
df_top_50 = pd.read_csv('Nome do arquivo upado.csv', sep=';')
print("Colunas do DataFrame após leitura do CSV:")
print(df_top_50.columns)
# Rename the 'Weight' column to 'Peso' to match expectations
df_top_50 = df_top_50.rename(columns={'Weight': 'Peso'}) # Corrected from 'Weight (%)' to 'Weight'
# Clean and convert 'Peso' column to numeric, handling problematic characters like '-'
df_top_50['Peso'] = df_top_50['Peso'].str.replace(',', '.').replace('-', np.nan).astype(float)
# Filter out invalid or problematic tickers that cause yfinance errors
df_top_50 = df_top_50[df_top_50['Ticker'].notna()].copy() # Remove rows with NaN Ticker
df_top_50 = df_top_50[df_top_50['Ticker'].str.strip() != ''].copy() # Remove empty or whitespace-only Tickers
df_top_50 = df_top_50[df_top_50['Ticker'] != '-'].copy() # Remove single hyphen Tickers
# Explicitly filter out currency symbols and other known non-stock tickers
problematic_symbols = ['_CURRENCYEUR', '_CURRENCYGBP', '_CURRENCYCHF', '_CURRENCYDKK', '_CURRENCYUSD', '_CURRENCYNOK', '_CURRENCYSEK', '___ADI2VD0K2', '2330', '5930', '700', '660', '9988'] # Added common problematic entries from EIMI, if they appear as tickers
df_top_50 = df_top_50[~df_top_50['Ticker'].isin(problematic_symbols)].copy()
dados_empresas = []
print("Extraindo os dados financeiros atuais... Isso será bem mais rápido.\n")
for index, row in df_top_50.iterrows():
ticker = row['Ticker']
peso = row['Peso'] # This line was the error. We needed the correct column name.
try:
acao = yf.Ticker(ticker)
info = acao.info
# Check if info is empty, which indicates a problematic ticker for yfinance
if not info or len(info) <= 1: # len(info) <= 1 often means only 'trailingPegRatio' or similar, indicating no real data
print(f"Aviso: Não foi possível obter dados para o ticker {ticker}. Pulando este ativo.")
continue
bs = acao.balance_sheet
inc = acao.financials
def dado_recente(df, nome_linha):
try: return df.loc[nome_linha].iloc[0]
except (KeyError, IndexError): return np.nan
roe = info.get('returnOnEquity', np.nan)
roa = info.get('returnOnAssets', np.nan)
liquidez_corrente = info.get('currentRatio', np.nan)
liquidez_seca = info.get('quickRatio', np.nan)
ebitda = info.get('ebitda', np.nan)
market_cap = info.get('marketCap', np.nan)
caixa_total = info.get('totalCash', np.nan)
divida_total = info.get('totalDebt', np.nan)
ebit = dado_recente(inc, 'EBIT')
capital_investido = dado_recente(bs, 'Invested Capital')
ativos_totais = dado_recente(bs, 'Total Assets')
passivos_totais = dado_recente(bs, 'Total Liabilities Net Minority Interest')
passivo_circulante = dado_recente(bs, 'Current Liabilities')
roic = (ebit / capital_investido) if (pd.notna(ebit) and pd.notna(capital_investido) and capital_investido != 0) else np.nan
divida_liq_ebitda = ((divida_total - caixa_total) / ebitda) if (pd.notna(divida_total) and pd.notna(caixa_total) and pd.notna(ebitda) and ebitda != 0) else np.nan
p_ebit = (market_cap / ebit) if (pd.notna(market_cap) and pd.notna(ebit) and ebit != 0) else np.nan
p_ebitda = (market_cap / ebitda) if (pd.notna(market_cap) and pd.notna(ebitda) and ebitda != 0) else np.nan
passivos_ativos = (passivos_totais / ativos_totais) if (pd.notna(passivos_totais) and pd.notna(ativos_totais) and ativos_totais != 0) else np.nan
liquidez_imediata = (caixa_total / passivo_circulante) if (pd.notna(caixa_total) and pd.notna(passivo_circulante) and passivo_circulante != 0) else np.nan
dados = {
'Ticker': ticker,
'Peso': peso,
'ROE Atual (%)': roe * 100 if pd.notna(roe) else np.nan,
'ROA Atual (%)': roa * 100 if pd.notna(roa) else np.nan,
'ROIC Atual (%)': roic * 100 if pd.notna(roic) else np.nan,
'Dívida Líq/EBITDA': divida_liq_ebitda,
'P/EBIT': p_ebit,
'P/EBITDA': p_ebitda,
'Liquidez Corrente': liquidez_corrente,
'Liquidez Seca': liquidez_seca,
'Liquidez Imediata': liquidez_imediata,
'Passivos/Ativos (%)': passivos_ativos * 100 if pd.notna(passivos_ativos) else np.nan
}
dados_empresas.append(dados)
except Exception as e:
print(f"Aviso: Erro ao processar o ticker {ticker}: {e}. Pulando este ativo.")
continue
# Ensure df_resultados is created even if dados_empresas is empty
df_resultados = pd.DataFrame(dados_empresas)
print("--- Dados Extraídos por Empresa ---")
print(df_resultados.round(2).to_string(index=False))
print("\n" + "-"*80 + "\n")
def media_ponderada(valores, pesos):
mascara = valores.notna() & pesos.notna()
if not mascara.any(): return np.nan
return np.average(valores[mascara], weights=pesos[mascara])
print("---" * 10 + "\nMÉDIA PONDERADA ATUAL DO FUNDO\n" + "---" * 10)
colunas_para_media = [c for c in df_resultados.columns if c not in ['Ticker', 'Peso']]
if not df_resultados.empty:
for coluna in colunas_para_media:
resultado = media_ponderada(df_resultados[coluna], df_resultados['Peso'])
if "(%)" in coluna:
print(f"{coluna}: {resultado:.2f}%")
else:
print(f"{coluna}: {resultado:.2f}x")
else:
print("Nenhum dado financeiro foi extraído após a filtragem de tickers.")
pedir para rodar o código, nesse passo alguns erros podem surgir e o próprio gemini oferece soluções, peça para as executar e ele tentar rodar novamente
Após isso ele ira buscar os dados, ignorar o que não encontrou no site e te dar as medias
Deixei abaixo o resultado que consegui para o SPYL versão irlandesa do SPY