OptiNod 아카데미

트레이딩뷰 백테스트 방법 — 첫 설정부터 CSV 분석까지

전략 적용부터 자본·수수료·슬리피지와 기간 설정, 거래 0건 처리, 결과 해석과 CSV 분석까지 따라갑니다. 같은 조건을 기록해 다음 검증과 비교합니다.

첫 백테스트는 설정과 거래 기록을 함께 남기는 실행입니다. 같은 조건이 남아야 다음 결과와 비교할 수 있습니다.


전략을 차트에 올렸는데 거래가 나오지 않거나, 수수료를 넣자 수익이 사라지는 경우가 있습니다. 이때는 어떤 규칙이 어떤 크기로 주문을 만들었는지부터 살펴봅니다.


트레이딩뷰 백테스트는 매매 규칙을 과거 데이터에 적용해 모의 거래 결과를 보는 과정입니다. 차트의 매수·매도 표시, 실제 주문 체결, 전략 보고서의 모의 거래는 각각 다른 기록입니다.


이 글에서는 전략 적용 → 비용과 기간 설정 → 첫 거래 확인 → 결과 읽기 → 거래 목록 저장 순서로 따라갑니다. 마지막에는 저장한 CSV를 OptiNod에서 분석하고, 손실에 기여한 거래를 다음 검증에 연결합니다.


전략을 적용하면 주문과 결과를 함께 볼 수 있습니다


일반 캔들 차트에서 거래소가 포함된 심볼과 봉 주기를 먼저 정합니다. 사용할 권한이 있는 전략을 차트에 추가하고 이름, 소스 버전, 입력값을 기록합니다. 평균선 같은 지표를 추가하는 것만으로는 백테스트 거래가 생기지 않습니다. 전략에는 strategy() 선언과 모의 주문을 생성하는 명령이 필요합니다.


현재 공식 문서는 차트 아래 화면을 전략 보고서(Strategy report), 결과 탭을 Metrics와 Trades로 설명합니다. 계정의 언어와 화면 버전에 따라 전략 테스터(Strategy Tester), 개요(Overview), 거래 목록(List of Trades) 등 기존 명칭이 보일 수 있습니다. 화면에서 거래 목록과 성과 지표를 각각 찾습니다. 전략 공식 문서


일반 캔들을 기준으로 시작하면 합성 가격을 사용하는 차트의 체결 가정이 섞이는 일을 줄일 수 있습니다. 전략을 추가한 뒤에는 진입과 청산 기록이 실제로 생성됐는지 봅니다.


이 예제는 OptiNod Learn - SMA 10/30 Backtest Guide v1.0.0입니다. NASDAQ:AAPL을 선택해 일반 캔들 1D에서 실행했으며, 화면 피드는 NASDAQ by Cboe One으로 표시됐습니다. 검수일은 2026-10-01입니다. 빠른 SMA 10이 느린 SMA 30을 위로 교차하면 롱, 아래로 교차하면 청산하는 자체 작성 교육 예제입니다. 별도 손절·익절이나 실거래 알림은 없으며, 성과를 추천하기 위한 전략이 아닙니다.


  1. TradingView의 Pine Editor에서 새 스크립트를 열고 아래 코드를 붙여넣습니다.
  2. 코드를 차트에 적용한 뒤 NASDAQ:AAPL, 1D, 일반 캔들인지 맞춥니다.
  3. 전략 설정의 Inputs에서 기간과 Base Entry Amount를, Properties에서 자본·비용·체결 설정을 대조합니다.
  4. 보고서의 거래 목록과 지표를 열고, 아래 실측 결과와 같은 조건에서 비교합니다.

//@version=6
// OptiNod Learn educational example v1.0.0. AAPL standard candles, 1D.
// Simulated orders only. No alerts or webhook payloads are defined.
strategy("OptiNod Learn - SMA 10/30 Backtest Guide", overlay=true, pyramiding=0, initial_capital=10000, currency=currency.USD, default_qty_type=strategy.fixed, default_qty_value=1, commission_type=strategy.commission.percent, commission_value=0.05, slippage=1, margin_long=100, margin_short=100, process_orders_on_close=false, calc_on_every_tick=false, calc_on_order_fills=false, use_bar_magnifier=false)

