├── .gitignore
├── README.md
├── app.py
├── images
├── logo-250-100-transparente.png
├── pie-chart-dollar-svgrepo-com.svg
└── pie-chart-svgrepo-com.svg
├── requirements.txt
└── tickers_ibra.csv
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | venv
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Stock Market Dashboard
2 | A Python Dashboard for brazilian stock market made with Streamlit.
3 |
4 | 
5 |
6 | Live Demo: https://stockdashboardcq.streamlit.app/
7 |
8 | Youtube video: https://youtu.be/LAHlE_Lt9N4
9 |
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import numpy as np
4 | import yfinance as yf
5 | import plotly.express as px
6 | from datetime import datetime
7 | from streamlit_extras.metric_cards import style_metric_cards
8 | from streamlit_extras.grid import grid
9 |
10 |
11 | def build_sidebar():
12 | st.image("images/logo-250-100-transparente.png")
13 | ticker_list = pd.read_csv("tickers_ibra.csv", index_col=0)
14 | tickers = st.multiselect(label="Selecione as Empresas", options=ticker_list, placeholder='Códigos')
15 | tickers = [t+".SA" for t in tickers]
16 | start_date = st.date_input("De", format="DD/MM/YYYY", value=datetime(2023,1,2))
17 | end_date = st.date_input("Até", format="DD/MM/YYYY", value="today")
18 |
19 | if tickers:
20 | prices = yf.download(tickers, start=start_date, end=end_date)["Adj Close"]
21 | if len(tickers) == 1:
22 | prices = prices.to_frame()
23 | prices.columns = [tickers[0].rstrip(".SA")]
24 |
25 | prices.columns = prices.columns.str.rstrip(".SA")
26 | prices['IBOV'] = yf.download("^BVSP", start=start_date, end=end_date)["Adj Close"]
27 | return tickers, prices
28 | return None, None
29 |
30 | def build_main(tickers, prices):
31 | weights = np.ones(len(tickers))/len(tickers)
32 | prices['portfolio'] = prices.drop("IBOV", axis=1) @ weights
33 | norm_prices = 100 * prices / prices.iloc[0]
34 | returns = prices.pct_change()[1:]
35 | vols = returns.std()*np.sqrt(252)
36 | rets = (norm_prices.iloc[-1] - 100) / 100
37 |
38 | mygrid = grid(5 ,5 ,5 ,5 ,5 , 5, vertical_align="top")
39 | for t in prices.columns:
40 | c = mygrid.container(border=True)
41 | c.subheader(t, divider="red")
42 | colA, colB, colC = c.columns(3)
43 | if t == "portfolio":
44 | colA.image("images/pie-chart-dollar-svgrepo-com.svg")
45 | elif t == "IBOV":
46 | colA.image("images/pie-chart-svgrepo-com.svg")
47 | else:
48 | colA.image(f'https://raw.githubusercontent.com/thefintz/icones-b3/main/icones/{t}.png', width=85)
49 | colB.metric(label="retorno", value=f"{rets[t]:.0%}")
50 | colC.metric(label="volatilidade", value=f"{vols[t]:.0%}")
51 | style_metric_cards(background_color='rgba(255,255,255,0)')
52 |
53 | col1, col2 = st.columns(2, gap='large')
54 | with col1:
55 | st.subheader("Desempenho Relativo")
56 | st.line_chart(norm_prices, height=600)
57 |
58 | with col2:
59 | st.subheader("Risco-Retorno")
60 | fig = px.scatter(
61 | x=vols,
62 | y=rets,
63 | text=vols.index,
64 | color=rets/vols,
65 | color_continuous_scale=px.colors.sequential.Bluered_r
66 | )
67 | fig.update_traces(
68 | textfont_color='white',
69 | marker=dict(size=45),
70 | textfont_size=10,
71 | )
72 | fig.layout.yaxis.title = 'Retorno Total'
73 | fig.layout.xaxis.title = 'Volatilidade (anualizada)'
74 | fig.layout.height = 600
75 | fig.layout.xaxis.tickformat = ".0%"
76 | fig.layout.yaxis.tickformat = ".0%"
77 | fig.layout.coloraxis.colorbar.title = 'Sharpe'
78 | st.plotly_chart(fig, use_container_width=True)
79 |
80 |
81 | st.set_page_config(layout="wide")
82 |
83 | with st.sidebar:
84 | tickers, prices = build_sidebar()
85 |
86 | st.title('Python para Investidores')
87 | if tickers:
88 | build_main(tickers, prices)
--------------------------------------------------------------------------------
/images/logo-250-100-transparente.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codigoquant/stock_dashboard/e3474ef684f4c92b026b331048afe52566f71e4d/images/logo-250-100-transparente.png
--------------------------------------------------------------------------------
/images/pie-chart-dollar-svgrepo-com.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/images/pie-chart-svgrepo-com.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | altair==5.2.0
2 | anyio==4.2.0
3 | appdirs==1.4.4
4 | attrs==23.2.0
5 | beautifulsoup4==4.12.3
6 | blinker==1.7.0
7 | cachetools==5.3.2
8 | certifi==2023.11.17
9 | charset-normalizer==3.3.2
10 | click==8.1.7
11 | contourpy==1.2.0
12 | cycler==0.12.1
13 | entrypoints==0.4
14 | exceptiongroup==1.2.0
15 | Faker==22.6.0
16 | favicon==0.7.0
17 | fonttools==4.47.2
18 | frozendict==2.4.0
19 | gitdb==4.0.11
20 | GitPython==3.1.41
21 | h11==0.14.0
22 | htbuilder==0.6.2
23 | html5lib==1.1
24 | httpcore==0.17.3
25 | httpx==0.24.1
26 | idna==3.6
27 | importlib-metadata==7.0.1
28 | Jinja2==3.1.3
29 | jsonschema==4.20.0
30 | jsonschema-specifications==2023.12.1
31 | kiwisolver==1.4.5
32 | lxml==4.9.4
33 | Markdown==3.5.2
34 | markdown-it-py==3.0.0
35 | markdownlit==0.0.7
36 | MarkupSafe==2.1.3
37 | matplotlib==3.8.2
38 | mdurl==0.1.2
39 | more-itertools==10.2.0
40 | multitasking==0.0.11
41 | numpy==1.26.3
42 | packaging==23.2
43 | pandas==2.1.4
44 | peewee==3.17.0
45 | pillow==10.2.0
46 | plotly==5.18.0
47 | protobuf==4.25.2
48 | pyarrow==14.0.2
49 | pydeck==0.8.1b0
50 | Pygments==2.17.2
51 | pymdown-extensions==10.7
52 | pyparsing==3.1.1
53 | python-dateutil==2.8.2
54 | pytz==2023.3.post1
55 | PyYAML==6.0.1
56 | referencing==0.32.1
57 | requests==2.31.0
58 | rich==13.7.0
59 | rpds-py==0.17.1
60 | six==1.16.0
61 | smmap==5.0.1
62 | sniffio==1.3.0
63 | soupsieve==2.5
64 | st-annotated-text==4.0.1
65 | streamlit==1.30.0
66 | streamlit-camera-input-live==0.2.0
67 | streamlit-card==1.0.0
68 | streamlit-embedcode==0.1.2
69 | streamlit-extras==0.3.6
70 | streamlit-faker==0.0.3
71 | streamlit-image-coordinates==0.1.6
72 | streamlit-keyup==0.2.2
73 | streamlit-toggle-switch==1.0.2
74 | streamlit-vertical-slider==2.5.5
75 | tenacity==8.2.3
76 | toml==0.10.2
77 | toolz==0.12.0
78 | tornado==6.4
79 | typing_extensions==4.9.0
80 | tzdata==2023.4
81 | tzlocal==5.2
82 | urllib3==2.1.0
83 | validators==0.22.0
84 | watchdog==3.0.0
85 | webencodings==0.5.1
86 | yfinance
87 | zipp==3.17.0
88 |
--------------------------------------------------------------------------------
/tickers_ibra.csv:
--------------------------------------------------------------------------------
1 | ,0
2 | 0,AALR3
3 | 1,ABCB4
4 | 2,ABEV3
5 | 3,AESB3
6 | 4,AGRO3
7 | 6,ALPA4
8 | 7,ALUP11
9 | 8,AMAR3
10 | 9,AMBP3
11 | 10,ANIM3
12 | 11,ARML3
13 | 12,ARZZ3
14 | 13,ASAI3
15 | 14,AURE3
16 | 15,AZUL4
17 | 16,B3SA3
18 | 17,BBAS3
19 | 18,BBDC3
20 | 19,BBDC4
21 | 20,BBSE3
22 | 21,BEEF3
23 | 22,BHIA3
24 | 23,BLAU3
25 | 24,BMOB3
26 | 25,BPAC11
27 | 26,BPAN4
28 | 27,BRAP4
29 | 28,BRFS3
30 | 29,BRKM5
31 | 30,BRSR6
32 | 31,CAML3
33 | 32,CASH3
34 | 33,CBAV3
35 | 34,CCRO3
36 | 35,CEAB3
37 | 36,CIEL3
38 | 37,CMIG3
39 | 38,CMIG4
40 | 39,CMIN3
41 | 40,COGN3
42 | 41,CPFE3
43 | 42,CPLE6
44 | 43,CRFB3
45 | 44,CSAN3
46 | 45,CSMG3
47 | 46,CSNA3
48 | 47,CURY3
49 | 48,CVCB3
50 | 49,CXSE3
51 | 50,CYRE3
52 | 51,DASA3
53 | 52,DIRR3
54 | 53,DXCO3
55 | 54,ECOR3
56 | 55,EGIE3
57 | 56,ELET3
58 | 57,ELET6
59 | 58,EMBR3
60 | 59,ENAT3
61 | 60,ENEV3
62 | 61,ENGI11
63 | 62,EQTL3
64 | 63,ESPA3
65 | 64,EVEN3
66 | 65,EZTC3
67 | 66,FESA4
68 | 67,FLRY3
69 | 68,FRAS3
70 | 69,GFSA3
71 | 70,GGBR4
72 | 71,GGPS3
73 | 72,GMAT3
74 | 73,GOAU4
75 | 74,GRND3
76 | 75,GUAR3
77 | 76,HAPV3
78 | 77,HBSA3
79 | 78,HYPE3
80 | 79,IFCM3
81 | 80,IGTI11
82 | 81,INTB3
83 | 82,IRBR3
84 | 83,ITSA4
85 | 84,ITUB3
86 | 85,ITUB4
87 | 86,JALL3
88 | 87,JBSS3
89 | 88,JHSF3
90 | 89,KEPL3
91 | 90,KLBN11
92 | 91,LAVV3
93 | 92,LEVE3
94 | 93,LJQQ3
95 | 94,LOGG3
96 | 95,LREN3
97 | 96,LUPA3
98 | 97,LWSA3
99 | 98,MATD3
100 | 99,MBLY3
101 | 100,MDIA3
102 | 101,MGLU3
103 | 102,MILS3
104 | 103,MLAS3
105 | 104,MOVI3
106 | 105,MRFG3
107 | 106,MRVE3
108 | 107,MTRE3
109 | 108,MULT3
110 | 109,MYPK3
111 | 110,NEOE3
112 | 111,NTCO3
113 | 112,ODPV3
114 | 113,ONCO3
115 | 114,ORVR3
116 | 115,PCAR3
117 | 116,PETR3
118 | 117,PETR4
119 | 118,PETZ3
120 | 119,PGMN3
121 | 120,PLPL3
122 | 121,PNVL3
123 | 122,POMO4
124 | 123,POSI3
125 | 124,PRIO3
126 | 125,PSSA3
127 | 126,PTBL3
128 | 127,QUAL3
129 | 128,RADL3
130 | 129,RAIL3
131 | 130,RAIZ4
132 | 131,RANI3
133 | 132,RAPT4
134 | 133,RCSL3
135 | 134,RDOR3
136 | 135,RECV3
137 | 136,RENT3
138 | 137,ROMI3
139 | 138,RRRP3
140 | 139,SANB11
141 | 140,SAPR11
142 | 141,SBFG3
143 | 142,SBSP3
144 | 143,SEER3
145 | 144,SIMH3
146 | 145,SLCE3
147 | 146,SMFT3
148 | 147,SMTO3
149 | 148,SOMA3
150 | 149,SRNA3
151 | 150,STBP3
152 | 151,SUZB3
153 | 152,TAEE11
154 | 153,TASA4
155 | 154,TEND3
156 | 155,TGMA3
157 | 156,TIMS3
158 | 157,TOTS3
159 | 158,TRIS3
160 | 159,TRPL4
161 | 160,TTEN3
162 | 161,TUPY3
163 | 162,UGPA3
164 | 163,UNIP6
165 | 164,USIM5
166 | 165,VALE3
167 | 166,VAMO3
168 | 167,VBBR3
169 | 168,VIVA3
170 | 169,VIVT3
171 | 170,VLID3
172 | 171,VULC3
173 | 172,VVEO3
174 | 173,WEGE3
175 | 174,WIZC3
176 | 175,YDUQ3
177 | 176,ZAMP3
178 |
--------------------------------------------------------------------------------