[#5] 파인스크립트 강좌 - 조건문과 반복문

[#5] 파인스크립트 강좌 - 조건문과 반복문
‘연산자’ 편에 이어지는 강의입니다.

이제 값(데이터)을 어떻게 판단하고 얼마나 반복할지 배워 자동화 로직을 완성해 보겠습니다.

제어 흐름(Control Flow)이 왜 필요할까요?

가격이 목표치에 도달했을 때 매수/매도를 결정하고, N개의 봉을 스캔해 특정 패턴이 있는지 확인하려면
프로그래밍 언어가 제공하는 조건문(Conditional statement)반복문(Loop) 이 필수입니다.
파인스크립트 v5부터는 if, switch, for 구조를 지원하므로 클래식 언어와 거의 동일한 사고방식으로 코드를 작성할 수 있습니다.

조건문(Conditional Statement)

if‧else if‧else 기본형

// 예: 캔들 색상 판단
isBull  = close > open
isDoji  = math.abs(close - open) < (high - low) * 0.1

if isBull
    label.new(bar_index, high,  "양봉", color=color.green)
else if isDoji
    label.new(bar_index, high,  "도지", color=color.gray)
else
    label.new(bar_index, high,  "음봉", color=color.red)
  • 들여쓰기 4칸이 필수입니다. 틀리면 컴파일 오류가 발생합니다.
  • 조건이 series<bool> 형이어야 하며, na가 들어가면 false로 처리됩니다.

다중 분기용 switch

switch가독성이 좋고, 값을 반환할 수도 있어서 트릭 컬러링에 자주 쓰입니다.

barColor = switch
    close > open => color.green
    close < open => color.red
    => color.gray            // 나머지(동가) 처리
plotcandle(open, high, low, close, color = barColor)
  • => 뒤에 표현식을 한 줄로 작성합니다.
  • 모든 분기가 return 을 생략하면 side-effect 용도로도 사용할 수 있습니다.

단일 라인 조건부(?:) 다시 보기

앞 강의에서 소개했던 삼항 연산자도 조건문 계열입니다.
짧게 써야 가독성이 살아납니다.

반복문(Loop)

중요: 대부분의 지표 연산은 ta.* 빌트인으로 해결할 수 있으므로,
루프는 “특수 계산”이나 “배열 조작”이 필요할 때만 사용하세요.

3-1. for 문 기본형

//@version=5
indicator("For Loop Demo", overlay = true)

len = 5
var float sumClose = 0.0

for i = 0 to len - 1
    sumClose += close[i]

avgClose = sumClose / len
plot(avgClose, "5-Bar AVG", color = color.orange)
  • 구조: for <카운터> = <시작> to <끝> [by <스텝>]
  • <끝> 값까지 포함하며, from > to이면 자동으로 내림(loop-down) 합니다.
  • break, continue 도 지원합니다. (사용 시 성능 프로파일링 권장)

배열 전용 루프

string[] tickers = array.from("AAPL", "MSFT", "TSLA")
for t in tickers
    h = request.security(t, "D", high)
    // ... 로직 ...
  • for <element> in <array> 형태.
  • [index, value] 두 개 튜플로도 받을 수 있습니다.

while 문은 없다?

파인스크립트에는 전통적 while 이 없습니다.
무한 루프 위험을 차단하기 위한 언어 설계 철학이므로,
조건 반복이 필요하면 for + break 패턴이나 빌트인 함수를 사용합니다.

실전 예제 ① — 조건문으로 ‘스탑로스’ 구현

//@version=5
strategy("Stop-Loss Demo", overlay = true)

longCond = ta.crossover(close, ta.sma(close, 20))
if longCond
    strategy.entry("Long", strategy.long)

stopLoss = strategy.position_avg_price * 0.97   // 3% 손절
takeProf  = strategy.position_avg_price * 1.05  // 5% 익절

if strategy.position_size > 0
    if close <= stopLoss
        strategy.close("Long", comment = "손절")
    else if close >= takeProf
        strategy.close("Long", comment = "익절")

if 중첩으로도 충분히 복잡한 매매 로직을 깔끔하게 관리할 수 있습니다.

실전 예제 ② — 반복문으로 ‘마지막 N봉 패턴’ 탐색

//@version=5
indicator("Engulfing Scanner", overlay = true)

N = input.int(30, "검색 범위")
var int lastBar = na

for i = 1 to N
    isBullEngulf = close[i]  > open[i]  and       // 현재봉 상승
                   open[i]   < close[i+1] and    // 이전봉 음봉
                   close[i]  > open[i+1] and
                   open[i]   <= close[i+1]

    if isBullEngulf
        lastBar := i
        break   // 가장 최근 패턴만 잡고 루프 종료

plotshape(lastBar == 1 ? 1 : na, title = "Bull Engulf",  style = shape.triangleup,
          location = location.belowbar, color = color.lime, size = size.tiny)
  • break첫 번째 발견 후 루프를 즉시 탈출 → CPU 절약.
  • 동일 로직을 ta.pattern.* 으로 대체할 수도 있으니 성능 비교해 보세요.

흔한 오류 & 최적화 팁

유형 원인 & 증상 해결책
Unreachable code break 다음 줄에 코드가 있는데 접근 불가 불필요한 코드 제거
Loop executes too often 배열 길이만큼 매 봉마다 반복 → 슬로다운 var 캐시·조건분기·Profiler 사용
조건에 na 포함 if na(x) 는 항상 false 취급 nz() 혹은 x != na 로 안전 처리
배열 크기 초과 array.get(a, i) 에서 인덱스 오류 array.size(a) 체크 & min()

7. 성능 프로파일링 한눈에 보기

  • Pine Profiler (파인 에디터 우측 상단 🐢 아이콘) 으로 루프 시간호출 횟수를 측정하세요.
  • 빌트인 함수(ta.*)는 내부 C++ 최적화가 되어 있어 루프보다 빠르고 메모리 안전합니다.
  • 조건문·반복문을 최소화하고, 결과를 var 시리즈에 캐싱하면 프레임 드랍을 줄일 수 있습니다.

오늘의 핵심 정리

  1. 조건문ifswitch 두 축이며, switch 가 가독성이 뛰어난 다중 분기용입니다.
  2. 반복문for 만 존재하며, 배열·범위·튜플 반복을 지원합니다.
  3. 루프 사용 전 빌트인 함수 대체 가능 여부를 반드시 검토하세요.
  4. break, continue, Profiler 로 성능을 관리하면 차트가 가볍습니다.