// 0 - Period / Capital: first input group, before signal and visual inputs.
string G_CAP = "0 · Period · Capital"
int startTime = input.time(1704067200000, "Start Time", group=G_CAP, inline="win") // 2024-01-01 00:00 UTC
int endTime = input.time(1767225600000, "End Time", group=G_CAP, inline="win", tooltip="Entries use bar opening times in [start, end). An open position is closed at the first calculated bar at or after end; market fills normally occur on the next available tick.") // 2026-01-01 00:00 UTC
float leverage = input.float(1.0, "Leverage", minval=1.0, maxval=1.0, step=1.0, group=G_CAP, tooltip="This educational stock example is unleveraged: 1x only. Margin requirement is 100%.")
float baseAmount = input.float(1000.0, "Base Entry Amount", minval=0.0, group=G_CAP, inline="amt")
string amountUnit = input.string("$", "", options=["%", "$"], group=G_CAP, inline="amt", tooltip="Margin budget per entry in USD. % uses current strategy equity; $ uses a fixed amount. Whole-share rounding makes actual exposure no greater than the budget at the signal close.")
bool useVarSizing = input.bool(true, "Variable Position Sizing", group=G_CAP, tooltip="The standard header keeps this control. This simple example always uses multiplier 1, so toggling it does not change sizing.")

string G_SIGNAL = "1 · Moving Averages"
int fastLength = input.int(10, "Fast SMA", minval=1, group=G_SIGNAL)
int slowLength = input.int(30, "Slow SMA", minval=1, group=G_SIGNAL)

