호돌찌의 AI 연구소
article thumbnail

 

Python이라는 도구를 활용해서 직전 글(아래 Reference) 막바지에 소개한 10 종목을 바탕으로 어떻게 포트폴리오를 구성하는지, 이렇게 구성했을 때 어떤 구조를 가지게 되는지 알아보고자 합니다. 

 

!pip install yfinance
!pip install PyPortfolioOpt
!pip install pulp

 

import datetime
import matplotlib.pyplot as plt
import pandas_datareader.data as web
import pandas as pd
from tqdm import tqdm
import numpy as np
import yfinance as yf

 

8월 초에 쓰고 자산배분 글을 바로 이어 썼어야 했는데 못본 사이에 종가가 꽤나 변화된 것을 알 수 있습니다. 엔비디아와 마이크로소프트는 청정구역을 연일 개척해나가고 있습니다.(저는 없어서 배가 아프네요!)

종목(티커) 종가 21.08.27 기준 상장일
마이크로소프트(MSFT) 299.72 1986.3.14
엔비디아(NVDA) 226.36 1999.1.22
애플(AAPL) 148.60 1981.8.7
페이스북(FB) 372.63 2012.5.18
테슬라(TSLA) 711.92 2010.7.2
아마존(AMZN) 3349.63 1997.5.16
메인 스트리트 캐피털(MAIN) 42.01 2007.10.5
제이피모건체이스(JPM) 163.05 1981.8.7
리얼티인컴(O) 71.55 1994.10.21
스타벅스(SBUX) 115.12 1992.6.26

 

위의 표에 있는 종목을 tickers로 지정하고 데이터를 yfinance를 이용해 불러와 줍니다. 주식에서 일봉 단위로 기준으로 할 때 보통 종가가 기준이 됩니다. 여기서 Adj Close는 종가가 아닌 수정 종가입니다. 수정 종가란 권리 제공이나 증자, 액면분할 등 해당 주식의 가치를 반영하기 위해 주식의 종가를 수정한 가격을 뜻합니다. 따라서 수정 종가를 데이터로 활용하셔야 합니다. 

 

tickers = [
           'MSFT','NVDA','O','AAPL','FB','TSLA','JPM','SBUX','MAIN','AMZN'
         ]

ohlc = yf.download(tickers,
                   start = '2013-01-01',
                   end = '2021-08-22') # 수정예정
                   
                   
prices = ohlc["Adj Close"].dropna(how="all")
prices.head()

 

 

페이스북이 위에서 제시한 종목들 중 제일 늦게 상장하였기 때문에 2013년 1월 2일부터 종목을 살펴보겠습니다. 

Row는 날짜, Columns는 개별종목입니다. 

 

df = prices[prices.index >= "2013-01-01"]
df

 

시기에 따른 수정주가 그래프를 한번 확인해 보겠습니다. 

 

title = 'Portfolio Adj. Close Price History    '

my_stocks = df
plt.figure(figsize=(12.2,4.5)) # width = 12.2in, height = 4.5

for c in my_stocks.columns.values:
  plt.plot( my_stocks[c],  label=c) #plt.plot( X-Axis , Y-Axis, line_width, alpha_for_blending,  label)
plt.title(title)
plt.xlabel('Date',fontsize=18)
plt.ylabel('Adj. Price USD ($)',fontsize=18)
plt.legend(my_stocks.columns.values, loc='upper left')
plt.show()

 

 

(아마존과 테슬라 덩치가 큰 것을 확인할 수 있습니다. 테슬라는 작년 여름에 분할을 했었는데 아마존은 정말 서운하다 싶을 정도로 분할을 하질않네요!)

 

이제는 전략 하나를 구성할 예정인데 정말 단순하게 제시한 종목들이 총 10개이기 때문에 비중을 10%씩 종목을 보유하는 것입니다. 따라서 0.1씩 weights를 부여하겠습니다. 

 

weights = np.array([0.1, 0.1, 0.1, 0.1, 0.1,0.1, 0.1, 0.1, 0.1, 0.1])

 

그다음 pandas에서 pct_change() 함수를 이용해보겠습니다. 함수를 적용하면 일별 주가상승률을 나타낼 수 있습니다. 

공식은 (당일 종가/전일 종가 -1)이라고 생각하면 됩니다. 

 

returns = df.pct_change()
returns

 

이 일별 주가상승률의 공분산 행렬을 산출하고 252(평균 1년 영업일 수)를 곱하면 1년 단위의 수익률 공분산 행렬을 산출할 수 있습니다. 

 

cov_matrix_annual = returns.cov() * 252
cov_matrix_annual

이 공분산 행렬 앞뒤로 weight를 곱하면 포트폴리오 분산 기댓값이 나타납니다. 공식은 다음과 같습니다. 

Expected portfolio variance = W^t * (cov_matrix_annual) * W 

 

