첫 기준선: 단순 모멘텀 전략 만들기
근거와 검증 범위 — 교육용 기준선 코드
단순 모멘텀의 신호·체결 지연·비중·비용 규칙을 코드로 제시합니다. 검증된 실제 성과 수치는 제시하지 않으며, 실제 주문·호가·부분 체결을 재현하는 운영 시스템은 아닙니다.
AI 모델의 성과를 평가하려면, 결과를 보고 바꾸지 않은 단순 규칙과 동일한 비교 조건을 먼저 고정해야 한다. 이 글에서 만드는 모멘텀 전략은 수익을 보장하는 답이 아니라, 이후 실험이 공유할 출발선이다.
지난 5편에서는 수익률만으로 전략을 판단하지 않고 최대낙폭, turnover, 비용 민감도를 함께 보는 평가표를 정했다. 이번 글에서는 그 평가표를 실제로 적용할 첫 공통 기준선, 즉 이후 AI·ML 모델이 비교 대상으로 삼을 단순 모멘텀 전략을 만든다.
처음에는 AI 모델이 더 많은 정보를 쓰면 자연스럽게 더 좋은 전략이 될 것이라고 생각했다. 하지만 복잡한 결과는 단순한 비교 대상이 없으면 해석하기 어렵다. AI가 높은 누적수익률을 보였더라도, 같은 ETF 집합·같은 기간·같은 거래비용·같은 거래시점의 단순 규칙보다 나은지 확인하지 못하면 그 숫자가 무엇을 뜻하는지 알 수 없다.
그래서 이번 글의 목표는 "가장 좋아 보이는 전략"을 찾는 것이 아니다. 누구나 같은 데이터 스냅샷과 설정으로 다시 실행할 수 있는 기준선을 먼저 고정하는 것이다. 대상 독자는 pandas 수준의 Python 기초로 처음 재현 가능한 백테스트를 만들어 보려는 개인 투자자다.
모멘텀이라는 이름 아래에는 서로 다른 전략이 있다. 상대적으로 성과가 좋은 자산을 사고 나쁜 자산을 파는 횡단면 모멘텀과, 각 자산 자신의 과거 수익률을 신호로 쓰는 시계열 모멘텀은 구분해야 한다. [S1] [S2] 이 글은 숏 포지션 없이 ETF를 보유하거나 현금으로 대기하는 규칙에 맞춰, 후자의 신호 개념을 단순화해 사용한다.
이 글의 모든 예제와 코드는 교육·연구 목적이며, 특정 ETF의 매수·매도 추천이나 미래 수익 보장이 아니다.
1. 기준선 규칙: "12개월 신호가 양수면 보유, 아니면 현금"
이 전략은 학계가 검증한 최적 해법도, 미래에 우월할 전략이라는 주장도 아니다. 이후 실험을 흔들리지 않는 조건에서 비교하기 위해 의도적으로 단순화한 프로젝트 규칙이다.
| 항목 | 이 글의 고정 규칙 |
|---|---|
| 신호 | 월말 기준 최근 12개월 수익률 |
| 매수 조건 | 최근 12개월 수익률이 양수인 ETF |
| 자산 배분 | 양수 신호 ETF를 동일가중 |
| 현금 규칙 | 양수 신호 ETF가 없으면 현금 100% |
| 초기 lookback 구간 | 첫 유효 12개월 신호 전까지 ETF 0%·현금 100%, 평가에는 포함 |
| 리밸런싱 | 월 1회 |
| 실행 시점 | 월말 신호 확인 뒤 다음 거래일부터 적용 |
| 포지션 제약 | 롱 또는 현금만, 숏·레버리지 미사용 |
| 비용 | 0·5·10·20bp one-way 민감도 시나리오 |
시계열 모멘텀 연구가 쓰는 자산군과 구현은 이 글의 ETF 롱/현금 규칙과 다르다. [S2] 따라서 12개월 lookback, 월별 리밸런싱, 양수 신호, 동일가중이 유일한 표준이거나 최적값이라고 말할 수 없다. 규칙은 다음과 같이 요약된다.
월말에 각 ETF의 최근 12개월 수익률을 계산한다. 양수인 ETF가 하나라도 있으면 → 그 ETF들을 동일가중으로 보유 양수인 ETF가 없으면 → 현금 100%월말 신호는 다음 거래일부터 적용한다.예를 들어 후보 ETF가 넷이고 월말 신호가 아래와 같다면, 양수인 A·C를 절반씩 보유하고 B·D와 현금은 0%가 된다. 네 ETF 신호가 모두 음수라면 현금이 100%다.
| ETF | 최근 12개월 수익률 | 다음 기간 목표 비중 |
|---|---|---|
| ETF_A | 양수 | 50% |
| ETF_B | 음수 | 0% |
| ETF_C | 양수 | 50% |
| ETF_D | 음수 | 0% |
여기서 중요한 것은 "양수인 ETF만 보유한다"는 규칙 자체보다, 이 규칙을 결과를 확인하기 전에 고정한다는 점이다. 백테스트를 돌린 뒤 성과가 나쁘다는 이유로 12개월을 11개월로, 월별을 주별로, 동일가중을 임의 가중으로 계속 바꾸면 기준선은 비교 기준의 역할을 잃는다.
2. 데이터와 유동성: 선언이 아니라 기록으로 확인한다
"충분히 유동적인 ETF를 사용했다"는 문장 하나로는 부족하다. ETF 거래에는 중개 수수료와 추가 거래비용이 발생할 수 있고, bid-ask spread도 잠재 수익을 낮추는 비용이다. 유동성과 거래량이 높은 ETF일수록 spread가 좁은 경향이 있다는 SEC의 설명이 있다. [S3] 마찬가지로 재현성은 코드를 공개하는 것만이 아니다. 어떤 파일을 입력으로 썼는지, 그 파일이 언제 내려받은 무엇인지, 가격 열이 무엇을 반영하는지까지 고정해야 한다. 예컨대 ETF 총수익률의 한 공시 사례는 분배금 재투자를 가정하되 중개 수수료는 포함하지 않는다고 설명한다. [S5] 즉 가격 데이터의 분배금·분할 처리와, 전략 차원의 거래비용 차감은 분리해서 기록해야 한다.
실제 백테스트마다 아래 표를 채운다.
| 기록 항목 | 내용 |
|---|---|
| ETF 목록 | 티커, 선정일, 상장일, 제외 사유 — 성과 확인 전에 확정 |
| 관측기간 | 시작일·종료일, 각 ETF의 사용 가능 시작일 |
| 공급자·원본 | 데이터 공급자 이름, 원본 URL 또는 파일 경로, 내려받은 시각(UTC) |
| 가격 열 정의 | adjusted close인지 총수익률 지수인지 |
| 분배금·분할 처리 | 공급자 정의 또는 확인 가능한 문서 |
| 결측치 규칙 | 제거·보류·재색인 여부와 이유 |
| 원본 보관 | CSV 파일명, SHA-256 해시, 코드 버전 |
| 유동성 근거 | 관측기간별 거래대금, median bid-ask spread, 거래중단 여부 |
| 생존편향 점검 | 당시 투자 가능 여부, 상장일 이후 자료만 사용했는지 |
이 글은 특정 ETF가 언제나 충분히 유동적이라고 판정하지 않는다. 관측기간별 거래대금, spread, 상장일, 거래중단 여부를 직접 확인하지 않은 상태에서는 그런 판정을 일반화할 수 없기 때문이다. 이 글의 후보군과 데이터셋에 생존편향이나 과거 투자 가능성 문제가 있는지도 아직 검증하지 못했다.
3. 시간 순서: 월말에 알게 된 정보는 다음 거래일부터 쓴다
특히 조심할 것은 정보를 알게 된 시점과 거래한 시점을 섞지 않는 것이다. 월말 종가로 최근 12개월 수익률을 계산했다면, 그 월말 종가가 확정되기 전에 이미 그 신호로 거래했다고 가정해서는 안 된다. 이 글은 일별 조정가격의 전일 종가~당일 종가 수익률을 사용하므로 시간 순서를 다음과 같이 고정한다.
월말 가격 확정 → 최근 12개월 수익률 계산 → 양수 신호 ETF 식별, 목표 비중 산출 → 신호일 뒤 EXECUTION_LAG_TRADING_DAYS번째 거래일 종가까지 기존 비중 유지 → 그 종가 뒤 비용을 차감하고 목표 비중으로 리밸런싱 → 그다음 거래일부터 새 비중으로 일별 수익률 반영EXECUTION_LAG_TRADING_DAYS = 1이면 신호일 다음 첫 거래일 종가 뒤에 리밸런싱한다. 그 실행일의 전일 종가~당일 종가 수익률은 아직 기존 비중에, 새 목표 비중은 그다음 거래일부터의 수익률에 반영된다. 이 규약은 종가만 있는 교육용 근사이며, 실제 체결가격·주문 방식·부분 체결을 재현한 결과가 아니다.
4. 비교군도 같은 조건에 둔다: 동일가중 매수 후 보유
모멘텀 전략이 무엇을 바꾸었는지 보려면 같은 자산집합·기간·데이터·비용 정의를 공유하는 비교군이 필요하다. 이 글의 비교군은 동일가중 매수 후 보유다. 같은 ETF 집합, 같은 관측 시작·종료일, 같은 조정가격 데이터를 쓰고, 시작 시점에 동일가중으로 배분한 뒤 리밸런싱하지 않는다. 전략과 비교군 모두 비용 전·후 결과를 계산하되, 비교군은 최초 진입 비용만 반영한다.
이 비교는 모멘텀과 매수 후 보유 중 어느 쪽이 우월한지 미리 정하기 위한 것이 아니다. 이후 AI 모델까지 포함해, 신호 규칙이 바뀌었을 때 무엇이 달라졌는지 같은 조건에서 읽기 위한 기준이다. 결과표를 볼 때 던질 질문은 다음과 같다.
- 전략이 결과를 바꾼 것인가, ETF 구성과 기간 선택이 바꾼 것인가?
- 비용 전과 후의 차이는 turnover와 어떤 관계가 있는가?
- 현금 보유 월이 늘어난 대가와 효과는 무엇이었는가?
- 더 낮은 최대낙폭이 더 낮은 수익률이나 더 많은 현금 비중과 함께 나타났는가?
5. 거래비용: 5편의 평가표를 이번 기준선에 고정한다
5편에서 정한 비용 민감도와 turnover 평가표는 여기서 다시 설명하지 않는다. 이번 글에서는 그 정의를 코드의 실행 순서에 고정해 이후 ML 실험에도 그대로 적용한다.
turnover_t = Σ_i |실행 직전 ETF 비중_i − 목표 비중_i|비용_t = one-way 비용률 × turnover_t × 실행 직전 순자산최초 현금 상태에서의 진입도 turnover에 포함하며, 0·5·10·20bp는 실제 비용의 공통값이 아니라 연구용 민감도 시나리오다. 실행일에는 비용을 차감한 순자산을 목표 비중으로 다시 배분하므로, 비용은 이후 비중과 복리에 계속 반영된다. 이 가중치 변화량은 공시용 portfolio turnover와 다른, 프로젝트 내부 정의다. [S8] ETF 거래에는 수수료와 거래비용이 발생할 수 있으므로 가정과 포함 범위를 공개해야 한다. [S3] [S4] 현금 수익률은 코드에서 0%로 고정하며, 이는 시장금리의 대리값이 아니라 단순화 가정이다.
6. 재현 가능한 백테스트 코드
입력은 넓은 형식의 일별 가격 CSV 하나다. date 열과 ETF별 가격 열로 구성되며, 모든 ETF 열은 분배금·분할 처리 방식을 확인한 같은 종류의 가격(모두 adjusted close이거나 모두 총수익률 지수)이어야 한다.
date,ETF_A,ETF_B,ETF_C,ETF_D2020-01-02,100.12,50.43,...2020-01-03,99.80,50.71,...6.1 실행 전에 고정할 설정
성과를 보기 전에 확정하는 값이다. 출처·내려받은 시각·가격 열 정의·결측치 규칙은 별도 메타데이터로 함께 기록한다.
from pathlib import Pathimport numpy as npimport pandas as pdCODE_VERSION = "baseline-momentum-v1.0"RAW_PRICE_FILE = Path("data/prices_adjusted_close.csv")# 성과를 보기 전에 확정한 ETF 목록UNIVERSE = ("ETF_A", "ETF_B", "ETF_C", "ETF_D")LOOKBACK_MONTHS = 12REBALANCE_FREQUENCY = "ME" # 월말(month-end)EXECUTION_LAG_TRADING_DAYS = 1 # 신호일 다음 거래일 종가 뒤 실행COST_SCENARIOS_BP = [0, 5, 10, 20] # one-way, 연구용 민감도ALLOW_SHORT = FalseCASH_RETURN_ASSUMPTION = 0.0 # 현금 잔액 일별 수익률(단순화 가정)RISK_FREE_RETURN_DAILY = 0.0 # Sharpe의 무위험수익률TRADING_DAYS_PER_YEAR = 252 # 연환산 가정# 난수는 사용하지 않는다. 같은 입력·설정이면 같은 결과가 나와야 한다.6.2 신호 → 월별 목표 비중
월말 가격으로 12개월 수익률을 계산하고, 양수 신호 ETF만 동일가중한 목표 비중을 만든다. 첫 유효 신호 전의 월말들은 ETF 0%·현금 100%로 남긴다.
def make_monthly_targets(prices: pd.DataFrame) -> pd.DataFrame: month_end = prices.resample(REBALANCE_FREQUENCY).last() momentum_12m = month_end.pct_change(periods=LOOKBACK_MONTHS, fill_method=None) targets = pd.DataFrame(0.0, index=momentum_12m.index, columns=prices.columns) for signal_date, row in momentum_12m.iterrows(): winners = row.index[row.gt(0) & row.notna()] if len(winners) > 0: targets.loc[signal_date, winners] = 1.0 / len(winners) # winners가 없으면 ETF 비중은 모두 0, 현금 100% return targets6.3 신호일 → 실행일 (다음 거래일 지연)
월말 신호를 EXECUTION_LAG_TRADING_DAYS번째 거래일 종가 뒤에 리밸런싱하도록 실행 날짜로 옮긴다. 미래 정보가 신호에 섞이지 않게 하는 지점이다.
def move_targets_to_execution_dates( prices: pd.DataFrame, monthly_targets: pd.DataFrame) -> pd.DataFrame: rows = [] for signal_date, target in monthly_targets.iterrows(): first_after = prices.index.searchsorted(signal_date, side="right") exec_pos = first_after + EXECUTION_LAG_TRADING_DAYS - 1 if exec_pos < len(prices.index): rows.append((prices.index[exec_pos], target)) if not rows: raise ValueError("실행 가능한 리밸런싱일이 없습니다.") out = pd.DataFrame( [t for _, t in rows], index=[d for d, _ in rows], columns=prices.columns ) if out.index.has_duplicates: raise ValueError("동일 실행일에 여러 목표 비중이 생성됐습니다.") return out6.4 일별 포트폴리오: 수익률 → turnover → 비용
각 거래일 종가 수익률을 리밸런싱 전 보유분에 먼저 반영하고, 실행일이면 turnover에 비례한 비용을 순자산에서 차감한 뒤 목표 비중으로 재배분한다. 비용은 이후 비중과 복리에 계속 반영된다.
def run_portfolio( daily_returns: pd.DataFrame, target_on_execution: pd.DataFrame, one_way_cost_rate: float,) -> pd.DataFrame: columns = daily_returns.columns target_lookup = {d: target_on_execution.loc[d] for d in target_on_execution.index} asset_values = pd.Series(0.0, index=columns) cash_value = 1.0 rows = [] for date, asset_return in daily_returns.iterrows(): value_at_open = asset_values.sum() + cash_value # 기존 보유분에 전일~당일 종가 수익률, 현금엔 일별 가정 수익률 asset_values = asset_values * (1.0 + asset_return) cash_value = cash_value * (1.0 + CASH_RETURN_ASSUMPTION) value_before_trade = asset_values.sum() + cash_value if value_before_trade <= 0: raise ValueError("수익률 반영 뒤 포트폴리오 가치가 0 이하입니다.") pre_trade_weights = asset_values / value_before_trade turnover = 0.0 trading_cost = 0.0 if date in target_lookup: target = target_lookup[date] if not np.isclose(target.sum(), 0.0) and not np.isclose(target.sum(), 1.0): raise ValueError("ETF 목표 비중의 합은 0 또는 1이어야 합니다.") # 최초 현금 상태에서의 진입도 포함하는 프로젝트 내부 정의 turnover = float((target - pre_trade_weights).abs().sum()) trading_cost = value_before_trade * one_way_cost_rate * turnover value_after_trade = value_before_trade - trading_cost if value_after_trade <= 0: raise ValueError("거래비용 차감 뒤 포트폴리오 가치가 0 이하입니다.") asset_values = target * value_after_trade cash_value = value_after_trade - asset_values.sum() else: value_after_trade = value_before_trade rows.append({ "date": date, "net_return": value_after_trade / value_at_open - 1.0, "turnover": turnover, "trading_cost": trading_cost, "cash_weight": cash_value / value_after_trade, }) return pd.DataFrame(rows).set_index("date")6.5 나머지 배선
전체 스크립트는 위 함수들을 다음 순서로 엮는다. 분량 관계로 본문에는 핵심만 실었고, 아래 항목은 그대로 코드로 옮기면 된다.
- 가격 로드 검증 — 날짜 오름차순·중복 없음·결측 없음·양수 가격을 확인하고, 하나라도 어긋나면 실행을 중단한다. 결측 행을 제거하거나 날짜를 재색인·보간하지 않는다.
- 비교군 목표 비중 — 시작일에
1/N한 행뿐인 DataFrame. - 비용 시나리오 반복 —
COST_SCENARIOS_BP의 각 값으로run_portfolio를 처음부터 다시 돌려 성과표 행을 만든다. - 성과 지표 — 비용 차감 후 수익률로 누적수익률·CAGR·연환산 변동성(√252)·최대낙폭·Sharpe(무위험수익률
RISK_FREE_RETURN_DAILY)·총 turnover·현금 월 수·현금 평균 비중을 계산한다. - 실험 기록 저장 — 결과표와 함께 코드 버전, 원본 CSV의 SHA-256 해시, Python·pandas·numpy 버전, 전체 설정값을 JSON으로 남긴다. 재현 대조용이다.
이 코드는 교육용 기준선이다. 실제 운영을 위한 주문 시스템이나 체결 엔진이 아니며, 시가·호가·부분 체결·세금·시장충격을 직접 모델링하지 않는다.
7. 성과표 읽는 법: "누가 이겼나"보다 "무엇을 같은 조건에서 계산했나"
이 글에는 검증되지 않은 실제 성과 수치나 "AI보다 낫다"는 결론을 넣지 않는다. 독자가 고정한 데이터 스냅샷과 코드로 아래 형태의 표를 직접 생성한다.
| 전략 | 비용 | 누적수익률 | CAGR | 연환산 변동성 | 최대낙폭 | Sharpe | 총 turnover | 현금 월 수 | 현금 평균 비중 |
|---|---|---|---|---|---|---|---|---|---|
| 단순 모멘텀 | 0·5·10·20bp | … | … | … | … | … | … | … | … |
| 동일가중 매수 후 보유 | 0·5·10·20bp | … | … | … | … | … | … | … | … |
표 아래에는 계산 조건을 함께 고정한다. 같은 수치라도 아래가 다르면 비교가 성립하지 않는다.
- 전략·비교군 공통 평가 시작일·종료일 (공통 거래일 파일의 첫 행·마지막 행)
- 초기 lookback 처리: 첫 유효 신호 전까지 현금 100%이며 평가에서 제외하지 않음
- 현금 월 수: 각 달 마지막 거래일 현금 비중이 0보다 큰 달의 수, 초기 현금 구간 포함
- 사용한 ETF 목록 / 가격 열 정의 / 원본 파일 SHA-256 / 코드 버전 / 수익률 빈도
- CAGR·변동성·최대낙폭·Sharpe 계산식과 연환산 방식,
TRADING_DAYS_PER_YEAR - turnover 계산식, 최초 진입 포함 여부, one-way 비용의 해석, 비용 차감 시점
- 현금 수익률 가정
CASH_RETURN_ASSUMPTION, 결측치 규칙
Sharpe ratio의 계산 가정과 단독 판정의 한계는 5편에서 다뤘다. [S7] 이 표는 고정한 데이터 스냅샷과 가정에서 계산한 과거 요약값일 뿐이다.
8. 검증 체크리스트: 단순한 전략일수록 구현 오류를 의심한다
단순 모멘텀의 어려움은 규칙이 많다는 데 있지 않다. 작은 시점 오류, 데이터 처리 차이, 비용 정의 차이가 성과를 바꾼다는 데 있다. 코드를 실제 데이터에 붙이기 전에 아래를 확인한다.
- ETF 목록과 선정 기준을 성과 확인 전에 정했는가?
- 각 ETF가 백테스트 시작 시점에 실제로 상장돼 있었는가?
- 가격 열이 조정가격인지 총수익률인지, 분배금·분할 처리 방식을 기록했는가?
- 원본 파일과 SHA-256 해시, 코드 버전, 설정값을 결과와 함께 저장했는가?
- 월말 신호가 다음 거래일부터 적용되며, 신호 계산에 미래 가격이 섞이지 않았는가?
- 양수 신호가 없을 때 현금 비중이 100%가 되는가?
- 최초 진입을 turnover와 비용에 포함했는가?
- 전략과 비교군이 같은 데이터·기간·비용 정의로, 비용 전·후를 같은 지표로 계산하는가?
- 같은 입력·설정으로 두 번 실행했을 때 같은 결과가 나오는가?
작은 인공 입력으로 다음도 확인할 수 있다. ETF가 하나뿐이고 신호가 계속 양수면 100% 비중을 유지하는가, 모든 신호가 음수인 월엔 현금이 100%가 되는가, 현금에서 ETF로 이동할 때 turnover와 비용이 발생하는가, 매수 후 보유는 최초 진입 뒤 turnover가 0인가.
9. 나의 판단 변화: 막연한 기대에서 고정된 비교 조건으로
| 단계 | 기록 |
|---|---|
| 이전 생각 | AI 모델이 더 많은 정보를 쓰면 단순 규칙보다 좋은 결과를 낼 가능성이 높다고 막연히 생각했다. |
| 이번에 확인한 것 | 단순한 규칙도 데이터 열 정의, 월말 신호, 실행 지연, 결측치, turnover, 비용 차감 시점을 정확히 맞추지 않으면 비교 기준이 될 수 없다. |
| 현재 판단 | 먼저 누구나 다시 실행할 수 있는 단순 기준선을 만들고, 이후 AI 모델도 같은 자산집합·데이터·비용·평가표 아래에서 비교한다. |
| 아직 모르는 것 | 이 기준선이나 이후 AI 모델이 미래에 우월할지, 실제 체결비용을 감당할 수 있을지는 백테스트만으로 알 수 없다. |
10. 이 기준선이 답하지 못하는 질문
기준선을 고정하면 비교는 더 정직해지지만, 백테스트의 불확실성이 사라지지는 않는다.
- 횡단면 모멘텀과 시계열 모멘텀은 신호와 포트폴리오 구성이 다르므로, 같은 이름이라는 이유로 결과를 섞어 해석하면 안 된다. [S1] [S2]
- 고정 bp 비용의 체결 한계는 5편에서 정리했다. 여기서는 그 한계를 해결했다고 주장하지 않고, 같은 비용 시나리오를 기준선과 이후 ML 실험에 동일하게 적용할 뿐이다. [S3] [S4]
- 사용할 가격 공급자의 조정가격 산식·수정 이력·상장폐지 ETF 포함 여부를 하나의 데이터셋으로 검증하지 못했다. 이 글의 후보군이 과거 각 시점에 투자 가능했는지도 확인하지 못했다.
- 다음 거래일 종가 뒤 리밸런싱은 시간 순서를 고정하기 위한 근사이며, 실제 체결가격·주문 방식·부분 체결을 재현한 모형이 아니다.
- 세금·계좌 조건·거래소·주문 규모·시장충격은 이 조사에서 개별 사례별로 검증하지 못했다.
- 과거 성과표는 미래 수익률을 보장하지 않으며 특정 ETF의 매수·매도 근거가 아니다.
특히 여러 규칙·기간·ETF 조합을 반복해 시험한 뒤 가장 좋아 보이는 조합만 채택하면, 과거 데이터에 맞춘 결과를 발견했을 위험이 커진다. [S6] 그래서 다음 ML 실험에서도 성과가 좋아 보인다는 이유만으로는 아래를 바꾸지 않는다.
| 유지할 것 | 바꿀 것 (예측 모델만) |
|---|---|
| ETF 집합, 데이터 스냅샷(파일·해시·조정 방식), 관측기간 | 모델 입력 변수 |
| 월별 리밸런싱, 다음 거래일 실행, 롱/현금 제약 | 학습 구간과 검증 구간 |
| turnover 정의와 0·5·10·20bp 비용 시나리오 | 재학습 주기 |
| 성과표 지표, 비교군(매수 후 보유 + 이 기준선) | 신호를 점수·확률로 바꾸는 방식 |
결론: 좋은 기준선은 화려한 전략이 아니라 고정된 비교 조건이다
이번 글의 기준선은 한 문장으로 요약된다.
월말 기준 최근 12개월 수익률이 양수인 ETF만 동일가중으로 보유하고, 양수 신호가 없으면 현금으로 둔다.
이 규칙은 최적화된 답도, 미래 성과를 약속하는 전략도 아니다. 그 가치는 이후 AI 모델이 같은 데이터·비용·거래시점·위험 평가표 아래에서 무엇을 실제로 바꾸는지 확인하게 해 준다는 데 있다. 복잡한 모델의 출발점은 복잡한 설명이 아니라, 누구나 다시 실행할 수 있는 단순한 기준선이다.
이 글의 모든 예제와 코드는 교육·연구 목적이며 투자 조언이 아니다. 특정 ETF의 매수·매도 추천이나 수익 보장을 제공하지 않는다.
Sources
- [S1] Returns to Buying Winners and Selling Losers: Implications for Stock Market Efficiency | Narasimhan Jegadeesh and Sheridan Titman; The Journal of Finance | March 1993 | https://onlinelibrary.wiley.com/doi/abs/10.1111/j.1540-6261.1993.tb04702.x ↩
- [S2] Time series momentum | Tobias J. Moskowitz, Yao Hua Ooi, and Lasse Heje Pedersen; Journal of Financial Economics | May 2012 | https://doi.org/10.1016/j.jfineco.2011.11.003 ↩
- [S3] Updated Investor Bulletin: Exchange-Traded Funds (ETFs) | U.S. Securities and Exchange Commission, Office of Investor Education and Advocacy | 2023-02-23 | https://www.investor.gov/introduction-investing/general-resources/news-alerts/alerts-bulletins/investor-bulletins-24 ↩
- [S4] GIPS® Standards Handbook for Firms | CFA Institute and Global Investment Performance Standards | November 2020 | https://www.gipsstandards.org/standards/gips-standards-for-firms/gips-standards-handbook-for-firms/ ↩
- [S5] State Street® SPDR® S&P 500® ETF Trust Prospectus | State Street Global Advisors Trust Company and PDR Services LLC, filed with the U.S. Securities and Exchange Commission | 2026-01-26 | https://www.sec.gov/Archives/edgar/data/884394/000119312526023648/d935960d497.htm ↩
- [S6] The Probability of Backtest Overfitting | David H. Bailey, Jonathan M. Borwein, Marcos López de Prado, and Qiji Jim Zhu | 2015-02-27 | https://www.davidhbailey.com/dhbpapers/backtest-prob.pdf ↩
- [S7] The Sharpe Ratio | William F. Sharpe; Stanford University reprint of The Journal of Portfolio Management article | Fall 1994 | https://web.stanford.edu/~wfsharpe/art/sr/SR.htm ↩
- [S8] Form N-1A Registration Statement — Voya VACS Index Series S Portfolio | Voya Investors Trust, filed with the U.S. Securities and Exchange Commission | 2026-05-01 | https://www.sec.gov/Archives/edgar/data/837276/000083727626000042/f44756d1.htm ↩
오류 제보·의견 보내기
글 제목과 주소가 포함된 메일 초안을 엽니다. 내용과 받는 사람을 확인한 뒤 보내주세요.
받는 사람: [email protected]
메일 앱에서 작성메일 앱이 열리지 않으면 아래 내용을 복사해 평소 쓰는 이메일에 붙여 넣으세요.
관련 글
퀀트·데이터 연구 거래비용을 넣어도 결론은 같을까: 합성 포트폴리오의 회계와 위험경로 검사
합성 포트폴리오에 거래비용을 적용해 매수대금과 현금 장부를 점검합니다. 종료수익, 회전율, 최대낙폭이 각각 무엇을 보여주는지 구분합니다.
퀀트·데이터 연구 첫 백테스트는 수익률보다 수량부터: 매수 후 보유와 모멘텀의 한 구간 회계
가상의 세 자산으로 매수 후 보유와 모멘텀 전략의 수량, 현금, 종료평가액을 대조합니다. 실제 시장 성과를 비교하기 전 공통 회계 규칙을 점검합니다.