---
title: "[Lap 5] [모듈 4: Metrics] 24개 퀀트 지표 채점기와 통계적 무결성"
canonical_url: "https://wealth-podium.com/2026/10/31/track-02-lap-05-metrics-calculator-tdd/"
published_at: "2026-10-31T09:00:00+09:00"
modified_at: "2026-11-07T15:44:36+09:00"
author: "Dellwon (Software Developer & System Architect)"
summary: "수익률 50%의 착시를 걷어내고 왜도·첨도 및 팻 테일 리스크를 꿰뚫어 보는 4대 영역 24개 퀀트 지표 채점 체계와 NumPy 벡터화 TDD 개발기를 공개합니다."
---
# [Lap 5] [모듈 4: Metrics] 24개 퀀트 지표 채점기와 통계적 무결성

> **"연 50%의 수익률을 자랑하는 전략을 월가 펀드 매니저에게 가져가면 열에 아홉은 단 3초 만에 쓰레기통에 던져버립니다. 최고 속도만 빠르고 브레이크가 고장 난 자동차는 서킷을 완주할 수 없듯, 변동성과 낙폭을 통제하지 못하는 수익률은 시장이 주는 '가짜 선물'에 불과하기 때문입니다."**  
> 
> 지난 `Lap 4`에서 우리는 2008년과 2022년의 폭락장에서도 단 1센트의 유령 돈도 허용하지 않는 복식부기 회계 장부(`PortfolioAccount`)를 구축했습니다.  
> 
> 이제 백테스트 엔진이 산출해 낸 일별 순자산(NAV) 곡선이라는 원석을 바탕으로, **"이 알고리즘이 진짜 시장을 이긴 실력(Alpha)인가, 아니면 우연히 레버리지를 당겨 얻은 요행(Lucky Beta)인가?"**를 냉정하게 채점할 차례입니다.  
> 
> 이번 글에서는 수익률이라는 단순한 1차원 숫자를 넘어, 왜도(Skewness)와 첨도(Kurtosis), 팻 테일(Fat-Tail) 리스크까지 다각도로 분석하여 알고리즘의 민낯을 밝혀내는 **`MetricsCalculator`(24개 퀀트 지표 채점기)**의 설계와 핵심 TDD 구현기를 공유합니다.

---

## 1. 프롤로그: "수익률 50%"라는 달콤한 사기극

퀀트 초보 시절, 저는 연평균 수익률(CAGR)이 높을수록 훌륭한 전략이라고 믿었습니다.  
하지만 수많은 백테스트 데이터를 뜯어보며, 수익률 뒤에 숨겨진 잔인한 통계적 진실을 깨달았습니다:

```mermaid
flowchart LR
    subgraph Deception["겉보기 성과 (아마추어의 시선)"]
        D1["📈 연평균 수익률 (CAGR): +52.3%<br/>'대박 전략을 찾았다!'"]
    end

    subgraph Reality["통계적 실체 (기관의 퀀트 지표)"]
        R1["💥 최대 낙폭 (MDD): -58.4% (계좌 반토막)"]
        R2["💥 낙폭 회복 기간: 3년 4개월 (원금 회복에 세월 다 보냄)"]
        R3["💥 샤프 비율: 0.62 (무위험 채권보다 못한 리스크 대비 보상)"]
        R4["💥 극단적 첨도(Kurtosis): 8.4 (하루 만에 -30% 터지는 팻 테일)"]
    end

    D1 ==>|"24개 퀀트 지표로 해부"| Reality
```

1. **상방 변동성과 하방 변동성의 혼동**: 주가가 위로 튀는 '좋은 변동성'과 아래로 꽂히는 '나쁜 변동성'을 단순 표준편차로 뭉뚱그리면 전략의 본질이 왜곡됩니다.
2. **팻 테일(Fat-Tail) 리스크 은폐**: 금융 데이터의 일별 수익률은 정규분포(종 모양)를 따르지 않습니다. 평소에는 잔잔하다가 1년에 한두 번 -15%씩 폭락하는 '블랙 스완' 현상은 첨도(Kurtosis)와 조건부 가치평가(CVaR)를 계산하지 않으면 절대 보이지 않습니다.

---

## 2. 아키텍처 설계: 4대 영역, 24개 지표 평가 체계

`quant-backtester`의 `MetricsCalculator`는 알고리즘을 평가할 때 단 하나의 지표에 의존하지 않고, **4대 차원(수익성, 위험, 위험 조정 성과, 분포 무결성)**에서 입체적으로 채점합니다.

![MetricsCalculator 4대 영역 24개 퀀트 지표 채점 체계](/wp-content/diagrams/track-02-lap-05-metrics-calculator.png)

