백테스팅 기본기: strategy() 함수를 이용한 이동평균 교차(Cross) 전략 수익률 검증

안녕하세요, 여러분! 👋 주식이나 코인, 선물 차트를 보실 때 가장 먼저 켜보는 지표가 혹시 무엇인가요? 아마 열이면 아홉은 이동평균선(Moving Average, MA)을 꼽으실 겁니다.

그중에서도 단기 이평선이 장기 이평선을 위로 뚫고 올라가는 ‘골든크로스(Golden Cross)’가 나오면 가슴이 두근거리며 "앗, 매수 타이밍인가?!" 하고 설레고, 반대로 아래로 꺾이는 ‘데드크로스(Dead Cross)’가 뜨면 덜컥 겁부터 먹게 되죠. 투자자들 사이에서 가장 친숙하면서도 클래식한 매매법이 아닐까 싶습니다.

그런데 문득 이런 의문, 한 번쯤 품어보지 않으셨나요?

"정말 이 단순한 교차 신호대로만 매매하면, 실제로 안정적인 수익을 거둘 수 있을까?"

남들의 카더라 통신이나 막연한 감에 소중한 내 자산을 덜컥 맡길 수는 없는 법입니다. 내 매매 전략이 과거 차트 데이터 속에서 진짜로 통했는지 객관적으로 두들겨보는 과정, 즉 ‘백테스팅(Backtesting)’이 반드시 필요한 이유가 바로 여기에 있습니다.

이번 포스팅에서는 트레이딩뷰(TradingView)의 Pine Script v5와 strategy() 함수를 활용하여, 이동평균 교차 전략의 수익률을 내 손으로 직접 낱낱이 검증해 보는 방법을 처음부터 끝까지 알기 쉽게 파헤쳐 보겠습니다. 코딩을 잘 몰라도 걱정 마세요. 저만 믿고 가볍게 따라오시면 됩니다! 🚀

파인스크립트와 백테스팅의 기초 개념을 시각적으로 빠르게 익히고 싶다면 아래 영상들을 함께 참고해 보세요.

이동평균선 교차 신호, 코드 4줄로 자동표시하기/ 트레이딩뷰 파인스크립트 #02

승률 50%인데 왜 돈을 벌었을까? / 트레이딩뷰 파인스크립트 백테스트 #04


1. indicator() vs strategy() : 백테스팅을 위한 첫걸음

파인스크립트로 스크립트를 작성할 때 가장 먼저 결정해야 하는 것은 스크립트의 유형입니다. 많은 초보자가 indicator() 상태에서 매수/매도 화살표만 그린 뒤 수익률이 왜 계산되지 않는지 의아해하곤 합니다.

  • indicator() (지표 스크립트)

    • 차트 위에 이동평균선, RSI, MACD 같은 지표를 그리거나 특정 조건에서 화살표(shape)나 알람(alert)을 띄우는 용도입니다.

    • 가상의 매매를 실행하지 않으며, 백테스팅 성과 리포트를 생성하지 않습니다.

  • strategy() (전략 스크립트)

    • 매수(strategy.entry), 청산(strategy.close), 손절/익절 등의 주문을 가상으로 실행합니다.

    • 초기 자본금, 거래 수수료, 슬리피지(Slippage) 등을 설정할 수 있으며, 트레이딩뷰 하단의 [전략 테스터(Strategy Tester)] 탭을 통해 총수익률, 승률, 최대 자산 낙폭(MDD) 등을 한눈에 파악할 수 있습니다.

따라서 수익률 검증이 목적이라면 반드시 스크립트 상단에 strategy() 선언을 사용해야 합니다.


2. 이동평균 교차 전략 Pine Script v5 실전 코드

트레이딩뷰 전략 테스터 'Overview' 탭 화면. 'Data Trader - Supertrend [Whitebox]' 전략의 백테스팅 결과로, 순이익 22,477.81 USDT, 승률 42.31%, 수익 팩터 1.266, 최대 낙폭 -8,605.55 USDT 등 주요 성과 지표와 함께 등락을 반복하는 누가 자산 곡선 차트가 표시되어 있다.


