시장을 이기는 방법-(2)

팩터 투자와 포트폴리오

2026.01.04 | 조회 346 |
0
|
PRAESENTIA의 프로필 이미지

PRAESENTIA

투자, 퀀트, AI에 관한 기록

(지난 편을 먼저 읽고 오시는 걸 추천드립니다)

https://maily.so/praesentia/posts/x1zgwg53oqg

 

첨부 이미지

 

지난 글에서는 팩터 투자와 알파&베타에 대해 이야기를 했습니다. 간단히 요약하자면, 시장의 초과수익은 규칙성이 없고 랜덤에 가까워 보였지만, 계량적으로 분석해본 결과 '팩터(설명 가능한 수익 요인)'가 존재함을 밝혀냈다는 내용이었습니다. 대표적인 팩터로는 사이즈 팩터, 밸류 팩터 등이 있으며, 일반적으로 시가총액이 작고 저평가된 종목들이 초과수익을 거둔다고 볼 수 있습니다.

 

이번 편에서는 시장을 이기는 두 번째 방법, '포트폴리오'에 관한 내용을 다루고자 합니다. 팩터 투자보다 역사가 오래된 연구 분야이자, 어떤 면에서는 일반 대중들이 참고하기에 훨씬 유용한 내용이 아닐까 싶습니다. 본문 중간중간에 수식들이 제법 등장할 텐데, 모든 수식을 다 이해할 필요는 없고 이런 의미구나 하며 큰 흐름을 따라오시는 걸 추천드립니다.

 


1. 다양한 성과 측정 지표

본격적인 포트폴리오 이론에 들어가기 앞서, 몇 가지 성과 측정 지표에 대해 소개를 하고자 합니다. 포트폴리오의 중요성을 제대로 이해하기 위해서 필요한 과정이라 차근차근 짚어보겠습니다.

 

1-1. 변동성(Volatility)

첨부 이미지

여기 두 종목의 주식이 있습니다. A 종목의 경우 3년 동안 일관된 수익률을 기록한 반면, B 종목의 경우 21년과 23년 수익률은 A보다 좋았지만 22년도 수익률이 다소 아쉬운 모습입니다. 3년 누적 수익률로 봤을 때 둘의 성과는 동일합니다. 이때 둘 중 어느 종목의 투자 매력도가 높을까요?

 

많은 투자자들이 수익률을 중요시 여깁니다. 물론 수익률은 중요한 성과 지표 중 하나입니다만, 결과론적 지표라는 점에서 한계를 갖습니다. 해당 성과에 도달하기까지의 과정(리스크)은 대변하지 못한다는 것이죠.

 

위의 두 종목도 그런 점에서 수익률 만으로 비교하기에는 한계를 갖습니다. 둘의 차이를 제대로 알기 위해서는 '변동성(Volatility)'이라는 개념이 필요합니다. 주가가 얼마나 위아래로 진폭을 보이며 움직였는지를 측정하는 값입니다. 보통 일자별 종가 데이터의 표준편차(std)를 계산해서 활용합니다.

 

변동성이 높은 종목일수록 투자 매력도는 떨어집니다. 변동성이 높다는 건 크게 상승한 적도 많지만, 그만큼 크게 하락한 구간도 많다는 뜻입니다. 그런 종목은 진입 타이밍을 재는 것도 쉽지 않고, 하락했을 때 손절/익절 여부를 판단하는 것도 매우 어렵습니다. 때문에 같은 수익률이라면 낮은 변동성의 자산군이 더 매력적이라 말할 수 있겠습니다. 

 

그런 관점에서 위 두 종목 중에서는 A가 더 매력적인 주식입니다. B와는 달리 변동성이 거의 없이 꾸준한 우상향을 보였기 때문입니다.

 

 

1-2. 샤프 비율(Sharpe Ratio, SR)

이제 우리는 두 가지 주요 지표를 알고 있습니다. 수익률과 변동성. 이쯤되면 많은 연구자들은 이런 충동을 느낍니다. '두 지표를 하나로 합칠 수 없을까?'. 이런 배경으로 만들어진 지표가 바로 '샤프 비율'입니다. 

 

