전략의 설정값(기간, 배수, 손절 폭)을 바꿔 가며 백테스트하는 것을 최적화라고 합니다.
같은 전략이라도 input을 어떻게 만들었는지에 따라 최적화가 쉬워지기도, 의미 없는 결과만 나오기도 합니다. 이 글에서는 최적화하기 좋은 input 설계법을 정리합니다.

이 글에서 배우는 것
  • 최적화에 맞는 input 종류와 범위·단계 정하기
  • 조합 수를 줄이는 방법
  • 의미 없는 조합 걸러내기
  • 최적화 결과를 고르는 기준

※ 예제 코드는 파인스크립트 v6 기준입니다.

1. 최적화할 값은 숫자 input으로

최적화는 값을 일정한 간격으로 바꿔 가며 반복 백테스트하는 작업입니다. 그래서 바꿀 값은 input.int(), input.float() 로 만들고, 최솟값·최댓값·단계를 함께 지정해 두는 것이 좋습니다.

// ✓ 범위와 단계가 분명한 input
atrLen = input.int(10, "ATR 기간", minval = 5, maxval = 30, step = 1)
factor = input.float(3.0, "ATR 배수", minval = 1.0, maxval = 5.0, step = 0.5)
slPct  = input.float(2.0, "손절 (%)", minval = 0.5, maxval = 5.0, step = 0.5)
  • minval, maxval 은 말이 되는 범위로 잡습니다. (ATR 기간 1이나 500은 의미가 없음)
  • step 은 결과가 눈에 띄게 달라지는 간격으로 잡습니다. 0.01 단위로 바꾸면 조합만 늘고 차이는 거의 없습니다.
  • 켜고 끄는 기능은 input.bool(), 방식 선택은 input.string(options = [...]) 으로 만들면 조합에 포함하기 쉽습니다.

2. 파라미터 수와 조합 수

조합 수는 각 input 값 개수의 곱입니다.

input범위값 개수
ATR 기간5 ~ 30, 단계 126
ATR 배수1.0 ~ 5.0, 단계 0.59
손절 (%)0.5 ~ 5.0, 단계 0.510
합계26 × 9 × 10 = 2,340 조합
  • input을 하나 더할 때마다 조합 수가 몇 배로 늘어납니다. 한 번에 최적화할 값은 2~3개가 적당합니다.
  • 먼저 넓은 범위·큰 단계로 대략 좋은 구간을 찾고, 그 구간만 좁은 범위·작은 단계로 다시 확인하면 시간이 크게 줄어듭니다.
  • 결과에 거의 영향이 없는 값은 고정값으로 두고 최적화에서 뺍니다.

3. 의미 없는 조합 걸러내기

빠른 이동평균이 느린 이동평균보다 길어지는 조합처럼, 논리적으로 맞지 않는 조합이 생길 수 있습니다. 이런 조합은 거래가 나지 않도록 막아 두면 결과 표에서 쉽게 구분할 수 있습니다.

fastLen = input.int(20, "빠른 이동평균", minval = 5,  maxval = 50,  step = 5)
slowLen = input.int(60, "느린 이동평균", minval = 20, maxval = 200, step = 10)

validParams = fastLen < slowLen           // 빠른 기간이 느린 기간보다 짧을 때만 매매

if validParams and ta.crossover(ta.ema(close, fastLen), ta.ema(close, slowLen))
    strategy.entry("Long", strategy.long)

위처럼 ta.* 함수를 조건 안에서 호출하면 경고가 날 수 있습니다. 실제 코드에서는 이동평균을 조건문 밖에서 변수로 먼저 계산해 두세요.

또는 두 값의 관계를 input으로 만드는 방법도 있습니다. 조합이 항상 유효해집니다.

fastLen = input.int(20, "빠른 이동평균", minval = 5, maxval = 50, step = 5)
ratio   = input.float(3.0, "느린/빠른 배율", minval = 1.5, maxval = 5.0, step = 0.5)
slowLen = int(math.round(fastLen * ratio))

4. 퍼센트와 배수로 만들기

손절·익절을 가격이나 틱으로 받으면 종목마다 값을 다시 찾아야 합니다. 퍼센트나 ATR 배수로 만들면 여러 종목·시간봉에 같은 범위로 최적화할 수 있습니다.

// ✗ 종목마다 의미가 다름
slTicks = input.int(500, "손절 (틱)")

// ✓ 어느 종목에서나 같은 의미
slPct  = input.float(2.0, "손절 (%)", minval = 0.5, maxval = 5.0, step = 0.5)
slAtr  = input.float(2.0, "손절 (ATR 배수)", minval = 1.0, maxval = 4.0, step = 0.5)

5. input을 보기 좋게 정리하기

group 과 inline 으로 묶어 두면, 설정 화면에서도 최적화 결과를 적용할 때도 헷갈리지 않습니다.

atrLen = input.int(10, "ATR 기간", minval = 5, maxval = 30, group = "① 진입 신호")
factor = input.float(3.0, "ATR 배수", minval = 1.0, maxval = 5.0, step = 0.5, group = "① 진입 신호")

tpPct  = input.float(4.0, "익절 %", minval = 1.0, maxval = 10.0, step = 0.5, group = "② 청산", inline = "tp")
slPct  = input.float(2.0, "손절 %", minval = 0.5, maxval = 5.0,  step = 0.5, group = "② 청산", inline = "tp")

entryMsg = input.text_area("", "롱 진입 주문메시지", group = "③ TVExtBot")

※ 주문메시지 같은 텍스트 input은 최적화 대상이 아닙니다. 최적화할 숫자 input과 그룹을 나눠 두세요.

6. 결과를 고르는 기준

순이익이 가장 큰 조합 하나를 고르면 과최적화되기 쉽습니다. 아래 기준을 함께 보세요.

  • 주변 값도 좋은가: 선택한 값에서 한 단계씩 바꿔도 결과가 크게 나빠지지 않는 안정된 구간을 고릅니다.
  • 거래 횟수가 충분한가: 거래가 수십 회 이하인 조합은 우연일 가능성이 큽니다.
  • 최대 낙폭(MDD)을 견딜 수 있는가: 순이익보다 MDD가 실제 운용을 결정합니다.
  • 다른 기간에서도 통하는가: 앞 기간에서 찾은 값을 뒤 기간에 적용해 확인합니다.

자세한 검증 방법은 백테스트와 실전이 다른 이유에서 다룹니다.

7. TVExtBot 옵티마이저로 자동 최적화하기

트레이딩뷰에서 값을 하나씩 바꿔 백테스트하려면 조합마다 설정 창을 열고 결과를 옮겨 적어야 합니다. TVExtBot 옵티마이저는 전략의 input 조합을 자동으로 백테스트해 순이익·승률·MDD 등을 한 번에 비교할 수 있게 해 줍니다. 이 글처럼 범위와 단계가 분명한 숫자 input으로 전략을 만들어 두면 옵티마이저에서 범위를 잡기가 훨씬 쉽습니다. 설치와 사용 방법은 TVExtBot 옵티마이저 사용법을 참고해 주세요.


최적화해 볼 전략이 필요하다면 전략 예제 3가지 (RSI·볼린저·이평)로 시작해 보세요.