변동성 타겟팅이란?
변동성 타겟팅(Volatility Targeting)은 포트폴리오의 실현 변동성을 일정 수준으로 유지하는 퀀트 투자 전략입니다. 시장이 급변할 때 자동으로 포지션 크기를 조절해 리스크를 관리합니다. 레이 달리오의 브리지워터나 AQR 같은 글로벌 헤지펀드에서 핵심 리스크 관리 기법으로 활용하고 있습니다.
전통적인 고정 비중 투자(예: 주식 60%, 채권 40%)는 변동성이 급등하면 포트폴리오 전체 리스크가 함께 치솟습니다. 변동성 타겟팅은 이 문제를 해결합니다.
핵심 원리: 포지션 사이징 공식
변동성 타겟팅의 핵심은 단순한 공식 하나입니다:
포지션 비중 = 목표 변동성 / 실현 변동성
예시:
목표 변동성 = 15% (연율)
현재 실현 변동성 = 30%
→ 포지션 비중 = 15% / 30% = 0.5 (자본의 50%만 투자)
현재 실현 변동성 = 10%
→ 포지션 비중 = 15% / 10% = 1.5 (레버리지 150%)
변동성이 높을 때는 포지션을 줄이고, 낮을 때는 늘리는 역추세 리스크 관리 방식입니다. 이를 통해 포트폴리오의 일별 손익 분포를 안정적으로 유지할 수 있습니다.
파이썬으로 구현하는 변동성 타겟팅
실제 파이썬 자동매매 시스템에 변동성 타겟팅을 적용하는 코드를 살펴보겠습니다.
import numpy as np
import pandas as pd
class VolatilityTargeting:
def __init__(self, target_vol=0.15, lookback=20, max_leverage=2.0):
"""
target_vol: 목표 연간 변동성 (0.15 = 15%)
lookback: 실현 변동성 계산 기간 (거래일)
max_leverage: 최대 레버리지 제한
"""
self.target_vol = target_vol
self.lookback = lookback
self.max_leverage = max_leverage
def realized_volatility(self, prices: pd.Series) -> float:
"""최근 N일 실현 변동성 (연율화)"""
returns = prices.pct_change().dropna()
recent = returns.tail(self.lookback)
daily_vol = recent.std()
return daily_vol * np.sqrt(252) # 연율화
def position_weight(self, prices: pd.Series) -> float:
"""변동성 기반 포지션 비중 계산"""
rv = self.realized_volatility(prices)
if rv == 0:
return 1.0
weight = self.target_vol / rv
return min(weight, self.max_leverage) # 레버리지 상한
def backtest(self, prices: pd.Series) -> pd.DataFrame:
"""변동성 타겟팅 백테스트"""
returns = prices.pct_change().dropna()
weights = []
strat_returns = []
for i in range(self.lookback, len(returns)):
hist = prices.iloc[:i+1]
w = self.position_weight(hist)
weights.append(w)
strat_returns.append(returns.iloc[i] * w)
result = pd.DataFrame({
'date': returns.index[self.lookback:],
'raw_return': returns.iloc[self.lookback:].values,
'weight': weights,
'strategy_return': strat_returns
}).set_index('date')
return result
EWMA 변동성으로 반응 속도 개선
단순 이동 표준편차 대신 EWMA(지수가중이동평균)를 사용하면 최근 변동성 변화에 더 빠르게 반응할 수 있습니다.
def ewma_volatility(returns: pd.Series, span=20) -> float:
"""EWMA 실현 변동성 (연율화)"""
ewma_var = returns.ewm(span=span).var().iloc[-1]
return np.sqrt(ewma_var * 252)
# GARCH(1,1) 예측 변동성 활용
from arch import arch_model
def garch_forecast_vol(returns: pd.Series) -> float:
"""GARCH(1,1) 1일 예측 변동성"""
model = arch_model(returns * 100, vol='Garch', p=1, q=1)
result = model.fit(disp='off')
forecast = result.forecast(horizon=1)
daily_var = forecast.variance.iloc[-1, 0] / 10000
return np.sqrt(daily_var * 252)
EWMA는 구현이 간단하면서도 빠른 반응 속도를 제공하고, GARCH는 변동성 클러스터링 현상을 모델링할 수 있어 더 정교한 예측이 가능합니다.
변동성 타겟팅 + 자동매매 연동
서킷브레이커와 함께 사용하면 더욱 견고한 자동매매 시스템을 구축할 수 있습니다.
class VolTargetTrader:
def __init__(self, exchange_client, target_vol=0.15):
self.client = exchange_client
self.vol_target = VolatilityTargeting(target_vol=target_vol)
self.rebalance_threshold = 0.1 # 10% 이상 변화 시 리밸런스
def check_rebalance(self, symbol: str, prices: pd.Series):
"""리밸런스 필요 여부 확인 및 실행"""
target_weight = self.vol_target.position_weight(prices)
current_weight = self.get_current_weight(symbol)
diff = abs(target_weight - current_weight) / current_weight
if diff > self.rebalance_threshold:
self.execute_rebalance(symbol, target_weight)
return True
return False
def execute_rebalance(self, symbol: str, target_weight: float):
"""포지션 리밸런스 실행"""
equity = self.client.get_equity()
target_notional = equity * target_weight
current_notional = self.client.get_position_value(symbol)
delta = target_notional - current_notional
if abs(delta) > 10: # 최소 주문 금액
side = 'buy' if delta > 0 else 'sell'
price = self.client.get_price(symbol)
qty = abs(delta) / price
self.client.create_order(symbol, side, qty)
print(f"리밸런스: {side} {qty:.4f} {symbol} "
f"(비중: {target_weight:.1%})")
멀티에셋 변동성 타겟팅
여러 자산에 동시 적용할 때는 자산 간 상관관계도 고려해야 합니다.
| 구분 | 개별 자산 타겟팅 | 포트폴리오 타겟팅 |
|---|---|---|
| 변동성 계산 | 자산별 개별 변동성 | 공분산 행렬 기반 포트폴리오 변동성 |
| 상관관계 | 무시 | 반영 |
| 분산 효과 | 과소평가 가능 | 정확히 반영 |
| 구현 복잡도 | 낮음 | 높음 |
| 적합한 경우 | 단일 전략, 소수 자산 | 멀티 전략, 다수 자산 |
def portfolio_vol_target(returns_df: pd.DataFrame,
target_vol=0.15,
lookback=60):
"""멀티에셋 포트폴리오 변동성 타겟팅"""
recent = returns_df.tail(lookback)
cov_matrix = recent.cov() * 252 # 연율화 공분산
n = len(returns_df.columns)
equal_weights = np.ones(n) / n
port_vol = np.sqrt(
equal_weights @ cov_matrix.values @ equal_weights
)
scaling = target_vol / port_vol
adjusted_weights = equal_weights * scaling
return adjusted_weights
실전 운용 시 주의사항
변동성 타겟팅을 실제 자동매매에 적용할 때 반드시 고려할 점들입니다:
- 거래비용: 잦은 리밸런스는 수수료를 증가시킵니다. 리밸런스 임계값(threshold)을 설정해 불필요한 거래를 줄이세요.
- 변동성 점프: 급격한 변동성 상승(VIX 스파이크 등) 시 뒤늦게 포지션을 줄이게 됩니다. 예측 변동성(GARCH)이나 내재 변동성을 병행하면 선제적 대응이 가능합니다.
- 레버리지 제한: 저변동성 구간에서 과도한 레버리지를 방지하는 상한선이 필수입니다. 일반적으로 1.5~2배를 권장합니다.
- 룩백 기간: 너무 짧으면 노이즈에 민감하고, 너무 길면 반응이 느립니다. 20~60 거래일이 일반적입니다.
- 리밸런스 주기: 일별 리밸런스가 이론적으로 최적이지만, 주간 리밸런스도 대부분의 효과를 얻을 수 있습니다.
변동성 타겟팅의 성과 특성
학술 연구와 실증 분석에 따르면, 변동성 타겟팅은 다음과 같은 성과 특성을 보입니다:
- 샤프 비율 개선: 고정 비중 대비 약 10~30% 샤프 비율 향상
- 최대 낙폭 감소: 위기 시 자동 디레버리지로 꼬리 리스크 축소
- 수익률 분포 정규화: 첨도(kurtosis)와 왜도(skewness)가 개선
- 위기 후 회복: 변동성 하락 시 자동으로 포지션을 확대해 반등 수혜
다만 변동성이 갑자기 급등하는 첫날에는 아직 높은 포지션을 유지하고 있어 손실을 피하기 어렵습니다. 이를 보완하려면 내재 변동성(옵션 시장)이나 거시 지표를 추가 시그널로 활용하는 것이 좋습니다.
마무리
변동성 타겟팅은 시장 상황에 따라 포지션 크기를 자동으로 조절하는 체계적인 리스크 관리 기법입니다. 구현이 비교적 단순하면서도 포트폴리오 성과를 유의미하게 개선할 수 있어, 퀀트 투자와 자동매매의 기본 빌딩 블록으로 널리 사용됩니다. 파이썬과 함께라면 누구나 자신의 트레이딩 시스템에 적용해볼 수 있습니다.