스튜디오 사용법¶
Quantiq 스튜디오는 전략 코드를 작성하고 백테스트로 검증하는 작업 공간입니다.
화면 구성 한눈에 보기¶
코드 에디터¶
- QuantiqDSL 구문 강조
- 자동완성/함수 인자 도움말
- 문법 오류 표시
- 우측 API 참조 패널
AI 어시스트 패널¶
- 전략 초안 작성, 리팩터링, 설명 보조에 사용합니다.
- 계정 플랜에 따라 사용 가능 여부가 달라질 수 있습니다.
차트 영역¶
- 코드에서 선언한 오버레이/마커를 확인할 수 있습니다.
- 기본 종목: 첫 진입 시
KRW-BTC(비트코인) 5분봉이 자동 로드됩니다. 검색창에 코드(예:KRW-ETH,BTC-XRP,USDT-BTC)나 한글명을 입력해 KRW + BTC + USDT 마켓 어디로든 전환할 수 있습니다. - 타임프레임을 바꿔 신호 형태를 비교할 수 있습니다(
1T/3T/5T/10T/15T/30T/60T(=1H)/4H/1D/1W/1M). - 24/7 캔들: Upbit는 24시간 거래되므로 정규장 필터 없이 모든 시간대의 봉이 차트에 표시됩니다. 일봉 시간 정렬은 UTC 자정 기준입니다.
- 차트를 왼쪽으로 스크롤하면 과거 데이터가 타임프레임별로 독립적으로 추가 로딩됩니다. 더 이상 가져올 데이터가 없으면 해당 타임프레임의 로딩이 멈춥니다. 분봉은 약 3개월, 시간봉은 약 2개월, 일봉은 약 3년까지 조회할 수 있습니다.
- 스튜디오 차트는 편집/검증용 표면이며, 실시간 운용 확인은 거래 탭에서 수행하는 것이 좋습니다.
- 차트 시세 조회는 Upbit API 키 저장 전에도 가능합니다. 시세 데이터는 Upbit Quotation API(무인증)에서 가져오므로 키를 저장하지 않은 상태에서도 모든 마켓의 차트를 살펴볼 수 있습니다. 자동 매매(주문 발주, 체결 통보)만 키 저장 후 동작합니다 — 시세 조회와 주문 인증은 분리되어 있습니다.
- 빠른 초기 로드 + 자동 prefetch: 첫 진입 시 분봉 3페이지(약 600봉, 5분봉 기준 ~50시간)가 동시 fetch로 즉시 로드됩니다. 좌측 스크롤이 가시 영역의 절반 정도에 닿으면 다음 3페이지가 자동으로 prefetch되어 사용자가 로딩을 거의 느끼지 못합니다. Upbit Quotation API의 10 req/s 캡 안에서 동시 페이지 요청을 활용해, KIS 시절보다 한 번에 더 많은 봉을 빠르게 불러옵니다. 마지막 페이지는 필요 봉 수만큼만 요청하므로 (예: count=201이면 200+1로 호출) rate-limit 버킷을 절약합니다.
- 로딩 실패 동작: 동시 fetch 중 하나라도 일시 장애(예: 429, 네트워크 타임아웃)가 발생하면 부분 데이터를 반환하지 않고 전체 요청이 실패로 처리됩니다. 사용자는 다시 스크롤하거나 차트 테스트를 눌러 재시도할 수 있습니다. 이전엔 일부 페이지 실패 시 짧은 결과가 정상 응답으로 보여 "과거 데이터 끝"으로 오인해 스크롤이 멈추던 회귀를 차단합니다. 페이지 경계에서 동일 타임스탬프 캔들이 여러 페이지에 중복될 경우 더 최근 cursor 페이지가 우선합니다(deterministic).
- 오버레이/마커 계산 범위: DSL 평가는 스크립트가
chart("5T")로 명시한 스케일에서 수행합니다(예: 5T 차트면 5T 봉마다 평가). 보조 스케일(예: 자동 추가되는 1T 시뮬레이션 base)은 스크립트가 직접 참조하지 않는 한 평가 base로 쓰이지 않으므로, 오버레이는 로딩된 5T 봉 전체 범위를 커버합니다. 스크립트가 멀티 타임프레임(예:chart("1T")도 함께 사용)이면 가장 작은 사용 스케일이 평가 base가 됩니다.
백테스트 패널¶
- 단일 종목/유니버스(여러 종목 동시) 백테스트를 실행할 수 있습니다.
- 실행 중에는 진행 상태가 단계별로 표시됩니다 (데이터 확인 → 백필(과거 데이터 수집) → 계산 → 결과 정리 → 결과 저장 중 → 완료).
- 완료 후 이력에서 다시 열기/재실행이 가능합니다.
- 종목 추가는 직접 입력하거나 검색창에 코드(
KRW-BTC등)·한글명(비트코인등)을 입력합니다. 국내주식 시절의 관심종목 그룹 가져오기 모달은 Upbit 피벗에서 제거되었습니다(PR-1, 2026-04-28). 거래 탭의 전략 편집 패널 안내와 동일한 검색 표면을 사용합니다.
AI 결과 분석¶
백테스트가 완료되면 결과 패널 하단에 AI 결과 분석 버튼이 나타납니다.
- 버튼을 누르면 주요 지표(수익률, MDD(최대 낙폭), 승률 등)를 기반으로 AI가 한줄 요약 / 강점 / 우려 / 개선 제안 4개 섹션으로 분석을 생성합니다.
- 분석은 백테스트 실행 1건당 1회만 생성됩니다. 생성 후에는 버튼이 사라지고 결과가 고정 표시됩니다. 다시 분석받으려면 백테스트를 새로 실행하세요.
메모¶
결과 패널 하단에 자유 텍스트 메모를 남길 수 있습니다. 메모는 해당 백테스트 실행에 귀속되며, 이력에서 다시 열어도 유지됩니다.
처음 스튜디오에 접속했을 때¶
스튜디오를 처음 열면 백테스트 패널 상단에 인라인 안내 카드가 표시됩니다. 종목과 기간을 설정하고 백테스트를 실행하는 방법을 안내합니다. 거래 탭에서 전략을 등록하면 카드가 자동으로 사라집니다.
Upbit 키 없이도 백테스트 가능
Upbit Quotation API(차트/체결 데이터)는 비인증으로 호출할 수 있어서 API 키를 저장하기 전에도 차트 로딩과 백테스트가 모두 동작합니다. 키는 실주문(매수/매도)을 보낼 때만 필요합니다. 키 저장은 운영 가이드 — 업비트 API 키를 참고하세요.
백테스트 기간은 calendar day 기준
Upbit는 24/7 거래되므로 백테스트 기간(from_date ~ to_date)은 휴장일 없이 매일 캔들이 있다고 가정해 candle 수를 계산합니다. KIS 국내주식 시절의 거래일(trading day) 기반 환산은 더 이상 적용되지 않습니다(예: 7일 범위 1T 백테스트는 7 × 1440 = 10,080 분봉 시도).
전략 만들기: 4단계¶
1. 새 전략 시작¶
- 새 전략을 눌러 편집을 시작합니다.
- 기본 템플릿을 기반으로 코드/파라미터를 수정합니다.
- 필요한 종목/기간을 정해 백테스트합니다.
2. 코드 작성¶
version("1.0")
description("RSI 반등 전략")
param("rsi_period", "RSI 기간", 14)
c = chart("1D")
rsi = ta.rsi(c.close, script_params["rsi_period"])
if rsi.cross_up(30):
buy(tag="RSI 반등")
else:
hold()
3. 저장/테스트¶
- Ctrl+S 또는 저장 버튼으로 저장합니다.
- 저장은 내 스크립트 작업본 저장입니다.
- 공개 공유는 별도의 커뮤니티 등록으로 진행합니다.
4. 커뮤니티 등록¶
- 저장된 내 스크립트에서 커뮤니티 등록을 선택합니다.
- 제목/요약/태그/이미지를 입력합니다.
- 게시 후 관리는 탐색 탭의 내 게시물에서 수행합니다.
게시물 코드는 게시 시점 스냅샷으로 고정됩니다.
게시 후 수정·삭제 주의
게시된 코드는 수정할 수 없습니다. 게시물 삭제는 복구되지 않으므로, 보존이 필요하면 삭제 대신 숨김을 사용하세요.
백테스트 결과 해석¶
백테스트 완료 후 결과 패널의 상세뷰에 표시되는 지표를 해석하는 방법입니다.
핵심 지표¶
| 지표 | 설명 | 기준 |
|---|---|---|
| 총수익률 | 초기 자산 대비 최종 자산 증감률 | 높을수록 좋음 |
| 최대 낙폭(MDD) | 고점 대비 최대 하락폭 | 낮을수록 좋음, -20% 이내 권장 |
| 승률 | 수익 거래 / 전체 거래 비율 | 손익비와 함께 해석 필요 |
| 손익비(Profit Factor) | 총 이익 / 총 손실 | 1.5 이상이면 양호, 2.0 이상이면 우수 |
| 총 거래 수 | 기간 내 완료된 거래 건수 | 너무 적으면 통계 신뢰도 낮음 |
고급 지표¶
| 지표 | 설명 | 기준 |
|---|---|---|
| 샤프(Sharpe) | 위험 대비 초과 수익률 | 1.0 이상 양호, 2.0 이상 우수 |
| 소르티노(Sortino) | 하방 위험만 반영한 수익 효율 | 샤프보다 보수적 지표 |
| 칼마(Calmar) | 연환산 수익률 / MDD | 높을수록 낙폭 대비 회복 효율 좋음 |
| 변동성(연) | 수익률의 연환산 표준편차 | 20% 이하면 비교적 안정적 |
해석 시 주의사항¶
과적합(Overfitting) 주의
백테스트 결과가 좋아도 실전에서 성과가 다를 수 있습니다. 파라미터를 과도하게 최적화하면 과거 데이터에만 맞춰진 전략이 됩니다. 충분한 기간(최소 3개월 이상)으로 테스트하고, 잔고가 작은 별도 계정에서 소액 실거래로 실시간 동작을 1차 검증한 뒤 본 자본금에 적용하세요(Upbit는 별도 paper-trading 환경이 없습니다).
승률과 손익비 함께 보기
승률이 낮아도 손익비가 높으면 수익 전략일 수 있습니다. 예: 승률 40% + 손익비 3.0이면, 3번 손실에 1번 이익이지만 이익이 손실의 3배라 전체 수익이 플러스입니다.
백테스트 사용 팁¶
- 분봉 데이터는 기간이 너무 길면 실패합니다. 최근 1~3개월부터 시작하세요.
- 멀티 타임프레임 전략은 모든 타임프레임 데이터가 준비되어야 합니다. 일봉 + 분봉을 동시에 쓴다면 두 데이터 모두 충분한 기간을 설정하세요.
- 유니버스(여러 종목에 동시 적용) 결과의 종목별 기여율은 포트폴리오 기준 값으로 해석하세요.
실패 시 확인 순서¶
- 코드 문법 오류가 없는지
- 선택한 기간에 데이터가 충분한지
- 종목/타임프레임 조합이 과도하지 않은지
- 네트워크/로그인 상태가 정상인지
단축키¶
| 단축키 | 기능 |
|---|---|
| Ctrl+S | 저장 |
| Ctrl+Space | 자동완성 |
| Ctrl+Z | 실행 취소 |
| Ctrl+Shift+Z | 다시 실행 |
| Ctrl+/ | 주석 토글 |
파라미터 수정 위치¶
- 코드 기본값 수정: 스튜디오 코드에서
param(...)수정 - 실행 중 전략 파라미터 조정: 거래 탭의 전략 편집 패널
역할 시각화 — @screener / @trade / @universe.metric¶
@screener, @trade, @universe.metric 데코레이터가 붙은 함수는 에디터에서 자동으로 강조됩니다.
- 함수 배경색: 역할마다 다른 색으로 함수 범위를 표시합니다.
- 역할 배지: 데코레이터 위에 작은 배지(
@screener/@trade/@universe.metric)가 나타납니다. - unified 함수 (
@screener+@trade동시 적용): 두 배지가 함께 표시됩니다.
에디터를 단일 코드 화면으로 유지하면서 역할만 시각화하므로, 함수를 분리하거나 탭을 나누지 않아도 됩니다.
스크리너 테스트 (Screener Test)¶
우측 탭에서 스크리너 테스트를 선택하면 작성 중 스크립트를 현시점 시장(KRW 마켓 전체)에 1회 적용한 결과를 확인할 수 있습니다. 운영 중 전략의 라이브 funnel이 아니라, 편집 중 스크립트의 검증 도구입니다. 평가 대상 universe는 활성 전략 여부와 무관하게 KRW 마켓 전체로 유지되므로, 거래대금/등락률 같은 ranking 조건도 strategy 미활성 상태에서 그대로 동작합니다(universe.in_top("trade_value_24h", n=50) 등). 일시적인 마켓 리스트 fetch 실패가 발생한 사이클에서는 baseline 보존이 잠시 누락될 수 있고, 다음 동기화에서 자동 복구됩니다.
사용 방법¶
- 우측 탭에서 스크리너 테스트를 엽니다.
- 패널 우상단의 새로고침 버튼을 누르면 평가가 시작됩니다 (universe 200 종목 1회 sweep, 약 10초 소요).
- 결과는 두 섹션으로 정렬되어 표시됩니다.
- 통과 (IN, 상단 강조): 스크리너 조건을 통과한 종목 + 통과 근거 evidence 라인.
- 탈락 (OUT, 하단 비강조): 사유 tag 그룹별 묶음 + 핵심 evidence 1~2개.
Evidence 라인 — 무엇이 보이나요?¶
Evidence는 사용자 스크립트가 호출한 universe.* / ta.* 표현을 기반으로 자동 생성됩니다.
| 호출 패턴 | Evidence 라벨 예시 |
|---|---|
universe.in_top("trade_value_24h", n=50) |
거래대금 24h Top 50 (#3, 1,247억) |
universe.in_bottom("volatility_1h", n=10) |
변동성 1h Bottom 10 |
universe.rank("trade_value_24h") |
거래대금 24h 랭크 (#3) |
universe.percentile("change_pct_24h") |
등락률 24h 백분위 (85.0%) |
ta.rsi(c.close, 14) |
RSI(14) (28.50) |
ta.crossover(fast, slow) |
Crossover |
ta.crossunder(fast, slow) |
Crossunder |
탈락 사유의 우선순위:
release(tag="...")/hold(tag="...")사용자 명시 tag — 1순위.- tag가 없으면 마지막 실패한 universe / ta 호출이 자동 sentence로 변환됩니다 (예: "거래대금 24h Top 50 미달 (#87)").
오류 상태¶
- 스크립트 평가 실패: 모든 종목이 동일한
평가 오류:reason_tag로 떨어지면 종목 행 대신 패널 상단에 "스크립트 평가 실패" 카드가 표시되고 원문 메시지가 노출됩니다. 컴파일 오류뿐 아니라 sandbox 런타임 오류·타임아웃까지 같은 카드로 안내합니다. - universe 캐시 미준비: 자격증명이 등록되지 않았거나 엔진 초기화 전이면 "universe 미준비" 안내가 표시됩니다. Settings에서 Upbit 키를 등록한 뒤 다시 시도하세요.
- 워밍업 진행 중: 자격증명 등록 직후 또는 재기동 직후에는 KRW 전 종목 × 9개 봉 스케일을 사전 적재하는 캔들 워밍업이 진행됩니다. 이 기간(
engine.warmup_phase == "WARMING_UP")에는 sweep 호출이 503 +detail.code == "warmup_in_progress"로 차단되며, 패널은 "워밍업 진행 중" 카드 + 진행률 bar(예: "84 / 200 쌍 로드 (42%)")로 안내합니다. 진행률 bar는candle_warmup_progressWS 스트림에 reactive로 묶여 있어 사용자가 새로고침을 다시 누르지 않아도 매 push마다 자동 갱신됩니다. 새로고침 버튼은 비활성화되지 않으므로, 진행률이 100%에 가까워졌을 때 한 번 더 눌러 sweep을 시작할 수 있습니다. 운영 스트립 하단에도 동일한 진행률이 "전체 종목 워밍업 중" row로 노출됩니다. 첫 기동은 약 200초, 재기동은 영구 캐시 fast-path로 수 초 안에 완료됩니다. 단순 "실행 실패" 카피와 다른 워밍업 전용 PENDING UX가 노출됩니다. - 스크립트가 비어 있을 때: 새로고침 버튼이 비활성화되고 사용 안내 카피만 보입니다.
- 스크립트/파라미터 변경 시: 이전 결과는 stale로 간주돼 자동으로 비워지고 안내 상태로 돌아갑니다. 새로고침을 다시 눌러 현재 스크립트 결과를 확인하세요.
screen() / release() 같이 호출하면?
한 평가에서 screen()과 release()가 모두 호출되면 마지막 호출이 결정합니다 (spec §5.1 last-call-wins). 예: screen(); release(tag="bail") → OUT, release(); screen() → IN. Studio "스크리너 테스트" 결과 분류도 동일 규칙을 그대로 따릅니다.
알아두기¶
운영 중 funnel은 별도
운영 탭에 활성화된 전략의 실시간 파이프라인 상태(유니버스 → 스크리너 통과 → 활성 포지션)는 운영 탭의 기존 UI에서 확인하세요. Studio "스크리너 테스트"는 작성 중 스크립트의 1회 평가만 수행하며, 운영 funnel과 분리되어 있습니다.
캔들 히스토리 한계 (현재 단계)
sweep 평가에는 universe 종목별 캔들 히스토리 사전 워밍업이 적용되지 않습니다. 그래서 universe.* 조건 + screen() / release() 기반 evidence는 정상 동작하지만, ta.rsi / ta.ema 같은 N봉 의존 지표는 last() 값이 비어 보일 수 있습니다. 캔들 워밍업을 sweep에 적용하는 것은 후속 단계에서 다룹니다.
scope
현재 sweep은 KRW 마켓 전체를 평가합니다. BTC / USDT 마켓 또는 명시 종목 list로의 scope 지정은 후속 이슈에서 도입됩니다.
universe.* 스크리너 스크립트 테스트¶
universe.in_top(), universe.rank() 같은 universe.* 표현을 사용하는 스크리너 스크립트를 스튜디오에서 열어 차트 테스트를 실행하면 평가는 정상 동작하지만 빈 universe 캐시 기반으로 동작합니다.
| 상황 | universe.* 결과 |
|---|---|
| 스튜디오 차트 테스트 (엔진 미실행) | in_top() → False, rank() → None (빈 캐시) |
| 엔진 실행 중 (Upbit 키 저장 후) | 실시간 시장 데이터 기반 실제 값 |
스튜디오 테스트에서 universe.*가 의미 있는 결과를 내려면 Upbit 키를 설정하고 엔진을 시작한 뒤 운영 탭에서 전략을 활성화하세요. 스크립트 문법이나 @screener / @trade 흐름 자체를 검증하는 용도라면 빈 캐시 상태에서도 오류 없이 실행됩니다.
엔진이 시작되지 않은 상태에서 /api/dsl/evaluate (스튜디오 평가/probe 경로) 도 동일하게 빈 스코프 universe 캐시로 폴백합니다. 이전에는 이 폴백 경로에서 내부 TypeError가 발생할 수 있었으나 현재는 정상 평가가 진행되며 universe.* 결과만 빈 캐시 기준이 됩니다.