지금까지 기초자산과 커버드콜의 수익률을 비교 분석해 보았습니다. 기초자산과 커버드콜은 수익률 경향이 매우 비슷한 자산이기에 수익률 위주의 비교로도 투자 판단을 내리는데 크게 무리가 없지만, 투자자는 좀 더 신중하게 위험까지 고려하고 싶을 수 있습니다. 이 글에서는 위험을 어떻게 추정해서 표현할 수 있는지 살펴봅니다.
위험이 무엇인지는 투자자마다 다를 수 있습니다. 어떤 투자자는 1년 후 자녀의 대학 등록금에 사용할 자금을 조금 더 불리기 위해 투자하고 있을 수 있습니다. 그렇다면 1년 후 -10% 이상 손실이 발생하는 경우가 위험일 수 있습니다. 만일 1년 이내에 -10% 이상의 손실이 발생하면, 바로 투자를 중단하고 모두 회수하겠다는 전략을 세웠다면, 손실률은 동일하게 -10%를 사용하지만, 위험의 정의가 다릅니다.
또 다른 투자자는 은퇴 후 사용하기 위해 20년간 적립식으로 시장 지수를 추종하는 주식형 ETF에 투자할 수 있습니다. 20년 후 목표 금액에 미달하는 경우가 위험일 수도 있고, 제1금융권 예금 이율의 2배로 이하로 연평균 복리 수익률을 거두는 것이 위험일 수도 있습니다.
투자자마다 투자 목표가 다릅니다. 이 때문에 투자자는 투자 성과 분석 방법을 공부해서 각자의 투자 목표에 맞춰 분석할 수 있도록 합니다. 제가 구글 시트로 투자 성과를 분석하는 방법을 연재하고 책으로도 펴낸 주된 이유이며, 파이썬 연재를 진행하는 이유도 여기에 있습니다.
참고: 이 글과 전후 몇 편의 글은 기초자산과 커버드콜을 사례로 파이썬을 활용하여 자산의 성과를 비교 분석하는 방법을 소개합니다. 제 책과 글을 통해 여러 차례 상세하게 설명했지만, 커버드콜은 장기 투자자에게 투자 가치가 없다는 결론이 나오게 됩니다. 커버드콜도 투자자에 따라서는 투자할 가치가 있다고 반론하는 댓글에는 답변하지 않습니다. 대개는 데이터를 어떻게 분석했고, 분석 결과의 의미가 무엇인지 충분히 이해하지 못했기에 나오는 의문이거나, 데이터 분석의 전제를 고려하지 않은 지적이기 때문입니다.
주의: 이 글은 특정 상품 또는 특정 전략에 대한 추천의 의도가 없습니다. 이 글에서 제시하는 수치는 과거에 그랬다는 기록이지, 앞으로도 그럴 거라는 예상이 아닙니다. 분석 대상, 기간, 방법에 따라 전혀 다른 결과가 나올 수 있습니다. 데이터 수집, 가공, 해석 단계에서 의도하지 않은 오류가 있을 수 있습니다. 일부 설명은 편의상 현재형으로 기술하지만, 데이터 분석에 대한 설명은 모두 과거형으로 이해해야 합니다.
투자 기간에 따른 위험의 변화
투자자마다 다를 수 있는 위험을 한 가지 위험 지표로 설명하는 것은 불가능합니다. 표준 편차, MDD(Maximum Drawdown; 최대 손실률), CVaR(Conditional Value-at-Risk)과 같은 일반화된 지표가 있기는 하지만, 투자자는 이를 참고하여 본인에게 맞춰 해석하거나, 경우에 따라서 적합한 위험 지표를 만들어서 사용해야 할 수 있습니다.
이 글에서는 두 가지 위험 지표를 살펴봅니다. 하나는 하위 k% 순위 수익률을 살펴보는 것이고, 다른 하나는 CVaR입니다. 하위 k% 순위 수익률은 제가 자주 사용하는 위험 지표이고, CVaR은 좀 더 일반화된 위험 지표라 할 수 있습니다.
MDD의 경우에는 참고 용도로는 괜찮지만, 위험이 과대 평가되는 경향이 있기에 제 경우에는 주된 위험 지표로 사용하지는 않습니다. 장기 투자자라면 MDD 대신 하위 k% 순위 수익률이나 CVaR을 사용하는 것도 괜찮다고 생각합니다.
다음은 기초자산과 커버드콜에 대해 1개월 단위로 투자 기간을 늘려가며 투자했을 때, 평균과 하위 10% 순위 수익률을 구해 그래프로 그리는 코드입니다.
mean_d = {}
low_d = {}
MAX_YEARS = 5
LOW_AT = 0.1
for m in range(1, MAX_YEARS * 12 + 1):
mdf = df.pct_change(m * 21).dropna()
mean = mdf.mean()
low = mdf.quantile(LOW_AT)
mean_d[m] = mean
low_d[m] = low
mean_df = pd.DataFrame(mean_d).T
low_df = pd.DataFrame(low_d).T
mean_df.columns = df.columns
low_df.columns = df.columns + f' (Low rank {LOW_AT * 100:.0f}%)'
ax = mean_df.plot()
plt.gca().set_prop_cycle(None)
low_df.plot(ls = ':', ax = ax)
plt.gca().yaxis.set_major_formatter(PercentFormatter(xmax = 1, decimals = 0))
years = np.arange(1, MAX_YEARS + 1)
plt.xticks(years * 12, years)
plt.show()
코드의 주요 부분을 설명합니다. 앞에서 설명했던 부분은 추가로 해설하지 않습니다. 이 연재는 가능하면 처음부터 차근차근 직접 실행해 가며 읽기를 권합니다. 어렵다고 느끼는 경우의 상당수는 실제 어렵기 때문이 아닙니다. 순서대로 차근차근 하나씩 직접 해보면서 공부하지 않았기 때문에 어렵다고 생각하는 경우가 대부분입니다.
mean_df.columns = df.columns
low_df.columns = df.columns + f' (Low rank {LOW_AT * 100:.0f}%)'
평균 수익률을 담은 mean_df DataFrame의 칼럼명을 기초 데이터와 동일하게 맞췄습니다. 하위 10% 순위 수익률을 담은 low_df DataFrame의 칼럼명에는 ' (Low 10%)'를 덧붙였습니다.
ax = mean_df.plot()
plt.gca().set_prop_cycle(None)
low_df.plot(ls = ':', ax = ax)
평균 수익률로 선그래프를 그립니다. 이어서 하위 10% 순위 수익률로도 선그래프를 그립니다. DataFrame으로 그래프를 그리면, 앞서 그려진 그래프 위에 추가되는 것이 아니라 새로운 그래프가 만들어집니다.
이미 만들어져 있는 그래프에 추가로 그리고자 하는 경우에는 ax(Axes)를 지정합니다. 첫 번째 plot()의 실행 결과로 ax가 나옵니다. 두 번째 그래프를 그릴 때 이 ax를 인자로 넘겨 그리면 됩니다.
파이썬은 그래프를 그릴 때, 색상 팔레트의 색을 순서대로 사용합니다. mean_df로 2개의 선을 그렸기에 색상 2개를 사용했습니다. low_df로도 2개의 선을 더 그릴 것이니 이후 색상 2개를 사용할 것입니다.
동일한 자산에 대해서는 같은 색상으로 표시하면 이해하기 쉽습니다. plt.gca().set_prop_cycle(None)는 팔레트를 처음부터 사용하도록 재설정합니다. 동일한 형태의 선으로 그리면 구분이 어려우니 점선으로 바꾸었습니다.
앞서 기초자산과 커버드콜 분석에서 어느 정도 짐작했을 법한 결과가 나옵니다. 투자 기간이 길어질수록 기초자산과 커버드콜의 누적 수익률의 차이가 커집니다. 참고: 이 그래프는 로그 스케일로 그리는 게 적절합니다.
하위 10% 순위 수익률을 보면, 1년 이내에는 거의 차이가 없었지만, 투자 기간이 길어질수록 그 차이가 점차 커지고 있습니다. 눈여겨보아야 하는 부분은 4년 ~ 5년에 해당되는 기간입니다. 기초자산의 하위 순위 10% 수익률이 커버드콜의 평균 수익률과 만납니다.
무슨 의미일까요? 5년간 커버드콜에 투자해서 얻었던 평균 수익률은 같은 기간 기초자산에 투자해서 얻는 하위 10% 순위 수익률에 해당했다는 뜻입니다. 다르게 말하면 5년 정도 투자하면 커버드콜의 평균 위험이 기초자산의 하위 10% 순위에 해당된다고 볼 수 있습니다.
충분히 오래 투자하면 커버드콜이 더 위험한 상품이었다는 의미입니다.
CVaR, VaR 위험 지표
제 경우에는 하위 k% 순위 수익률로 위험을 주로 분석하지만, 투자 성과 분석에 널리 사용하는 주요 위험 지표로 CVaR이 있습니다. CVaR 지표의 정의를 보면 적분이 포함된 수식으로 정의되어 있어 뭔가 복잡해 보입니다. 사실 개념은 간단합니다. 하위 k% 이하 순위 수익률의 평균입니다.
왜 이렇게 복잡하게 정의가 되어 있냐면, 일반화된 수익률 모델을 사용하기 때문입니다. 예를 들어 보겠습니다. 슈퍼 전자라는 새로운 기업이 상장되었습니다. 회사채를 발행했습니다. 1년이 지났습니다. 아직까지 부도가 난 적이 없습니다. 부도 위험은 얼마일까요? 부도 위험을 추정해야 채권 매니저는 투자 결정을 할 수 있습니다.
단순히 과거 데이터로만 추정하면 부도 위험은 0%입니다. 부도가 난 적이 없기 때문입니다. 합리적인 추정일까요? 채권 매니저가 슈퍼 전자의 부도 위험이 0%라고 믿고, 포트폴리오에 편입해도 괜찮을까요?
당연히 아닙니다. 과거 데이터만으로는 현실적인 수준의 정확도로 부도 위험을 추정할 수 없습니다. 현재 거래되고 있는 대부분의 회사채는 부도가 난 적이 없었을 것이기 때문입니다. 이런 경우 사용하는 복잡한 모델이 있습니다. 그 최종 결과가 신용평가회사가 매기는 회사채 등급입니다.
슈퍼 전자의 회사채 등급이 BBB라고 하겠습니다. 이제 채권 매니저는 BBB 등급 회사채의 평균 부도율을 고려하면 슈퍼 전자 회사채를 포트폴리오에 편입할지 여부를 결정할 수 있습니다. 편입한다면 어느 정도 비중을 둘 지도 판단할 수 있을 것입니다.
CVaR 지표의 정의가 복잡해 보이는 이유도 이 때문입니다. 과거 데이터에 대한 하위 k% 이하 순위 수익률의 평균이 아니라, 추정한 수익률 모델에서 하위 k% 이하 순위 수익률의 평균을 말하기 때문입니다. 수익률 모델을 추정할 때 과거 데이터를 고려할 수 있지만, 모델의 전부는 아닙니다. 이 때문에 일반화하여 적분 형태로 표현하는 것입니다.
그런데 가만히 보면 비슷한 계산을 이미 한 적이 있습니다. 주어진 투자 기간에 대해 하위 k% 순위 수익률을 찾아 그래프로 그렸습니다. VaR(Value-at-Risk) 지표입니다. VaR이라는 이름 대신 하위 k% 순위 수익률로 소개하는 것은 어떤 지표인지 이해가 쉽기도 하지만, 수익률 모델을 따로 만들지 않았기 때문입니다.
기초자산과 커버드콜의 CVaR
기초자산과 커버드콜로 CVaR을 구해 그래프로 그려봅니다. 저희는 수익률 모델을 만들 수 없지만, 과거 데이터가 10년치 정도 있으니 이를 수익률 모델이라 간주하고 계산합니다.
mean_d = {}
low_d = {}
cvar_d = {}
MAX_YEARS = 5
LOW_AT = 0.05
for m in range(1, MAX_YEARS * 12 + 1):
mdf = df.pct_change(m * 21).dropna()
mean = mdf.mean()
low = mdf.quantile(LOW_AT)
cvar = mdf[mdf <= low].mean()
mean_d[m] = mean + 1
low_d[m] = low + 1
cvar_d[m] = cvar + 1
mean_df = pd.DataFrame(mean_d).T
low_df = pd.DataFrame(low_d).T
cvar_df = pd.DataFrame(cvar_d).T
mean_df.columns = df.columns
low_df.columns = df.columns + f' (Low rank {LOW_AT * 100:.0f}%)'
cvar_df.columns = df.columns + f' (CVaR {(1 - LOW_AT) * 100:.0f}%)'
ax = mean_df.plot()
plt.gca().set_prop_cycle(None)
low_df.plot(ls = ':', ax = ax)
plt.gca().set_prop_cycle(None)
cvar_df.plot(ls = '--', ax = ax)
plt.gca().yaxis.set_major_formatter(PercentFormatter(xmax = 1, decimals = 0))
years = np.arange(1, MAX_YEARS + 1)
plt.xticks(years * 12, years)
plt.yscale('log', base = 1.1)
yticks = np.array([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
plt.yticks(ticks = yticks + 1,
labels = [f'{round(tick * 100)}%' for tick in yticks])
plt.show()
앞서 코드와 거의 동일합니다. 달라진 부분 위주로 설명합니다.
LOW_AT = 0.05
하위 5%를 위험 기준으로 삼았습니다.
cvar = mdf[mdf <= low].mean()
low는 하위 5% 순위에 해당되는 수익률입니다. low 이하의 수익률에 대해 평균을 취하면 CVaR이 됩니다.
이후 코드는 수익률 대신 자산비로 DataFrame을 만들고 로그 스케일로 그래프를 그렸습니다. 다음과 같은 결과가 나옵니다.
세로축이 로그 스케일이기에, 평균 수익률은 직선에 가깝게 표현되었습니다. 하위 5% 순위 수익률(VaR 95%)을 보면 투자 기간이 길어질수록 기초자산이 커버드콜보다 더 많이 값이 커집니다. 다르게 말하면 투자 기간이 길어질수록 상대적으로 커버드콜이 더 위험했다는 의미입니다.
CVaR 95%는 하위 5% 수익률의 평균이므로 VaR 95%보다 항상 작은 값입니다. 기초자산과 커버드콜의 CVaR 95%도 VaR 95%와 동일한 양상을 보이고 있습니다. 투자 기간이 길어지면, 커버드콜의 위험이 상대적으로 더 높았습니다.
연평균 복리 수익률로 살펴본 VaR과 CVaR
투자 기간이 길어지면 상대적으로 위험이 더 높다는 의미는 격차가 더 벌어지면서 확고해진다는 의미입니다. 다음은 연평균 복리 수익률로 환산해서 그래프를 그리는 코드입니다.
powers = 1 / (mean_df.index.to_numpy() / 12)
ax = mean_df.pow(powers, axis = 0).plot()
plt.gca().set_prop_cycle(None)
low_df.pow(powers, axis = 0).plot(ls = ':', ax = ax)
plt.gca().set_prop_cycle(None)
cvar_df.pow(powers, axis = 0).plot(ls = '--', ax = ax)
plt.gca().yaxis.set_major_formatter(PercentFormatter(xmax = 1, decimals = 0))
years = np.arange(1, MAX_YEARS + 1)
plt.xticks(years * 12, years)
plt.yscale('log', base = 1.1)
yticks = np.arange(-0.1, 0.2, 0.02)
plt.yticks(ticks = yticks + 1,
labels = [f'{round(tick * 100)}%' for tick in yticks])
plt.xlim(12)
plt.ylim(0.9, 1.14)
plt.show()
powers = 1 / (mean_df.index.to_numpy() / 12)
투자 개월수에 따라 연평균 복리 수익률로 환산할 지수승을 구합니다.
ax = mean_df.pow(powers, axis = 0).plot()
연평균 복리 수익률로 환산해서 그래프를 그립니다.
상단에 있는 연평균 복리 수익률은 기초자산의 경우 13% 내외, 커버드콜은 10% 초반대로 안정적입니다. 장기 투자에서는 투자 기간이 길어질수록 이 평균 수익률(수익률 분포에 따라서는 중앙값이 좀 더 적절할 수 있습니다)을 향해 모든 연평균 수익률(여기서는 VaR과 CVaR)이 수렴하는 현상이 관찰됩니다. 참고: 투자 기간이 길어질수록 위험이 줄어드는 이 현상이 장기 투자를 해야 하는 근본적인 이유입니다. 이에 대해서는 참고 도서에 자세히 설명되어 있습니다.
VaR과 CVaR은 각각 해당 자산의 평균 수익률로 수렴하기에 투자 기간이 충분히 길어지면 두 자산 사이의 간격은 일정 수준을 유지하는 안정적인 상태가 될 수 있습니다. 그 차이는 기초자산과 커버드콜의 평균 수익률 차이 정도가 될 것입니다.
정리하며
기초자산과 커버드콜 지수의 위험을 그래프로 표현하고 해석하는 방법을 살펴보았습니다. 투자자마다 각자에게 맞는 위험 지표는 다를 수 있습니다. 이 글에서는 일반적으로 많이 사용하는 하위 k% 순위 수익률(VaR)과 CVaR로 살펴보았습니다.
기초자산과 커버드콜의 위험은 투자 기간이 길어질수록 감소하는 현상이 발생했습니다. 이는 장기적으로 안정적인 성장률을 거두는 자산에서 나타나는 일반적인 특성입니다. 하지만 기초자산과 커버드콜은 그 구조상 일정 이상의 평균 수익률 격차가 발생하게 됩니다. 그리고 그 차이는 위험을 표시하는 VaR, CVaR에도 나타나게 됩니다.
이어지는 글에서는 기초자산과 커버드콜 수익률의 관계 안정성에 대해 살펴봅니다.
참고: 연재와 관련한 질문은 댓글로 남겨주시기 바랍니다. 답변을 드리거나 이후 연재에서 다룰 수 있도록 노력하겠습니다.
참고 서적: 왜 위험한 주식에 투자하라는 걸까? - 장기 투자와 분산 투자에 대한 통계학적 시각
이어지는 글: [파이썬 분석 19] 관계의 안정성을 살펴보자 (상관 계수 변화를 통한 관찰)
연재 목록: 자산 배분 분석 방법 책 소개, 연재글 및 사례 모음 [목록]
함께 읽으면 좋은 글 (최신 글)
- [파이썬 분석 17] 투자 분석은 왜 통계적으로 접근해야 하나? (기초자산과 커버드콜의 경우)
- [파이썬 분석 16] 기초자산과 커버드콜 (기초자산 수익률에 따른 커버드콜 수익률 분포, +구글 드라이브 이용)
- [파이썬 분석 15] 기초자산과 커버드콜 (지수 개발사의 기초자산과 커버드콜 지수 + 외부 파일 읽기)
- [파이썬 분석 14] 기초자산과 커버드콜 - 두 자산의 성과를 비교해 보자 (TIGER 미국배당다우존스와 TIGER 미국배당다우존스타겟커버드콜2호)
- [파이썬 분석 13] 시간이 흐름에 따른 주가의 변화는 표현해 보자 (이동평균, 하위 순위 주가, +rolling())
함께 읽으면 좋은 글 (인기 글)
'주식투자' 카테고리의 다른 글
[파이썬 분석 22] 고정 금액 인출식 성과를 인플레이션을 고려해서 추정해 보자 (1) | 2025.04.25 |
---|---|
[파이썬 분석 21] 적립식 성과를 인플레이션을 고려해서 추정해 보자 (0) | 2025.04.24 |
[파이썬 분석 20] 인플레이션을 고려해 보자 (한국은행 소비자물가지수 데이터 사용) (0) | 2025.04.24 |
[파이썬 분석 19] 관계의 안정성을 살펴보자 (상관 계수 변화를 통한 관찰) (0) | 2025.04.23 |
[파이썬 분석 17] 투자 분석은 왜 통계적으로 접근해야 하나? (기초자산과 커버드콜의 경우) (0) | 2025.04.21 |
[파이썬 분석 16] 기초자산과 커버드콜 (기초자산 수익률에 따른 커버드콜 수익률 분포, +구글 드라이브 이용) (0) | 2025.04.20 |
[파이썬 분석 15] 기초자산과 커버드콜 (지수 개발사의 기초자산과 커버드콜 지수 + 외부 파일 읽기) (0) | 2025.04.20 |
[파이썬 분석 14] 기초자산과 커버드콜 - 두 자산의 성과를 비교해 보자 (TIGER 미국배당다우존스와 TIGER 미국배당다우존스타겟커버드콜2호) (0) | 2025.04.19 |