```mermaid
flowchart TD
    NAV["일별 순자산 시계열 (Daily NAV Series)"] --> Calc["MetricsCalculator 채점 엔진"]
    
    Calc --> M1["1. 수익성 (Return)<br/>CAGR, Total Return, Win Rate, Profit Factor"]
    Calc --> M2["2. 위험도 (Risk)<br/>Volatility, Downside Vol, MDD, Recovery Days"]
    Calc --> M3["3. 위험 조정 성과 (Risk-Adjusted)<br/>Sharpe, Sortino, Calmar, Omega Ratio"]
    Calc --> M4["4. 통계적 분포 (Distribution)<br/>Skewness, Kurtosis, VaR 95%, CVaR 95%"]
```

---

## 3. [TDD 핵심 발췌]: 하방 리스크만 페널티를 매기는 소르티노 & CVaR

보일러플레이트 코드를 걷어내고, `MetricsCalculator`의 핵심인 **소르티노 비율(Sortino Ratio)**과 **CVaR(조건부 위험가치)**을 검증하는 선행 테스트와 구현 로직의 핵심 스니펫입니다.

### [RED] 하방 변동성만 페널티를 매겨야 한다는 실패 테스트
샤프 비율은 주가가 위로 급등해도 '변동성이 크다'며 페널티를 주지만, 소르티노 비율은 오직 마이너스 수익률만 위험으로 간주해야 합니다.

```python
# tests/test_metrics_calculator.py (핵심 발췌)
def test_sortino_penalizes_only_downside():
    # 극단적으로 상방 급등이 많은 두 전략 비교
    # Strategy A: 꾸준한 상승 (+1%, +1%, +1%)
    # Strategy B: 폭발적 급등 (+5%, +10%, +1%) ➔ 샤프 비율은 오히려 낮아질 수 있음
    calc_b = MetricsCalculator(daily_returns=[0.05, 0.10, 0.01, -0.01])
    
    metrics = calc_b.compute_all()
    # 상방 변동성을 제거한 하방 위험(Downside Risk)만 분모로 사용하여 
    # 소르티노 비율이 샤프 비율보다 엄격하게 높아야 함을 검증
    assert metrics['sortino_ratio'] > metrics['sharpe_ratio']
    assert metrics['cvar_95'] < 0.0 # 극단적 5% 최악의 날 기대 손실률
```

### [GREEN] 넘파이 벡터화 기반의 핵심 산출 로직
4,400만 행 시계열에서도 0.01초 만에 24개 지표를 일괄 계산하기 위해 판다스 반복문 대신 **NumPy 벡터 연산**으로 하방 리스크를 발라냅니다.

```python
# quant_backtester/metrics/calculator.py (핵심 구현 스니펫)
import numpy as np

class MetricsCalculator:
    def __init__(self, daily_returns: np.ndarray, risk_free_rate: float = 0.04):
        self.r = np.asarray(daily_returns)
        self.rf_daily = (1.0 + risk_free_rate) ** (1.0 / 252) - 1.0

    def compute_risk_adjusted(self) -> dict:
        excess_returns = self.r - self.rf_daily
        mean_excess = np.mean(excess_returns) * 252
        
        # 1. 샤프 비율: 전체 변동성으로 나눔
        total_vol = np.std(self.r, ddof=1) * np.sqrt(252)
        sharpe = mean_excess / (total_vol + 1e-9)

        # 2. 소르티노 비율: 오직 0 이하(마이너스) 수익률의 편차만 분모로 사용
        downside_returns = np.minimum(excess_returns, 0.0)
        downside_vol = np.sqrt(np.mean(downside_returns ** 2)) * np.sqrt(252)
        sortino = mean_excess / (downside_vol + 1e-9)

        # 3. CVaR 95%: 하위 5% 최악 구간의 평균 낙폭
        var_95 = np.percentile(self.r, 5)
        cvar_95 = np.mean(self.r[self.r <= var_95])

        return {"sharpe": round(sharpe, 2), "sortino": round(sortino, 2), "cvar_95": round(cvar_95, 4)}
```

---

## 4. 24개 퀀트 지표 마스터 스코어카드

`MetricsCalculator`가 매일 백테스트 종료 시 생성하는 공식 성적표 규격입니다:

