Programming

[Python] 퀀트 투자 기법 적용 결과 (한국편)

better_coco 2022. 9. 17. 11:00


퀀트 투자 기법 적용하기 (미국편) 에서 다루었던 동일한 기법을 적용할 거다.
미국편에서는 기법을 적용하면서 데이터 전처리까지 같이 설명하는 식이었는데, 한국편에서는 데이터를 수집할 때 이미 처리를 해서 가져왔기 때문에 기법만 적용하는 식으로 정리할까 한다.

기법도 이미 미국편을 참고하면 함수화되어 있어, 이번 포스팅에서는 함수 적용 후 결과를 살펴보자.

[미국편]

 

[Python] 퀀트 투자 기법 적용하기 Part 1. (미국편)

지난 포스팅에서 yahoo finance 에서 미국 주식 데이터를 긁어오는 내용을 다뤘었다. 이번 포스팅에서는 퀀트 기법에 적용해보기 위해, 어떤 데이터들을 먼저 수집해야하는지를 다뤄보자. 우선 적

thisiswhoiam.tistory.com

 

 

[Python] 퀀트 투자 기법 적용하기 Part 2. (미국편)

지난 번 포스팅에서는 퀀트 투자 기법을 적용하기 위해 필요한 데이터를 수집하는 함수를 만들었다. 그럼 이번 포스팅에서는 실제로 투자 기법을 하나씩 구현해보도록 하자. (데이터는 이미 수

thisiswhoiam.tistory.com

 

[한국편]

 

[Python] naver finance 에서 원하는 정보 긁어오기 Part 1. (한국편)

이번 포스팅에서는 naver finance 에서 데이터를 긁어오는 걸 할 텐데, naver finance 에서 제공하는 API 를 이용하려 한다. 먼저 데이터를 긁어오기 전에 한국 주식 거래소에서 거래되는 종목들의 ticker

thisiswhoiam.tistory.com

 

 

[Python] naver finance 에서 원하는 정보 긁어오기 Part 2. (한국편)

지난 포스팅에서 naver finance 에서 제공하는 "Financial Summary" 정보를 크롤링하는 법을 다뤘었다. 그럼 이번에는 크롤링한 데이터에서 우리가 필요한 정보를 추출하고, 만일 원하는 데이터가 없다면

thisiswhoiam.tistory.com

 

지난 포스팅을 보면 전체 코드를 돌렸을 때 반환되는 데이터의 형태는 아래와 같았다.

 

all_df = pd.DataFrame(tmp, columns=['PER', 'PBR', 'PSR', 'MarketCap', 'CurrentAssets', 'TotalLiabilities', 'DebtRatio', 'ROA', 'NetIncome', 'GP/A'])


여기서 우리가 아는 기법들을 적용하는 함수를 정의해보자.

방법론 1) Graham

def graham(df):
    graham_df = df[(df['ROA'] > 5) & (df['PBR'] > 0.2) & (df['DebtRatio'] < 50)].sort_values('PBR')
    
    return graham_df


방법론 2) NCAV

def ncav(df):
    filtered_df = df[(df['PER'] > 0.2) & (df['PER'] < 5) & (df['NetIncome'] > 0)]    
    tight_ncav = filtered_df[filtered_df['CurrentAssets'] - filtered_df['TotalLiabilities'] > filtered_df['MarketCap']]
    #loose_ncav = filtered_df[(filtered_df['CurrentAssets'] - filtered_df['TotalLiabilities']) * 0.85 > filtered_df['MarketCap']]

    return tight_ncav



방법론 3) 3P Combo

from scipy.stats import rankdata

def combo_3p(df):
    per_rank = list(rankdata(list(df['PER'])))
    pbr_rank = list(rankdata(list(df['PBR'])))
    psr_rank = list(rankdata(list(df['PSR'])))
    
    ele = [x + y + z for x, y, z in zip(per_rank, pbr_rank, psr_rank)]
    
    # 따로 rank 값을 정규화하진 않았다. (rank 차이가 중요한 것이 아니라 순서만 활용하므로)
    df['Rank'] = ele
    df.sort_values(['Rank'], inplace=True)
    
    return df


방법론 4) PBR + GP/A

def pbr_gpa(df):
    per_rank = list(rankdata(list(df['PBR'])))
    
    # 결과를 reverse 하기 위해 전체 데이터 갯수에서 rank 를 뺌 (rankdata 값은 전체 데이터 갯수보다 크지 않음)
    gpa_rank = list(len(df['GP/A']) - rankdata(list(df['GP/A'].astype(int))))
        
    ele = [x + y for x, y in zip(per_rank, gpa_rank)]
    
    df['Rank2'] = ele
    df.sort_values(['Rank2'], inplace=True)
    
    return df

 



[종합 결과 해석]
총 4가지 투자 기법들을 모두 만족하는 (AND 조건) 종목들을 추려보면 아래와 같다.
여기서 Graham 과 NCAV 기법은 Y/N 로 이분법적인 결과를 반환하지만, 3P Combo 와 PBR + GP/A 기법은 rank 값으로 반환하기 때문에 상위 500 개 종목 기준으로 추려냈다.
(전체 종목이 2,000 여개이기 때문에 25% 정도로 추려냄)

퀀트 기법 적용 결과


위의 종목들을 분야별로 쪼개서 보면, 아래의 pie chart 와 같다.
분기별 데이터가 아닌 연간 데이터로 투자 기법을 적용했기 때문에 2021년 12월 데이터가 반영된 것을 감안하면, 이슈가 되었던 분야였던 것은 맞는 것 같다. (인플레이션이나 자동차 수급 문제)

종목 분야별 비율


철강 쪽은 명확하게는 모르겠지만 원자재 수급 문제로 인한 것이 아닐까 추측해본다.
전체 raw data 는 google spread sheet 로 공유하니, 한 번 둘러보는 것도 좋을 듯 하다.
(참고. 따로 null 값에 대한 전처리 등은 진행하지 않고 추출한 그대로의 raw data 이며, 비율값을 제외한 데이터 단위는 "억원" 입니다.)

https://docs.google.com/spreadsheets/d/11iuRKkcI0iWGaZrCLB5dQKn8UW8BYm61KZo7gJeOqoE/edit?usp=sharing

 

QuantAnalysis_Example_Results

결과 CODE,NAME,분야,PER,PBR,PSR,MarketCap,CurrentAssets,TotalLiabilities,DebtRatio,ROA,NetIncome,GP/A,3P Combo_adjusted,PBR + GP/A_adjusted,Graham,NCAV(tight) 001940,KISCO홀딩스,철강,2.36,0.21,0.14,2240,12584,2674,0.19,10.97,1784,0.16,3,14,Y,Y 036

docs.google.com