string G_VIEW = "2 · Visuals"
bool showAverages = input.bool(true, "Show averages", group=G_VIEW)
color fastColor = input.color(#10b981, "Fast", group=G_VIEW, inline="palette")
color slowColor = input.color(#9aa0b5, "Slow", group=G_VIEW, inline="palette")

// AAPL whole shares. Quantity uses the signal close, not an unknowable future fill.
qtyFor(float stateMult) =>
    float margin = (amountUnit == "%" ? strategy.equity * baseAmount / 100.0 : baseAmount) * (useVarSizing ? stateMult : 1.0)
    math.floor(math.max(margin, 0.0) * leverage / (close * syminfo.pointvalue))

bool inWindow = time >= startTime and time < endTime
float fastSma = ta.sma(close, fastLength)
float slowSma = ta.sma(close, slowLength)
bool longSignal = ta.crossover(fastSma, slowSma)
bool exitSignal = ta.crossunder(fastSma, slowSma)
float entryQty = qtyFor(1.0)

if inWindow and longSignal and strategy.position_size == 0 and entryQty > 0
    strategy.entry("Long", strategy.long, qty=entryQty, comment="Long")

if strategy.position_size > 0 and time >= endTime
    strategy.close("Long", comment="Time exit")
else if strategy.position_size > 0 and exitSignal
    strategy.close("Long", comment="Exit")

// Layout: Minimal Overlay. Two averages explain the educational crossover.
plot(showAverages ? fastSma : na, "Fast SMA", color=fastColor, linewidth=2)
plot(showAverages ? slowSma : na, "Slow SMA", color=slowColor, linewidth=1)

수량은 신호 종가에서 1,000 USD 예산을 정수 주식 수로 내림해 계산합니다. 1,000 USD를 그대로 거래금액으로 넣는 주문이 아닙니다. 다음 봉 갭과 슬리피지 때문에 실제 체결 금액은 그 예산과 다를 수 있습니다. 레버리지는 1배로 고정했고, Variable Position Sizing은 켜져 있지만 배율이 항상 1이므로 켜고 꺼도 수량은 같습니다.


실제로 사용한 기간·자본 입력
실제로 사용한 기간·자본 입력UTC 00:00이 한국 시간 화면에서 09:00으로 표시됩니다. (2026-10-01)

비용과 주문 크기를 먼저 맞추면 비교할 조건이 남습니다


전략 설정의 속성(Properties)에서 자본과 주문 크기, 수수료와 슬리피지를 맞춥니다. 다음 표는 실제 실행에 사용한 설정과 단위입니다.


항목실제 사용한 값단위결과에 영향을 주는 이유
초기 자본·통화10,000 USDUSD시작 자산과 수익률 기준입니다
기준 투입금액1,000, 단위 $USD/진입 예산코드가 신호 종가로 정수 주식 수를 계산합니다
레버리지·증거금1배, 롱·숏 증거금 100%배, %레버리지 없이 자본 범위에서 모의 주문합니다
수수료0.05%/주문진입·청산 각각 거래금액의 0.05%입니다
슬리피지1tick시장가·스톱 체결 가격에 적용됩니다
봉 상세 수준Default (4 ticks per bar)봉당 4개 가격 지점과거 봉 체결에 기본 OHLC 가정을 사용합니다
스크립트 실행On bar close봉 마감봉이 마감될 때 교차를 계산합니다
주문 실행 지연One tick1 tick생성된 시장가 주문은 다음 이용 가능한 틱에서 체결됩니다

슬리피지의 가격 차이는 tick 수 × 종목의 최소 tick 크기입니다. 주문 크기를 자산 비율로 설정하면 진입 시점의 자산에 따라 금액이 달라집니다. 코드가 주문마다 수량을 직접 지정했다면 기본 주문 크기를 바꿔도 그 주문은 달라지지 않을 수 있습니다. 속성의 공식 정의


첫 비교에서는 증거금과 재계산·체결 옵션까지 함께 기록합니다. 비용이나 주문 크기를 바꾼 효과를 전략 규칙이 좋아진 효과와 섞지 않습니다.


Properties의 기본 주문 크기는 1로 표시됐지만, 이 코드는 strategy.entry()에 qty를 직접 넘기므로 실제 수량은 Inputs의 기준 투입금액에서 계산합니다. 보고서의 Default detalization과 Script execution, 전략 설정의 Properties를 함께 대조합니다.


실제로 사용한 자본·비용·체결 설정
실제로 사용한 자본·비용·체결 설정초기 자본 10,000 USD, 수수료 0.05%, On bar close와 기본 봉 상세 수준을 대조합니다. (2026-10-01)

기간은 차트 데이터와 전략의 날짜 조건을 함께 봅니다


일반 백테스트는 차트에 로드된 데이터에서 실행됩니다. 전략의 날짜 입력은 그 안에서 주문을 제한하는 조건이며, 오래된 데이터를 추가로 불러오는 기능은 아닙니다. 전략에 기간 입력이 있다면 시작·종료일을 맞추고 실제 거래 시각이 그 의도와 맞는지 봅니다.


Testing period 같은 기간 선택과 Deep Backtesting은 별도 기능입니다. 계정에서 사용할 수 있는 범위와 화면에 표시된 결과 기간을 기준으로 기록합니다. 지원 요금제나 메뉴가 보이지 않을 때는 기간 선택이 항상 제공된다고 가정하지 않습니다. 기간과 차트 데이터 안내


차트 표시 시간대, 거래소 세션, 데이터의 첫 봉과 계산 준비 구간도 함께 남깁니다. 같은 날짜 입력만으로 두 실행의 데이터 범위가 같아지는 것은 아닙니다.


실측 Inputs는 시작 2024-01-01 00:00 UTC, 종료 2026-01-01 00:00 UTC입니다. 한국 시간 화면에서는 각각 09:00으로 표시됐습니다. 진입 신호를 계산한 봉의 시작 시간이 시작 이상·종료 미만일 때만 새 주문을 만듭니다.


보고서 상단의 계산 범위는 1980-12-12~2026-09-30이었지만, 날짜 필터로 제한한 진입 구간과는 다릅니다. 실제 첫 진입은 2024-01-30, 마지막 청산은 2025-12-23입니다. 준비 계산은 로드된 이전 봉도 사용하므로 보고서 기간을 진입 기간으로 읽지 않습니다.


종료 후 포지션이 남았다면 종료 시각 이후 첫 계산 봉에서 청산 주문을 만들고, 다음 이용 가능한 틱에 체결합니다. 종료 시각에 정확히 청산되는 코드가 아니며, 기간 안에서 만든 진입 주문도 다음 봉 체결 시 기간 밖으로 넘어갈 수 있습니다.


거래 0건이면 주문이 만들어지는 경로부터 좁힙니다


거래가 없다면 먼저 스크립트가 전략인지, 주문을 생성하는 명령이 있는지 봅니다. 차트의 실행 오류 표시가 있다면 내용을 열어 오류를 읽습니다. 그다음 날짜 조건과 차트 데이터가 겹치는지, 진입 조건이 성립했는지 살펴봅니다.


주문 수량이 0이거나 자본과 증거금이 주문 규모를 감당하지 못해도 거래가 나오지 않을 수 있습니다. 선물의 계약 금액은 차트 가격에 포인트 가치와 수량을 적용하므로 가격만 보고 자본이 충분하다고 판단하지 않습니다.


거래 0건의 확인 순서: 전략 종류와 실행 오류 → 데이터와 날짜 범위 → 진입 조건 → 주문 수량과 자본 순서로 좁힙니다. 한 번에 여러 설정을 바꾸기보다 한 항목을 바꾼 뒤 거래가 생기는지 봅니다. 첫 거래가 나오면 진입·청산 시각, 가격, 수량과 신호를 원래 차트에 대조합니다.


거래가 생성되지 않는 이유를 따라 원인을 찾은 뒤 성과 지표로 넘어갑니다. 거래가 없는 실행과 손실이 난 실행은 서로 다른 다음 행동이 필요합니다.


실제로 Fast SMA와 Slow SMA를 모두 10으로 맞추자 보고서에 “This report requires trade data”가 표시됐습니다. 같은 평균선끼리는 위·아래 교차가 생기지 않아 주문 조건이 충족되지 않은 경우입니다. Slow SMA를 30으로 복원하면 원래 10/30 교차 조건으로 돌아갑니다. 이 사례에서는 조건 미충족이 원인이며, 자본을 늘리는 것으로 해결할 문제가 아닙니다.


SMA 10/10에서 거래가 없는 보고서
SMA 10/10에서 거래가 없는 보고서동일한 평균선은 교차가 생기지 않습니다. Slow SMA를 30으로 복원합니다. (2026-10-01)

순손익 다음에는 손실이 나온 거래로 돌아갑니다


순손익(Net PnL)에는 설정 수수료가 이미 반영됩니다. 지급 수수료(Commission paid)를 다시 빼면 비용을 두 번 차감합니다. 미청산 손익(Open PnL)은 종료된 거래의 손익과 따로 봅니다. 수수료 처리


지표읽는 기준이 값만으로 알 수 없는 것
종료 거래 수진입 후 종료된 거래를 셉니다앞으로 같은 빈도로 거래가 나오는지
PF수익 거래 손익 합 ÷ 손실 거래 손익 합의 절댓값입니다수익이 일부 거래·기간에 집중됐는지
평균 거래 결과순손익 ÷ 종료 거래 수입니다거래별 손익의 분포와 큰 손실의 크기
최대 낙폭봉중·종가 간 방식과 %의 분모를 함께 봅니다이후 낙폭이 이 범위에 머무는지

종료 거래 수, PF, 평균 거래 결과는 미청산 포지션을 포함하지 않습니다. 손실 합이 0이면 유한한 PF 하나로 비교하기 어렵습니다. 모든 전략에 적용할 합격 PF나 최소 거래 수를 정하지 않고, 거래 시각과 손익 분포를 함께 봅니다.


봉중(intrabar) 최대 낙폭은 포지션 보유 중 봉 안의 가격 움직임을 포함합니다. 종료 거래의 누적손익만으로 구한 낙폭과 같지 않을 수 있습니다. 초기 자본 대비 %와 다른 분모의 %도 구분합니다. 봉중 낙폭, 초기 자본 대비 낙폭을 대조한 뒤 큰 손실 거래의 전후 차트를 엽니다.


같은 소스로 실행한 TradingView 화면과 영어 거래 목록 CSV를 대조했습니다. CSV는 진입·청산 18행, 종료 거래는 9건입니다. 진입 행과 청산 행에 같은 거래 손익이 반복되므로 검산에는 청산 행만 사용했습니다.


항목실제 예제 결과의미이 값만으로 알 수 없는 것
종료 거래9건, 수익 3건·손실 6건종료된 거래의 표본입니다이후 거래 빈도와 재현성
Total PnL169.84 USD, +1.70%CSV 청산 행의 순손익 합과 일치합니다다른 기간에서도 같은 손익이 나오는지
Profit factor화면 1.81, CSV 약 1.81015379.48 ÷ 209.64로 검산했습니다소수 수익 거래에 대한 의존 정도
Expectancy18.87 USD169.84 ÷ 9 ≈ 18.87111입니다개별 거래의 손실 규모와 분포
Max drawdown화면 239.05 USD, 2.35%TradingView의 해당 계산에서 표시된 최대 낙폭입니다CSV만으로 같은 봉중 경로를 복원할 수 있는지

CSV의 손익 합계는 169.84 USD입니다. 양수 손익 합 379.48 USD와 음수 손익 절댓값 합 209.64 USD는 각 거래의 반올림된 CSV 필드를 합한 값입니다. TradingView의 손실 합계 화면은 209.63 USD로 표시돼 0.01 USD 차이가 났으며, 반올림된 행의 합과 내부 집계 표시가 조금 다를 수 있음을 남겼습니다.


화면 낙폭 2.35%를 239.05 ÷ 10,000으로 다시 만든 %라고 설명하지 않습니다. 그 계산은 약 2.3905%이므로 표시된 낙폭 지표의 계산 기준을 구분합니다. 수익률 +1.70%는 169.84 ÷ 10,000 × 100 = 1.6984%를 반올림한 값과 일치합니다.


TradingView 실제 실행 결과
TradingView 실제 실행 결과종료 거래 9건, 순손익 169.84 USD, PF 1.81을 기록했습니다. (2026-10-01)

거래 목록 CSV를 넣으면 손실 구간을 다시 볼 수 있습니다


거래 목록(Trades 또는 List of Trades)의 내보내기(Download)에서 CSV를 저장합니다. 성과 지표 내보내기와 거래 목록 내보내기는 담기는 정보가 다릅니다. 화면에 XLSX 전체 보고서가 제공되더라도 이 가이드에서 OptiNod에 넣는 입력은 거래 목록 CSV입니다. 공식 내보내기 안내


파일을 열어 거래 번호, 진입·청산 시각과 순손익이 있는지 봅니다. 입출력 파일명과 앞서 기록한 전략·심볼·봉 주기·설정을 함께 보관합니다. CSV의 진입 행과 청산 행을 단순히 모두 세면 종료 거래 수와 다를 수 있습니다.


OptiNod 분석 화면에 거래 목록 CSV를 넣고 먼저 종료 거래 수와 순손익을 원래 보고서와 대조합니다. 한국어·영어 헤더의 거래 목록이 지원됩니다. 다른 언어에서 파일이 인식되지 않으면 TradingView 표시 언어를 한국어 또는 영어로 바꾸고 다시 내보냅니다. 종료되지 않은 거래만 있는 파일은 종료 거래 분석에 사용할 수 없습니다.


분석은 로그인 없이 시작할 수 있으며 계정에 저장할 때 로그인 또는 가입이 필요합니다. 결과에서 손실에 기여한 거래와 기간을 찾은 뒤 그 거래의 차트와 조건으로 돌아갑니다. CSV 기반 낙폭은 원래 봉중 최대 낙폭을 그대로 복원한 값이 아니므로 계산 기준을 함께 읽습니다.


이번 실행에서는 영어 거래 목록 CSV의 18행을 그대로 OptiNod에 넣어 분석이 열리는 것을 확인했습니다. OptiNod의 완료 포지션은 9, 실현손익 표시는 170 USD, PF는 1.81이었습니다. 170 USD는 169.84 USD의 화면 반올림이며, 첫 거래는 2024-01-30 진입·2024-02-12 청산, 손익 -13.65 USD로 표시됐습니다.


OptiNod의 239 USD는 화면에 명시된 거래내역 기반 추정 낙폭입니다. TradingView의 239.05 USD와 반올림 숫자가 비슷하더라도 공식 봉중 MDD를 그대로 복원했다는 뜻은 아닙니다. 다음에는 거래 목록에서 이 첫 손실 거래를 열어 진입·청산 조건과 비용을 원래 차트에 대조합니다.


동일 CSV의 OptiNod 분석 결과
동일 CSV의 OptiNod 분석 결과완료 포지션 9개, PF 1.81과 거래내역 기반 추정 낙폭이 표시됩니다. (2026-10-01)

다음 실행에서는 바꿀 조건과 남겨둘 조건을 나눕니다


비용을 바꿔 비교할 때는 소스·입력·심볼·봉·기간·주문 크기를 고정합니다. 다른 기간을 볼 때는 규칙과 비용을 고정하고 기간을 바꿉니다. 한 파일을 앞뒤로 나눈 분석은 새로운 데이터 구간에서 전략을 다시 실행한 검증과 구분합니다.


비용과 체결은 슬리피지·수수료·유동성, 신호 시점은 룩어헤드와 리페인팅, 설정 주변의 안정성은 과최적화에서 이어서 봅니다. 최적화에 쓰지 않은 구간에서 절차를 반복하는 방법은 워크포워드 분석, 실제 거래와 달라진 지점은 백테스트와 실전에 연결합니다.


다음 실행을 저장할 때는 무엇을 바꿨는지 한 줄로 적습니다. 같은 조건과 거래 기록이 남아 있으면 결과 차이를 만든 거래로 돌아갈 수 있습니다.

내 백테스트 결과 점검하기

최적화 결과 CSV나 TradingView 전략 거래 목록을 올리면 성과 지표와 강건성 점검 결과를 함께 보여 줍니다. 로그인하지 않아도 분석할 수 있습니다.

내 결과 파일 분석하기 분석 예시 먼저 보기