본문 바로가기

코딩/퀀트 투자

[파이썬/ 웹 스크래핑] 벤저민 그레이엄의 투자 전략에 따른 종목 선정 - 방어 투자자(2)

1. 목표

 

저번 포스팅에 이어서 벤저민 그레이엄의 방어 투자자를 위한 7가지 투자 전략 중 나머지 3가지 전략을 통한 종목 선정을 할 것이다.

 

앞에서 다룬 4가지 전략에 대한 내용 및 코드는 아래의 글을 참조하면 된다.

 

 

[파이썬/ 웹 스크래핑] 벤저민 그레이엄의 투자 전략에 따른 종목 선정 - 방어 투자자(1)

1. 목표 미국 주식을 대상으로 벤저민 그레이엄의 투자 전략에 따라 종목 선정을 하는 것이다. 투자 전략은 <현명한 투자자>라는 책의 내용을 토대로 설정했으며, 투자 성향에 따라 방어 투자자,

coding-gongbu.tistory.com

 

 

 

 

2. 방어 투자자를 위한 7가지 투자 전략 요약

 

(1) 기업의 적정 규모:

- 연 매출액(revenue)이 3억 5천 달러 이상인 종목

 

 

(2) 재무 구조의 건전성:

- 유동비율(current ratio)이 2 이상인 종목

- 장기부채가 운전자본 이하인 종목

 

 

(3) 이익의 안정성:

- 지난 10년 동안 해마다 이익을 낸 종목, 즉 10년간 당기순이익(net income)이 마이너스가 없는 종목

 

 

(4) 배당 실적:

- 지난 20년간 빠짐없이 배당을 지급한 종목

 

 

(5) 이익 증가:

- 지난 10년간 3년 평균 EPS 증가율이 33% 이상인 종목

 

 

(6) 적정 PER:

- 현재 주가가 최근 3년 평균 이익의 15배 이하인 종목

(최근 3년 평균 이익은 주당 순이익인 EPS의 평균으로 구한다.

따라서 "현재 주가 / 3년 평균 EPS <= 15"를 만족하는 종목을 선정한다.)

 

 

(7) 적정 PBR:

현재 PBR이 1.5 이하인 종목

PBR * PER이 22.5 이하인 종목

(PER은 (6)에서 구한 PER(= 현재 주가 / 3년 평균 EPS) 값을 사용했다.)

 

 

 

 

네 번째, 현재 주가가 최근 3년 평균 EPS의 15배 이하, 현재 PBR이 1.5 이하, PBR * PER이 22.5 이하를 만족하는 종목 탐색 (투자 전략 (6), (7))

 

먼저 위 조건을 만족하는 종목들을 선정하기 위해서 지난 3년간 EPS, 현재의 PBR과 현재 주가 정보가 필요하다. 

 

그중 3년간의 EPS 정보는 세 번째 파트에서 추출해서 dataframe의 형태로 df_eps.csv 파일에 저장되어 있다. (이에 대한 자세한 정보는 저번 포스팅을 참고하면 된다.)

 

따라서 세 번째 조건에 의해 필터링 된 종목들에 대한 현재의 PBR과 현재 주가만 추출하면 된다. (여기서 현재 주가로 최근 종가를 이용했다.)

 

PBR과 현재 주가 정보는 finviz.com에서 웹 스크래핑을 통해 추출하고, dataframe의 형태로 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_3.csv')
tickers = tickers['Symbol'].tolist()

columns = ['P/B', 'Prev Close']
df_filter = pd.DataFrame(index=tickers, columns=columns)

for ticker in tickers:
    #p/b 크롤링
    url = f'https://finviz.com/quote.ashx?t={ticker}'
    html = get_html(url)
    soup = BeautifulSoup(html, 'lxml')
    df_filter.loc[ticker, 'P/B'] = soup.find('td', text='P/B').find_next('td').text

    #최근 종가(prev close) 크롤링
    df_filter.loc[ticker, 'Prev Close'] = soup.find('td', text='Prev Close').find_next('td').text