샤프 비율의 수식은 간단합니다. "수익률 / 변동성"입니다. 물론 실제 수식에서는 무위험 수익률을 뺀다거나, 기간에 비례하여 곱해주는 상수값이 있지만, 핵심은 수익률을 변동성으로 나눈 지표입니다. 즉 샤프 비율이 높은 자산일수록 수익이 좋고 변동성은 낮다는 의미이며, 그만큼 매력적인 자산이라는 뜻입니다. 여러 헤지펀드나 투자 직무에서 수익률 이상으로 중요시 여기는 지표가 바로 이 샤프 비율입니다.

 

첨부 이미지

예시를 들기 위해, 한국인이 사랑하는 대표 ETF 3종을 들고 왔습니다. QQQ(진한 파란색), QLD(노란색), TQQQ(하늘색)입니다. QQQ는 나스닥 지수를 추종하는 미국 기술주 대표 ETF입니다. QLD와 TQQQ는 QQQ의 레버리지 상품들입니다. QQQ가 1% 오르면 QLD는 2%, TQQQ는 3% 상승하는 대신, 반대로 QQQ가 1% 하락하면 각각 2배, 3배씩 하락하는 구조입니다. 

 

많은 분들이 단기에 큰 성과를 거두기 위해 QLD나 TQQQ와 같은 레버리지 상품을 큰 비중으로 투자하시곤 합니다. 물론 시장 상황에 맞게 적절한 레버리지 ETF를 매매하는 것은 하나의 전략이 될 수 있겠습니다만, 장기적으로는 좋은 판단이라 보기 어렵습니다. 위의 차트를 보면 TQQQ의 수익률이 제일 좋아 보이지만, 최근 10년치 샤프 비율을 놓고 보면 이야기가 달라집니다. 

 

최근 10년 평균 Sharpe Ratio 순위: QQQ(0.92) > QLD(0.84) > TQQQ(0.82)

 

이처럼 샤프 비율은 수익률만으로는 판단하기 어려웠던 리스크에 관한 부분까지 함께 고려하는 종합 지표라고 볼 수 있습니다. 

 

 

1-3. 최대 낙폭(Max Draw Down, MDD)

첨부 이미지

최대 낙폭(MDD)이란 전고점 대비 몇 퍼센트까지 떨어졌는지를 측정한 값입니다. 쉽게 말해 최악의 손실 구간이라 생각하면 되는데, 만약 MDD가 -50%라면 최고점에서 반토막까지 나본 적 있다는 뜻입니다. 해당 지표를 통해 우리는 감수해야 할 최대한의 리스크 크기를 짐작해볼 수 있습니다.

 

위의 차트를 보면 세 종류 ETF의 2011~2022년 MDD가 기록되어 있습니다. TQQQ(파랑), QQQ(빨강), SPY(노랑)입니다. 약 10년이라는 기간 동안 SPY는 최대 22%까지 하락해본 적 있고, QQQ는 32%, TQQQ는 80%를 기록했습니다. 달리 말하면, TQQQ를 단순 보유하고 있었을 경우 2022년 5분의 1토막이 났다는 뜻입니다. 

 

이처럼 변동성 외에도 리스크 관리 측면에서 많은 자산운용사들이 MDD를 체크하곤 합니다. 특정 자산이나 전략의 최대 낙폭을 인지하고 있어야 그것이 현실적으로 보유할 만한 자산인지, 그리고 보유한다면 리스크 관리 전략을 어떻게 구성할 것인지 확립할 수 있기 때문입니다.

 

 

이밖에도 운용사 및 증권사에서 확인하는 지표들은 다양하게 있습니다. Calmar Ratio, VaR, CVaR, Win rate, Turnover 등등. 물론 이것들도 전부 공부하고 확인하면 도움이 되겠지만, 이제 막 투자에 입문하는 단계에서 이 모든 것들을 고려하기란 어려운 일입니다. 우선은 수익률, 변동성, 샤프 비율, MDD를 기본으로 삼으시고, 차후에 본인 전략에 맞춰 지표를 추가해가는 걸 권장드립니다.

 


