팩터 결합 전략에서 IC보다 더 먼저 봐야 하는 것들
IC 하나만으로는 전략의 안정성을 설명하기 어렵습니다. 턴오버, 군집화, 상관구조, 리밸런싱 비용까지 함께 점검해야 팩터 결합의 실제 가치를 판단할 수 있습니다.
IC는 필요조건이지 충분조건이 아니다
팩터 기반 전략을 평가할 때 가장 먼저 나오는 지표가 IC(Information Coefficient)입니다. 예측 수익률과 실제 수익률 사이의 스피어만 상관계수로, IC가 높을수록 “좋은 팩터”처럼 보입니다.
그런데 실전에 붙이면 IC가 좋았던 팩터가 수익을 내지 못하는 경우가 꽤 있습니다. IC 자체가 틀린 게 아니라, IC만 보고 넘어간 것들이 문제입니다.
1. 턴오버: 거래비용이 알파를 먹는다
IC가 0.05인 팩터가 있다고 해봅시다. 이 팩터로 포트폴리오를 구성하면 월 기준으로 그럴듯한 초과수익이 나옵니다. 그런데 이 팩터가 매주 리밸런싱을 요구한다면?
거래비용이 0.1%에 불과해도, 주 1회 리밸런싱이면 연간 약 5%의 비용이 발생합니다. IC 0.05짜리 팩터의 연간 예상 알파가 이것보다 크지 않으면 실질 수익은 마이너스입니다.
팩터의 **자기상관(autocorrelation)**을 먼저 확인해야 합니다. 이번 주의 팩터 값과 다음 주의 팩터 값이 얼마나 비슷한가를 보는 것입니다. 자기상관이 낮으면 포지션이 자주 바뀌고, 자기상관이 높으면 천천히 바뀝니다.
import pandas as pd
from scipy.stats import spearmanr
# 팩터 자기상관 계산
factor_series = factor_df['factor_value']
autocorr_1 = factor_series.autocorr(lag=1) # 1기간 후
autocorr_4 = factor_series.autocorr(lag=4) # 4기간 후
print(f"1기간 자기상관: {autocorr_1:.3f}")
print(f"4기간 자기상관: {autocorr_4:.3f}")
자기상관이 0.9 이상이면 천천히 리밸런싱해도 됩니다. 0.5 이하면 매 기간 많이 움직인다는 뜻이므로 비용 시뮬레이션이 필수입니다.
2. 팩터 군집화: 분산투자처럼 보이는 집중투자
팩터를 5~6개 결합하면 분산이 잘 될 것 같습니다. 그런데 팩터들끼리 상관관계가 높으면 하나 쓰는 것과 크게 다르지 않습니다.
대표적인 경우가 모멘텀 팩터 계열입니다. 3개월 수익률, 6개월 수익률, 12개월 수익률을 각각 팩터로 쓰면 세 가지를 결합한 것처럼 보이지만, 이 셋의 상관관계는 0.7~0.9 수준인 경우가 많습니다.
팩터 결합 전에 상관관계 매트릭스를 그려보는 게 기본입니다.
import seaborn as sns
import matplotlib.pyplot as plt
# 팩터 상관관계 히트맵
corr_matrix = factor_df[factor_cols].corr(method='spearman')
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='RdBu_r',
center=0, ax=ax, cbar_kws={'shrink': 0.8})
plt.title('Factor Correlation Matrix')
plt.tight_layout()
상관관계가 0.6 이상인 팩터 쌍이 있다면 하나만 남기거나 PCA로 직교화하는 걸 고려해야 합니다.
3. ICIR: IC의 평균보다 일관성이 더 중요하다
IC 평균이 0.05여도 어떤 달은 0.3이고 어떤 달은 -0.2라면 실전에서 쓰기가 어렵습니다. 포지션 크기를 어떻게 조절해야 할지 기준이 없어지기 때문입니다.
**ICIR(Information Coefficient Information Ratio)**은 IC 평균을 IC 표준편차로 나눈 값입니다. 샤프 비율처럼 일관성을 측정합니다.
import numpy as np
# ICIR 계산
ic_series = []
for period in periods:
returns = get_forward_returns(period)
factor_values = get_factor_values(period)
ic, _ = spearmanr(factor_values, returns)
ic_series.append(ic)
ic_array = np.array(ic_series)
icir = ic_array.mean() / ic_array.std()
print(f"IC Mean: {ic_array.mean():.4f}")
print(f"IC Std: {ic_array.std():.4f}")
print(f"ICIR: {icir:.3f}")
일반적으로 ICIR 0.5 이상이면 안정적인 팩터로 봅니다. 0.3 이하면 IC 평균이 아무리 높아도 신뢰하기 어렵습니다.
4. 팩터 붕괴 속도: 언제까지 예측력이 유지되는가
팩터 예측력이 1개월 뒤에도 유지되는지, 아니면 1주일 만에 사라지는지에 따라 리밸런싱 주기가 결정됩니다.
포워드 리턴 기간을 달리하면서 IC를 계산해보면 됩니다.
horizons = [1, 5, 10, 21, 63] # 1일, 1주, 2주, 1개월, 3개월
ic_by_horizon = {}
for h in horizons:
forward_ret = returns.shift(-h)
ic_vals = []
for t in timestamps:
ic, _ = spearmanr(factor.loc[t], forward_ret.loc[t])
ic_vals.append(ic)
ic_by_horizon[h] = np.mean(ic_vals)
# IC가 horizon에 따라 어떻게 변하는지 확인
for h, ic_mean in ic_by_horizon.items():
print(f"Horizon {h:3d}d → IC: {ic_mean:.4f}")
IC가 21일(1개월)까지 큰 변화 없이 유지된다면 월별 리밸런싱으로도 충분합니다. 5일 이후 급격히 떨어진다면 주간 리밸런싱이 필요하고, 이 경우 비용 계산이 더 중요해집니다.
실전 체크 순서
팩터를 포트폴리오에 편입하기 전에 이 순서로 확인합니다.
첫째, 팩터 간 상관관계를 봅니다. 0.6 이상인 쌍이 있으면 정리합니다.
둘째, 자기상관을 확인합니다. 낮으면 리밸런싱 비용을 엄격하게 계산합니다.
셋째, ICIR을 계산합니다. 0.3 미만이면 실전 사용에 신중해야 합니다.
넷째, IC가 어느 기간까지 유지되는지 확인합니다. 이게 리밸런싱 주기의 기준입니다.
다섯째, 비용 차감 후 수익이 여전히 의미 있는지 시뮬레이션합니다.
IC 숫자 하나만 보고 “좋은 팩터다”라는 결론을 내리는 건 50미터 달리기 기록만 보고 마라톤 선수를 선발하는 것과 비슷합니다.