{ "cells": [ { "metadata": {}, "cell_type": "markdown", "source": [ "# Estratégia Magic Formula de Joel Greenblatt\n", "\n", "A Magic Formula é uma estratégia de investimento que classifica ações com base em dois critérios principais:\n", "\n", "- **Qualidade**: medida pelo Retorno sobre o Capital Investido (ROIC)\n", "- **Valor**: medida pelo Rendimento de Lucros (Earnings Yield)" ], "id": "f0f9bbafd34ec9e" }, { "cell_type": "code", "id": "initial_id", "metadata": { "collapsed": true, "ExecuteTime": { "end_time": "2025-04-13T20:27:04.058395Z", "start_time": "2025-04-13T20:26:52.206786Z" } }, "source": "!pip install pandas numpy requests beautifulsoup4", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/usr/bin/bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory\r\n", "Collecting pandas\r\n", " Using cached pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (89 kB)\r\n", "Collecting numpy\r\n", " Using cached numpy-2.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (62 kB)\r\n", "Collecting yfinance\r\n", " Using cached yfinance-0.2.55-py2.py3-none-any.whl.metadata (5.8 kB)\r\n", "Requirement already satisfied: requests in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (2.32.3)\r\n", "Requirement already satisfied: beautifulsoup4 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (4.13.3)\r\n", "Requirement already satisfied: python-dateutil>=2.8.2 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from pandas) (2.9.0.post0)\r\n", "Collecting pytz>=2020.1 (from pandas)\r\n", " Using cached pytz-2025.2-py2.py3-none-any.whl.metadata (22 kB)\r\n", "Collecting tzdata>=2022.7 (from pandas)\r\n", " Using cached tzdata-2025.2-py2.py3-none-any.whl.metadata (1.4 kB)\r\n", "Collecting multitasking>=0.0.7 (from yfinance)\r\n", " Using cached multitasking-0.0.11-py3-none-any.whl.metadata (5.5 kB)\r\n", "Requirement already satisfied: platformdirs>=2.0.0 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from yfinance) (4.3.7)\r\n", "Collecting frozendict>=2.3.4 (from yfinance)\r\n", " Using cached frozendict-2.4.6-py313-none-any.whl.metadata (23 kB)\r\n", "Collecting peewee>=3.16.2 (from yfinance)\r\n", " Using cached peewee-3.17.9-cp313-cp313-linux_x86_64.whl\r\n", "Requirement already satisfied: charset-normalizer<4,>=2 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from requests) (3.4.1)\r\n", "Requirement already satisfied: idna<4,>=2.5 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from requests) (3.10)\r\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from requests) (2.4.0)\r\n", "Requirement already satisfied: certifi>=2017.4.17 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from requests) (2025.1.31)\r\n", "Requirement already satisfied: soupsieve>1.2 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from beautifulsoup4) (2.6)\r\n", "Requirement already satisfied: typing-extensions>=4.0.0 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from beautifulsoup4) (4.13.2)\r\n", "Requirement already satisfied: six>=1.5 in /home/geron/Projects/python-for-finances/.venv/lib/python3.13/site-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)\r\n", "Using cached pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.7 MB)\r\n", "Using cached numpy-2.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.1 MB)\r\n", "Using cached yfinance-0.2.55-py2.py3-none-any.whl (109 kB)\r\n", "Using cached frozendict-2.4.6-py313-none-any.whl (16 kB)\r\n", "Using cached multitasking-0.0.11-py3-none-any.whl (8.5 kB)\r\n", "Using cached pytz-2025.2-py2.py3-none-any.whl (509 kB)\r\n", "Using cached tzdata-2025.2-py2.py3-none-any.whl (347 kB)\r\n", "Installing collected packages: pytz, peewee, multitasking, tzdata, numpy, frozendict, pandas, yfinance\r\n", "Successfully installed frozendict-2.4.6 multitasking-0.0.11 numpy-2.2.4 pandas-2.2.3 peewee-3.17.9 pytz-2025.2 tzdata-2025.2 yfinance-0.2.55\r\n" ] } ], "execution_count": 1 }, { "metadata": { "ExecuteTime": { "end_time": "2025-04-13T20:27:40.137379Z", "start_time": "2025-04-13T20:27:39.725248Z" } }, "cell_type": "code", "source": [ "import numpy as np\n", "import pandas as pd\n", "import requests\n", "from bs4 import BeautifulSoup" ], "id": "737ea007e532eace", "outputs": [], "execution_count": 2 }, { "metadata": { "ExecuteTime": { "end_time": "2025-04-13T20:55:39.461968Z", "start_time": "2025-04-13T20:55:39.453184Z" } }, "cell_type": "code", "source": [ "def obter_acoes_b3():\n", " url = \"https://www.fundamentus.com.br/resultado.php\"\n", " headers = {\n", " 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0'\n", " }\n", "\n", " response = requests.get(url, headers=headers)\n", " soup = BeautifulSoup(response.text, 'html.parser')\n", "\n", " tabela = soup.find('table', {'id': 'resultado'})\n", " dados = []\n", "\n", " for linha in tabela.find_all('tr')[1:]:\n", " colunas = linha.find_all('td')\n", " ticker = colunas[0].text.strip()\n", "\n", " # Extrair métricas fundamentalistas\n", " ev_ebit = colunas[10].text.strip().replace('.', '').replace(',', '.')\n", " roic = colunas[16].text.strip().replace('.', '').replace(',', '.')\n", " liquidez = colunas[18].text.strip().replace('.', '').replace(',', '.')\n", " divida_pl = colunas[19].text.strip().replace('.', '').replace(',', '.')\n", "\n", " # Converter para float, tratando valores inválidos\n", " try:\n", " ev_ebit = float(ev_ebit) if ev_ebit != '-' else np.nan\n", " roic = float(roic[:-1]) if '%' in roic else float(roic)\n", " liquidez = float(liquidez)\n", " divida_pl = float(divida_pl)\n", "\n", " # Calcular Earnings Yield (inverso do EV/EBIT)\n", " earnings_yield = 1 / ev_ebit if ev_ebit > 0 else np.nan\n", "\n", " dados.append({\n", " 'Ticker': ticker,\n", " 'ROIC': roic,\n", " 'EV/EBIT': ev_ebit,\n", " 'Earnings Yield': earnings_yield,\n", " 'Liquidez Media': liquidez,\n", " 'Divida Bruta/PL': divida_pl\n", " })\n", " except (ValueError, ZeroDivisionError):\n", " continue\n", "\n", " return pd.DataFrame(dados)" ], "id": "5a0af3f299da432", "outputs": [], "execution_count": 33 }, { "metadata": { "ExecuteTime": { "end_time": "2025-04-13T20:55:40.849860Z", "start_time": "2025-04-13T20:55:40.092717Z" } }, "cell_type": "code", "source": [ "acoes_df = obter_acoes_b3()\n", "acoes_df" ], "id": "eee764781bd7c385", "outputs": [ { "data": { "text/plain": [ " Ticker ROIC EV/EBIT Earnings Yield Liquidez Media Divida Bruta/PL\n", "0 PORP4 -2.08 0.00 NaN 2.239900e+07 0.00\n", "1 POPR4 19.93 0.00 NaN 5.458030e+08 0.82\n", "2 MNSA3 145.70 0.00 NaN -9.105000e+06 -6.52\n", "3 CFLU4 32.15 0.00 NaN 6.035100e+07 0.06\n", "4 CSTB4 20.11 0.00 NaN 8.420670e+09 0.14\n", ".. ... ... ... ... ... ...\n", "986 UBBR4 0.33 0.00 NaN 1.031720e+10 0.00\n", "987 VSTE3 0.06 25.50 0.039216 1.043280e+09 0.33\n", "988 UBBR11 0.33 0.00 NaN 1.031720e+10 0.00\n", "989 UBBR3 0.33 0.00 NaN 1.031720e+10 0.00\n", "990 LJQQ3 0.03 4.86 0.205761 5.459970e+08 0.98\n", "\n", "[991 rows x 6 columns]" ], "text/html": [ "
| \n", " | Ticker | \n", "ROIC | \n", "EV/EBIT | \n", "Earnings Yield | \n", "Liquidez Media | \n", "Divida Bruta/PL | \n", "
|---|---|---|---|---|---|---|
| 0 | \n", "PORP4 | \n", "-2.08 | \n", "0.00 | \n", "NaN | \n", "2.239900e+07 | \n", "0.00 | \n", "
| 1 | \n", "POPR4 | \n", "19.93 | \n", "0.00 | \n", "NaN | \n", "5.458030e+08 | \n", "0.82 | \n", "
| 2 | \n", "MNSA3 | \n", "145.70 | \n", "0.00 | \n", "NaN | \n", "-9.105000e+06 | \n", "-6.52 | \n", "
| 3 | \n", "CFLU4 | \n", "32.15 | \n", "0.00 | \n", "NaN | \n", "6.035100e+07 | \n", "0.06 | \n", "
| 4 | \n", "CSTB4 | \n", "20.11 | \n", "0.00 | \n", "NaN | \n", "8.420670e+09 | \n", "0.14 | \n", "
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 986 | \n", "UBBR4 | \n", "0.33 | \n", "0.00 | \n", "NaN | \n", "1.031720e+10 | \n", "0.00 | \n", "
| 987 | \n", "VSTE3 | \n", "0.06 | \n", "25.50 | \n", "0.039216 | \n", "1.043280e+09 | \n", "0.33 | \n", "
| 988 | \n", "UBBR11 | \n", "0.33 | \n", "0.00 | \n", "NaN | \n", "1.031720e+10 | \n", "0.00 | \n", "
| 989 | \n", "UBBR3 | \n", "0.33 | \n", "0.00 | \n", "NaN | \n", "1.031720e+10 | \n", "0.00 | \n", "
| 990 | \n", "LJQQ3 | \n", "0.03 | \n", "4.86 | \n", "0.205761 | \n", "5.459970e+08 | \n", "0.98 | \n", "
991 rows × 6 columns
\n", "| \n", " | Ticker | \n", "ROIC | \n", "EV/EBIT | \n", "Earnings Yield | \n", "Liquidez Media | \n", "Divida Bruta/PL | \n", "ROIC_Rank | \n", "EY_Rank | \n", "Magic_Rank | \n", "
|---|---|---|---|---|---|---|---|---|---|
| 453 | \n", "AHEB3 | \n", "61.47 | \n", "2.17 | \n", "0.460829 | \n", "2.444130e+08 | \n", "0.02 | \n", "7.0 | \n", "25.0 | \n", "32.0 | \n", "
| 455 | \n", "AHEB5 | \n", "61.47 | \n", "2.48 | \n", "0.403226 | \n", "2.444130e+08 | \n", "0.02 | \n", "7.0 | \n", "30.0 | \n", "37.0 | \n", "
| 459 | \n", "AHEB6 | \n", "61.47 | \n", "2.80 | \n", "0.357143 | \n", "2.444130e+08 | \n", "0.02 | \n", "7.0 | \n", "32.0 | \n", "39.0 | \n", "
| 367 | \n", "CSPC4 | \n", "45.33 | \n", "1.43 | \n", "0.699301 | \n", "2.126670e+09 | \n", "1.48 | \n", "23.5 | \n", "16.5 | \n", "40.0 | \n", "
| 371 | \n", "CSPC3 | \n", "45.33 | \n", "1.43 | \n", "0.699301 | \n", "2.126670e+09 | \n", "1.48 | \n", "23.5 | \n", "16.5 | \n", "40.0 | \n", "
| 433 | \n", "SYNE3 | \n", "50.87 | \n", "2.41 | \n", "0.414938 | \n", "1.073780e+09 | \n", "0.76 | \n", "16.0 | \n", "28.0 | \n", "44.0 | \n", "
| 435 | \n", "CPFG4 | \n", "36.99 | \n", "0.95 | \n", "1.052632 | \n", "3.614430e+09 | \n", "0.42 | \n", "37.5 | \n", "7.0 | \n", "44.5 | \n", "
| 437 | \n", "CPFG3 | \n", "36.99 | \n", "0.97 | \n", "1.030928 | \n", "3.614430e+09 | \n", "0.42 | \n", "37.5 | \n", "8.0 | \n", "45.5 | \n", "
| 396 | \n", "PALF11 | \n", "46.56 | \n", "2.84 | \n", "0.352113 | \n", "3.055110e+09 | \n", "3.00 | \n", "19.0 | \n", "33.0 | \n", "52.0 | \n", "
| 403 | \n", "PALF5 | \n", "46.56 | \n", "2.87 | \n", "0.348432 | \n", "3.055110e+09 | \n", "3.00 | \n", "19.0 | \n", "34.0 | \n", "53.0 | \n", "
| 405 | \n", "PALF3 | \n", "46.56 | \n", "2.88 | \n", "0.347222 | \n", "3.055110e+09 | \n", "3.00 | \n", "19.0 | \n", "35.0 | \n", "54.0 | \n", "
| 380 | \n", "ENER3 | \n", "51.72 | \n", "3.09 | \n", "0.323625 | \n", "1.167120e+09 | \n", "3.89 | \n", "11.0 | \n", "44.0 | \n", "55.0 | \n", "
| 381 | \n", "ENER6 | \n", "51.72 | \n", "3.09 | \n", "0.323625 | \n", "1.167120e+09 | \n", "3.89 | \n", "11.0 | \n", "44.0 | \n", "55.0 | \n", "
| 379 | \n", "ENER5 | \n", "51.72 | \n", "3.09 | \n", "0.323625 | \n", "1.167120e+09 | \n", "3.89 | \n", "11.0 | \n", "44.0 | \n", "55.0 | \n", "
| 382 | \n", "TEFC11 | \n", "46.72 | \n", "3.45 | \n", "0.289855 | \n", "4.585600e+10 | \n", "2.95 | \n", "17.0 | \n", "52.0 | \n", "69.0 | \n", "