2. 포트폴리오 최적화

포트폴리오 이론의 출발점은 굉장히 단순했습니다. '수익률과 변동성이 서로 다른 두 개의 자산을 몇 대 몇으로 섞어야 이상적일까?'. 저희도 같은 질문에서 출발해보겠습니다.

 

여기 두 종목의 주식이 있습니다. A 주식은 기대수익률 8%, 변동성 17%이고, B 주식은 기대수익률 6%, 변동성은 13%입니다. 두 종목의 상관계수(Correlation)이 0.5라고 했을 때, 이상적인 포트폴리오를 만들려면 A와 B를 몇 대 몇으로 섞어야 할까요?

 

첨부 이미지

문제에 쉽게 접근하기 위해 A종목과 B종목의 비중을 0:10부터 10:0까지 조절해가며 수익률과 변동성을 측정해보았습니다. (포트폴리오의 수익률과 변동성을 계산하는 이론식이 있지만, 여기서는 결과값만 보여드리겠습니다). 이걸 차트로 표현하면 다음과 같습니다.

 

첨부 이미지

위 차트에서 파란색 점으로 표기된 노드 하나하나가 개별의 포트폴리오입니다. 맨 밑에 있는 점은 수익률 6%, 변동성 13%의 포트폴리오로, B 종목에 100% 할당한 경우에 해당됩니다. 반대로 오른쪽 맨 위에 있는 점은 수익률 8%, 변동성 17%의 포트폴리오로, A 종목에 100% 할당한 경우입니다. 이제 여기서 두 개의 포트폴리오를 집중해서 보겠습니다.

 

첨부 이미지

이 두 포트폴리오는 13%로 거의 동일한 변동성을 지니고 있습니다. 하지만 기대수익률은 각각 7%와 6%로 확연한 비교우위를 보입니다. 즉, 같은 종목들로 구성된 포트폴리오라 하더라도, 비중 배합을 어떻게 하느냐에 따라 성과는 굉장히 달라질 수 있습니다.

 

그렇지만 여전히 의문은 남아 있습니다. '상대적으로 성과가 더 뛰어난 비중 배합이 있다는 건 알겠는데, 그래서 그중 최적의 조합은 뭔데?'라는 것입니다. 여기서 우리가 이전에 배운 샤프 비율이 등장합니다. 

Image Source: Investopedia
Image Source: Investopedia

위 이미지에서 진한 파란색으로 그려진 곡선(Efficient Frontier)이 앞서 두 종목으로 구성된 포트폴리오 곡선과 동일한 개념입니다. 이때 우리는 y절편(무위험자산 수익률, 보통 2%로 지정)을 지나면서 해당 곡선에 접하는 접선을 그릴 수 있습니다. 이때 이 직선의 기울기의 의미가 굉장히 중요합니다.

 

직선의 기울기 = (기대수익률 - 무위험 수익률) / 변동성 --> 샤프 비율

 

즉, 이 그래프에서 직선의 기울기는 곧 샤프 비율을 뜻합니다. 그리고 우리는 위에서 배웠습니다. 샤프 비율이 높으면 높을수록 좋은 자산/전략이라는 것을 말이죠. 때문에 직선의 기울기가 최대가 되면서 Efficient Frontier와 교점이 있는 지점을 찾다보면, 접점이 하나뿐인 접선이 그려지게 됩니다. 이 접선을 학문 용어로는 '자본시장선(Capital Market Line)'이라 부릅니다. 그리고 이때의 접점이 최적의 포트폴리오(Ideal Market Portfolio)가 됩니다. 

 

첨부 이미지

