1. 산술 수익률의 비대칭성(50% 손실 후 원금 회복에는 100% 수익 필요)을 이해합니다.
2. 금융 공학 및 퀀트 분석에서 로그 수익률(Log Return)을 사용하는 이유(시간 가법성, 정규성)를 배웁니다.
3.
numpy를 활용해 로그 수익률을 계산하고, 누적 수익률을 검증하는 코드를 구현합니다.투자를 시작할 때 가장 먼저 마주하는 숫자는 바로 '수익률'이에요. 빨간불이 들어오면 기분이 좋고, 파란불이 들어오면 우울해지죠.
그런데 여러분, 혹시 이런 계산을 해보신 적 있나요?
"100만 원짜리 주식이 50% 올랐다가, 다시 50% 떨어지면 얼마가 될까요?"
직관적으로는 +50%와 -50%가 상쇄되어 원금 100만 원이 될 것 같죠? 하지만 계산기를 두드려보면 충격적인 결과가 나옵니다.
- 100만 원 × 1.5 (+50%) = 150만 원
- 150만 원 × 0.5 (-50%) = 75만 원
무려 25%나 손해를 보게 돼요. 이것이 바로 '산술 수익률(Arithmetic Return)의 비대칭성'이에요. 50%가 떨어지면 원금을 회복하기 위해 50%가 아니라 100%가 올라야 하죠.
오늘은 이 수익률의 착시를 해결하고, 금융 공학이나 머신러닝에서 표준으로 사용하는 '로그 수익률(Log Return)'에 대해 알아볼게요.
산술 수익률 vs 로그 수익률
우리가 MTS에서 보는 일반적인 수익률은 산술 수익률이에요. 계산은 쉽지만 치명적인 단점이 있죠. 바로 '더하기가 안 된다'는 점이에요.
오늘 10% 오르고 내일 10% 올랐다고 해서, 이틀간 총수익률이 20%가 아니죠? 복리 효과 때문에 곱하기 연산을 해야 해요. 기간이 길어질수록 계산은 복잡해지고, 통계적 분포도 찌그러지게 됩니다.
반면, 로그 수익률은 마법 같은 성질을 가져요. 자연로그(ln)를 씌우면 '곱하기가 더하기로' 변하거든요.
이 수식의 의미는 간단해요. "오늘 가격의 로그값에서 어제 가격의 로그값을 빼면 수익률이 나온다"는 뜻이에요.
왜 로그 수익률을 써야 할까요?
- 시간 가법성 (Time Additivity): 1일 차 수익률, 2일 차 수익률... n일 차 수익률을 그냥 더하기만 하면 총수익률이 나와요.
- 대칭성: 주가가 100원에서 50원이 되면 로그 수익률은 약 -0.693, 다시 100원이 되면 +0.693이에요. 절댓값이 같아서 상승과 하락의 힘을 동일하게 비교할 수 있죠.
- 정규분포 근사: 주가 자체는 0 아래로 내려갈 수 없어서 분포가 한쪽으로 쏠려 있지만, 로그 수익률은 정규분포에 가까운 형태를 띱니다. 그래서 통계 분석이나 머신러닝 모델에 넣을 때 훨씬 유리해요.
파이썬 구현: Numpy로 로그 수익률 계산하기
이론은 머리가 아프니 코드로 직접 확인해 보죠. 수학 연산에 최적화된 numpy 라이브러리를 사용하면 아주 간단해요.
Step 1: 데이터 준비 및 라이브러리 임포트
먼저 numpy를 불러오고 삼성전자 데이터를 준비합니다.
import pandas as pd
import numpy as np
import yfinance as yf
# 삼성전자 데이터 가져오기
df = yf.download("005930.KS", period="1y", progress=False)
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.droplevel(1)
# 수정주가(Adj Close) 선택
if 'Adj Close' in df.columns:
df = df[['Adj Close']].rename(columns={'Adj Close': 'Price'})
else:
df = df[['Close']].rename(columns={'Close': 'Price'})
Step 2: 산술 수익률 vs 로그 수익률 계산
일반 수익률(pct_change)과 로그 수익률(np.log)을 각각 계산해 봅니다.
# 1. 산술 수익률 (Simple Return)
# 공식: (현재가 - 과거가) / 과거가
df['Simple_Return'] = df['Price'].pct_change()
# 2. 로그 수익률 (Log Return)
# 공식: ln(현재가 / 과거가)
# shift(1)은 하루 전 데이터를 의미
df['Log_Return'] = np.log(df['Price'] / df['Price'].shift(1))
Step 3: 누적 수익률 비교 (가법성 확인)
로그 수익률의 가장 큰 장점인 '더하기'를 확인해 볼게요. cumsum()(누적 합) 함수를 사용했을 때, 로그 수익률은 정확히 최종 수익률을 반영하지만, 산술 수익률을 그냥 더하면 엉터리 값이 나옵니다.
# 산술 수익률의 누적 (단순 합산 -> 오차 발생)
print("산술 수익률 단순 합:", df['Simple_Return'].sum())
# 로그 수익률의 누적 (단순 합산 -> 정확함)
print("로그 수익률 단순 합:", df['Log_Return'].sum())
# 실제 총 수익률 검증 (마지막 가격 / 첫 가격 - 1)
total_return = (df['Price'].iloc[-1] / df['Price'].iloc[0]) - 1
print("실제 총 수익률:", total_return)
# 결론: 로그 수익률의 합을 지수함수(exp)로 되돌리면 실제 총 수익률과 일치함
print("로그 합의 변환:", np.exp(df['Log_Return'].sum()) - 1)
어때요? 로그 수익률을 다 더한 다음 다시 지수(exp)를 취하니 실제 수익률과 정확히 일치하죠?
이처럼 데이터를 길게 연결해서 분석하거나, 변동성을 예측하는 모델을 만들 때는 반드시 로그 수익률을 사용해야 데이터의 왜곡을 막을 수 있답니다.
이제 수익률 계산법까지 마스터했네요. 그런데 차트를 보다 보면 주가가 너무 들쑥날쑥해서 추세를 보기 어려울 때가 있죠? 다음 시간에는 이 거친 파도를 부드럽게 다림질해 주는 '평활화(Smoothing)와 이동평균'의 진짜 원리에 대해 알아볼게요.
전체 소스 코드 확인하기 (Click)
import pandas as pd
import numpy as np
import yfinance as yf
# 1. 데이터 가져오기 (삼성전자)
df = yf.download("005930.KS", period="1y", progress=False)
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.droplevel(1)
# 수정주가(Adj Close) 선택
if 'Adj Close' in df.columns:
df = df[['Adj Close']].rename(columns={'Adj Close': 'Price'})
else:
df = df[['Close']].rename(columns={'Close': 'Price'})
# 2. 산술 vs 로그 수익률 계산
df['Simple_Return'] = df['Price'].pct_change()
df['Log_Return'] = np.log(df['Price'] / df['Price'].shift(1))
# 3. 누적 수익률 검증
print("산술 수익률 단순 합 (오류):", df['Simple_Return'].sum())
print("로그 수익률 단순 합 (정상):", df['Log_Return'].sum())
# 실제 총 수익률 (Price_End / Price_Start - 1)
total_return = (df['Price'].iloc[-1] / df['Price'].iloc[0]) - 1
print("실제 총 수익률:", total_return)
print("로그 합의 변환(exp):", np.exp(df['Log_Return'].sum()) - 1)
'시스템 트레이딩 소개' 카테고리의 다른 글
| 주가를 맞출 수 있다는 '지식 착각'과 기계적 대응의 중요성 (1) | 2026.03.17 |
|---|---|
| 시스템 트레이딩 단점과 3가지 착각 (0) | 2026.03.16 |
| 초보자를 위한 주식 자동매매 시작하는 법 (3가지 필수 준비물) (0) | 2026.03.16 |
| 똑똑한 사람도 주식판에서 망하는 과학적 이유 (0) | 2026.03.15 |
| 주식 자동매매로 뇌동매매를 극복하는 5단계 완벽 가이드 (0) | 2026.03.15 |