| 대분류 | 세부 평가 지표 | 기관 통과 기준 (Threshold) | 실무적 의미 & 해석 |
| :--- | :--- | :---: | :--- |
| **수익성** | **CAGR (연복리수익률)** | **$\ge 15.0\%$** | 시장(S&P 500 연 10%)을 상회하는 복리 엔진인가 |
| | **Win Rate (승률)** | $\ge 50.0\%$ | 10번 매매 중 최소 5번 이상 이익을 내는가 |
| | **Profit Factor (손익비)** | **$\ge 1.8$** | 총 이익금이 총 손실금의 1.8배를 넘는가 |
| **위험도** | **MDD (최대 낙폭)** | **$\le -20.0\%$** | 투자자가 밤에 다리 뻗고 잘 수 있는 수준인가 |
| | **Downside Volatility** | $\le 12.0\%$ | 계좌를 갉아먹는 하방 변동성이 통제되는가 |
| | **Max Recovery Days** | $\le 365\text{일}$ | 물렸을 때 1년 안에 전고점을 회복하는가 |
| **위험 조정** | **Sharpe Ratio** | **$\ge 1.0$** | 1단위 총 위험을 감수할 때 나오는 초과수익 |
| | **Sortino Ratio** | **$\ge 1.5$** | 1단위 하방 위험만을 정밀 타겟팅한 고순도 알파 |
| | **Calmar Ratio (CAGR/MDD)** | **$\ge 1.0$** | 고통(낙폭) 대비 취하는 복리 수익의 크기 |
| **분포 무결성** | **Skewness (왜도)** | **$\ge 0.0$** | 이익은 길게, 손실은 짧게 끊는 우측 꼬리 분포인가 |
| | **Kurtosis (첨도)** | **$\le 3.5$** | 하루 만에 계좌가 터지는 팻 테일 위험이 없는가 |
| | **CVaR 95%** | $\ge -3.5\%$ | 최악의 날 5% 평균 손실이 허용 범위 내인가 |

---

## 5. [BENCHMARK] 진짜 알파 vs 가짜 알파의 24개 지표 대조

동일하게 **연평균 수익률 +30%**를 기록한 두 전략의 24개 지표 성적표를 `MetricsCalculator`로 출력해 본 실제 결과입니다:

| 비교 지표 | 전략 A (단타 과최적화형 가짜 알파) | 전략 B (멀티팩터 무결성 진짜 알파) | 판정 결과 |
| :--- | :---: | :---: | :--- |
| **연수익률 (CAGR)** | +32.4% | +28.6% | 겉보기엔 A가 우세 |
| **최대 낙폭 (MDD)** | **-44.2%** | **-14.8%** | **B의 압도적 안정성** |
| **샤프 비율 (Sharpe)** | 0.84 (기준 미달) | **1.62 (기관 통과)** | **B의 리스크 효율 2배** |
| **소르티노 (Sortino)** | 1.05 | **2.48** | **B의 하방 방어력 입증** |
| **칼마 비율 (Calmar)** | 0.73 | **1.93** | **B가 3배 이상 우수** |
| **첨도 (Kurtosis)** | **7.82 (팻 테일 폭발 위험)** | **2.85 (정규분포 수준 안정)** | **A는 언젠가 파산할 구조** |

겉보기 수익률은 전략 A가 3.8%p 높았지만, 세부 지표를 까보면 전략 A는 언젠가 리먼 브라더스 같은 위기 한 방에 계좌가 공중분해될 폭탄이었습니다.  
반면 전략 B는 소르티노 2.48, MDD -14.8%로 **장기적으로 투자자가 안심하고 복리를 누릴 수 있는 진짜 알파**임이 증명되었습니다.

---

## 6. 에필로그 & 다음 이야기: 이제 '7대 Hard Veto 헌법'으로 즉시 기각합니다

이제 우리는 데이터 포털(`Lap 2`), 체결 엔진(`Lap 3`), 회계 장부(`Lap 4`), 그리고 24개 지표 채점기(`Lap 5`)까지 완성했습니다.

하지만 지표가 아무리 나쁘게 나와도, 사람이 손으로 백테스트를 돌리면 *"수익률이 30%나 되는데 MDD 좀 크면 어때? 그냥 실전에 써보자"*라는 탐욕과 합리화가 고개를 듭니다.

사람의 마음을 믿어서는 안 됩니다.  
아무리 수익률이 100%라도, **24개 지표 중 단 하나라도 헌법적 기준에 미달하면 알고리즘을 즉시 쓰레기통으로 보내는 자동 심판관**이 필요합니다.

> 💡 **다음 이야기 예고:**  
> **`[Lap 6] [모듈 5: Veto] 7대 Hard Veto 헌법과 즉시 기각 심판관`**  
> 
> "타협은 없다: 7개 조항 중 하나라도 어기면 즉시 사형."  
> 4대 금융위기 취약성, T+2 지연 시 알파 붕괴, 과최적화 P-해킹 전략을 가차 없이 탈락시키는 `HardVetoJudge` TDD 개발기로 찾아뵙겠습니다.
