본문 바로가기

코딩/퀀트 투자

[파이썬/ 웹 스크래핑] 기업 가치(EV, enterprise value)를 통한 종목 선정

1. 목표

 

미국 주식을 대상으로 기업 가치(EV, enterprise value)에 따라 종목 선정을 하는 것을 목표로 한다.

 

 

https://kr.freepik.com/vectors/arrow by rawpixel.com

 

 

 

 

2. NEV(negative enterprise value) 4가지 투자 전략

 

(1) 금융주(financial stock)가 아닌 종목

 

 

(2) 미국 주식예탁증서(ADR, america depositary receipts)가 아닌 종목

 

 

(3) 기업가치(EV, enterprise value)가 0 미만인 종목

 

- 기업가치 = 시가 총액(market cap) + 총 부채(total debt) - 현금 및 현금성 자산(cash and equivalents)

 

- 기업가치가 마이너스라는 것이 의미하는 것은?

 

: 기업가치가 마이너스인 종목은 회사가 정말로 원한다면 부채를 갚고 한 번에 모든 주식을 사들이는 것보다 더 많은 현금을 가지고 있다는 것을 의미한다.

안정성도 어느 정도 보장되며, 발전성도 높다는 것을 의미한다.

 

 

(4) 일일 거래량(daily volume)이 20,000 이상인 종목

 

 

 

위의 투자 전략은 아래의 글을 참조했다.

 

 

Negative Enterprise Value Screen Strategy

Stock Screen Strategy and Backtest Series NCAV and NNWC Screen Strategy CROIC and ROIC Screen Strategy Negative Enterprise Value Screen Strategy Negative Enterprise Value I've written extensively about how companies with negative enterprise values are

www.oldschoolvalue.com

 

 

 

 

 

Photo by Christopher Gower on Unsplash

 

 

첫 번째, 금융주(financial stock)가 아니고, 미국 주식예탁증서(ADR)가 아닌 종목을 선정 (투자 전략 (1), (2))

 

먼저 모든 미국 주식 종목들의 ticker를 FinanceDataReader 라이브러리를 통해서 가져와서 csv 파일에 저장한다.

 

FinanceDataReader 라이브러리 설치 및 업데이트는 다음을 통해서 가능하다.

 

pip install finance-datareader # 설치
pip install -U finance-datareader # 업데이트

 

코드는 다음과 같다.

 

import FinanceDataReader as fdr
import pandas as pd

# 최신 미국 주식 LIST 가져오기
df_nasdaq = fdr.StockListing('NASDAQ')
df_nyse = fdr.StockListing('NYSE')
df_amex = fdr.StockListing('AMEX')
df_stock = pd.concat([df_nasdaq,df_nyse,df_amex])
df_stock = df_stock.reset_index()
nasdaq = df_nasdaq.Symbol.tolist()
nyse = df_nyse.Symbol.tolist()
amex = df_amex.Symbol.tolist()
stock_list = nasdaq+nyse+amex

df_tickers = pd.DataFrame({'Symbol': stock_list})
df_tickers.to_csv('tickers.csv')

 

다음으로 위에서 가져온 미국 주식 종목에서 금융주(financial stock)이거나, 미국 주식예탁증서(ADR)인 종목을 제외해서 csv 파일로 저장한다.

 

이때 금융주인 ticker list는 investing.com의 웹 스크래핑을 통해서 추출하고,

 

 

Stock Screener - Investing.com

Stock Screener - research and filter stocks based on key parameters and metrics such as stock price, market cap, dividend yield and more.

www.investing.com

 

미국 주식예탁증서인 ticker list는 stockmarketmba.com에서 받은 csv 파일에서 추출한다.

 

 

List of ADRs

Current as of yesterday.

stockmarketmba.com

 

코드는 다음과 같다.

 

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import pandas as pd

driver = webdriver.Chrome('C:/Program Files/chromedriver_win32/chromedriver.exe')
driver.implicitly_wait(3)

tickers_filter = []

for i in range(1, 45):
    driver.get(f'https://www.investing.com/stock-screener/?sp=country::5|sector::1|industry::a|equityType::a|exchange::a%3Ceq_market_cap;{i}')
    try:
        driver.find_element_by_link_text('Overview').send_keys(Keys.ENTER)
    except:
        continue
    time.sleep(3)
    html = driver.page_source
    soup = BeautifulSoup(html, 'lxml')
    select = soup.select('.symbol.left.bold.elp')
    for s in select:
        text = s.find_next(class_='left').text
        tickers_filter.append(text)

df = pd.read_csv('tickers.csv')
tickers = df['Symbol'].tolist()

df1 = pd.read_csv('List of ADRs.csv')
tickers_filter1 = df1['Symbol'].tolist()

tickers_result = list(set(list(set(tickers) - set(tickers_filter))) - set(tickers_filter1))

tickers_df = pd.DataFrame({'Symbol' : tickers_result})
tickers_df.to_csv('tickers_result_1.csv')

 

 

 

 

두 번째, 기업가치(EV, enterprise value)가 0 미만인 종목 선정 (투자 전략 (3))

 

