ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 효율적 투자선(Efficient Frontier) 포트폴리오 최적화(feat.파이썬)(2)
    빅데이터 2021. 10. 10. 21:34

    요약

    1. 과거의 주가를 활용한 샤프지수 극대화 효율적 투자선 포트폴리오는 미래의 샤프지수 극대화를 보장하지 않는다.

    2. 기간을 변경해보아도 마찬가지다.

    3. 포트폴리오 구성비율 결정에 효율적 투자선 모델은 적합하지 않다.

    4. 다음에는 Risk Parity를 적용해보자.


    https://inv42195.tistory.com/7

     

    효율적 투자선(Efficient Frontier) 포트폴리오 최적화(feat.파이썬)(1)

    투자할 종목군을 선정한 다음 고민할 것은 종목당 최적 투자비율일 것이다. 특히 나처럼 분산투자를 지향하는 투자자라면 더욱 고민되는 부분이다. 먼 옛날 공부했던 '재무관리'의 이론과 비교

    inv42195.tistory.com

    가치투자연구소 카페 쪽빛하늘님께서 저번 포스팅을 보고 개인투자자 순매수 상위 기업으로 최적화 하는 것을 제안해 주셨다. 흥미로운 제안이라 바로 파이썬을 돌려보았다.


    모델구성(A_model)

    종목구성 : 2021년 상반기 개인투자자 누적순매수 상위 10개 종목

    최적화 기간 : 2021년 상반기

    최적화 방법 : 효율적투자선 max sharpe

    검증 기간 : 2021년 3분기

    검증 방법 : 최적화 비율로 3분기 투자

     

    참고로 KRX정보데이터시스템에 접속하면 투자자별 순매수상위종목을 필터링 할 수 있다.

    http://data.krx.co.kr/contents/MDC/MDI/mdiLoader/index.cmd?menuId=MDC0201

     

    KRX 정보데이터시스템

    증권·파생상품의 시장정보(Marketdata), 공매도정보, 투자분석정보(SMILE) 등 한국거래소의 정보데이터를 통합하여 제공 서비스

    data.krx.co.kr

     

    소스코드(A_model)

    start = '20210104'
    end = '20210630'
    year = 0.5
    
    name_1 = ['삼성전자', 'SK하이닉스', '현대모비스', '카카오', 'LG전자',
              '현대차', '삼성SDI', '삼성전기', 'NAVER', '기아']
    code_1 =[]
    
    for x in name_1:
        code_1.append(code(x))
    
    weight_1 = np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) #변수명 변경 필요
    
    df = chart(name_1, code_1) #변수명 변경 필요
    
    title = 'Portfolio Close Price History'
    my_stocks = df
    plt.figure(figsize=(15, 10))
    
    for c in my_stocks.columns.values:
        plt.plot(my_stocks[c], label=c)
        
    plt.title(title)
    plt.xlabel('Date', fontsize=18)
    plt.ylabel('Close Price KRW', fontsize=18)
    plt.legend(my_stocks.columns.values, loc='upper left')
    plt.show()
    
    df_new = df.pct_change()
    cov = df_new.cov()*247
    # 최근 6년 평균 연간 거래일
    
    corrmat = df_new.corr()
    plt.figure(figsize=(10,10))
    cm = np.corrcoef(df.values.T)
    hm = sns.heatmap(cm, cmap='Blues', cbar=True, annot=True, square=True, fmt='.2f',
                     linewidths=0.01, xticklabels=df.columns, yticklabels=df.columns)
    plt.show()
    
    port_var = np.dot(weight_1.T, np.dot(cov, weight_1)) #변수명 변경 필요
    port_std = np.sqrt(port_var)
    port_SAR = (np.mean(ret(code_1))**(1/year))-1 #변수명 변경 필요
    
    per_var = str(round(port_var, 4) * 100) +'%'
    per_vols = str(round(port_std, 4) * 100) +'%'
    per_ret = str(round(port_SAR, 4) * 100) +'%'
    sr = str(round(port_SAR/port_std, 2))
    
    print('Expected annual return:'+ per_ret)
    print('Annual volatility:' + per_vols)
    print('Sharpe Ratio:' + sr)
    
    mu = expected_returns.mean_historical_return(df)
    S = risk_models.sample_cov(df)
    
    ef = EfficientFrontier(mu, S)
    weights = ef.max_sharpe()
    cleaned_weights = ef.clean_weights()
    print(cleaned_weights)
    ef.portfolio_performance(verbose=True)

    <동일비중 - 2021 상반기>

    Expected annual return : 57.89%

    Annual volatility : 27.23%

    Sharpe Ratio : 2.13

    <효율적투자선 max sharpe - 2021 상반기>

    OrderedDict([('삼성전자', 0.0), ('SK하이닉스', 0.0), ('현대모비스', 0.0), ('카카오', 1.0), ('LG전자', 0.0), ('현대차', 0.0), ('삼성SDI', 0.0), ('삼성전기', 0.0), ('NAVER', 0.0), ('기아', 0.0)])

    Expected annual return: 340.8%

    Annual volatility: 39.0%

    Sharpe Ratio: 8.68

    카카오 몰빵투자가 샤프지수가 최대화 되는 포트폴리오라고 한다. 그러면 이 최적화 포트의 3분기 성과는 어떨까? 결과는 처참했다. 연평균 -73.2%, 분기손익으로 환산하면 -28% 정도 된다. 동일가중 포트폴리오를 그대로 운용했을 때는 -40.16% 분기손익으로 환산하면 -12%의 결과를 얻을 수 있다. 과거의 우수한 샤프지수가 미래에도 통할 것이라는 가정이 완벽하게 박살난 것을 볼 수 있다.

    <동일비중 - 2021 3분기>

    Expected annual return : -40.16%

    Annual volatility : 16.79%

    Sharpe Ratio : -2.39

    <효율적투자선 max sharpe - 2021 3분기>

    OrderedDict([('삼성전자', 0.0), ('SK하이닉스', 0.0), ('현대모비스', 0.0), ('카카오', 1.0), ('LG전자', 0.0), ('현대차', 0.0), ('삼성SDI', 0.0), ('삼성전기', 0.0), ('NAVER', 0.0), ('기아', 0.0)])

    Expected annual return: -73.2%

    Annual volatility: 36.78%

    Sharpe Ratio: -1.99


    혹시 짧은 기간설정 때문일까? 시계열을 늘려서 한번만 더 검증해보자.

    모델구성(B_model)

    종목구성 : 2016년 ~ 2020년 5년 개인투자자 누적순매수 상위 10개 종목

    (셀트리온헬스케어, 카카오게임즈는 2016년 1월 이후 상장으로 제외, 카카오게임즈ㄷㄷㄷ)

    최적화 기간 : 2016년 ~ 2020년 5년

    최적화 방법 : 효율적투자선 max sharpe

    검증 기간 : 2021년 1~3분기

    검증 방법 : 최적화 비율로 2021년 1~3분기 투자

    소스코드(B_model)

    start = '20160104'
    end = '20201230'
    year = 5
    
    name_1 = ['삼성전자', '한국전력', '현대차', 'LG디스플레이', 'KT&G',
            '한국항공우주', '신한지주', 'SK', 'NAVER', '현대로템']
    code_1 =[]
    
    for x in name_1:
        code_1.append(code(x))
    
    weight_1 = np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) #변수명 변경 필요
    
    df = chart(name_1, code_1) #변수명 변경 필요
    
    title = 'Portfolio Close Price History'
    my_stocks = df
    plt.figure(figsize=(15, 10))
    
    for c in my_stocks.columns.values:
        plt.plot(my_stocks[c], label=c)
        
    plt.title(title)
    plt.xlabel('Date', fontsize=18)
    plt.ylabel('Close Price KRW', fontsize=18)
    plt.legend(my_stocks.columns.values, loc='upper left')
    plt.show()
    
    df_new = df.pct_change()
    cov = df_new.cov()*247
    # 최근 6년 평균 연간 거래일
    
    corrmat = df_new.corr()
    plt.figure(figsize=(10,10))
    cm = np.corrcoef(df.values.T)
    hm = sns.heatmap(cm, cmap='Blues', cbar=True, annot=True, square=True, fmt='.2f',
                     linewidths=0.01, xticklabels=df.columns, yticklabels=df.columns)
    plt.show()
    
    port_var = np.dot(weight_1.T, np.dot(cov, weight_1)) #변수명 변경 필요
    port_std = np.sqrt(port_var)
    port_SAR = (np.sum(ret(code_1) * weight_1)**(1/year))-1 #변수명 변경 필요
    
    per_var = str(round(port_var, 4) * 100) +'%'
    per_vols = str(round(port_std, 4) * 100) +'%'
    per_ret = str(round(port_SAR, 4) * 100) +'%'
    sr = str(round(port_SAR/port_std, 2))
    
    print('Expected annual return:'+ per_ret)
    print('Annual volatility:' + per_vols)
    print('Sharpe Ratio:' + sr)
    
    mu = expected_returns.mean_historical_return(df)
    S = risk_models.sample_cov(df)
    
    ef = EfficientFrontier(mu, S)
    weights = ef.max_sharpe()
    cleaned_weights = ef.clean_weights()
    print(cleaned_weights)
    ef.portfolio_performance(verbose=True)

    <동일비중 - 2016~2020 5년>

    Expected annual return : 4.03%

    Annual volatility : 18.55%

    Sharpe Ratio : 0.22

    <효율적투자선 max sharpe - 2016~2020 5년>

    OrderedDict([('삼성전자', 0.79635), ('한국전력', 0.0), ('현대차', 0.0), ('LG디스플레이', 0.0), ('KT&G', 0.0), ('한국항공우주', 0.0), ('신한지주', 0.0), ('SK', 0.0), ('NAVER', 0.20365), ('현대로템', 0.0)])

    Expected annual return: 26.4%

    Annual volatility: 24.1%

    Sharpe Ratio: 1.01

    삼성전자, 네이버 몰빵형 구성이 샤프지수가 최대화 되는 포트폴리오라고 한다. 그러면 이 최적화 포트의 2021년 3분기까지의 성과는 어떨까? 결과는 역시 별로였다. 연평균 수익률 -0.06%의 손실을 기록했다. 그에 반해 동일비중 포트폴리오는 15.3%의 수익을 기록했다. 역시 과거의 위험-수익 상관관계는 미래에도 반복됨을 보장하지 않는 것을 확인할 수 있었다.

    <동일비중 - 2021 1~3분기>

    Expected annual return : 15.34%

    Annual volatility : 17.59%

    Sharpe Ratio : 0.87

    <효율적투자선 max sharpe - 2021 1~3분기>

    OrderedDict([('삼성전자', 0.79635), ('한국전력', 0.0), ('현대차', 0.0), ('LG디스플레이', 0.0), ('KT&G', 0.0), ('한국항공우주', 0.0), ('신한지주', 0.0), ('SK', 0.0), ('NAVER', 0.20365), ('현대로템', 0.0)])

    Expected annual return: -0.06%

    Annual volatility: 20.94%

    Sharpe Ratio: -0.0

     

     

     

    텔레그램

    https://t.me/marathoninvest

     

    마라톤투자

    페이스를 유지하기 위한 최소한의 공부

    t.me

     

    네이버 블로그

    https://blog.naver.com/gurwjdz

     

    Marathon Investment : 네이버 블로그

    흔들리지 않는 것이 강한 것, 투자는 마라톤

    blog.naver.com

     

    티스토리

    https://inv42195.tistory.com/

     

    마라톤투자

    흔들리지 않는 것이 강한 것, 투자는 마라톤

    inv42195.tistory.com

     

Designed by Tistory.