import FinanceDataReader as fdr
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

pd.options.display.float_format = '{:,.3f}'.format

동종업계 평균 수익률보다 더 좋은 수익률을 보여준다.#

mdl_data = pd.read_pickle('mdl_data.pkl')
mdl_data.head().style.set_table_attributes('style="font-size: 12px"').format(precision=3)
  open high low close volume change code name kosdaq_return return win_market close_r1 close_r2 close_r3 close_r4 close_r5 max_close
2021-01-05 2270 2285 2200 2250 410263 -0.004 060310 3S 1.008 0.996 0 1.018 1.018 0.998 0.967 0.971 1.018
2021-01-06 2225 2310 2215 2290 570349 0.018 060310 3S 0.996 1.018 1 1.000 0.980 0.950 0.954 0.950 1.000
2021-01-07 2290 2340 2240 2290 519777 0.000 060310 3S 1.008 1.000 0 0.980 0.950 0.954 0.950 0.959 0.980
2021-01-08 2300 2315 2225 2245 462568 -0.020 060310 3S 0.999 0.980 0 0.969 0.973 0.969 0.978 0.973 0.978
2021-01-11 2230 2275 2130 2175 409057 -0.031 060310 3S 0.989 0.969 0 1.005 1.000 1.009 1.005 1.002 1.009


우선 과거 60일 평균 수익율 값을 return_mean 에 저장합니다. 그리고 종목에 sector 정보를 추가합니다.

kosdaq_list = pd.read_pickle('kosdaq_list.pkl')

data_h6 = pd.DataFrame()

for code, sector in zip(kosdaq_list['code'], kosdaq_list['sector']):
    
    # 종목별 처리
    data = mdl_data[mdl_data['code']==code].sort_index().copy()
    data.dropna(inplace=True)
    
    # 최근 60일 평균 수익율            
    data['return_mean'] = data['return'].rolling(60).mean() # 종목별 최근 60 일 수익율의 평균
    data['sector'] = sector  # 섹터 정보   
  
    data.dropna(subset=['return_mean'], inplace=True)    
    data_h6 = pd.concat([data, data_h6], axis=0)

    
data_h6['sector_return'] = data_h6.groupby(['sector', data_h6.index])['return'].transform(lambda x: x.mean()) # 섹터와 날짜별 평균 값
data_h6['return over sector'] = (data_h6['return']/data_h6['sector_return'])

data_h6.to_pickle('data_h6.pkl')  


종목이 몇 개 없는 섹터는 평균의 의미가 없으므로 섹터에 종목이 최소한 10 개 이상이 있는 섹터만 보겠습니다.

data_h6 = pd.read_pickle('data_h6.pkl')  
sector_count = data_h6.groupby('sector')['code'].nunique().sort_values() # 섹터 별로 종목 수 계산
data_h6x = data_h6[data_h6['sector'].isin(sector_count[sector_count>=10].index)].copy() # 섹터 별로 10개 이상이 있는 종목이 있는 섹터만 추출


섹터 평균 수익율 대비 종목 수익율이 아주 낮거나, 높은 경우에 미래 수익률이 높게 나왔습니다. 종목 수익률이 섹터 평균 수익률과 비슷한 경우(‘return over sector’ 값이 1 근처인 경우)는 예상 수익율이 낮게 나타나고 있습니다.

data_h6x['sector_return'] = data_h6x.groupby(['sector', data_h6x.index])['return'].transform(lambda x: x.mean())
data_h6x['return over sector'] = (data_h6x['return']/data_h6x['sector_return'])
ranks = pd.qcut(data_h6x['return over sector'], q=10)
print(data_h6x.groupby(ranks)['max_close'].describe(percentiles=[0.1, 0.9]))
data_h6x.groupby(ranks)['max_close'].mean().plot(figsize=(12,5))
                        count  mean   std   min   10%   50%   90%   max
return over sector                                                     
(0.688, 0.973]     26,887.000 1.042 0.087 0.700 0.974 1.022 1.126 2.968
(0.973, 0.983]     26,886.000 1.034 0.067 0.702 0.982 1.019 1.099 2.171
(0.983, 0.989]     26,886.000 1.030 0.060 0.704 0.984 1.016 1.087 2.286
(0.989, 0.994]     26,886.000 1.028 0.060 0.700 0.985 1.014 1.083 2.194
(0.994, 0.998]     26,889.000 1.027 0.058 0.819 0.985 1.013 1.080 2.729
(0.998, 1.002]     26,883.000 1.026 0.059 0.700 0.985 1.012 1.078 2.652
(1.002, 1.007]     26,886.000 1.027 0.062 0.700 0.984 1.012 1.080 3.027
(1.007, 1.014]     26,886.000 1.028 0.062 0.700 0.983 1.013 1.084 3.380
(1.014, 1.027]     26,886.000 1.031 0.068 0.700 0.980 1.014 1.093 2.412
(1.027, 1.399]     26,887.000 1.043 0.105 0.700 0.970 1.019 1.136 3.703
<AxesSubplot:xlabel='return over sector'>
../_images/5.1.6_Hypothesis_6_8_2.png