콘텐츠로 이동

중급자 트랙

기본 전략을 작성할 수 있다면 이 트랙부터 시작하세요. 운영 품질을 높이고 더 정교한 전략을 만드는 데 필요한 기술을 다룹니다.

각 단계는 30~60분 분량입니다.


1단계: 멀티 타임프레임 전략

읽을 문서

이 단계에서 배우는 것

상위 타임프레임으로 추세를 파악하고, 하위 타임프레임에서 진입 타이밍을 잡는 구조입니다.

version("1.0")
description("멀티 TF 전략 — 일봉 추세 + 5분봉 진입")

c_daily = chart("1D")    # 추세 확인
c_5m = chart("5T")       # 진입 타이밍

# 일봉 기준 추세 판단
daily_trend = ta.ema(c_daily.close, 20)
is_uptrend = c_daily.close[0] > daily_trend[0]

# 5분봉 기준 진입
fast = ta.ema(c_5m.close, 5)
slow = ta.ema(c_5m.close, 20)

if is_uptrend and fast.cross_up(slow):
    buy(tag="상승추세 + 5분봉 골든크로스")
elif fast.cross_down(slow):
    sell(tag="5분봉 데드크로스")
else:
    hold()

cross_up() vs ta.crossover()의 차이

series.cross_up(other) ta.crossover(s1, s2)
반환 bool TSeries
사용처 if 조건 직접 사용 시계열 계산 후 인덱스 접근
예시 if fast.cross_up(slow): ta.crossover(fast, slow)[0]

체크포인트

  • [ ] chart("1D")chart("5T")를 동시에 사용하는 전략을 작성했다
  • [ ] ta.valuewhen, ta.barssince 중 하나를 사용해봤다

2단계: 실행 간 상태 유지 (var)

읽을 문서

이 단계에서 배우는 것

스크립트는 이벤트마다 처음부터 다시 실행됩니다. 따라서 이전 실행의 값을 기억하려면 var를 사용해야 합니다.

# 일반 변수 — 이벤트마다 초기화됨
counter = 0
counter += 1   # 항상 1

# var — 실행 간 유지됨
var.init(counter=0)
var.counter += 1   # 누적됨

실전 예시: 연속 상승 봉 카운팅

var.init(up_count=0)

if c.close[0] > c.close[1]:
    var.up_count += 1
else:
    var.up_count = 0

# 3봉 연속 상승 시 매수
if var.up_count >= 3:
    buy(tag=f"{var.up_count}봉 연속 상승")
else:
    hold()

주의사항

  • var에 저장하는 값은 JSON으로 직렬화 가능해야 합니다 (int, float, str, bool, list, dict만 허용)
  • 총 저장 용량 제한: 64KB
  • NumPy 배열, 커스텀 객체는 저장 불가

체크포인트

  • [ ] var.init()으로 초기 상태를 선언하고 실행 간 값을 유지하는 코드를 작성했다
  • [ ] JSON 직렬화 제약을 이해하고 저장 타입을 올바르게 선택했다

3단계: 시각화와 운영 로그

읽을 문서

이 단계에서 배우는 것

전략이 왜 매매했는지 백테스트 차트에서 바로 확인할 수 있도록 오버레이와 마커를 추가합니다.

c = chart("1D")
fast = ta.sma(c.close, 5)
slow = ta.sma(c.close, 20)

# 차트에 선 표시
c.line("단기MA", fast, color="orange")
c.line("장기MA", slow, color="blue")

if fast.cross_up(slow):
    c.marker("BUY", color="green", position="below", shape="triangle_up")
    buy(tag="골든크로스", reason="5일선이 20일선 상향 돌파")
elif fast.cross_down(slow):
    c.marker("SELL", color="red", position="above", shape="triangle_down")
    sell(tag="데드크로스", reason="5일선이 20일선 하향 돌파")
else:
    hold()

운영 로그 남기기

log(f"RSI: {rsi[0]:.1f}, 포지션: {position.qty}")

reason 문자열은 나중에 백테스트 결과를 분석할 때 "왜 그 시점에 매매했는가"를 복기하는 데 핵심입니다. 의미 있는 값을 기록하세요.

체크포인트

  • [ ] c.line(), c.marker()로 차트에 신호를 표시했다
  • [ ] reason 파라미터에 의미 있는 문자열을 남기는 습관을 들였다

4단계: 선언형 청산 규칙 (rule.*)

읽을 문서

이 단계에서 배우는 것

손절, 익절, 트레일링 스탑, 장마감 청산을 코드 몇 줄로 선언합니다. 직접 if 조건을 작성하는 것보다 간결하고 실수 여지가 적습니다.

version("1.0")
description("rule.* 사용 예시")

# 청산 규칙 선언 (진입 조건보다 먼저 작성)
rule.order_on("5T")                                          # 5분봉 마감 시 주문
rule.stop_loss(pct=param("손절%", "손절 기준", 3.0))          # 3% 손절
rule.take_profit(pct=param("익절%", "익절 기준", 10.0),       # 10% 익절 (50% 수량)
                 qty_ratio=0.5)
rule.trailing_stop(pct=param("트레일링%", "트레일링 기준", 2.0))  # 2% 트레일링
rule.close_before(minutes=param("장마감전(분)", "장마감 전 정리", 10))  # 장마감 10분 전 청산

c = chart("5T")
if barstate("5T").is_confirmed:
    if ta.crossover(c.close, ta.sma(c.close, 20))[0]:
        buy(qty=10)
    else:
        hold()

우선순위: 사용자가 명시적으로 호출한 sell()/exit()rule.*보다 우선합니다.

체크포인트

  • [ ] rule.stop_loss(), rule.trailing_stop() 중 하나를 전략에 추가했다
  • [ ] param()과 조합하여 UI에서 값을 조정할 수 있도록 했다
  • [ ] rule.* vs 직접 sell() 호출의 우선순위를 이해했다

중급자 점검 기준

전략을 실전에 적용하기 전에 확인하세요.

  • 타임프레임을 2~3개 이하로 유지했다 (많을수록 실행 비용과 복잡도가 증가)
  • reason 문자열만 보고도 매매 의도를 복기할 수 있다
  • var에 저장하는 값이 JSON 직렬화 가능하고 64KB를 넘지 않는다
  • 백테스트 결과와 실시간 실행 결과가 크게 다르지 않다

다음 단계