1952년, 위의 연구 내용을 토대로 포트폴리오 이론을 처음 학문화하고 발전시킨 사람이 바로 '해리 마르코위츠'입니다. 현대 자산운용 이론의 토대를 만든 사람이자, 해당 연구로 노벨 경제학상을 받은 분이기도 합니다. 그는 이 연구에서 사용된 포트폴리오 최적화 이론의 이름을 'Mean-Variance Optimization(MVO)'이라 명명했으며, 이후에 나온 포트폴리오 이론들은 MVO의 변형 혹은 보완이라 불릴 만큼 큰 영향을 미쳤습니다. 

 

그는 자신의 연구와 관련하여 이런 어록을 남기기도 했습니다. '주식시장에서 유일한 공짜 점심은 다각화(Diversification) 뿐이다'. 특정 종목의 상승/하락을 정확히 예측하는 건 거의 불가능한 일이지만, 한정된 종목들 중에서 최적의 비중 조합으로 비교우위의 포트폴리오를 지향하는 것은 얼마든지 가능하다는 의미일 것입니다. 

 


3. 코드 예시 및 주의점

포트폴리오 이론을 처음 접하는 분이시라면 이제까지의 내용이 다소 어렵게 다가왔을 것입니다. 특히 수식적인 내용들이 계속 등장하다 보니, '내 포트폴리오에 그래서 어떻게 접목하라는 거야?' 이런 의문이 들 텐데, 다행히 저희에겐 GPT가 있습니다. GPT에게 포트폴리오 최적화 코드를 짜달라고 요청한 다음 예시 종목 몇 개를 갖고서 최적의 조합을 산출해보겠습니다. 

 

import numpy as np
import pandas as pd
import yfinance as yf

from scipy.optimize import minimize
import plotly.express as px
import plotly.graph_objects as go

# =========================
# 0) 설정
# =========================
tickers = ["AAPL", "NVDA", "JPM", "JNJ", "UNH", "KO", "NFLX"]
start = "2023-01-01"
rf = 0.02  # 연 2% (예시용)

# =========================
# 1) 데이터 로딩 & 수익률
# =========================
prices = yf.download(tickers, start=start, auto_adjust=True)["Close"].dropna()
rets = prices.pct_change().dropna()

mu = rets.mean() * 252
cov = rets.cov() * 252

n_assets = len(tickers)

def port_stats(w):
    w = np.array(w)
    r = float(w @ mu.values)
    v = float(np.sqrt(w.T @ cov.values @ w))
    s = (r - rf) / v
    return r, v, s

# =========================
# 2) 최적화: Max Sharpe / Min Vol
# =========================
bounds = [(0.0, 1.0)] * n_assets
cons_sum1 = {"type": "eq", "fun": lambda w: np.sum(w) - 1.0}
w0 = np.ones(n_assets) / n_assets

# Max Sharpe = minimize -Sharpe
res_ms = minimize(lambda w: -port_stats(w)[2], w0, method="SLSQP", bounds=bounds, constraints=[cons_sum1])
w_ms = res_ms.x
r_ms, v_ms, s_ms = port_stats(w_ms)

# Min Vol
res_mv = minimize(lambda w: port_stats(w)[1], w0, method="SLSQP", bounds=bounds, constraints=[cons_sum1])
w_mv = res_mv.x
r_mv, v_mv, s_mv = port_stats(w_mv)

# =========================
# 3) 랜덤 포트폴리오(구름) 생성
# =========================
N = 100000
W = np.random.random((N, n_assets))
W = W / W.sum(axis=1, keepdims=True)

rand_ret = W @ mu.values
rand_vol = np.sqrt(np.einsum("ij,jk,ik->i", W, cov.values, W))
rand_sharpe = (rand_ret - rf) / rand_vol

cloud = pd.DataFrame({
    "Volatility": rand_vol,
    "Return": rand_ret,
    "Sharpe": rand_sharpe
})

# =========================
# 4) 그림 1: 리스크-리턴 + 마커 강조 (Plotly)
# =========================
fig1 = px.scatter(
    cloud,
    x="Volatility",
    y="Return",
    hover_data={"Sharpe":":.2f", "Volatility":":.2%","Return":":.2%"},
    title="Random Portfolios",
)
fig1.update_traces(marker=dict(size=4, opacity=0.35))