아래는 20일 단기 이동평균선과 50일 장기 이동평균선의 교차를 감지하여 자동으로 매수 및 청산(매도)을 진행하는 전체 Pine Script v5 코드입니다.

//@version=5

strategy("이동평균 교차 백테스팅 전략", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.05, slippage=1)


// ==========================================

// 1. 사용자 입력 파라미터 (Inputs)

// ==========================================

shortPeriod = input.int(20, title="단기 이동평균 기간", minval=1)

longPeriod  = input.int(50, title="장기 이동평균 기간", minval=1)


// ==========================================

// 2. 지표 계산 (Calculations)

// ==========================================

shortMA = ta.sma(close, shortPeriod)

longMA  = ta.sma(close, longPeriod)


// ==========================================

// 3. 차트 시각화 (Plotting)

// ==========================================

plot(shortMA, color=color.blue, linewidth=2, title="단기 MA (20)")

plot(longMA, color=color.orange, linewidth=2, title="장기 MA (50)")


// ==========================================

// 4. 매매 조건 정의 (Conditions)

// ==========================================

// ta.crossover: shortMA가 longMA를 상향 돌파 (골든크로스)

longCondition = ta.crossover(shortMA, longMA)


// ta.crossunder: shortMA가 longMA를 하향 돌파 (데드크로스)

shortCondition = ta.crossunder(shortMA, longMA)


// ==========================================

// 5. 가상 주문 실행 (Execution)

// ==========================================

// 골든크로스 발생 시 롱(매수) 포지션 진입

if (longCondition)

    strategy.entry("MA_Long", strategy.long)


// 데드크로스 발생 시 기존 롱 포지션 청산

if (shortCondition)

    strategy.close("MA_Long")


3. 핵심 함수 및 코드 구조 정밀 해설

작성한 코드가 내부적으로 어떻게 동작하는지 핵심 함수 위주로 하나씩 짚어보겠습니다.

1) strategy() 초기 설정값

  • overlay=true: 전략 지표 및 매매 화살표를 메인 가격 차트 위에 겹쳐서 표시합니다.

  • initial_capital=10000: 가상 시뮬레이션을 위한 초기 자본금을 $10,000로 설정합니다.

  • default_qty_type=strategy.percent_of_equity & default_qty_value=100: 매 진입 시 현재 총 자산의 100%를 복리로 투자하도록 설정합니다.

  • commission_value=0.05 & slippage=1: 현물/선물 거래 시 발생하는 거래 수수료(0.05%)와 1틱의 슬리피지를 반영하여 백테스팅의 현실성을 높입니다.

2) ta.sma() 및 교차 함수

  • ta.sma(close, period): 지정한 기간 동안의 종가(close) 기준 단순 이동평균(Simple Moving Average)을 계산합니다.

  • ta.crossover(A, B): A가 B를 위로 돌파하는 순간 true가 됩니다. (골든크로스)

  • ta.crossunder(A, B): A가 B를 아래로 돌파하는 순간 true가 됩니다. (데드크로스)

3) strategy.entry() 및 strategy.close()

  • strategy.entry("MA_Long", strategy.long): "MA_Long"이라는 이름으로 롱(매수) 포지션에 진입합니다. 이미 포지션이 열려있다면 무시되거나 설정에 따라 수량이 추가됩니다.

  • strategy.close("MA_Long"): "MA_Long" 이름으로 열린 포지션을 즉시 시장가로 청산합니다.


4. 백테스팅 성과 리포트 해석법

코드를 트레이딩뷰 [파인 에디터(Pine Editor)]에 넣고 [차트에 넣기]를 누르면, 차트 하단 [전략 테스터] 탭에 다음과 같은 성과 리포트가 출력됩니다. 이 지표들을 종합적으로 평가하는 것이 백테스팅의 핵심입니다.

