거래비용을 넣어도 결론은 같을까: 합성 포트폴리오의 회계와 위험경로 검사
근거와 검증 범위 — 합성 계산·제공된 실행 기록
SYN_A/B/C 합성 입력으로 비용·회전율·낙폭 회계를 설명합니다. 본문에 인용한 PASS는 프로젝트 제공 실행 기록이며 독립 재실행 결과가 아닙니다. 실제 ETF 성과나 브로커 비용을 검증한 결과로 해석할 수 없습니다.
4편에서 수량과 종료평가액을 맞췄다면, 다음 질문은 그 수량을 사는 데 비용이 들 때도 장부가 정확히 닫히는가다. 이번 글은 같은 SYN_A/B/C 합성 입력에 거래비용을 더해 종료수익, 회전율, 최대낙폭이 각각 다른 질문에 답한다는 점을 확인한다.
1~4편에서 미국 ETF 연구 후보로 언급한 SPY·IEF·GLD의 실제 가격 원자료, 거래일, 배당·분할 자료는 아직 확보되지 않았다. 따라서 이 글은 실제 ETF 시장백테스트나 실거래 성과 분석이 아니다. 비용률도 실제 브로커 수수료의 추정치가 아니라, 회계 규칙이 바뀔 때 결과가 어떻게 달라지는지 보는 민감도 가정이다.
이번 합성 입력은 4편과 같다. SYN_A/B/C의 실행가격은 모두 100, 종료평가가격은 각각 120·90·120, 초기자산은 1000이다. 매수 후 보유는 최초에 세 자산을 동일가중으로 매수한 뒤 수량을 고정한다. 모멘텀은 양수 신호를 받은 SYN_A만 보유한다. 여기서 말하는 종료가치는 보유분의 평가액이며, 종료 시 전량 매도하는 청산비용은 포함하지 않는다.
비용률은 초기자산이 아니라 실제 매수대금에 적용한다
비용률을 bp 기준으로 다음처럼 둔다.
c = bp / 10000초기자산 1000을 매수대금과 거래비용으로 정확히 모두 사용하려면, 실제 매수대금 N은 다음 예산 제약을 만족해야 한다.
N + cN = 1000N = 1000 / (1 + c)비용 = cN즉 N + 비용 = 1000이다. 비용을 단순히 c × 1000으로 계산한 뒤 초기자산에서 빼는 방식은 편리한 근사일 수 있지만, 비용까지 포함해 예산을 정확히 소진하는 이 식과는 구분해야 한다.
예를 들어 10bp는 c = 0.001이다. 이때 실제 매수대금은 1000 / 1.001이고, 비용은 그 매수대금의 0.1%다. 분수 기반 계산은 이런 항등식을 반올림 오차 없이 검사하는 데 적합하다. Python 표준 라이브러리의 Fraction은 유리수 산술을 제공한다. [S1]
from fractions import Fraction as Finitial_cash = F(1000)cost_bp = F(10)c = cost_bp / F(10000)notional = initial_cash / (F(1) + c)entry_cost = c * notionalassert notional + entry_cost == initial_cash여기서 notional은 실제 매수대금, entry_cost는 최초 진입비용이다. 이 작은 검사는 전략의 좋고 나쁨을 판단하지 않는다. 대신 비용을 어느 금액에 곱했고, 현금이 남거나 초과 사용되지 않았는지를 확인한다.
같은 최초 진입비용에서는 순위가 유지된다
비용이 없었던 4편의 종료평가액은 매수 후 보유 1100, 모멘텀 1200이었다. 최초 진입비용만 적용하면 최초에 실제로 매수한 금액이 1000 / (1+c)로 줄어든다. 따라서 종료평가액도 같은 비율로 줄어든다.
매수 후 보유 종료평가액 = 1100 / (1 + c)모멘텀 종료평가액 = 1200 / (1 + c)수익률 = 종료평가액 / 1000 - 1| 비용 시나리오 | 초기비용 | 매수 후 보유 종료평가액 | 모멘텀 종료평가액 |
|---|---|---|---|
| 0bp | 0 | 1100 | 1200 |
| 5bp | 0.49975012493753124 | 1099.4502748625687 | 1199.400299850075 |
| 10bp | 0.999000999000999 | 1098.901098901099 | 1198.8011988011988 |
| 20bp | 1.996007984031936 | 1097.804391217565 | 1197.6047904191616 |
이 합성 사례에서는 두 전략이 모두 같은 1 / (1+c) 인수로 축소된다. 따라서 0·5·10·20bp 어느 시나리오에서도 모멘텀의 종료평가액이 매수 후 보유보다 크다는 순서는 바뀌지 않는다.
그렇다고 비용이 결론을 바꾸지 않는다는 일반 법칙이 생기는 것은 아니다. 전략마다 거래 횟수, 리밸런싱 시점, 매수·매도 방향, 비용률, 보유 현금이 다르면 비용의 영향도 달라진다. 이번 결과는 같은 최초 진입비용만 적용한 특정 합성 장부의 산술 검사일 뿐이다. 특히 표의 값은 청산 후 현금이 아니라, 청산비용을 아직 빼지 않은 종료 시점 보유분의 평가액이다.
프로젝트 제공 실행기록에는 2026-09-18 표준 Python fractions로 합성 비용검사를 실행해 PASS한 것으로 남아 있다. 다만 현재 조사 환경에서는 이를 독립 재실행하지 못했으므로, 그 PASS는 프로젝트 제공 기록으로만 취급한다. Fraction을 이용한 산식 표현 자체는 표준 라이브러리 문서로 확인할 수 있다. [S1]
완전교체에서는 회전율 정의를 먼저 적는다
최초 진입과 달리, 기존 자산을 전액 팔고 다른 자산을 전액 사는 완전교체에는 매도와 매수가 모두 있다. 거래 직전 자산이 1000이고, 동일가격에서 완전교체하며 비용률이 c라고 가정해 보자.
매도대금은 1000이다. 매도비용과 새 자산 매수비용을 모두 반영한 실제 매수대금은 다음과 같다.
매도대금 = 1000매수대금 N = 1000 × (1 - c) / (1 + c)총비용 = c × (1000 + N)N + 총비용 = 1000이 글의 프로젝트 회전율은 비용 민감도 검사용으로 다음처럼 정의한다.
turnover = (매도대금 + 매수대금) / 거래직전자산따라서 매도와 매수를 모두 분자에 넣고, 1/2 계수는 사용하지 않는다. 현금 자체도 매매대금으로 세지 않는다. 10bp에서는 총비용과 회전율이 모두 정확히 2000 / 1001이며, 1.998001998은 표시용 반올림값이다.
from fractions import Fraction as Fdef entry_notional(cash, cost_rate): return cash / (F(1) + cost_rate)def switch_notional(value_before_trade, cost_rate): return value_before_trade * (F(1) - cost_rate) / (F(1) + cost_rate)cash = F(1000)c = F(10, 10000)entry = entry_notional(cash, c)assert entry + c * entry == cashbuy = switch_notional(cash, c)cost = c * (cash + buy)turnover = (cash + buy) / cashassert buy + cost == cashassert cost == F(2000, 1001)assert turnover == F(2000, 1001)이 회전율을 펀드 공시의 포트폴리오 회전율과 혼동하면 안 된다. 미국 펀드 공시의 회전율은 최근 회계연도 평균 포트폴리오 가치 등을 기준으로 하는 별도 지표다. 높은 회전율은 거래비용 및 과세와 연관될 수 있지만, 공시 지표의 값을 이 프로젝트 비용식에 그대로 대입할 수는 없다. [S3]
또한 거래비용은 수수료만 뜻하지 않을 수 있다. 스프레드, 시장충격, 기회비용도 비용 구성요소로 논의된다. [S4] 실제 자료를 연결할 때는 c에 무엇을 포함했는지 명시하고, 이미 포함한 스프레드나 슬리피지를 별도 항목으로 다시 차감하지 않도록 해야 한다.
종료수익이 같아도 손실경로는 다르다
종료가치만 보면 두 전략이나 두 포트폴리오를 너무 쉽게 같은 위험으로 오해할 수 있다. 다음은 4편의 전략과 무관한, 손실경로 개념만 설명하기 위한 별도 합성 경로다.
| 합성 경로 | 종료수익 | 관측점 최대낙폭 |
|---|---|---|
[1000, 1050, 1100] | 10% | 0% |
[1000, 800, 1100] | 10% | -20% |
두 경로는 모두 1100 / 1000 - 1 = 10%로 끝난다. 하지만 첫 번째 경로는 각 관측점에서 이전 고점보다 낮아지지 않아 관측점 최대낙폭이 0%다. 두 번째 경로는 1000에서 800으로 하락하므로 관측점 최대낙폭이 -20%다.
최대낙폭은 이전 고점에서 뒤이은 저점까지의 하락을 측정하며, 분석 기간과 관측 빈도에 따라 값이 달라질 수 있다. [S5] 따라서 위의 -20%는 일별 가격을 복원한 실제 전략 낙폭이 아니라, 제시한 세 관측점에서 계산한 값이다. 종료수익은 “어디에 도착했는가”를, 최대낙폭은 “어떤 손실을 지나왔는가”를 묻는다.
아직 CAGR·연환산 변동성·Sharpe를 계산하지 않는 이유
현재 합성 예시는 날짜가 없는 한 구간의 실행가와 종료평가가만 제공한다. 실제 거래일, 일별 관측 간격, 충분한 수익률 표본, 기준수익률, 연환산계수, 표본표준편차 산식이 정해져 있지 않다.
그래서 CAGR, 연환산 변동성, Sharpe 수치를 제시하지 않는다. 사후 Sharpe는 차익수익률의 평균과 표준편차를 사용하므로, 단일 종료가치만으로는 필요한 수익률 표본을 만들 수 없다. [S6] 수치를 생략하는 것은 계산을 덜 한 것이 아니라, 자료와 가정이 없는 지표를 그럴듯하게 만들지 않기 위한 범위 통제다.
실제 데이터를 확보한 뒤에는 원자료 검사, 날짜 정렬, 신호일·실행일·평가일 매핑, 일별 또는 명시한 주기의 수익률 생성, 기준수익률과 연환산계수 선택, 표본표준편차 산식 문서화가 선행되어야 한다. 그때 종료수익과 최대낙폭을 같은 일별 경로에서 함께 계산할 수 있다.
6편의 모델 비교를 위한 준비
다음 6편에서 로지스틱 비교로 넘어가려면, 먼저 실제 시계열 자료와 시간순 검증 설계가 필요하다. 가격 원자료와 날짜를 확인하고, 비용 구성요소와 회전율 정의를 고정하며, 수익률과 손실경로를 같은 관측 빈도로 계산해야 한다.
시계열 예측에서는 자기상관과 비정상성 때문에 일반적인 교차검증을 단순 적용하기 어렵고, 표준 K-fold의 타당성도 오차 구조를 포함한 가정에 좌우된다. [S7] 따라서 임의 셔플이나 완료된 월별 재학습을 주장하기보다, 시간 순서를 보존한 검증 규칙을 먼저 설계해야 한다.
이 글의 SYN_A/B/C와 비용 시나리오는 교육·연구용 합성 회계 예시다. 실제 SPY·IEF·GLD의 성과나 실제 거래비용, 특정 전략의 우위를 뜻하지 않으며, 특정 ETF의 매수·매도를 권유하거나 수익을 보장하지 않는다.
Sources
- [S1] fractions — Rational numbers | Python Software Foundation | 2026-09-16 | https://docs.python.org/3.14/library/fractions.html ↩
- [S3] Form N-1A | U.S. Securities and Exchange Commission | 2023-12-11 | https://www.sec.gov/files/form-n-1a.pdf ↩
- [S4] Request for Comments on Measures To Improve Disclosure of Mutual Fund Transaction Costs | U.S. Securities and Exchange Commission | 2003-12-19 | https://www.sec.gov/rules-regulations/2003/12/request-comments-measures-improve-disclosure-mutual-fund-transaction-costs ↩
- [S5] Sculpting Investment Portfolios: Maximum Drawdown and Optimal Portfolio Strategy | Prasad Ramani, CFA / CFA Institute | 2013-02-12 | https://blogs.cfainstitute.org/blog/2013/02/12/sculpting-investment-portfolios-maximum-drawdown-and-optimal-portfolio-strategy/ ↩
- [S6] The Sharpe Ratio | William F. Sharpe / Stanford University | Fall 1994 | https://web.stanford.edu/~wfsharpe/art/sr/sr.htm ↩
- [S7] A note on the validity of cross-validation for evaluating autoregressive time series prediction | Christoph Bergmeir, Rob J. Hyndman, Bonsoo Koo | 2018-01-01 | https://talks.robjhyndman.com/publications/cv-time-series/ ↩
오류 제보·의견 보내기
글 제목과 주소가 포함된 메일 초안을 엽니다. 내용과 받는 사람을 확인한 뒤 보내주세요.
받는 사람: [email protected]
메일 앱에서 작성메일 앱이 열리지 않으면 아래 내용을 복사해 평소 쓰는 이메일에 붙여 넣으세요.
관련 글
퀀트·데이터 연구 수익률보다 먼저 봐야 할 것: 손실 경로와 거래비용
같은 최종수익률이라도 손실 경로와 거래비용에 따라 평가가 달라집니다. 가상 예제로 변동성, 최대낙폭, Sharpe와 회전율을 함께 읽는 방법을 설명합니다.
퀀트·데이터 연구 첫 기준선: 단순 모멘텀 전략 만들기
AI·ML 모델과 비교하기 전에, 결과를 보고 바꾸지 않을 단순 롱/현금 모멘텀 기준선을 먼저 고정한다. 12개월 신호·월별 리밸런싱·동일가중·거래비용 시나리오를 재현 가능한 Python 코드로 만드는 법.