Aplicação Web com Python e Streamlit
Atualmente, a criação de uma aplicação web já não é um processo complicado. Streamlit é uma biblioteca Python para criação de web apps de forma simples e rápida. Com ela, não é necessário saber HTML, CSS ou JavaScript. Tudo é escrito diretamente em Python. Neste post, usaremos Streamlit para criar uma pequena aplicação web de análise do mercado financeiro.
Os Dados
Usaremos um conjunto de dados disponível no Kaggle nesse link. Ele tem os dados de ações e empresas de todos os membros do popular índice financeiro S&P 500. Sua descrição é a seguinte:
O Standard and Poor’s 500 ou S&P 500 é o benchmark financeiro mais famoso do mundo. Este índice do mercado de ações acompanha o desempenho de 500 grandes empresas listadas em bolsas de valores nos Estados Unidos. Em 31 de dezembro de 2020, mais de US$ 5,4 trilhões foram investidos em ativos vinculados ao desempenho desse índice. Como o índice inclui várias classes de ações de algumas empresas constituintes – por exemplo, Classe A (GOOGL) e Classe C (GOOG) da Alphabet – há na verdade 505 ações no indicador.
Para acompanhar o post, baixe os dados localmente no seu computador. Eles podem ser baixados diretamente do site do Kaggle ou usando a API da plataforma.
O Objetivo da Aplicação Web
O conjunto do Kaggle do S&P 500 conta com dois tipos de dados: séries temporais e dados gerais das empresas listadas. Iremos nos concentrar nos dados das empresas. Os dados possuem três arquivos, o foco do post será no arquivo sp500_companies.csv. Como o S&P 500 possui muitos dados, o objetivo da aplicação web desse post será fornecer uma análise super rápida sobre os maiores players de cada setor. A análise será exibida na forma de gráficos.
Bibliotecas
Usaremos várias bibliotecas típicas de ciência de dados, além, é claro, da biblioteca Streamlit:
- pandas
- NumPy
- matplotlib (para visualização)
- seaborn (para visualização)
- Streamlit
O App
Iniciaremos nosso app com os dados. Mostraremos os dados diretamente em nosso aplicativo na forma de uma tabela. Em um código Python que pode se chamar app.py, efetue as importações necessárias. Também é recomendável filtrar uns warnings.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import streamlit as st
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)
Depois, criamos um título e um subheader para nosso app, e apresentamos os dados do arquivo sp500_companies.csv.
st.title("S&P 500")
st.subheader("Dados Financeiros das Empresas Listadas pelo S&P 500")
with st.container(border=True):
st.subheader("Empresas Listadas no S&P 500")
df = pd.read_csv('PATH PARA SEU ARQUIVO/sp500_companies.csv')
st.dataframe(df)
Salve tudo e execute o código com o comando streamlit run app.py. Ele abrirá diretamente no navegador. Por enquanto, o app está assim:
Uma inspeção rápida na tabela deixa claro que ela é muito difícil de ser entendida sem a ajuda da ciência de dados. Nossa intenção é criar um app que faça exatamente isso. Contaremos com o pandas (leia mais sobre a biblioteca aqui, aqui e aqui) para nos auxiliar.
Análise Exploratória
Para explorar os dados, é melhor abri-los em um arquivo separado do arquivo do app. Qualquer exploração inicial com o pandas envolve os comandos head e info.
print(df.head())
Resultado:
Exchange Symbol Shortname ... Fulltimeemployees Longbusinesssummary Weight
0 NMS MSFT Microsoft Corporation ... 221000.0 Microsoft Corporation develops and supports so... 0.065276
1 NMS AAPL Apple Inc. ... 161000.0 Apple Inc. designs, manufactures, and markets ... 0.056234
2 NMS NVDA NVIDIA Corporation ... 29600.0 NVIDIA Corporation provides graphics, and comp... 0.046326
3 NMS AMZN Amazon.com, Inc. ... 1525000.0 Amazon.com, Inc. engages in the retail sale of... 0.038222
4 NMS GOOG Alphabet Inc. ... 182502.0 Alphabet Inc. offers various products and plat... 0.037157
[5 rows x 16 columns]
Comando info:
print(df.info())
Resultado:
RangeIndex: 503 entries, 0 to 502
Data columns (total 16 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Exchange 503 non-null object
1 Symbol 503 non-null object
2 Shortname 503 non-null object
3 Longname 503 non-null object
4 Sector 503 non-null object
5 Industry 503 non-null object
6 Currentprice 503 non-null float64
7 Marketcap 503 non-null int64
8 Ebitda 474 non-null float64
9 Revenuegrowth 502 non-null float64
10 City 503 non-null object
11 State 483 non-null object
12 Country 503 non-null object
13 Fulltimeemployees 493 non-null float64
14 Longbusinesssummary 503 non-null object
15 Weight 503 non-null float64
dtypes: float64(5), int64(1), object(10)
memory usage: 63.0+ KB
None
Os resultados mostram que os dados têm 16 colunas com informações financeiras sobre todas as mais de 500 empresas listadas no S&P 500. Várias informações são interessantes para análises. Como nosso app é de análise financeira, uma questão que ele precisa responder é quais são os melhores setores para investimentos. Nos concentraremos em combinar informações que envolvem lucro, preço, valor de mercado. Nosso objetivo será apresentar essas informações de forma gráfica para que os usuários as entendam com facilidade.
Em qual setor devo investir?
De volta ao código do nosso app, daremos sequência ao que foi desenvolvido (a partir da linha 8 no trecho abaixo). Para auxiliar os usuários da aplicação web a entenderem quais são os melhores setores para investimentos, nos concentraremos na análise de 4 aspectos: o total de empresas por setor (usando count), a soma (sum) do preço atual (current price) do total de empresas em cada setor, a soma do maket cap e a média (mean) da taxa de crescimento de lucro (revenue growth) por setor. Tudo isso é facilmente calculado com o pandas.
st.title("S&P 500")
st.subheader("Dados Financeiros das Empresas Listadas pelo S&P 500")
with st.container(border=True):
st.subheader("Empresas Listadas no S&P 500")
df = pd.read_csv('PATH PARA SEU ARQUIVO/sp500_companies.csv')
st.dataframe(df)
# continuando aqui
f = {'Revenuegrowth':['mean'], 'Marketcap':['sum'], 'Currentprice':['sum'], 'Longname':['count']}
sector_breakdown = df.groupby('Sector').agg(f)
sector_breakdown.columns = sector_breakdown.columns.get_level_values(0)
sector_breakdown = sector_breakdown.reset_index()
sector_breakdown = sector_breakdown.sort_values('Longname', ascending=False)
Em seguida, preparamos as figuras mostrando esses dados com matplotlib e seaborn. Optamos por duas figuras para acomodá-las melhor no app. A primeira mostra o total de empresas por setor e a soma de seus preços. A segunda mostra o market cap total por setor e a média do crescimento de lucro. Como o índice S&P 500 lista os dados em inglês, eles aparecem assim nas figuras.
# fig 1
fig1, [ax1, ax2] = plt.subplots(figsize=(18,6), nrows=1, ncols=2)
plt.subplot(1, 2, 1)
ax1 = sns.barplot(x="Longname", y='Sector', data=sector_breakdown, palette=('rainbow'))
ax1.set_xlabel('Number of companies', weight='bold').set_fontsize('14')
ax1.set_ylabel('Sector', weight = 'bold').set_fontsize('14')
plt.subplot(1, 2, 2)
ax2 = sns.barplot(x="Currentprice", y='Sector', data=sector_breakdown, palette=('rainbow'))
ax2.set_xlabel('Total Current Price', weight='bold').set_fontsize('14')
ax2.set_ylabel('')
ax2.set_yticks([])
sns.despine()
fig1.suptitle('Análise por Setor\n', weight='bold').set_fontsize('16')
st.pyplot(fig1)
# fig 2
fig2, [ax3, ax4] = plt.subplots(figsize=(18,6), nrows=1, ncols=2)
plt.subplot(1, 2, 1)
ax3 = sns.barplot(x="Marketcap", y='Sector', data=sector_breakdown, palette=('rainbow'))
ax3.set_ylabel('Sector', weight = 'bold').set_fontsize('14')
ax3.set_xlabel('Total Market Cap', weight='bold').set_fontsize('14')
plt.subplot(1, 2, 2)
ax4 = sns.barplot(x="Revenuegrowth", y='Sector', data=sector_breakdown, palette=('rainbow'))
ax4.set_xlabel('Mean Revenue Growth', weight='bold').set_fontsize('14')
ax4.set_ylabel('')
ax4.set_yticks([])
sns.despine()
fig2.suptitle('Análise por Setor\n', weight='bold').set_fontsize('16')
st.pyplot(fig2)
Essas figuras ficam assim na aplicação web:
Análise Personalizada
Para finalizar nosso app, possibilitaremos também que seus usuários busquem informações específicas para os setores pelos quais eles se interessam mais. Para isso, precisamos criar um menu (selectbox) de opções com todos os setores disponíveis no índice S&P 500.
st.write('\n')
sectors = df['Sector'].unique()
option = st.selectbox(
'Qual setor você gostaria de ver em detalhes?',
(sectors), index=None, placeholder="Selecione uma opção...",)
if option == None:
st.write('')
else:
st.write('Você selecionou: ', option)
Quando um setor for selecionado por um usuário, repetiremos a análise feita anteriormente, mas com uma diferença: ao invés de mostrar os dados por setor, mostraremos os dados por indústria de um setor específico (veja a tabela). Portanto, no lugar do df original, entramos com os dados específicos para o setor selecionado (alvo).
if option != None:
alvo = df[df['Sector']==option]
f = {'Revenuegrowth':['mean'], 'Marketcap':['sum'], 'Currentprice':['sum'], 'Longname':['count']}
industry_breakdown = alvo.groupby('Industry').agg(f)
industry_breakdown.columns = industry_breakdown.columns.get_level_values(0)
industry_breakdown = industry_breakdown.reset_index()
industry_breakdown = industry_breakdown.sort_values('Longname', ascending=False)
Depois, preparamos as figuras (a partir da linha 6 abaixo) que também são equivalentes as mostradas anteriormente.
if option != None:
...
industry_breakdown = industry_breakdown.sort_values('Longname', ascending=False)
# continua a partir daqui
# fig 3
fig3, [ax1, ax2] = plt.subplots(figsize=(18,6), nrows=1, ncols=2)
plt.subplot(1, 2, 1)
ax1 = sns.barplot(x="Longname", y='Industry', data=industry_breakdown, palette=('rainbow'))
ax1.set_xlabel('Number of companies', weight='bold').set_fontsize('14')
ax1.set_ylabel('Industry', weight = 'bold').set_fontsize('14')
plt.subplot(1, 2, 2)
ax2 = sns.barplot(x="Currentprice", y='Industry', data=industry_breakdown, palette=('rainbow'))
ax2.set_xlabel('Total Current Price', weight='bold').set_fontsize('14')
ax2.set_ylabel('')
ax2.set_yticks([])
sns.despine()
fig3.suptitle('Análise por Indústria\n', weight='bold').set_fontsize('16')
st.pyplot(fig3)
# fig 4
fig4, [ax3, ax4] = plt.subplots(figsize=(18,6), nrows=1, ncols=2)
plt.subplot(1, 2, 1)
ax3 = sns.barplot(x="Marketcap", y='Industry', data=industry_breakdown, palette=('rainbow'))
ax3.set_ylabel('Industry', weight = 'bold').set_fontsize('14')
ax3.set_xlabel('Total Market Cap', weight='bold').set_fontsize('14')
plt.subplot(1, 2, 2)
ax4 = sns.barplot(x="Revenuegrowth", y='Industry', data=industry_breakdown, palette=('rainbow'))
ax4.set_xlabel('Mean Revenue Growth', weight='bold').set_fontsize('14')
ax4.set_ylabel('')
ax4.set_yticks([])
sns.despine()
fig4.suptitle('Análise por Indústria\n', weight='bold').set_fontsize('16')
st.pyplot(fig4)
Salve tudo e teste o app com diferentes seleções.
Conclusões
Neste post, usamos Streamlit para criar uma aplicação web super rápida para análise dos dados do mercado financeiro usando o conjunto de dados S&P 500 disponível no Kaggle. Nossa aplicação web contou com a ajuda da excelente biblioteca pandas e de outras bibliotecas tradicionais do Python para análise e visualização de dados. Para quem se interessou por esse tipo de análise, esse app pode ser facilmente expandido para mostrar outras variações dos dados. Ele também pode se beneficiar muito de uma etapa de pré-processamento para lidar com valores faltantes ou outros fatores específicos.