백테스트-MDD 구하는 방법(pandas)

 안녕하세요, 지난 포스팅에서 우리는 각종 수익률(월별 수익률, 누적 수익률, 월별 Log 수익률, 누적 Log 수익률)에 대해서 알아보았습니다. 그리고 이번 포스팅에서는 수익률만큼이나 중요한 MDD를 구하는 방법을 알아보도록 하겠습니다.

 

 MDD(Max-DrawDown)란 전략을 운영하는 기간 중 최고점 대비 최대 낙폭을 의미합니다. 크고 작은 낙폭 중 가장 큰 낙폭을 MDD라고 하는 것이죠. 예를 들어 LAA 전략에서 보여드렸던 수익률 그래프를 다시 한 번 보도록 하겠습니다.

 

LAA 전략 누적 Log 수익률 그래프

 

 이 그래프에서도 크고 작은 낙폭들이 보이고, 그 중 나름 큰 낙폭 세 지점을 찾아보았습니다. 그 중 가장 낙폭이 커보이는 것은 (1)번 구간 같아 보이네요. 그렇다면 LAA 전략의 MDD는 (1) 지점에서 최고점 대비 최저점의 낙폭이 됩니다.

 

 MDD가 중요한 이유는 심리적 요인에 때문입니다. 아무리 연복리 수익률이 높은 전략이라고 하더라도, MDD가 엄청나게 크다면 전략을 끝까지 유지하지 못하는 경우가 많습니다. 앞으로도 그런 수익률이 끝까지 보장된다는 확신이 없는 상태에서 자산이 반토막 난다면, 보통 사람들은 "이 전략은 더 이상 유효하지 않은 것 같아"하고 전략 운영을 중단해버리고 맙니다. 그리고 퀀트 투자에서는 '자신은 다르다, 특별하다, 견딜 수 있다'는 생각은 버리는게 좋습니다🤣 그렇기 때문에 애초에 MDD가 낮은 전략을 잘 선택하는게 중요하겠죠.

 

 이제 개념적으로 MDD가 무엇인지는 이해가 되셨을테니 MDD를 어떻게 구할 수 있는지 소스코드를 살펴보도록 하겠습니다.

 

 MDD를 구하기 위해서 우리는 가상의 잔액 필드(BALANCE)와, 누적 기간별 낙폭 필드(DD)를 추가합니다.

 

# 가상의 잔고 필드와 낙폭 필드 추가
col_list_BAL = [col+'_BAL' for col in df_PRICE[TICKER].columns]
col_list_DD = [col+'_DD' for col in df_PRICE[TICKER].columns]

df_PRICE[col_list_BAL] = (1+df_PRICE[col_list_P]/100).cumprod()
df_PRICE[col_list_DD] = -(df_PRICE[col_list_BAL].cummax() - df_PRICE[col_list_BAL]) / df_PRICE[col_list_BAL].cummax()

# 백분율을 %로 전환
df_PRICE[col_list_BAL+col_list_DD] = df_PRICE[col_list_BAL+col_list_DD] * 100

 

 가상의 잔액 필드는 첫 투자를 100으로 시작해서 기간별 수익률을 곱해서 얼마가 되는지를 확인합니다. 지난 포스팅에서도 활용했었던 누적곱 cumprod() 함수와, 누적 최대값을 찾는 cummax() 함수를 사용하였습니다.

 

 위의 소스 코드 중 이해가 잘 되지 않는 부분이 있다면 댓글로 문의해주세요!

 

결과 DataFrame)

가상의 잔고 필드와, DD 필드 추가 결과

 

 아래와 같이 낙폭 필드(DD)의 최대값을 구해보도록 하겠습니다. (편의상 -로 했기 때문에 실제로는 min() 함수를 사용합니다)

 

 그 결과 위험 자산인 주식과 금(SPY, QQQ, IWD, GLD)의 경우 경우 약 40~50%까지 낙폭이 발생하고, 안전 자산인 채권(SHY, IEF)는 1~7% 낙폭이 최대임을 알 수 있습니다.

 

자산별 DD 그래프

 

 역시나 주식의 낙폭이 가장 컸던 시기는 2008년 이후임을 알 수 있습니다. 

 


공감댓글, 공유는 큰 힘이 됩니다!

도움이 되셨다면 널리널리 알려주세요😉

 

 

 

 

댓글()