성과 지표한글 명칭이상적인 목표 수치 및 의미
Net Profit순이익초기 자본 대비 전체 백테스팅 기간 동안의 총 수익률입니다.
Percent Profitable승률전체 거래 건수 중 익절로 마무리된 거래의 비율입니다. 보통 Trend Following 전략은 35~45%만 나와도 손익비가 높으면 우수한 전략입니다.
Profit Factor수익 팩터총 이익 / 총 손실의 비율입니다. 1.0 미만은 손실 전략, 1.5 이상이면 실전 매매 검토가 가능한 우수한 전략으로 평가받습니다.
Max Drawdown (MDD)최대 자산 낙폭계좌 고점 대비 자산이 가장 크게 감소했던 비율입니다. 심리적 버팀 목이 되는 지표로, 보통 20% 이내를 권장합니다.
Avg Trade평균 거래 손익거래당 평균적으로 얻는 수익률입니다. 수수료 및 슬리피지를 극복할 수 있을 만큼 충분히 큰지 확인해야 합니다.


5. 실전 매매 적용 시 주의해야 할 3가지 함정

백테스팅 결과가 아무리 훌륭하게 나오더라도, 실전에 그대로 적용했을 때 동일한 수익을 보장하지는 않습니다. 다음과 같은 대표적인 백테스팅 함정을 반드시 체크해야 합니다.

  1. 횡보장(Ranging Market)에서의 잦은 손실 (Whipsaw)

    • 이동평균선은 추세 추종형(Lagging) 지표입니다. 명확한 상승/하강 추세가 없는 박스권 횡보장에서는 골든크로스와 데드크로스가 짧은 주기로 번갈아 발생하며 수수료와 슬리피지로 인해 계좌가 크게 깎일 수 있습니다.

  2. 수수료 및 슬리피지 미반영

    • 수수료를 0%로 설정하고 백테스팅을 돌리면 수백 번의 미세한 거래를 통해 엄청난 수익이 나는 것처럼 보이지만, 실제 매매 수수료를 적용하는 순간 마이너스 수익률로 반전되는 경우가 허다합니다.

  3. 과적합(Overfitting)의 위험

    • 특정 과거 기간(예: 2023년 불장)에만 최적의 수익을 내도록 이동평균 기간(예: 20일, 50일)을 지나치게 튜닝하면, 미래의 새로운 시장 조건에서는 제대로 작동하지 않을 가능성이 매우 높습니다.


💡 결론 및 발전 방향

단순 이동평균 교차 전략은 추세를 따라가는 가장 기초적인 시스템 매매 기법입니다. 이번 포스팅에서 배운 strategy() 함수 기본기를 바탕으로, 다음과 같은 조건들을 추가하여 전략을 한 단계 업그레이드해 보세요.

  • 변동성/추세 필터 추가: RSI(상대강도지수)가 50 이상이거나, ADX 지표가 강력한 추세를 나타낼 때만 진입하도록 조건 강화

  • 손절(Stop Loss) 및 익절(Take Profit) 설정: strategy.exit() 함수를 활용해 일정 손실률(예: -2%) 도달 시 즉시 손절하는 리스크 관리 로직 반영

  • 타임 프레임 변경: 15분봉, 1시간봉, 일봉 등 다양한 타임프레임에서 전략의 강건성(Robustness) 검증

감에 의존하는 매매에서 벗어나 데이터 기반의 시스템 매매로 나아가는 첫 단추, 지금 바로 트레이딩뷰에서 여러분만의 파인스크립트 전략을 백테스팅해 보세요!



댓글

이 블로그의 인기 게시물

엔트로픽 상장일 전망과 관련주 총정리: 클로드(Claude) 개발사의 IPO 주식 투자 가이드

RSI와 MACD를 결합한 나만의 커스텀 다중 하단 지표 제작 완벽 가이드

[파이썬 자동매매] CCXT 웹소켓(WebSocket)으로 해외 거래소 호가창 실시간 수집 및 DataFrame 재구성