먼저 위에서 필터링 된 종목들에 대해서 finviz.com의 웹 스크래핑을 통해 시가 총액(market cap), 총 부채(total debt)와 현금 및 현금성 자산(cash and equivalents)에 대한 정보를 추출해 csv 파일에 저장한다.

 

 

FINVIZ.com - Stock Screener

× Ever heard of Finviz*Elite? Our premium service offers you real-time quotes, advanced visualizations, technical studies, and much more. Become Elite and make informed financial decisions. Find out more --> Upgrade your FINVIZ experience Join thousands o

finviz.com

 

코드는 다음과 같다.

 

from bs4 import BeautifulSoup
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

tickers = pd.read_csv('tickers_result_1.csv')
tickers = tickers['Symbol'].tolist()

columns = ['Market Cap', 'Total Debt', 'Cash and Equivalents']
df_filter = pd.DataFrame(index=tickers, columns=columns)

driver = webdriver.Chrome('C:/Program Files/chromedriver_win32/chromedriver.exe')
driver.implicitly_wait(3)

for ticker in tickers:
    driver.get(f'https://finviz.com/quote.ashx?t={ticker}')
    try:
        driver.find_element_by_link_text('balance sheet').send_keys(Keys.ENTER)
    except:
        continue
    time.sleep(5)
    html = driver.page_source
    soup = BeautifulSoup(html, 'lxml')

    try:
        df_filter.loc[ticker, 'Market Cap'] = soup.find('td', text='Market Cap').find_next('td').text
    except:
        df_filter.loc[ticker, 'Market Cap'] = None

    for column in columns[1:]:
        try:
            r = soup.find(text=column).find_next(class_='snapshot-td2').find_next(class_='snapshot-td2').text
        except:
            continue

        try:
            df_filter.loc[ticker, column] = float(r.replace(',', ''))
        except:
            df_filter.loc[ticker, column] = None

df_filter.to_csv('df_filter_1.csv')

 

다음으로 위에서 추출한 정보들을 토대로 기업가치를 계산하고, 기업가치가 마이너스인 종목들을 필터링해 csv 파일로 저장한다.

 

이때 기업가치는 "시가 총액(market cap) + 총 부채(total debt) - 현금 및 현금성 자산(cash and equivalents)"로 계산한다.

 

코드는 다음과 같다.

 

import pandas as pd

df = pd.read_csv('df_filter_1.csv', index_col = 0)
df = df.dropna()
list = []

for i in df.index:
    l = len(df.loc[i, 'Market Cap'])

    if df.loc[i, 'Market Cap'][-1] == 'M':
        cap = float(df.loc[i, 'Market Cap'][:(l-2)])

    elif df.loc[i, 'Market Cap'][-1] == 'B':
        cap = float(df.loc[i, 'Market Cap'][:(l - 2)]) * 1000

    ev = cap + df.loc[i, 'Total Debt'] - df.loc[i, 'Cash and Equivalents']
    print(ev)

    if ev < 0:
        list.append(i)

df_result = pd.DataFrame({'Symbol' : list})
df_result.to_csv('tickers_result_2.csv')

 

 

 

세 번째, 일일 거래량(daily volume)이 20,000 이상인 종목 선정(투자 전략 (4))

 

먼저 위에서 필터링 된 종목들에 대해서 finviz.com의 웹 스크래핑을 통해서 일일 거래량에 대한 정보를 추출해 csv 파일에 저장한다.

 

코드는 다음과 같다.

 

from bs4 import BeautifulSoup
import pandas as pd
import requests as request

def get_html(url):
    _html = ""
    resp = request.get(url, headers={'User-agent' : 'Mozilla/5.0'})
    if resp.status_code == 200:
        _html = resp.text
    return _html

tickers = pd.read_csv('tickers_result_2.csv')
tickers = tickers['Symbol'].tolist()

df_filter = pd.DataFrame(index=tickers, columns=['Volume'])

for ticker in tickers:
    #Volume 스크래핑
    url = f'https://finviz.com/quote.ashx?t={ticker}'
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    df_filter.loc[ticker, 'Volume'] = int(soup.find('td', text='Volume').find_next('td').text.replace(',', ''))

df_filter.to_csv('df_filter_2.csv')

 

다음으로 위에서 추출한 정보를 통해서 거래량이 20,000 이상인 종목들을 필터링해 csv 파일에 저장한다.

 

코드는 다음과 같다.

 

import pandas as pd

df_filter = pd.read_csv('df_filter_2.csv', index_col=0)

list = []

for i in range(len(df_filter)):
    if df_filter.iloc[i, 0] < 20000:
        pass
    else:
        list.append(df_filter.index[i])

df_result = pd.DataFrame({'Symbol' : list})
df_result.to_csv('tickers_result_3.csv')

 

 

 

 

 

https://kr.freepik.com/vectors/backgroundBackground by iconicbestiary

 

 

3. 결론

 

NEV(negative enterprise value) 4가지 투자 전략을 미국 주식에 적용해본 결과 필터링 된 종목은 총 10개였다.

 

아래는 필터링 된 종목들의 ticker이다.

 

ABIO, CO, FFHL, BLCM, FRLN, SJ, CREG, GLTO, UK, GLYC