# Max Sharpe / Min Vol / Risk-free 점 추가
fig1.add_trace(go.Scatter(
    x=[v_ms], y=[r_ms],
    mode="markers+text",
    text=[f"Max Sharpe<br>Ret={r_ms:.2%}<br>Vol={v_ms:.2%}<br>Sharpe={s_ms:.2f}"],
    textposition="top center",
    marker=dict(symbol="star", size=14),
    name="Max Sharpe"
))

fig1.add_trace(go.Scatter(
    x=[v_mv], y=[r_mv],
    mode="markers+text",
    text=[f"Min Vol<br>Ret={r_mv:.2%}<br>Vol={v_mv:.2%}"],
    textposition="bottom center",
    marker=dict(symbol="diamond", size=12),
    name="Min Vol"
))

fig1.add_trace(go.Scatter(
    x=[0.0], y=[rf],
    mode="markers+text",
    text=[f"Risk-Free<br>{rf:.0%}"],
    textposition="bottom right",
    marker=dict(symbol="square", size=10),
    name="Risk-Free"
))

fig1.update_layout(
    xaxis_title="Volatility (annualized)",
    yaxis_title="Return (annualized)",
    template="plotly_white"
)

fig1.show()

# =========================
# 5) 그림 2: 최적 비중 바차트 (Max Sharpe)
# =========================
weights_df = pd.DataFrame({
    "Ticker": tickers,
    "Weight": w_ms
}).sort_values("Weight", ascending=False)

fig2 = px.bar(
    weights_df,
    x="Ticker",
    y="Weight",
    text=weights_df["Weight"].map(lambda x: f"{x:.1%}"),
    title="Max Sharpe Portfolio Weights"
)
fig2.update_traces(textposition="outside")
fig2.update_layout(yaxis_tickformat=".0%", template="plotly_white")
fig2.show()

# =========================
# 6) 그림 3: 누적수익률 (Max Sharpe vs Equal Weight vs SPY)
# =========================
# 포트폴리오 일간 수익률
port_ret_ms = (rets @ w_ms)
port_ret_eq = rets.mean(axis=1)  # 동일가중

# SPY 벤치마크
spy = yf.download(["SPY"], start=start, auto_adjust=True)["Close"].dropna()
spy_ret = spy.pct_change().dropna()

# 날짜 정렬/교집합 맞추기
common = port_ret_ms.index.intersection(spy_ret.index)
port_ret_ms = port_ret_ms.loc[common]
port_ret_eq = port_ret_eq.loc[common]
spy_ret = spy_ret.loc[common]

cum = pd.DataFrame({
    "Max Sharpe": (1 + port_ret_ms).cumprod(),
    "Equal Weight": (1 + port_ret_eq).cumprod(),
    "SPY": (1 + spy_ret.squeeze()).cumprod(),
})

fig3 = px.line(
    cum,
    title="Cumulative Growth (Start=1.0): Max Sharpe vs Equal Weight vs SPY"
)
fig3.update_layout(
    yaxis_title="Cumulative Value",
    xaxis_title="Date",
    template="plotly_white"
)
fig3.show()

# =========================
# 7) 텍스트 요약
# =========================
print("=== Max Sharpe Portfolio ===")
print(f"Annual Return: {r_ms:.2%} | Annual Vol: {v_ms:.2%} | Sharpe: {s_ms:.2f}")
print(pd.Series(w_ms, index=tickers).sort_values(ascending=False).map(lambda x: f"{x:.2%}"))
 

8개의 미국 주식에 대하여 2023년 1월 1일부터 현재까지로 기간 설정을 해서 시뮬레이션을 돌려보았습니다. (위의 코드는 GPT가 인위적으로 생성한 코드이고, 시각화를 위해 추가된 부분이 많을 뿐, 실제 로직 자체는 굉장히 단순합니다.) 그렇게 최적화된 결과물을 보면 다음과 같습니다.

 

첨부 이미지
첨부 이미지
첨부 이미지

