몬테카를로 시나리오를 두 배 늘리면 꼬리 위험도 정확해질까? ETF 12종 실험
몬테카를로 위험 시뮬레이션 결과가 들쭉날쭉하면 “시나리오를 두 배 더 뽑자”는 말이 쉽게 나옵니다. 그런데 추가로 생성한 756개의 시나리오는 실제로 어떤 위험 정보를 보탰을까요? 숫자가 안정되는 것과 시장의 꼬리 위험을 제대로 재현하는 것은 다른 문제입니다.
이번에는 ETF 12종의 실제 과거 가격, 여섯 가지 시나리오 생성법, 서로 짝을 맞춘 난수 시드 50개로 비교했습니다. 생성 수를 756개에서 1,512개로 늘리니 일부 추정값의 변동은 분명 줄었습니다. 하지만 Gaussian이 생성한 동반 급락 비율은 여전히 약 0.3180으로, 고정 학습 구간의 기준값 0.4211에 못 미쳤습니다.
‘동반 급락’은 쉽게 말해 SPY가 크게 하락한 날 다른 ETF도 몇 개나 같이 크게 하락했는가입니다. 각 ETF의 급락 기준은 학습 구간 수익률의 하위 5%로 미리 고정하고, 생성한 시나리오마다 유리하게 다시 설정하지 않았습니다.
위험 시나리오 생성기를 평가할 때는 세 가지를 구분하는 편이 좋습니다. 더 많이 생성하면 추정값이 안정되는가? 같은 날 여러 자산이 떨어지는 구조와 큰 움직임이 연속되는 현상을 보존하는가? 실제 표본외 데이터에서 위험 임계값이 보정되는가? 앞의 두 가지는 고정 학습 데이터로 비교하고, 세 번째는 범위를 좁힌 별도의 하루 VaR 검정입니다. 여섯 생성기의 표본외 우열을 매기는 검정이 아닙니다.
ETF 12종과 고정된 756거래일 학습 구간
가격 자료는 Boris Marjanovic의 Huge Stock Market Dataset에서 가져왔습니다. 원본 설명에는 CC0 라이선스와 배당·분할 조정 가격이 명시되어 있습니다. 주식, 국채, 신용채, 금, 원자재, 미국 달러, 부동산에 걸친 12개 ETF를 택했습니다. SPY 하나만 보면 자산 간 동반 하락을 살펴보기 어렵기 때문입니다. 정확한 티커 목록은 글 끝에 넣었습니다.
12개 원본 파일의 조정된 Close 열에서 모두 기록된 날짜의 교집합만 사용했고, 빈 날짜는 채우지 않았습니다. 이 Kaggle 자료에서 HYG의 첫 기록이 2007-04-11이어서 전체 공통 기간은 2007-04-11부터 2017-11-10까지 2,668개 가격 관측일입니다. 이를 일간 단순 수익률로 바꾼 뒤 매일 ETF 12종을 동일 가중치로 평균했습니다. 포트폴리오 정의는 끝까지 동일합니다.
시나리오 생성에는 처음 756개 일간 수익률만 사용합니다. 대략 3년 분량이며 2008년 시장 충격도 포함됩니다. 모든 방법이 똑같은 과거를 보고 경쟁하게 하려는 선택입니다. Student-t의 자유도는 5로 고정했고, 나중의 표본외 성과를 보고 조정하지 않았습니다.
| 방법 | 수익률 시나리오 생성 방식 |
|---|---|
| Gaussian | 학습 구간 평균과 공분산으로 다변량 정규 수익률 생성 |
| Student-t df=5 | 자유도 5의 다변량 t 분포, 공분산은 학습 구간과 일치 |
| IID Bootstrap | 하루치 ETF 수익률 행 전체를 독립적으로 복원 추출 |
| Moving-block 5 / 20 / 60 | 연속된 5일, 20일, 60일의 수익률 블록을 추출 |
여기서 먼저 피해야 할 함정은 두 실험의 난수가 다르면 우연한 차이를 시나리오 수 증가의 효과로 오해하기 쉽다는 것입니다. 그래서 방법별로 시드 1000–1049, 총 50개를 고정했습니다. 각 시드에서 먼저 1,512개를 만든 다음, 같은 시퀀스의 첫 756개를 작은 표본으로 썼습니다. 결국 756일치 과거 정보를 반복해서 뽑는 것이지 실제 시장 기록이 새로 756일 생기는 것은 아닙니다.
Student-t에도 주의할 점이 있습니다. ‘두꺼운 꼬리’ 분포를 쓴다고 분산까지 같이 키우면 비교가 흐트러집니다. 구현에서는 학습 공분산의 Cholesky 인자로 상관된 정규 벡터를 만든 뒤 √(3/χ²₅)를 곱합니다(χ²₅는 자유도 5의 카이제곱 변수). 이는 다변량 t의 척도 행렬을 학습 공분산의 3/5로 설정한 것과 같습니다. 이 보정을 빼면 생성 공분산이 의도한 값의 5/3배로 부풀어 오릅니다.
시나리오를 두 배 뽑으니 Monte Carlo 오차가 얼마나 줄었을까
먼저 하루 ES(5%)를 봤습니다. 수익률이 가장 나쁜 하위 5%에 속할 때의 평균 수익률입니다. 시드마다 ES를 하나씩 계산한 뒤, 756개와 1,512개를 사용한 경우 각각 시드 간 ES 표준편차를 비교했습니다. 이 수치는 난수 추출에 따른 산포를 재는 것이지 미지의 미래 시장을 얼마나 정확히 아는지를 뜻하지 않습니다.
| 생성 방법 | ES 시드 간 표준편차 비율: 1,512 / 756 |
|---|---|
| Gaussian | 0.718 |
| Student-t df=5 | 0.671 |
| IID Bootstrap | 0.746 |
| Moving-block 5 | 0.768 |
| Moving-block 20 | 0.681 |
| Moving-block 60 | 0.734 |
여섯 비율 모두 0.671–0.768 사이로 1보다 작습니다. 이번 50개 시드에서는 시나리오를 늘리자 ES 추정값이 서로 더 비슷해졌습니다. 1/√2≈0.707은 표본을 두 배로 늘릴 때 떠올릴 만한 직관이지만, ES처럼 꼬리에서 계산하는 통계량까지 똑같이 수렴할 필요는 없습니다.
동반 급락 지표는 다릅니다. 생성된 날짜 중 SPY가 학습 구간에서 정한 하위 5% 임계값 아래로 내려간 날을 고르고, 그날 나머지 11종 중 자기 임계값을 넘어서 하락한 비율을 구한 후 평균합니다. Gaussian의 학습 기준 대비 오차는 N=756에서 약 −0.1036, N=1,512에서 약 −0.1031로 거의 움직이지 않았습니다.
추출을 더 하면 계산 결과는 안정될 수 있지만, 생성기가 빠뜨린 동반 하락 패턴이 자동으로 채워지는 것은 아닙니다.
IID Bootstrap은 같은 날 같이 떨어진 자산은 기억하지만 변동성 군집은 잊는다
하루의 동반 하락이 비슷하다고 큰 하락이 며칠 연속 일어나는 방식까지 비슷한 것은 아닙니다. 다음 지표는 모두 ETF 12종을 동일 가중치로 평균한 일간 포트폴리오 수익률에서 계산했습니다. 절대 수익률의 1시차 자기상관 **ACF(1)**은 큰 움직임이 연달아 나타나는지를 거칠게 보여 주고, 60일 ES와 최대 낙폭은 더 긴 경로의 왼쪽 꼬리를 봅니다.
여기에는 계산상의 함정이 하나 있습니다. 며칠간의 손실을 구할 때 일간 수익률을 단순 합산하면 실제 누적 손실을 잘못 구할 수 있습니다. 생성 수익률 시퀀스를 하루씩 밀면서 연속된 60일 구간을 만들고, ∏(1+rₜ)-1로 복리 누적 수익률을 구했습니다. 가장 나쁜 5% 구간의 평균이 60일 ES입니다. 최대 낙폭은 구간마다 복리 순자산 경로에서 따로 계산하고, 구간별 낙폭의 5% 분위수를 냈습니다.
다음은 N=1,512에서 시드 50개의 지표 평균값과 같은 고정 학습 구간의 경험적 기준입니다.
| 시나리오 원천 | 동반 급락 비율 | 절대 수익률 ACF(1) | 60일 ES(5%) | 60일 최대 낙폭의 5% 분위수 |
|---|---|---|---|---|
| 학습 표본 기준 | 0.4211 | 0.3000 | -21.01% | -25.45% |
| Gaussian | 0.3180 | -0.0011 | -15.77% | -16.53% |
| Student-t df=5 | 0.3549 | -0.0005 | -15.97% | -17.00% |
| IID Bootstrap | 0.4265 | 0.0059 | -15.15% | -16.26% |
| Block 5 | 0.4209 | 0.2408 | -14.45% | -15.75% |
| Block 20 | 0.4227 | 0.2842 | -16.54% | -18.56% |
| Block 60 | 0.4113 | 0.2684 | -17.49% | -20.48% |
표를 한 칸씩 읽을 필요는 없습니다. IID Bootstrap은 같은 날짜의 ETF 수익률 행 전체를 뽑으므로 동반 급락 비율 0.4265가 학습 기준 0.4211에 가깝습니다. 하지만 날짜는 서로 독립적으로 뽑으므로 ACF(1)은 0.0059에 그쳤습니다. 학습 구간의 기준은 0.3000입니다.
즉, 어떤 자산이 같은 날 떨어졌는지는 기억하지만 큰 움직임이 연속해서 나타나는지는 거의 잊은 것입니다.
Block 20의 ACF(1)은 0.2842까지 올라 학습 기준과 가까워집니다. Block 60의 60일 ES도 IID의 **−15.15%**에서 **−17.49%**로 깊어지지만, 경험적 기준인 **−21.01%**와는 여전히 차이가 있습니다. 블록은 무조건 길수록 좋은 것이 아닙니다. Block 5의 60일 ES는 오히려 IID보다 얕았습니다.
왜 60일 구간을 겹치게 만들었을까요? 아예 겹치지 않으면 756일 학습 자료는 약 12개, 생성 1,512일은 약 25개의 60일 구간밖에 주지 않습니다. 독립적인 구간 열댓 개로 하위 5%를 추정한 숫자를 저는 믿기 어렵습니다. 그래서 하루씩 이동하며 학습 쪽 697개, 생성 쪽 1,453개 구간을 썼습니다. 다만 서로 겹치기 때문에 이를 각각 독립적인 위험 사건으로 셀 수는 없습니다. 학습 기간에는 2008년 충격이 포함되어 −21.01%는 그 시기의 경험적 참고값이지 반드시 정확히 맞혀야 할 진짜 기준점은 아닙니다.
Moving-block의 접합부와 과거 데이터 양 끝의 가중치는 다른 문제
Block 방법에서 ACF가 올라가자 저도 처음에는 “연속된 날짜를 보존하기 때문”이라고 생각했습니다. 그런데 추출기 코드를 다시 보니 두 가지 영향을 한데 묶어 설명하고 있었습니다.
첫째는 블록의 접합부입니다. 블록 내부는 실제로 연속된 날짜지만 다음 블록은 전혀 다른 과거 시점에서 시작할 수 있습니다. 블록 길이가 L이면 인접한 이틀 중 약 1/L이 접합부를 가로지릅니다. 블록들이 독립적으로 이어진다는 단순한 근사에서는 1시차 상관이 1−1/L 정도로 약해집니다. 학습 ACF 0.3000에 대입하면 L=5에서 약 0.240, L=20에서 약 0.285로, 관측된 0.2408 / 0.2842와 비슷합니다. 하지만 L=60 결과는 이 간단한 관계로 설명되지 않습니다. 어디까지나 직관적인 근사이지 실험을 대신하는 공식은 아닙니다.
둘째는 학습 데이터의 맨 앞과 뒤 날짜가 추출될 확률이 낮다는 점입니다. 일반적인 비순환 Moving-block은 블록 시작점을 0부터 756−L까지 고릅니다. 가장자리 날짜는 가운데 날짜보다 적은 수의 블록에 포함되므로 위치별 가중치가 최대 L배까지 벌어질 수 있습니다. 실제 영향이 얼마나 되는지 확인하려고, 시작점을 균등하게 고르고 마지막과 처음을 이어 주는 Circular Block으로 같은 50개 시드를 추가 비교했습니다.
| 블록 길이 | ACF(1): 일반 / 순환 | 60일 ES: 일반 / 순환 |
|---|---|---|
| 5 | 0.2408 / 0.2411 | -14.45% / -14.35% |
| 20 | 0.2842 / 0.2884 | -16.54% / -16.37% |
| 60 | 0.2684 / 0.2792 | -17.49% / -17.23% |
변화는 크지 않았습니다. Block 20의 ACF는 0.2842에서 0.2884, 60일 ES는 **−16.54%에서 −16.37%**로 바뀌었습니다. 경계 가중치 차이는 실제로 존재하지만 이번 자료에서 Block과 IID의 주된 차이를 설명하기에는 부족했습니다. Circular 역시 학습 기간의 마지막 날과 첫날을 인위적으로 연결하므로 언제나 더 낫다고 할 수 없습니다.
이 추가 실험 덕분에 블록 접합부가 시간 의존성을 끊는 효과와 과거 시계열의 양 끝을 덜 뽑는 효과를 구분할 수 있었습니다. Circular Block Resampling의 방법론 배경을 참고할 수 있습니다.
하루 VaR: 세 단기 방법 모두 전체 표본외 구간에서 보정 검정을 통과하지 못했다
여기부터는 질문을 좁힙니다. 실제 다음 거래일이 왔을 때 모델이 제시한 꼬리 임계값은 맞았을까요? 앞의 여섯 생성법을 표본외로 순위를 매기는 검정은 아닙니다. 검정 대상은 경험적 과거 분위수, Gaussian, 자유도 5의 Student-t라는 세 가지 하루 VaR 방법뿐입니다. 매 목표일마다 바로 앞의 실제 포트폴리오 수익률 756일로 임계값을 다시 계산합니다. 앞에서 시나리오 생성에 쓴 고정 학습 구간을 그대로 반복 사용하는 것이 아닙니다.
t5의 5% 분위수 역시 학습 구간 분산에 맞췄습니다. VaR ‘초과’는 다음 날 실제 포트폴리오 수익률이 모델이 예측한 왼쪽 5% 임계값보다 낮다는 뜻입니다. 표본외에서 하루 단위로 겹치지 않는 목표는 총 1,911일입니다.
| 하루 95% VaR 방법 | 초과 횟수 | 초과율 | Kupiec p값 | Christoffersen 독립성 p값 |
|---|---|---|---|---|
| 과거 경험 분위수 | 52 | 2.72% | 6.16e-7 | 0.0145 |
| Gaussian | 51 | 2.67% | 3.16e-7 | 0.0122 |
| Student-t df=5 | 62 | 3.24% | 1.75e-4 | 0.0171 |
명목상 5%라면 1,911일 동안 평균적으로 95.55회의 초과를 기대할 수 있습니다. 실제는 세 방법 모두 51–62회에 머물렀습니다. 초과가 적다고 보정을 통과한 것은 아닙니다. Kupiec은 횟수가 명목 빈도와 맞는지, Christoffersen은 초과 사건의 독립성을 보는 검정입니다. 표의 두 종류 p값 모두 작습니다.
이 결론은 전체 1,911일에 대한 것입니다. 초기의 756일 이동 학습창에는 2008년 충격이 들어 있지만 이후에는 점차 빠집니다. 시기를 나눈 추가 검정은 이번에 하지 않았습니다. 연속 이틀 초과 횟수도 세 방법에서 각각 5 / 5 / 6번뿐이므로 독립성 p값은 그 실제 사건 수와 함께 읽어야 합니다.
Block 60의 60일 ES를 여기에 억지로 끼워 넣지는 않았습니다. 60일 예측 목표를 날마다 이동해 만들면 구간이 크게 겹치고, 이를 처리할 별도의 표본외 검정 설계가 필요합니다. 이번에는 납득할 만한 방식으로 완성하지 못했습니다. 하루 VaR에 쓰는 Kupiec/Christoffersen 검정을 그대로 복사하면 검증한 것처럼 보이기만 하므로 여기서는 하루 VaR만 보고합니다.
Student-t에는 반직관적인 부분도 있습니다. “꼬리가 두꺼우니 VaR가 항상 더 보수적”이라는 말은 틀릴 수 있습니다. 자유도 5에서 분산을 맞춘 표준화 왼쪽 5% 분위수는 약 −1.56085로, Gaussian의 −1.64485보다 오히려 0에 가깝습니다. 분포 이름만으로 모든 신뢰수준에서 임계값의 방향을 판단할 수는 없습니다.
다음 계산 예산은 어디에 써야 할까
다음에 “값이 불안정하니 시나리오를 두 배 늘리자”는 제안을 받으면 저는 먼저 세 가지를 묻겠습니다. 흔들리는 것이 단순 추출 잡음인가? 동반 급락과 연속 손실의 구조는 얼마나 살아 있는가? 필요한 위험 기간에 맞는 표본외 보정 검정은 했는가? 시나리오 수 증가가 직접 답하는 것은 주로 첫 질문입니다.
Block 20, Block 60, Student-t 가운데 당장 운영 위험관리의 하나를 고르라고 해도 이 고정 학습 기간의 숫자로 우승자를 정하지 않겠습니다. Block 20의 ACF가 과거와 가깝다고 미래 커버리지까지 좋은 것은 아니고, Student-t가 두꺼운 꼬리를 가졌다고 95% VaR가 항상 더 보수적인 것도 아닙니다. 먼저 위험 기간을 정하고 그 기간에 맞는 OOS 검정을 해야 합니다.
남길 만한 두 장면은 Gaussian의 동반 급락 격차가 시나리오 두 배 증가에도 그대로 남았다는 점과, Circular Block 비교를 추가한 뒤 초기 설명을 좁혀야 했다는 점입니다. 누군가 “백만 개 위험 시나리오”를 내세운다면 저는 이렇게 물을 겁니다. 어떤 실제 정보를 되풀이한 것이며, 중요한 위험 구조는 얼마나 보존했나요?
작은 사례로 꼬리 통계량을 직접 계산해 보고 싶다면 vectorbt에서 NaN이 CVaR의 꼬리 표본 분모를 바꾸는 Python 예제부터 살펴볼 수 있습니다.
데이터 출처와 고정 조건: Kaggle Huge Stock Market Dataset v3; SPY, IWM, EFA, EEM, TLT, IEF, LQD, HYG, GLD, DBC, UUP, VNQ. 조정 종가의 공통 기간은 2007-04-11–2017-11-10이며 총 2,668개 행, 빈 날짜를 채우지 않았습니다. 고정 CSV SHA-256: 0a20c095f0d9400fbf7d30e17a0c664716f147c460b03bf5439cd980ef8bf38a. 시나리오 실험은 756일 학습 수익률과 짝지은 시드 50개를 사용했고 별도의 단기 VaR 검정에는 1,911개 일간 목표를 사용했습니다. 과거 자료를 이용한 위험 모델링 방법 비교이며 투자 조언은 아닙니다.