df_filter.to_csv('df_filter_4.csv')

 

다음으로 위에서 가져온 정보들을 바탕으로 현재 주가가 최근 3년 평균 EPS의 15배 이하, 현재 PBR이 1.5 이하, PBR * PER이 22.5 이하 세 가지 조건에 대해 종목들을 필터링해 csv 파일로 저장한다.

 

이때 세 번째 조건인 PBR * PER이 22.5 이하인 조건에서 PER 값으로 첫 번째 조건에서 구한 최근 3년 평균 EPS 값을 사용했다.

 

코드는 다음과 같다.

 

import pandas as pd
import math

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

#현재 주가가 최근 3년 평균 EPS의 15배 이하

list = []
list_value = []

for i in range(len(df_filter)):
    eps_sum = 0
    count = 0
    for j in range(3):
        if math.isnan(df_eps.loc[df_filter.index[i], f'{j+1}년 전']):
            pass
        else:
            eps_sum = eps_sum + df_eps.loc[df_filter.index[i], f'{j + 1}년 전']
            count = count + 1
    try:
        eps_mean = eps_sum/count
    except:
        eps_mean = float('nan')

    list_value.append(df_filter.iloc[i , 1] / eps_mean)

    if (df_filter.iloc[i, 1] / eps_mean) <= 15:
        list.append(df_filter.index[i])

df_filter['P/E'] = list_value

#현재 PBR이 1.5이하

list1 = []

for i in list:
    if (df_filter.loc[i, 'P/B'] <= 1.5):
        list1.append(i)

#PBR * PER이 22.5 이하

list2 = []

for i in list1:
    if (df_filter.loc[i, 'P/B'] * df_filter.loc[i, 'P/E']) < 22.5:
        list2.append(i)

df_result = pd.DataFrame({'Symbol' : list2})
df_result.to_csv('tickers_result_4.csv')

 

 

 

 

다섯 번째, 지난 20년간 빠짐없이 배당을 지급한 종목 탐색 (투자 전략 (4))

 

먼저 필터링 된 종목들의 배당 실적 정보를 yfinance 라이브러리를 이용해서 가져온다.

 

yfinance에서 제공하는 배당 실적 정보를 가공해서, index를 연도, column을 ticker로 하는 각 연도별 배당 횟수를 저장하는 dataframe으로 csv 파일에 저장한다.

 

코드는 다음과 같다.

 

import yfinance as yf
import pandas as pd

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

yf_div = pd.DataFrame()
for i in tickers:
    x = pd.DataFrame(yf.Ticker(i).dividends)
    x.index = x.index.year
    x = x.rename(columns={"Dividends":i})
    x = x.groupby(x.index).count()
    yf_div = pd.concat([yf_div, x], axis=1)

yf_div.to_csv("dividends_5.csv")

 

다음으로 위에서 가져온 정보를 바탕으로 지난 20년간 빠짐없이 배당금을 지급한 종목을 필터링해 csv 파일을 저장한다.

 

코드는 다음과 같다.

 

import pandas as pd
import math

df_div = pd.read_csv('dividends.csv', index_col=0)
df_div = df_div.sort_index(ascending=False)

list = []

for i in range(len(df_div.columns)):
    for j in range(20):
        if math.isnan(df_div.iloc[j, i]):
            break
        if j == 19:
            list.append(df_div.columns[i])
            
df_result = pd.DataFrame({'Symbol' : list})
df_result.to_csv('tickers_result_5.csv')

 

3. 결론

 

미국 주식에 벤저민 그레이엄의 7가지 투자 전략을 모두 적용해본 결과 필터링 된 종목은 없었다.

 

그래서 마지막 필터링 조건이었던 배당 실적을 제외한 결과를 살펴본 결과 아래 5개의 종목이 선정됐다.

 

MOMO, IBA, HOLI, ENVA, MLR