port_variance = np.dot(weights.T, np.dot(cov_matrix_annual, weights))
port_variance

 

0.045150259125422865 값을 얻을 수 있습니다. 여기 분산 기댓값에 square root를 적용하면 포트폴리오 변동성의 기댓값이 나타납니다. 공분산 행렬을 연 단위가 아닌 월 단위로 계산하여 변동성을 계산을 할 수 있습니다. 만약에 적용한다면 표준편차 값이 상당히 커질 것 같네요. 해석은 이 값(변동성)이 낮다는 뜻은 안정적이라고 표현이 가능합니다. 공식은 다음과 같습니다.

port_volatility = np.sqrt(port_variance)
port_volatility

 

0.21248590335695888 값을 얻을 수 있습니다.

 

위에서의 일별 주가상승률 행렬의 평균weights(동일비중)을 가중 평균하여 영업일을 곱하면 포트폴리오 연간 단순 수익률을 계산이 가능합니다. 

 

portfolioSimpleAnnualReturn = np.sum(returns.mean()*weights) * 252

 

percent_var = str(round(port_variance, 4) * 100) + '%'
percent_vols = str(round(port_volatility, 4) * 100) + '%'
percent_ret = str(round(portfolioSimpleAnnualReturn, 4)*100)+'%'
print("Expected annual return : "+ percent_ret)
print('Annual volatility/standard deviation/risk : '+percent_vols)
print('Annual variance : '+percent_var)

 

연 평균 단순 기대수익률 33%, 리스크 21% 임을 알 수 있습니다. risk가 제 개인적으로는 상당히 크다고 생각이 됩니다만 2013년부터 리밸런싱 없이 이대로 들고 있었다면 33% 연 수익률을 기대해볼 수 있었다는 뜻입니다. 33%면 10년 복리로 굴렸을 때 자산이 17.3배 정도 불어납니다. (역시 손투자는 미국 기술주와 배당주 입니다!)

 

이전에 Sharpe Ratio와 같은 포트폴리오 평가지표에 대해 알아보았습니다. Sharpe Ratio수익률/표준편차이기 때문에 아래처럼 간편히 계산할 수 있습니다.  

 

round(portfolioSimpleAnnualReturn/port_volatility,2)

 

Sharpe Ratio1.56이 계산됩니다. 장기 투자에서 1이 넘으면 정말 좋은 포트폴리오라고 이야기를 했었습니다. 저에게는 8~10년이 장기투자라고 생각을 하지만 다른 사람들은 20년, 30년이 장기투자라고 생각할 수 있기 때문에 의견이 분분해질 수 있습니다. 하지만 기술주 위주의 포트폴리오가 확실히 강한 것은 확실한 것 같습니다. 

 

제 생각을 정리해보겠습니다. 유튜브나 뉴스를 보면 댓글창에 미국의 기술주 성장세는 엄청나고 더 오를 여지가 있다, 계속 오른다, 인류가 멸망할 때까지 오를 것이다 진영과 말도 안 되는 거품이다 이렇게 싸우고 있는 진영이 여전히 존재합니다. 위 종목 10개를 실제로 7~8년 계속 들고 있다는 것은 너무나 힘든 일입니다. 그리고 이러한 수익률이 과거부터 현재까지는 뛰어났지만 미래를 보장하지는 않습니다. 그래도 투자를 안 하는 것보다는 위험 대응을 충분히 해두면서 시장에 어느 정도는 참여를 하고 있는 것이 맞다고 개인적으로 생각합니다. 

 

충분히 동일 비중으로 우리가 들어본 듯한 회사들을 구성하여 기술주, 은행주, 배당주 10개만 적당히 굴려도 이와 같은 결과를 얻었습니다. 하지만 다음 시간에는 비중을 최적화해서 접근하는 방식, 즉 수익률을 올리고 리스크를 줄이는 방법에 대해 이야기해보겠습니다. 또한 이러한 방식의 문제점과 체계적 위험과 비체계적 위험에 대해서도 추가로 논의해보겠습니다. 

 

<Reference>

https://randerson112358.medium.com/python-for-finance-portfolio-optimization-66882498847

 

Python For Finance Portfolio Optimization

Portfolio optimization is the process of selecting the best portfolio (asset distribution),out of the set of all portfolios being…

randerson112358.medium.com

https://hotorch.tistory.com/53

 

자산 배분 포트폴리오 - 3. 포트폴리오 성과 지표

포트폴리오 구성의 컨셉은 아이디어만 많다면 다양한 방법으로 포트폴리오를 짤 수 있습니다. 또한 공격적 성향, 안정적 성향 등 본인 성향에 따라 구성을 할 수 있습니다. 컨셉기준으로 성장주

hotorch.tistory.com

 

profile

호돌찌의 AI 연구소

@hotorch's AI Labs

포스팅이 도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!