dcfCalculator
1import math 2import requests 3from bs4 import BeautifulSoup 4 5""" 6Documentación de la clase FinanceAnalyzer 7""" 8 9 10class DcfCalculator: 11 def __init__(self, ticker=None): 12 """ 13 Inicializa el objeto FinanceAnalyzer con los datos financieros del ticker especificado. 14 15 Args: 16 ticker (str): El símbolo de ticker de la acción. 17 """ 18 self.balanceSheet = self.getBalanceSheet(ticker) 19 """El balance de la acción.""" 20 self.info = self.getInfo(ticker) 21 """La información básica de la acción.""" 22 self.financials = self.getFinancials(ticker) 23 """Los estados financieros de la acción.""" 24 self.incomeStmt = self.getIncomeStmt(ticker) 25 """El estado de ingresos de la acción.""" 26 self.cashFlow = self.getCashFlow(ticker) 27 """El flujo de efectivo de la acción.""" 28 29 def getAttribute(self, ticker, attribute, error_message): 30 """ 31 Obtiene los datos de yahoo finance 32 33 Args: 34 ticker (str): El símbolo de ticker de la acción. 35 attribute (str): El nombre del atributo a obtener. 36 error_message (str): El mensaje de error a mostrar si el atributo no se puede obtener. 37 38 Returns: 39 obj: El valor del atributo. 40 """ 41 try: 42 return getattr(ticker, attribute) 43 except: 44 raise Exception(error_message) 45 46 def getFinancials(self, ticker): 47 """ 48 Obtiene los estados financieros del ticker especificado. 49 50 Args: 51 ticker (str): El símbolo de ticker de la acción. 52 53 Returns: 54 obj: Los estados financieros del ticker. 55 """ 56 return self.getAttribute( 57 ticker, 58 "financials", 59 "No se pudo obtener los estados financieros de la acción", 60 ) 61 62 def getBalanceSheet(self, ticker): 63 """ 64 Obtiene el balance de la acción del ticker especificado. 65 66 Args: 67 ticker (str): El símbolo de ticker de la acción. 68 69 Returns: 70 obj: El balance de la acción. 71 """ 72 return self.getAttribute( 73 ticker, "balance_sheet", "No se pudo obtener el balance de la acción" 74 ) 75 76 def getIncomeStmt(self, ticker): 77 """ 78 Obtiene el estado de ingresos de la acción del ticker especificado. 79 80 Args: 81 ticker (str): El símbolo de ticker de la acción. 82 83 Returns: 84 obj: El estado de ingresos de la acción. 85 """ 86 return self.getAttribute( 87 ticker, 88 "income_stmt", 89 "No se pudo obtener el estado de los ingresos de la acción", 90 ) 91 92 def getInfo(self, ticker): 93 """ 94 Obtiene la información básica de la acción del ticker especificado. 95 96 Args: 97 ticker (str): El símbolo de ticker de la acción. 98 99 Returns: 100 obj: La información básica de la acción. 101 """ 102 return self.getAttribute( 103 ticker, "info", "No se pudo obtener la información de la acción" 104 ) 105 106 def getCashFlow(self, ticker): 107 """ 108 Obtiene el flujo de efectivo de la acción del ticker especificado. 109 110 Args: 111 ticker (str): El símbolo de ticker de la acción. 112 113 Returns: 114 obj: El flujo de efectivo de la acción. 115 """ 116 return self.getAttribute( 117 ticker, "cashflow", "No se pudo obtener el flujo de caja de la acción" 118 ) 119 120 def getEbitda(self): 121 """ 122 Calcula el EBITDA de la acción. 123 124 Returns: 125 float: El EBITDA de la acción. 126 """ 127 try: 128 ebitda = self.getLastYearValue(self.incomeStmt, "EBITDA") 129 except Exception as e: 130 raise Exception("No se pudo obtener el EBITDA de la acción") from e 131 return ebitda 132 133 def getEarnings(self): 134 """ 135 Calcula las ganancias de la acción. 136 137 Returns: 138 float: Las ganancias de la acción. 139 """ 140 try: 141 grossProfit = self.getLastYearValue(self.incomeStmt, "Gross Profit") 142 totalRevenue = self.getLastYearValue(self.incomeStmt, "Total Revenue") 143 return (grossProfit / totalRevenue) * 100 144 except Exception as e: 145 raise Exception("No se pudo obtener las ganancias de la acción") from e 146 147 def getRoe(self): 148 """ 149 Calcula el ROE (Return on Equity) de la acción. 150 151 Returns: 152 float: El ROE de la acción. 153 """ 154 try: 155 last_year_net_income = self.getLastYearValue(self.incomeStmt, "Net Income") 156 except Exception as e: 157 raise Exception("No se pudo obtener el net income de la acción") from e 158 159 try: 160 last_year_equity = self.getLastYearValue( 161 self.balanceSheet, "Stockholders Equity" 162 ) 163 except Exception as e: 164 raise Exception("No se pudo obtener el equity de la acción") from e 165 166 return (last_year_net_income / last_year_equity) * 100 167 168 def getPer(self): 169 """ 170 Obtiene el PER (Price to Earnings Ratio) de la acción. 171 172 Returns: 173 float: El PER de la acción. 174 """ 175 try: 176 return self.info["trailingPE"] 177 except: 178 raise Exception("No se pudo obtener el PER de la acción") 179 180 def getLastYearValue(self, data, label): 181 """ 182 Obtiene el valor del año pasado para una etiqueta de datos específica. 183 184 Args: 185 data (DataFrame): Los datos financieros. 186 label (str): La etiqueta de datos específica. 187 188 Returns: 189 float: El valor del año pasado para la etiqueta de datos especificada. 190 """ 191 try: 192 value = data.loc[label] 193 i = 0 194 last_year_value = value.iloc[i] 195 while math.isnan(value.iloc[i]): 196 i += 1 197 last_year_value = value.iloc[i] 198 return last_year_value 199 except: 200 try: 201 if label == "Current Debt And Capital Lease Obligation": 202 return self.getLastYearValue(data, "Current Deferred Liabilities") 203 except: 204 raise Exception(f"No se pudo obtener {label} de la acción") 205 raise Exception(f"No se pudo obtener {label} de la acción") 206 207 def getTotalDebt(self, balanceSheet): 208 """ 209 Calcula la deuda total de la acción. 210 211 Args: 212 balanceSheet (DataFrame): El balance de la acción. 213 214 Returns: 215 float: La deuda total de la acción. 216 """ 217 try: 218 return self.getLastYearValue(balanceSheet, "Total Debt") 219 except Exception as e: 220 raise Exception("No se pudo obtener la deuda total de la acción") from e 221 222 def getGrowthEstimates(self, ticker, option): 223 """ 224 Obtiene las estimaciones de crecimiento para la acción. 225 226 Args: 227 ticker (str): El símbolo de ticker de la acción. 228 229 Returns: 230 str: Las estimaciones de crecimiento. 231 """ 232 try: 233 if option == "yahoo": 234 return self.getGrowthEstimatesYahoo(ticker) 235 elif option == "zacks": 236 return self.getGrowthEstimatesZacks(ticker) 237 elif option == "seeking": 238 return self.getGrowthEstimatesSeeking(ticker) 239 240 except Exception as e: 241 return str(e) 242 243 def getGrowthEstimatesYahoo(self, ticker): 244 """ 245 Obtiene las estimaciones de crecimiento para la acción de la webd e Yahoo Finance. 246 247 Args: 248 ticker (str): El símbolo de ticker de la acción. 249 250 Returns: 251 str: Las estimaciones de crecimiento. 252 """ 253 url = f"https://finance.yahoo.com/quote/{ticker}/analysis?ltr=1" 254 headers = { 255 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 256 } 257 try: 258 response = requests.get(url, headers=headers) 259 response.raise_for_status() 260 soup = BeautifulSoup(response.text, "html.parser") 261 desired_table = soup.find_all("table")[5] 262 target_value = ( 263 desired_table.find_all("tr")[5].find_all("td")[1].text.strip() 264 ) 265 return target_value 266 except IndexError: 267 raise Exception( 268 "No se encontraron suficientes tablas, filas o celdas en la página" 269 ) 270 except requests.exceptions.RequestException as e: 271 raise Exception(f"Error en la solicitud: {e}") 272 273 def getGrowthEstimatesZacks(self, ticker): 274 """ 275 Obtiene las estimaciones de crecimiento para la acción de la web de Zacks. 276 277 Args: 278 ticker (str): El símbolo de ticker de la acción. 279 280 Returns: 281 str: Las estimaciones de crecimiento. 282 """ 283 url = f"https://www.zacks.com/stock/quote/{ticker}?q={ticker}" 284 headers = { 285 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 286 } 287 try: 288 response = requests.get(url, headers=headers) 289 response.raise_for_status() 290 soup = BeautifulSoup(response.text, "html.parser") 291 desired_table = soup.find_all("dl", class_="abut_bottom") 292 # print(desired_table) 293 target_value = desired_table[15].find_all("dd")[0].text.strip() 294 # print(target_value) 295 return target_value 296 except IndexError: 297 raise Exception( 298 "No se encontraron suficientes tablas, filas o celdas en la página" 299 ) 300 except requests.exceptions.RequestException as e: 301 raise Exception(f"Error en la solicitud: {e}") 302 303 def getGrowthEstimatesSeeking(self, ticker): 304 """ 305 Obtiene las estimaciones de crecimiento para la acción de la web de Seeking Alpha. 306 307 Args: 308 ticker (str): El símbolo de ticker de la acción. 309 310 Returns: 311 str: Las estimaciones de crecimiento. 312 """ 313 url = f"https://seekingalpha.com/symbol/{ticker}/growth" 314 headers = { 315 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 316 } 317 try: 318 response = requests.get(url, headers=headers) 319 # print(response) 320 response.raise_for_status() 321 soup = BeautifulSoup(response.text, "html.parser") 322 desired_table = soup.find_all("table")[0] 323 target_value = ( 324 desired_table.find_all("tr")[11].find_all("td")[1].text.strip() 325 ) 326 # print(target_value, 'hi') 327 return target_value 328 except IndexError: 329 raise Exception( 330 "No se encontraron suficientes tablas, filas o celdas en la página" 331 ) 332 except requests.exceptions.RequestException as e: 333 raise Exception(f"Error en la solicitud: {e}") 334 335 def waccCalculator(self, rf, rm): 336 """ 337 Calcula el costo promedio ponderado del capital (WACC). 338 339 Args: 340 rf (float): Tasa libre de riesgo. 341 rm (float): Retorno del mercado. 342 343 Returns: 344 float: El WACC calculado. 345 """ 346 last_year_total_debt = self.getTotalDebt(self.balanceSheet) 347 348 beta = self.info.get("beta", 1) 349 350 ke = rf + (beta * (rm - rf)) 351 352 e = self.info.get("marketCap") 353 if e is None: 354 raise Exception( 355 "No se pudo obtener la capitalización bursátil de la acción" 356 ) 357 358 total_debt_ED = e + last_year_total_debt 359 360 total_equity = ke * (e / total_debt_ED) 361 362 last_year_interest_expense = self.getLastYearValue( 363 self.financials, "Interest Expense" 364 ) 365 366 last_year_current_debt = self.getLastYearValue( 367 self.balanceSheet, "Current Debt And Capital Lease Obligation" 368 ) 369 370 last_year_long_term_debt = self.getLastYearValue( 371 self.balanceSheet, "Long Term Debt" 372 ) 373 374 kd = last_year_interest_expense / ( 375 last_year_current_debt + last_year_long_term_debt 376 ) 377 378 last_year_tax_provision = self.getLastYearValue( 379 self.incomeStmt, "Tax Provision" 380 ) 381 382 last_year_pretax_income = self.getLastYearValue( 383 self.incomeStmt, "Pretax Income" 384 ) 385 386 t = last_year_tax_provision / last_year_pretax_income 387 388 total_debt_cost = kd * (1 - t) * (last_year_total_debt / total_debt_ED) 389 390 return total_equity + total_debt_cost 391 392 def dcf(self, tickerStr, g, rf, rm, option): 393 """ 394 Calcula el valor intrínseco de una acción utilizando el modelo de descuento de flujos de efectivo (DCF). 395 396 Args: 397 tickerStr (str): El símbolo de ticker de la acción. 398 g (float): Tasa de crecimiento a perpetuidad. 399 rf (float): Tasa libre de riesgo. 400 rm (float): Retorno del mercado. 401 402 Returns: 403 list: Una lista que contiene varios valores calculados. 404 """ 405 try: 406 last_year_total_debt = self.getTotalDebt(self.balanceSheet) 407 growthFCF = self.getGrowthEstimates(tickerStr, option) 408 print(option, growthFCF) 409 printGrowthFCF = growthFCF 410 try: 411 growthFCF = float(growthFCF.replace("%", "")) / 100 412 except: 413 FCFGrow = self.cashFlow.iloc[0] 414 growthFCF = ( 415 (FCFGrow.iloc[0] / FCFGrow.iloc[-1]) ** (1 / len(FCFGrow)) 416 ) - 1 417 printGrowthFCF = "{:.2f}%".format(growthFCF * 100) 418 419 wacc = self.waccCalculator(rf, rm) 420 if type(wacc) != float: 421 raise Exception(wacc) 422 423 last_year_fcf = self.getLastYearValue(self.cashFlow, "Free Cash Flow") 424 printFCF = last_year_fcf 425 426 FCFn = [ 427 int(format(last_year_fcf * (1 + growthFCF) ** i, ".0f")) 428 for i in range(1, 6) 429 ] 430 431 terminal_value = (FCFn[-1] * (1 + g)) / (wacc - g) 432 FNFnLast = FCFn[-1] 433 FCFn[-1] = int(format(FCFn[-1] + terminal_value, ".0f")) 434 435 enterprise_value = sum( 436 [FCFn[i] / ((1 + wacc) ** (i + 1)) for i in range(5)] 437 ) 438 439 last_year_cash = self.getLastYearValue( 440 self.balanceSheet, "Cash Cash Equivalents And Short Term Investments" 441 ) 442 443 equity_value = enterprise_value + last_year_cash - last_year_total_debt 444 445 shares_outstanding = self.info["sharesOutstanding"] 446 447 intrinsic_value = equity_value / shares_outstanding 448 449 price = self.info["regularMarketPreviousClose"] 450 451 difference = 100 + (((intrinsic_value - price) / price) * 100) 452 453 FCFn.pop() 454 FCFn.append(FNFnLast) 455 456 return [ 457 (format((wacc * 100), ".2f") + " %"), 458 ("$ " + "{:,.0f}".format(printFCF).replace(",", ".")), 459 FCFn, 460 printGrowthFCF, 461 ("$ " + "{:,.0f}".format(equity_value, ".0f").replace(",", ".")), 462 ("$ " + str(price)), 463 ("$ " + format(intrinsic_value, ".2f")), 464 (format((difference), ".2f") + "%"), 465 ] 466 except Exception as e: 467 return str(e) 468 469 470# DcfCalculator("STX").getGrowthEstimates("AAPL") 471# DcfCalculator("STX").getGrowthEstimatesSeeking("AAPL")
11class DcfCalculator: 12 def __init__(self, ticker=None): 13 """ 14 Inicializa el objeto FinanceAnalyzer con los datos financieros del ticker especificado. 15 16 Args: 17 ticker (str): El símbolo de ticker de la acción. 18 """ 19 self.balanceSheet = self.getBalanceSheet(ticker) 20 """El balance de la acción.""" 21 self.info = self.getInfo(ticker) 22 """La información básica de la acción.""" 23 self.financials = self.getFinancials(ticker) 24 """Los estados financieros de la acción.""" 25 self.incomeStmt = self.getIncomeStmt(ticker) 26 """El estado de ingresos de la acción.""" 27 self.cashFlow = self.getCashFlow(ticker) 28 """El flujo de efectivo de la acción.""" 29 30 def getAttribute(self, ticker, attribute, error_message): 31 """ 32 Obtiene los datos de yahoo finance 33 34 Args: 35 ticker (str): El símbolo de ticker de la acción. 36 attribute (str): El nombre del atributo a obtener. 37 error_message (str): El mensaje de error a mostrar si el atributo no se puede obtener. 38 39 Returns: 40 obj: El valor del atributo. 41 """ 42 try: 43 return getattr(ticker, attribute) 44 except: 45 raise Exception(error_message) 46 47 def getFinancials(self, ticker): 48 """ 49 Obtiene los estados financieros del ticker especificado. 50 51 Args: 52 ticker (str): El símbolo de ticker de la acción. 53 54 Returns: 55 obj: Los estados financieros del ticker. 56 """ 57 return self.getAttribute( 58 ticker, 59 "financials", 60 "No se pudo obtener los estados financieros de la acción", 61 ) 62 63 def getBalanceSheet(self, ticker): 64 """ 65 Obtiene el balance de la acción del ticker especificado. 66 67 Args: 68 ticker (str): El símbolo de ticker de la acción. 69 70 Returns: 71 obj: El balance de la acción. 72 """ 73 return self.getAttribute( 74 ticker, "balance_sheet", "No se pudo obtener el balance de la acción" 75 ) 76 77 def getIncomeStmt(self, ticker): 78 """ 79 Obtiene el estado de ingresos de la acción del ticker especificado. 80 81 Args: 82 ticker (str): El símbolo de ticker de la acción. 83 84 Returns: 85 obj: El estado de ingresos de la acción. 86 """ 87 return self.getAttribute( 88 ticker, 89 "income_stmt", 90 "No se pudo obtener el estado de los ingresos de la acción", 91 ) 92 93 def getInfo(self, ticker): 94 """ 95 Obtiene la información básica de la acción del ticker especificado. 96 97 Args: 98 ticker (str): El símbolo de ticker de la acción. 99 100 Returns: 101 obj: La información básica de la acción. 102 """ 103 return self.getAttribute( 104 ticker, "info", "No se pudo obtener la información de la acción" 105 ) 106 107 def getCashFlow(self, ticker): 108 """ 109 Obtiene el flujo de efectivo de la acción del ticker especificado. 110 111 Args: 112 ticker (str): El símbolo de ticker de la acción. 113 114 Returns: 115 obj: El flujo de efectivo de la acción. 116 """ 117 return self.getAttribute( 118 ticker, "cashflow", "No se pudo obtener el flujo de caja de la acción" 119 ) 120 121 def getEbitda(self): 122 """ 123 Calcula el EBITDA de la acción. 124 125 Returns: 126 float: El EBITDA de la acción. 127 """ 128 try: 129 ebitda = self.getLastYearValue(self.incomeStmt, "EBITDA") 130 except Exception as e: 131 raise Exception("No se pudo obtener el EBITDA de la acción") from e 132 return ebitda 133 134 def getEarnings(self): 135 """ 136 Calcula las ganancias de la acción. 137 138 Returns: 139 float: Las ganancias de la acción. 140 """ 141 try: 142 grossProfit = self.getLastYearValue(self.incomeStmt, "Gross Profit") 143 totalRevenue = self.getLastYearValue(self.incomeStmt, "Total Revenue") 144 return (grossProfit / totalRevenue) * 100 145 except Exception as e: 146 raise Exception("No se pudo obtener las ganancias de la acción") from e 147 148 def getRoe(self): 149 """ 150 Calcula el ROE (Return on Equity) de la acción. 151 152 Returns: 153 float: El ROE de la acción. 154 """ 155 try: 156 last_year_net_income = self.getLastYearValue(self.incomeStmt, "Net Income") 157 except Exception as e: 158 raise Exception("No se pudo obtener el net income de la acción") from e 159 160 try: 161 last_year_equity = self.getLastYearValue( 162 self.balanceSheet, "Stockholders Equity" 163 ) 164 except Exception as e: 165 raise Exception("No se pudo obtener el equity de la acción") from e 166 167 return (last_year_net_income / last_year_equity) * 100 168 169 def getPer(self): 170 """ 171 Obtiene el PER (Price to Earnings Ratio) de la acción. 172 173 Returns: 174 float: El PER de la acción. 175 """ 176 try: 177 return self.info["trailingPE"] 178 except: 179 raise Exception("No se pudo obtener el PER de la acción") 180 181 def getLastYearValue(self, data, label): 182 """ 183 Obtiene el valor del año pasado para una etiqueta de datos específica. 184 185 Args: 186 data (DataFrame): Los datos financieros. 187 label (str): La etiqueta de datos específica. 188 189 Returns: 190 float: El valor del año pasado para la etiqueta de datos especificada. 191 """ 192 try: 193 value = data.loc[label] 194 i = 0 195 last_year_value = value.iloc[i] 196 while math.isnan(value.iloc[i]): 197 i += 1 198 last_year_value = value.iloc[i] 199 return last_year_value 200 except: 201 try: 202 if label == "Current Debt And Capital Lease Obligation": 203 return self.getLastYearValue(data, "Current Deferred Liabilities") 204 except: 205 raise Exception(f"No se pudo obtener {label} de la acción") 206 raise Exception(f"No se pudo obtener {label} de la acción") 207 208 def getTotalDebt(self, balanceSheet): 209 """ 210 Calcula la deuda total de la acción. 211 212 Args: 213 balanceSheet (DataFrame): El balance de la acción. 214 215 Returns: 216 float: La deuda total de la acción. 217 """ 218 try: 219 return self.getLastYearValue(balanceSheet, "Total Debt") 220 except Exception as e: 221 raise Exception("No se pudo obtener la deuda total de la acción") from e 222 223 def getGrowthEstimates(self, ticker, option): 224 """ 225 Obtiene las estimaciones de crecimiento para la acción. 226 227 Args: 228 ticker (str): El símbolo de ticker de la acción. 229 230 Returns: 231 str: Las estimaciones de crecimiento. 232 """ 233 try: 234 if option == "yahoo": 235 return self.getGrowthEstimatesYahoo(ticker) 236 elif option == "zacks": 237 return self.getGrowthEstimatesZacks(ticker) 238 elif option == "seeking": 239 return self.getGrowthEstimatesSeeking(ticker) 240 241 except Exception as e: 242 return str(e) 243 244 def getGrowthEstimatesYahoo(self, ticker): 245 """ 246 Obtiene las estimaciones de crecimiento para la acción de la webd e Yahoo Finance. 247 248 Args: 249 ticker (str): El símbolo de ticker de la acción. 250 251 Returns: 252 str: Las estimaciones de crecimiento. 253 """ 254 url = f"https://finance.yahoo.com/quote/{ticker}/analysis?ltr=1" 255 headers = { 256 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 257 } 258 try: 259 response = requests.get(url, headers=headers) 260 response.raise_for_status() 261 soup = BeautifulSoup(response.text, "html.parser") 262 desired_table = soup.find_all("table")[5] 263 target_value = ( 264 desired_table.find_all("tr")[5].find_all("td")[1].text.strip() 265 ) 266 return target_value 267 except IndexError: 268 raise Exception( 269 "No se encontraron suficientes tablas, filas o celdas en la página" 270 ) 271 except requests.exceptions.RequestException as e: 272 raise Exception(f"Error en la solicitud: {e}") 273 274 def getGrowthEstimatesZacks(self, ticker): 275 """ 276 Obtiene las estimaciones de crecimiento para la acción de la web de Zacks. 277 278 Args: 279 ticker (str): El símbolo de ticker de la acción. 280 281 Returns: 282 str: Las estimaciones de crecimiento. 283 """ 284 url = f"https://www.zacks.com/stock/quote/{ticker}?q={ticker}" 285 headers = { 286 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 287 } 288 try: 289 response = requests.get(url, headers=headers) 290 response.raise_for_status() 291 soup = BeautifulSoup(response.text, "html.parser") 292 desired_table = soup.find_all("dl", class_="abut_bottom") 293 # print(desired_table) 294 target_value = desired_table[15].find_all("dd")[0].text.strip() 295 # print(target_value) 296 return target_value 297 except IndexError: 298 raise Exception( 299 "No se encontraron suficientes tablas, filas o celdas en la página" 300 ) 301 except requests.exceptions.RequestException as e: 302 raise Exception(f"Error en la solicitud: {e}") 303 304 def getGrowthEstimatesSeeking(self, ticker): 305 """ 306 Obtiene las estimaciones de crecimiento para la acción de la web de Seeking Alpha. 307 308 Args: 309 ticker (str): El símbolo de ticker de la acción. 310 311 Returns: 312 str: Las estimaciones de crecimiento. 313 """ 314 url = f"https://seekingalpha.com/symbol/{ticker}/growth" 315 headers = { 316 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 317 } 318 try: 319 response = requests.get(url, headers=headers) 320 # print(response) 321 response.raise_for_status() 322 soup = BeautifulSoup(response.text, "html.parser") 323 desired_table = soup.find_all("table")[0] 324 target_value = ( 325 desired_table.find_all("tr")[11].find_all("td")[1].text.strip() 326 ) 327 # print(target_value, 'hi') 328 return target_value 329 except IndexError: 330 raise Exception( 331 "No se encontraron suficientes tablas, filas o celdas en la página" 332 ) 333 except requests.exceptions.RequestException as e: 334 raise Exception(f"Error en la solicitud: {e}") 335 336 def waccCalculator(self, rf, rm): 337 """ 338 Calcula el costo promedio ponderado del capital (WACC). 339 340 Args: 341 rf (float): Tasa libre de riesgo. 342 rm (float): Retorno del mercado. 343 344 Returns: 345 float: El WACC calculado. 346 """ 347 last_year_total_debt = self.getTotalDebt(self.balanceSheet) 348 349 beta = self.info.get("beta", 1) 350 351 ke = rf + (beta * (rm - rf)) 352 353 e = self.info.get("marketCap") 354 if e is None: 355 raise Exception( 356 "No se pudo obtener la capitalización bursátil de la acción" 357 ) 358 359 total_debt_ED = e + last_year_total_debt 360 361 total_equity = ke * (e / total_debt_ED) 362 363 last_year_interest_expense = self.getLastYearValue( 364 self.financials, "Interest Expense" 365 ) 366 367 last_year_current_debt = self.getLastYearValue( 368 self.balanceSheet, "Current Debt And Capital Lease Obligation" 369 ) 370 371 last_year_long_term_debt = self.getLastYearValue( 372 self.balanceSheet, "Long Term Debt" 373 ) 374 375 kd = last_year_interest_expense / ( 376 last_year_current_debt + last_year_long_term_debt 377 ) 378 379 last_year_tax_provision = self.getLastYearValue( 380 self.incomeStmt, "Tax Provision" 381 ) 382 383 last_year_pretax_income = self.getLastYearValue( 384 self.incomeStmt, "Pretax Income" 385 ) 386 387 t = last_year_tax_provision / last_year_pretax_income 388 389 total_debt_cost = kd * (1 - t) * (last_year_total_debt / total_debt_ED) 390 391 return total_equity + total_debt_cost 392 393 def dcf(self, tickerStr, g, rf, rm, option): 394 """ 395 Calcula el valor intrínseco de una acción utilizando el modelo de descuento de flujos de efectivo (DCF). 396 397 Args: 398 tickerStr (str): El símbolo de ticker de la acción. 399 g (float): Tasa de crecimiento a perpetuidad. 400 rf (float): Tasa libre de riesgo. 401 rm (float): Retorno del mercado. 402 403 Returns: 404 list: Una lista que contiene varios valores calculados. 405 """ 406 try: 407 last_year_total_debt = self.getTotalDebt(self.balanceSheet) 408 growthFCF = self.getGrowthEstimates(tickerStr, option) 409 print(option, growthFCF) 410 printGrowthFCF = growthFCF 411 try: 412 growthFCF = float(growthFCF.replace("%", "")) / 100 413 except: 414 FCFGrow = self.cashFlow.iloc[0] 415 growthFCF = ( 416 (FCFGrow.iloc[0] / FCFGrow.iloc[-1]) ** (1 / len(FCFGrow)) 417 ) - 1 418 printGrowthFCF = "{:.2f}%".format(growthFCF * 100) 419 420 wacc = self.waccCalculator(rf, rm) 421 if type(wacc) != float: 422 raise Exception(wacc) 423 424 last_year_fcf = self.getLastYearValue(self.cashFlow, "Free Cash Flow") 425 printFCF = last_year_fcf 426 427 FCFn = [ 428 int(format(last_year_fcf * (1 + growthFCF) ** i, ".0f")) 429 for i in range(1, 6) 430 ] 431 432 terminal_value = (FCFn[-1] * (1 + g)) / (wacc - g) 433 FNFnLast = FCFn[-1] 434 FCFn[-1] = int(format(FCFn[-1] + terminal_value, ".0f")) 435 436 enterprise_value = sum( 437 [FCFn[i] / ((1 + wacc) ** (i + 1)) for i in range(5)] 438 ) 439 440 last_year_cash = self.getLastYearValue( 441 self.balanceSheet, "Cash Cash Equivalents And Short Term Investments" 442 ) 443 444 equity_value = enterprise_value + last_year_cash - last_year_total_debt 445 446 shares_outstanding = self.info["sharesOutstanding"] 447 448 intrinsic_value = equity_value / shares_outstanding 449 450 price = self.info["regularMarketPreviousClose"] 451 452 difference = 100 + (((intrinsic_value - price) / price) * 100) 453 454 FCFn.pop() 455 FCFn.append(FNFnLast) 456 457 return [ 458 (format((wacc * 100), ".2f") + " %"), 459 ("$ " + "{:,.0f}".format(printFCF).replace(",", ".")), 460 FCFn, 461 printGrowthFCF, 462 ("$ " + "{:,.0f}".format(equity_value, ".0f").replace(",", ".")), 463 ("$ " + str(price)), 464 ("$ " + format(intrinsic_value, ".2f")), 465 (format((difference), ".2f") + "%"), 466 ] 467 except Exception as e: 468 return str(e)
12 def __init__(self, ticker=None): 13 """ 14 Inicializa el objeto FinanceAnalyzer con los datos financieros del ticker especificado. 15 16 Args: 17 ticker (str): El símbolo de ticker de la acción. 18 """ 19 self.balanceSheet = self.getBalanceSheet(ticker) 20 """El balance de la acción.""" 21 self.info = self.getInfo(ticker) 22 """La información básica de la acción.""" 23 self.financials = self.getFinancials(ticker) 24 """Los estados financieros de la acción.""" 25 self.incomeStmt = self.getIncomeStmt(ticker) 26 """El estado de ingresos de la acción.""" 27 self.cashFlow = self.getCashFlow(ticker) 28 """El flujo de efectivo de la acción."""
Inicializa el objeto FinanceAnalyzer con los datos financieros del ticker especificado.
Args: ticker (str): El símbolo de ticker de la acción.
30 def getAttribute(self, ticker, attribute, error_message): 31 """ 32 Obtiene los datos de yahoo finance 33 34 Args: 35 ticker (str): El símbolo de ticker de la acción. 36 attribute (str): El nombre del atributo a obtener. 37 error_message (str): El mensaje de error a mostrar si el atributo no se puede obtener. 38 39 Returns: 40 obj: El valor del atributo. 41 """ 42 try: 43 return getattr(ticker, attribute) 44 except: 45 raise Exception(error_message)
Obtiene los datos de yahoo finance
Args: ticker (str): El símbolo de ticker de la acción. attribute (str): El nombre del atributo a obtener. error_message (str): El mensaje de error a mostrar si el atributo no se puede obtener.
Returns: obj: El valor del atributo.
47 def getFinancials(self, ticker): 48 """ 49 Obtiene los estados financieros del ticker especificado. 50 51 Args: 52 ticker (str): El símbolo de ticker de la acción. 53 54 Returns: 55 obj: Los estados financieros del ticker. 56 """ 57 return self.getAttribute( 58 ticker, 59 "financials", 60 "No se pudo obtener los estados financieros de la acción", 61 )
Obtiene los estados financieros del ticker especificado.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: obj: Los estados financieros del ticker.
63 def getBalanceSheet(self, ticker): 64 """ 65 Obtiene el balance de la acción del ticker especificado. 66 67 Args: 68 ticker (str): El símbolo de ticker de la acción. 69 70 Returns: 71 obj: El balance de la acción. 72 """ 73 return self.getAttribute( 74 ticker, "balance_sheet", "No se pudo obtener el balance de la acción" 75 )
Obtiene el balance de la acción del ticker especificado.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: obj: El balance de la acción.
77 def getIncomeStmt(self, ticker): 78 """ 79 Obtiene el estado de ingresos de la acción del ticker especificado. 80 81 Args: 82 ticker (str): El símbolo de ticker de la acción. 83 84 Returns: 85 obj: El estado de ingresos de la acción. 86 """ 87 return self.getAttribute( 88 ticker, 89 "income_stmt", 90 "No se pudo obtener el estado de los ingresos de la acción", 91 )
Obtiene el estado de ingresos de la acción del ticker especificado.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: obj: El estado de ingresos de la acción.
93 def getInfo(self, ticker): 94 """ 95 Obtiene la información básica de la acción del ticker especificado. 96 97 Args: 98 ticker (str): El símbolo de ticker de la acción. 99 100 Returns: 101 obj: La información básica de la acción. 102 """ 103 return self.getAttribute( 104 ticker, "info", "No se pudo obtener la información de la acción" 105 )
Obtiene la información básica de la acción del ticker especificado.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: obj: La información básica de la acción.
107 def getCashFlow(self, ticker): 108 """ 109 Obtiene el flujo de efectivo de la acción del ticker especificado. 110 111 Args: 112 ticker (str): El símbolo de ticker de la acción. 113 114 Returns: 115 obj: El flujo de efectivo de la acción. 116 """ 117 return self.getAttribute( 118 ticker, "cashflow", "No se pudo obtener el flujo de caja de la acción" 119 )
Obtiene el flujo de efectivo de la acción del ticker especificado.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: obj: El flujo de efectivo de la acción.
121 def getEbitda(self): 122 """ 123 Calcula el EBITDA de la acción. 124 125 Returns: 126 float: El EBITDA de la acción. 127 """ 128 try: 129 ebitda = self.getLastYearValue(self.incomeStmt, "EBITDA") 130 except Exception as e: 131 raise Exception("No se pudo obtener el EBITDA de la acción") from e 132 return ebitda
Calcula el EBITDA de la acción.
Returns: float: El EBITDA de la acción.
134 def getEarnings(self): 135 """ 136 Calcula las ganancias de la acción. 137 138 Returns: 139 float: Las ganancias de la acción. 140 """ 141 try: 142 grossProfit = self.getLastYearValue(self.incomeStmt, "Gross Profit") 143 totalRevenue = self.getLastYearValue(self.incomeStmt, "Total Revenue") 144 return (grossProfit / totalRevenue) * 100 145 except Exception as e: 146 raise Exception("No se pudo obtener las ganancias de la acción") from e
Calcula las ganancias de la acción.
Returns: float: Las ganancias de la acción.
148 def getRoe(self): 149 """ 150 Calcula el ROE (Return on Equity) de la acción. 151 152 Returns: 153 float: El ROE de la acción. 154 """ 155 try: 156 last_year_net_income = self.getLastYearValue(self.incomeStmt, "Net Income") 157 except Exception as e: 158 raise Exception("No se pudo obtener el net income de la acción") from e 159 160 try: 161 last_year_equity = self.getLastYearValue( 162 self.balanceSheet, "Stockholders Equity" 163 ) 164 except Exception as e: 165 raise Exception("No se pudo obtener el equity de la acción") from e 166 167 return (last_year_net_income / last_year_equity) * 100
Calcula el ROE (Return on Equity) de la acción.
Returns: float: El ROE de la acción.
169 def getPer(self): 170 """ 171 Obtiene el PER (Price to Earnings Ratio) de la acción. 172 173 Returns: 174 float: El PER de la acción. 175 """ 176 try: 177 return self.info["trailingPE"] 178 except: 179 raise Exception("No se pudo obtener el PER de la acción")
Obtiene el PER (Price to Earnings Ratio) de la acción.
Returns: float: El PER de la acción.
181 def getLastYearValue(self, data, label): 182 """ 183 Obtiene el valor del año pasado para una etiqueta de datos específica. 184 185 Args: 186 data (DataFrame): Los datos financieros. 187 label (str): La etiqueta de datos específica. 188 189 Returns: 190 float: El valor del año pasado para la etiqueta de datos especificada. 191 """ 192 try: 193 value = data.loc[label] 194 i = 0 195 last_year_value = value.iloc[i] 196 while math.isnan(value.iloc[i]): 197 i += 1 198 last_year_value = value.iloc[i] 199 return last_year_value 200 except: 201 try: 202 if label == "Current Debt And Capital Lease Obligation": 203 return self.getLastYearValue(data, "Current Deferred Liabilities") 204 except: 205 raise Exception(f"No se pudo obtener {label} de la acción") 206 raise Exception(f"No se pudo obtener {label} de la acción")
Obtiene el valor del año pasado para una etiqueta de datos específica.
Args: data (DataFrame): Los datos financieros. label (str): La etiqueta de datos específica.
Returns: float: El valor del año pasado para la etiqueta de datos especificada.
208 def getTotalDebt(self, balanceSheet): 209 """ 210 Calcula la deuda total de la acción. 211 212 Args: 213 balanceSheet (DataFrame): El balance de la acción. 214 215 Returns: 216 float: La deuda total de la acción. 217 """ 218 try: 219 return self.getLastYearValue(balanceSheet, "Total Debt") 220 except Exception as e: 221 raise Exception("No se pudo obtener la deuda total de la acción") from e
Calcula la deuda total de la acción.
Args: balanceSheet (DataFrame): El balance de la acción.
Returns: float: La deuda total de la acción.
223 def getGrowthEstimates(self, ticker, option): 224 """ 225 Obtiene las estimaciones de crecimiento para la acción. 226 227 Args: 228 ticker (str): El símbolo de ticker de la acción. 229 230 Returns: 231 str: Las estimaciones de crecimiento. 232 """ 233 try: 234 if option == "yahoo": 235 return self.getGrowthEstimatesYahoo(ticker) 236 elif option == "zacks": 237 return self.getGrowthEstimatesZacks(ticker) 238 elif option == "seeking": 239 return self.getGrowthEstimatesSeeking(ticker) 240 241 except Exception as e: 242 return str(e)
Obtiene las estimaciones de crecimiento para la acción.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: str: Las estimaciones de crecimiento.
244 def getGrowthEstimatesYahoo(self, ticker): 245 """ 246 Obtiene las estimaciones de crecimiento para la acción de la webd e Yahoo Finance. 247 248 Args: 249 ticker (str): El símbolo de ticker de la acción. 250 251 Returns: 252 str: Las estimaciones de crecimiento. 253 """ 254 url = f"https://finance.yahoo.com/quote/{ticker}/analysis?ltr=1" 255 headers = { 256 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 257 } 258 try: 259 response = requests.get(url, headers=headers) 260 response.raise_for_status() 261 soup = BeautifulSoup(response.text, "html.parser") 262 desired_table = soup.find_all("table")[5] 263 target_value = ( 264 desired_table.find_all("tr")[5].find_all("td")[1].text.strip() 265 ) 266 return target_value 267 except IndexError: 268 raise Exception( 269 "No se encontraron suficientes tablas, filas o celdas en la página" 270 ) 271 except requests.exceptions.RequestException as e: 272 raise Exception(f"Error en la solicitud: {e}")
Obtiene las estimaciones de crecimiento para la acción de la webd e Yahoo Finance.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: str: Las estimaciones de crecimiento.
274 def getGrowthEstimatesZacks(self, ticker): 275 """ 276 Obtiene las estimaciones de crecimiento para la acción de la web de Zacks. 277 278 Args: 279 ticker (str): El símbolo de ticker de la acción. 280 281 Returns: 282 str: Las estimaciones de crecimiento. 283 """ 284 url = f"https://www.zacks.com/stock/quote/{ticker}?q={ticker}" 285 headers = { 286 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 287 } 288 try: 289 response = requests.get(url, headers=headers) 290 response.raise_for_status() 291 soup = BeautifulSoup(response.text, "html.parser") 292 desired_table = soup.find_all("dl", class_="abut_bottom") 293 # print(desired_table) 294 target_value = desired_table[15].find_all("dd")[0].text.strip() 295 # print(target_value) 296 return target_value 297 except IndexError: 298 raise Exception( 299 "No se encontraron suficientes tablas, filas o celdas en la página" 300 ) 301 except requests.exceptions.RequestException as e: 302 raise Exception(f"Error en la solicitud: {e}")
Obtiene las estimaciones de crecimiento para la acción de la web de Zacks.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: str: Las estimaciones de crecimiento.
304 def getGrowthEstimatesSeeking(self, ticker): 305 """ 306 Obtiene las estimaciones de crecimiento para la acción de la web de Seeking Alpha. 307 308 Args: 309 ticker (str): El símbolo de ticker de la acción. 310 311 Returns: 312 str: Las estimaciones de crecimiento. 313 """ 314 url = f"https://seekingalpha.com/symbol/{ticker}/growth" 315 headers = { 316 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" 317 } 318 try: 319 response = requests.get(url, headers=headers) 320 # print(response) 321 response.raise_for_status() 322 soup = BeautifulSoup(response.text, "html.parser") 323 desired_table = soup.find_all("table")[0] 324 target_value = ( 325 desired_table.find_all("tr")[11].find_all("td")[1].text.strip() 326 ) 327 # print(target_value, 'hi') 328 return target_value 329 except IndexError: 330 raise Exception( 331 "No se encontraron suficientes tablas, filas o celdas en la página" 332 ) 333 except requests.exceptions.RequestException as e: 334 raise Exception(f"Error en la solicitud: {e}")
Obtiene las estimaciones de crecimiento para la acción de la web de Seeking Alpha.
Args: ticker (str): El símbolo de ticker de la acción.
Returns: str: Las estimaciones de crecimiento.
336 def waccCalculator(self, rf, rm): 337 """ 338 Calcula el costo promedio ponderado del capital (WACC). 339 340 Args: 341 rf (float): Tasa libre de riesgo. 342 rm (float): Retorno del mercado. 343 344 Returns: 345 float: El WACC calculado. 346 """ 347 last_year_total_debt = self.getTotalDebt(self.balanceSheet) 348 349 beta = self.info.get("beta", 1) 350 351 ke = rf + (beta * (rm - rf)) 352 353 e = self.info.get("marketCap") 354 if e is None: 355 raise Exception( 356 "No se pudo obtener la capitalización bursátil de la acción" 357 ) 358 359 total_debt_ED = e + last_year_total_debt 360 361 total_equity = ke * (e / total_debt_ED) 362 363 last_year_interest_expense = self.getLastYearValue( 364 self.financials, "Interest Expense" 365 ) 366 367 last_year_current_debt = self.getLastYearValue( 368 self.balanceSheet, "Current Debt And Capital Lease Obligation" 369 ) 370 371 last_year_long_term_debt = self.getLastYearValue( 372 self.balanceSheet, "Long Term Debt" 373 ) 374 375 kd = last_year_interest_expense / ( 376 last_year_current_debt + last_year_long_term_debt 377 ) 378 379 last_year_tax_provision = self.getLastYearValue( 380 self.incomeStmt, "Tax Provision" 381 ) 382 383 last_year_pretax_income = self.getLastYearValue( 384 self.incomeStmt, "Pretax Income" 385 ) 386 387 t = last_year_tax_provision / last_year_pretax_income 388 389 total_debt_cost = kd * (1 - t) * (last_year_total_debt / total_debt_ED) 390 391 return total_equity + total_debt_cost
Calcula el costo promedio ponderado del capital (WACC).
Args: rf (float): Tasa libre de riesgo. rm (float): Retorno del mercado.
Returns: float: El WACC calculado.
393 def dcf(self, tickerStr, g, rf, rm, option): 394 """ 395 Calcula el valor intrínseco de una acción utilizando el modelo de descuento de flujos de efectivo (DCF). 396 397 Args: 398 tickerStr (str): El símbolo de ticker de la acción. 399 g (float): Tasa de crecimiento a perpetuidad. 400 rf (float): Tasa libre de riesgo. 401 rm (float): Retorno del mercado. 402 403 Returns: 404 list: Una lista que contiene varios valores calculados. 405 """ 406 try: 407 last_year_total_debt = self.getTotalDebt(self.balanceSheet) 408 growthFCF = self.getGrowthEstimates(tickerStr, option) 409 print(option, growthFCF) 410 printGrowthFCF = growthFCF 411 try: 412 growthFCF = float(growthFCF.replace("%", "")) / 100 413 except: 414 FCFGrow = self.cashFlow.iloc[0] 415 growthFCF = ( 416 (FCFGrow.iloc[0] / FCFGrow.iloc[-1]) ** (1 / len(FCFGrow)) 417 ) - 1 418 printGrowthFCF = "{:.2f}%".format(growthFCF * 100) 419 420 wacc = self.waccCalculator(rf, rm) 421 if type(wacc) != float: 422 raise Exception(wacc) 423 424 last_year_fcf = self.getLastYearValue(self.cashFlow, "Free Cash Flow") 425 printFCF = last_year_fcf 426 427 FCFn = [ 428 int(format(last_year_fcf * (1 + growthFCF) ** i, ".0f")) 429 for i in range(1, 6) 430 ] 431 432 terminal_value = (FCFn[-1] * (1 + g)) / (wacc - g) 433 FNFnLast = FCFn[-1] 434 FCFn[-1] = int(format(FCFn[-1] + terminal_value, ".0f")) 435 436 enterprise_value = sum( 437 [FCFn[i] / ((1 + wacc) ** (i + 1)) for i in range(5)] 438 ) 439 440 last_year_cash = self.getLastYearValue( 441 self.balanceSheet, "Cash Cash Equivalents And Short Term Investments" 442 ) 443 444 equity_value = enterprise_value + last_year_cash - last_year_total_debt 445 446 shares_outstanding = self.info["sharesOutstanding"] 447 448 intrinsic_value = equity_value / shares_outstanding 449 450 price = self.info["regularMarketPreviousClose"] 451 452 difference = 100 + (((intrinsic_value - price) / price) * 100) 453 454 FCFn.pop() 455 FCFn.append(FNFnLast) 456 457 return [ 458 (format((wacc * 100), ".2f") + " %"), 459 ("$ " + "{:,.0f}".format(printFCF).replace(",", ".")), 460 FCFn, 461 printGrowthFCF, 462 ("$ " + "{:,.0f}".format(equity_value, ".0f").replace(",", ".")), 463 ("$ " + str(price)), 464 ("$ " + format(intrinsic_value, ".2f")), 465 (format((difference), ".2f") + "%"), 466 ] 467 except Exception as e: 468 return str(e)
Calcula el valor intrínseco de una acción utilizando el modelo de descuento de flujos de efectivo (DCF).
Args: tickerStr (str): El símbolo de ticker de la acción. g (float): Tasa de crecimiento a perpetuidad. rf (float): Tasa libre de riesgo. rm (float): Retorno del mercado.
Returns: list: Una lista que contiene varios valores calculados.