자산배분

샤프지수를 활용한 최적의 포트폴리오 선택

unius 2022. 10. 23. 14:54
728x90
반응형

지난글에서 현재 내가 투자중인 애플, 마이크로소프, 엔비디아 3개 개별주식의 적정한 자산배분 비율에 관한 것을 알아보기 위해서 해리 마코위츠의 평균-분산 최적화[각주:1] 기법을 적용해보았다.

 

해리 마코위츠의 포트폴리오 최적화

나는 현재 미국시장의 개별주식과 나스닥3배 레버리지 ETF(TQQQ)에 투자하고 있다. 이글을 작성하는 시점에 TQQQ ETF의 수익률은 -40% 근처를 헤매고 있을 정도로 처참하다. 개별주식은 애플, 마이크

myportfolio.tistory.com

자산배분 비중에 따른 포트폴리오의 수익률과 변동성을 알아보기 위해서 몬테카를로 시뮬레이션을 통해 2만개의 포트폴리오 집합을 생성하고 시각화해서 주어진 리스크(변동성)에서 최대의 수익을 내는 포트폴리오 집합들을 이은 효율적 투자선(Efficient Frontier)을 설명하였다. 해리 마코위츠의 포트폴리오 선택 이론에 따르면 개별 리스크가 주어졌을 때 효율적 투자선보다 높은 수익률을 기대할 수는 없다. 그렇다면

효율적 투자선 위에 존재하는 무수히 많은 포트폴리오 집합중에서 리스크를 최소화하고 수익률은 최대화하는 포트폴리오를 어떻게 찾아낼 것인가?  


위와 같은 문제에 봉착하게 된다. 이를 해결하기 위한 여러가지 방법들이 있지만 이번 글에서는 마코위츠의 제자인 윌리엄 샤프가 창안한 샤프지수를 활용하는 방법을 알아본다. 먼저 아래의 수식을 보자

 

$\boldsymbol{Sharpe Ratio}= \frac{u_{p}-{r_{f}}}{\sigma_{p}}$

$u_{p}$ 포트폴리오 수익률

$r_{f}$ 무위험 이자율

$\sigma_{p}$ 포트폴리오 변동성

 

위 수식이 의미하는 바는 측정된 단위 위험당 무위험 초과 수익률을 의미한다. 즉, 우리는 샤프지수가 최대화 되는 포트폴리오를 선택하는 것은 좋은 선택일 수 있다. 또 다른 방법으로는 변동성이 최소가 되는 포트폴리오를 선택할 수도 있다. 아래 시뮬레이션에서는 무위험 이자율은 0으로 가정하여 진행한 결과이다

 

아래에서는 파이썬을 통해 효율적 투자선(Efficient), 파란색 별()로 표시한 샤프지수를 최대가 되도록 하는 포트폴리오 그리고 붉은색 별()로 표시한 변동성이 최소가 되는 포트폴리오를 시각화한 그래프와 최대 샤프지수 및 최소 변동성을 갖는 포트폴리오의 자산 비중을 출력하였다. 살펴볼 값은 최소 변동성 측면에서는 마이크로소프트의 비중이 높고 최대 샤프지수 측면에서는 애플의 비중이 높다는 점이다. 과거의 데이터를 기반으로 분석한 만큼 미래에도 적용된다고 보장할수는 없지만 수익성 측면에서는 애플과 엔비디아를 안정성 측면에서는 변동성이 큰 엔비디아는 비중을 적게하고 애플과 마이크로소프트의 비중을 높게 가져가야 한다는 결과는 이해할만 하다.

아래 소스코드는 포트폴리오의 목표수익률에 대해 변동성을 최소로 하는 효율적 투자선 위에 존재하는 포트폴리오 집합, 최대 샤프지수 그리고 최소 변동성을 갖는 포트폴리오 집합을 시각화 하는 코드이다. 

import scipy.optimize as sco

def ObjFunc(weights):
  return np.sqrt(np.dot(weights.T, np.dot(annual_cov, weights)))
 
 # 목표수익률 
rets = np.linspace(final_df['Returns'].min(), final_df['Returns'].max(), 100)
risks = []

assetCount = len(adj_df.columns)

# for문을 돌려 각 목표수익률에 맞는 포트폴리오 변동성을 계산
for ret in rets:

    # 투자 가중치 초기값 = 동일가중
    init_val = np.repeat(1/assetCount, assetCount)
    
    # 제약조건 (포트폴리오 목표 수익률, 현금 보유 비중 0)
    cons = ({'type': 'eq', 'fun': lambda w: np.dot(w, annual_ret) - ret},
            {'type': 'eq', 'fun': lambda w: np.sum(w) - 1})
    
    # 자산별 비중조건 (숏 포지션 불가능)
    bnd = tuple((0.0,1.0) for x in init_val)

    # 목표수익률 수준별 포트폴리오 최적화 수행
    risk = sco.minimize(ObjFunc, init_val, method='SLSQP', bounds=bnd, constraints=cons)

    # 최적화 알고리즘을 통해 찾아낸 최적 포트폴리오의 변동성 값을 리스트에 저장
    risks.append(risk['fun'])

# 포트폴리오 변동성 리스트를 배열로 변환
risks = np.array(risks)

# 좌측 경계선 데이터 수집, 가장 최소값을 갖는 데이터포인트의 위치를 반환
ind = np.argmin(risks)
erisks = risks[ind:]
erets = rets[ind:]

# 산포도를 이용해 시뮬레이션 결과 시각화
# x축: 포트폴리오 변동성
# y축: 포트폴리오 수익률
# 색깔: 포트폴리오 샤프비율
plt.figure(figsize=(10,8)) 
plt.scatter(x=final_df['Risk'], y=final_df['Returns'], c=final_df['Sharpe'], cmap='viridis', marker='o')
# 효율적 경계선 시각화
#plt.scatter(risks, rets, c=rets/risks, marker='x')
plt.plot(erisks, erets, 'r', lw=1.0)
# 최소분산, 최대샤프 포트폴리오 시각화
plt.scatter(x=max_sharpe['Risk'], y=max_sharpe['Returns'], c='b', marker='*', s=200)
plt.scatter(x=min_risk['Risk'], y=min_risk['Returns'], c='r', marker='*', s=200)
# x축 제목
plt.xlabel('Expected Volatility')
# y축 제목
plt.ylabel('Expected Returns')
# 그래프 타이틀
plt.title('Portfolio Simulation')
# 그래프 생성
plt.show()

print('max sharpe \n', max_sharpe)
print('min risk \n', min_risk)

 

 

  1. 1952년 발표한 '포트폴리오 선택(Portfolio Selection)'에서 포트폴리오의 예상 수익률과 리스크의 상관관계를 활용하여 포트폴리오를 최적화 하는 기법 [본문으로]
728x90
반응형