이렇게 최적의 포트폴리오 조합과 해당 기간 동안의 백테스트 결과까지 예쁘게 출력되는 것을 확인할 수 있습니다. 위의 코드를 변형한다면 특정 기간 동안, 내가 원하는 종목들의 조합을 다시 입력하여 최적의 비중을 산출해는 게 굉장히 쉬워지게 됩니다.

 

 

다만, 여기서 마르코위츠의 포트폴리오 이론의 2가지 한계점을 짚고 넘어가겠습니다. 

첫 번째는 '쏠림 현상'입니다. 위의 이미지 중에서 두 번째 이미지에 나와 있는 조합을 보면 이상한 점을 하나 발견할 수 있습니다. AAPL과 NFLX의 비중이 0으로 되어 있습니다. 이는 몇 가지 이유 때문인데, 우선 샤프 비율을 최대로 높이는 과정에서 변동성이 높은 기술주들은 상대적으로 순위가 밀리는 현상이 발생합니다. 또, 이미 NVDA가 종목에 들어가 있는 상태에서 다른 기술주들은 NVDA와 상관관계가 높은 만큼 중복해서 비중이 포함되기 어렵습니다. 이처럼 마르코위츠의 MVO 모델은 특정 종목에는 소외를, 또 그만큼 다른 종목에는 과한 비중을 부과하는 현상이 자주 발생하는데, 이를 '쏠림 현상'이라 부릅니다. 

두 번째 한계점은 '과거의 성과가 미래의 성과를 담보하지 않는다'는 것입니다. 마르코위츠의 포트폴리오 이론은 굉장히 강한 전제 조건을 토대로 하고 있습니다. 바로 '특정 자산의 기대수익과 변동성을 예측할 수 있다'는 것인데, 이 예측에는 과거 데이터에 기반한 자료가 사용됩니다. 즉 특정 A라는 종목이 지난 10년간 연평균 수익률 10%, 변동성 15%를 기록했으니, 다음 1년 동안에도 비슷한 양상일 것이다, 라고 가정하는 것입니다. 그렇지만 급변하는 시장 환경에서 이러한 전제는 쉽게 무너지기 때문에 명확한 한계점으로 지적 받습니다.

이를 해결하기 위해 2000년대 들어서 Risk Parity 모델이나 블랙-리터만 모형 등이 등장했고, 이후에도 상관계수를 변형한 다양한 기법들이 연구되는 추세입니다.

 

때문에 포트폴리오 최적화 시뮬레이션을 돌려보시되, 당장 한 번에 나오는 결과를 너무 맹신해서는 안 됩니다. 대신 GPT나 Gemini와 대화를 주고 받으면서 코드를 보완해나가는 것을 추천드립니다. 분명 코드 몇 줄만으로 위에서 언급한 문제점을 완화시키거나 우회하는 기법들이 존재하며, 또 주기적으로 리밸런싱을 함으로써 리스크를 줄이는 것도 가능합니다. 본 뉴스레터의 내용이 여러분의 포트폴리오 관리의 종점이 아닌 출발점이 되기를 바랍니다. 

 

오늘도 읽어주셔서 감사합니다.

 

 

다가올 뉴스레터가 궁금하신가요?

지금 구독해서 새로운 레터를 받아보세요

✉️

이번 뉴스레터 어떠셨나요?

PRAESENTIA 님에게 ☕️ 커피와 ✉️ 쪽지를 보내보세요!

댓글

의견을 남겨주세요

확인
의견이 있으신가요? 제일 먼저 댓글을 달아보세요 !
© 2026 PRAESENTIA

투자, 퀀트, AI에 관한 기록

뉴스레터 문의pbhoo95@gmail.com

메일리 로고

도움말 자주 묻는 질문 오류 및 기능 관련 제보

서비스 이용 문의admin@team.maily.so

메일리 사업자 정보

메일리 (대표자: 이한결) | 사업자번호: 717-47-00705 | 서울특별시 성동구 왕십리로10길 6, 11층 1109호

이용약관 | 개인정보처리방침 | 정기결제 이용약관 | 라이선스