6월 말까지 패리티 코퍼스의 기준 전략은 167개에서 252개로 늘었다. 코퍼스가 한 번도 건드리지 않은 버그 세 개는 커뮤니티에 공유된 스크립트에서 드러났다 — 빠져 있던 마진콜 강제 청산, 환율을 몰랐던 주문 여력 검사, 소리 없이 한 번도 활성화되지 않은 트레일링 스톱.
이 글의 수치는 2026년 6월 29일에 측정한 값이며 당시 그대로 두었습니다. 최신 결과는 패리티 측정 방법에서 확인하세요.
5월에 코퍼스를 마지막으로 글로 정리했을 때, 패리티 코퍼스에는 기준 전략 167개가 있었고 그중 165개가 TradingView 대비 거래 단위 엄격 패리티였다. 코퍼스는 그 뒤로도 커졌다. 6월 말에는 전략 252개, 그중 251개가 “excellent” 패리티(99.6%), 문서화된 이상 사례(anomaly) 1건, 실패 0건이 됐다.
헤드라인 숫자는 오히려 지루한 부분이다. 흥미로운 건 코퍼스가 건드리지 않은 곳이다. 우리가 모델링하지 않던 TradingView 브로커 동작 세 가지인데, 모두 252개 중 어느 전략도 타지 않은 코드 경로를 커뮤니티에 공유된 스크립트가 타면서 발견됐다. 이 글은 그중 세 가지를 차례로 짚어 본다.
2026-06-29 기준 코퍼스 현황
corpus/validation_report.md (2026-06-29)
Total probes: 252
Excellent: 251 (99.6%)
Anomaly: 1
Strong/Moderate/Weak/Minimal/Missing: 0
TV trades: 389,590
Engine trades: 389,688
Matched: 389,468
엔진은 코퍼스 전체에서 TradingView보다 거래를 98건 더 냈다. 기준 거래 389,590건 대비 0.025% 차이다. 이는 합계 기준이고, 전략별로 쪼개 보면 아래에서 다룰 anomaly 1건이 보탠 거래는 그중 한 건뿐이다. 나머지는 전략 23개에서 나왔다. 그 리포트의 채점 기준은 거래 수 차이가 1% 미만이면 허용했기 때문에, 이 23개는 모두 여전히 excellent 등급이었다. 대부분은 한두 건 차이였고, 98건 중 90건은 그중 네 개 전략에서 나왔다.
당시 가장 최근에 추가된 프로브 6개는 drawing 카테고리였다. Pine 드로잉 객체(line.get_price, label·box 좌표)를 차트 주석이 아니라 백테스트 시점의 데이터로 읽는 런타임을 내놓으면서 추가한 것이다. 그려 둔 선을 계산 상태로 쓰는 전략, 예를 들어 수동으로 고정한 추세선을 동적 지지선으로 쓰는 전략은 스크립트가 이미 삭제한 객체의 좌표도 엔진이 계속 내줘야 한다. TradingView가 그렇게 하듯이. 여섯 개 모두 excellent 등급을 받았다.
솔직하게 밝히는 anomaly 1건
맞지 않았던 전략 1건을 걸러 내 숨기지 않았다. anomaly-equity-mirror-strategy-equity-01은 마진 진입 허용(admission) 판정의 1× equity 경계 바로 위에 있다. 당시 우리 분석에 따르면(코퍼스 노트에는 신뢰도 95% 이상으로 기록돼 있다), TradingView 브로커 에뮬레이터는 바로 그 경계에서 단조적이지 않았다(non-monotonic). equity를 넘는 진입 일부는 받아 주고 equity에 못 미치는 진입 일부는 거부했는데, 봉마다 일관성이 없었다. 우리 엔진은 결정적(deterministic)이다. equity가 같으면 허용 여부 판단도 매번 같다. Pine 문서에 나온 마진 의미론으로 보면 이게 맞는 동작이고, 같은 분석에 따르면 그 경계에서 TradingView 브로커가 실제로 한 동작과는 달랐다. 이를 맞추려면 우리 쪽에 비결정성을 일부러 넣어야 했기에, 그렇게 하지 않았다. 이 차이는 숨기지 않고 문서화했으며, 252개 중 유일한 사례였다. (그 뒤 메인테이너가 2026-09-29에 잡은 기준선에서는 이 프로브가 excellent 등급을 받았고, 코퍼스 README에는 이 진단이 검토 중이라고 적혀 있다.)
버그 1: TradingView라면 강제 청산했을 포지션
TradingView 브로커는 마진 요건을 뚫고 내려간 포지션을 언제 정리할지 전략 로직이 정해 주기를 기다리지 않는다. 그냥 청산한다. 레버리지 포지션이나 숏 포지션의 equity가 크게 떨어져 필요 마진(required margin)이 계좌 equity를 넘으면, TradingView는 strategy.exit() 조건이 충족됐든 아니든 그렇게 된 바로 그 봉에서 청산한다. 청산가는 그 봉에서 포지션에 가장 불리한 가격이고, 청산 수량은 마진을 회복하는 데 필요한 양의 네 배로, 포지션 전체를 넘지 않는다.
엔진은 이를 모델링하지 않았다. 포지션을 그대로 들고 있다가 전략 자체 로직이 언젠가 닫도록 내버려 뒀다. 스톱이 타이트하지 않은 전략이라면, TradingView가 이미 청산한 포지션을 수십 봉 동안 더 들고 있을 수 있다는 뜻이다. 레버리지 포지션이나 숏 포지션을 마진콜이 날 때까지 들고 간, 커뮤니티에 공유된 스크립트 24개에서는 엔진이 한 번도 내지 않은 “Margin call” 청산이 TradingView 거래 목록에 찍혀 있었다.
수정 사항은 계좌 equity가 마진 요건을 깨면 강제 청산하는 로직이다. 청산가는 TradingView 브로커와 같은 방식으로 계산하고, 청산 수량은 심볼의 lot step 단위로 맞춘다(quantize). TradingView는 심볼의 lot step보다 작은 소수 lot을 청산하지 않는다. 실행할 때 lot step 값이 주어지면, 이제 우리도 그렇다.
무기한 선물(perpetual)에서 레버리지나 숏 전략을 백테스트하는 사람에게 가장 큰 영향이 있다. 낙폭 구간에서 equity 곡선이 지나치게 매끄러워 보였다면, 이게 원인이었을 법하다.
버그 2: 환율을 몰랐던 주문 여력 검사
Pine 전략은 심볼의 호가 통화(quote currency)와 다른 계좌 통화를 선언할 수 있다. 예를 들어 USDT 페어를 거래하면서 currency.INR을 쓰는 식이다. TradingView 브로커는 주문을 감당할 수 있는지 확인하기 전에, 주문의 명목 가치(notional)를 그 시점 환율로 계좌 통화로 환산한 다음, 같은 통화 기준의 equity와 비교한다.
엔진의 주문 여력 검사(affordability check)는 이 환산을 건너뛰었다. USDT 명목 가치를 INR 표시 equity와 환율이 1:1인 것처럼 그대로 비교한 것이다. 그래서 currency.INR을 선언한 전략은 실제보다 수십 배 더 여유 있어 보였다(USDT의 가치가 루피의 수십 배이기 때문이다). 영향을 받은 스크립트에서 엔진은 TradingView보다 거래를 대략 두 배 많이 냈다. TradingView 브로커가 여력 부족으로 거부한 진입까지 받아들였기 때문이다.
수정은 주문 여력 검사가 돌기 전에 필요 마진에 계좌 통화 환율을 적용하는 것이다. 주문 파이프라인에서 TradingView가 환율을 적용하는 바로 그 지점이다. 환율은 실행할 때 주어진 값을 쓰며, 엔진 기본값은 1:1이다. USD가 아닌 계좌 통화로 USD나 USDT 호가 심볼을 백테스트한 적이 있다면, 거래 수를 조용히 부풀리던 게 바로 이 버그였다.
버그 3: 한 번도 활성화되지 않은 트레일링 스톱
사용자가 우리보다 먼저 알아챘기를 가장 바라게 되는 버그다. 소리 없이 실패하기 때문이다. strategy.exit()은 트레일링 스톱을 지정하는 두 가지 방법을 지원한다. 진입가 기준 상대 거리인 trail_points, 그리고 절대 활성화 가격인 trail_price다.
// armed correctly today; trail_price-only calls used to never arm at all
strategy.exit("TS", from_entry = "Long", trail_price = close * 1.05, trail_offset = 10)
엔진의 활성화(arming) 조건은 trail_points만 확인했다. trail_price만으로 지정한 트레일링 청산은 에러 없이 컴파일되고 에러 없이 실행됐지만, 한 번도 활성화되지 않았다. 포지션은 트레일링 스톱 없이 백테스트 내내 조용히 방치됐다. 예외도, 로그 한 줄도, 거래도 없었다. 전략은 보호받는 것처럼 보였지만, 그렇지 않았다.
이 버그를 찾은 건 트레일링 스톱을 trail_price만으로 지정하는, 커뮤니티에 공유된 스크립트 덕분이다. 이 스크립트는 TradingView 거래의 절반밖에 맞추지 못했는데, 수정 후에는 99.7%를 맞췄다. 공개 코퍼스에는 trail_price를 쓰는 프로브가 하나도 없었기 때문에, 코퍼스 숫자로는 이 갭이 드러날 수 없었다. 코퍼스 분류 글에서 설명한 validation 카테고리가 바로 이런 갭을 위해 존재한다. 이 카테고리의 전략은 좁고 합성적이다. 수익성도 현실성도 없지만, Pine 기능 하나만 떼어 시험하도록 만들어서 이런 회귀가 “전체 숫자는 괜찮아 보였다” 뒤에 숨을 수 없게 한다.
수정 후에는 trail_points나 trail_price 중 하나만 있어도 트레일링 스톱을 활성화한다. trail_price를 쓴 Pine 전략의 equity 곡선이 트레일링 스톱이 아예 없는 것처럼 수상해 보였던 적이 있다면, 실제로 없었다. 이 수정을 처음 담은 v0.10.14(2026-07-02) 이전의 모든 엔진 릴리스에서.
이게 코퍼스를 두는 진짜 이유다
세 버그 중 코드 리뷰로 찾은 건 하나도 없다. 딱 맞는 모양의 전략이 엔진을 거치면서 TradingView와 맞지 않는 숫자를 냈기 때문에 찾았다. 스모크 테스트 몇 개가 아니라 167개, 이어서 252개, 그리고 계속 늘어나는 전략을 따로 떼어 둔 버전 관리 코퍼스로 유지하는 이유, 그리고 커뮤니티에 공유된 스크립트도 같은 diff로 돌리는 이유가 전부 여기에 있다. 이번 세 버그가 나온 곳도 바로 거기다. 헤드라인 숫자가 깔끔해도, 전략이 얼마를 벌거나 잃었는지를 바꾸는 버그가 그 뒤에 숨어 있을 수 있다. 그런 버그를 잡는 유일한 방법은 더 다양한 모양의 전략을 같은 정답(ground truth)에 대고 같은 diff로 계속 돌리는 것이다.
갭을 찾는 대로 프로브를 계속 추가하고, 숫자도 좋은 것이든 anomaly 1건이든 있는 그대로 계속 공개하겠다.
다음으로 볼 곳
- 갤러리 둘러보기: 지금의 공개 코퍼스 전략 312개. 전략마다 개별 페이지에서 패리티 결과와 거래 수를 볼 수 있다.
- 비슷한 마진 버그를 찾은 과정 읽기 — 다른 버그, 다른 경계, 같은 방법: 격리하고, diff하고, 고친다.
- Claude나 Cursor에서 백테스트하기: 무료 호스팅 MCP 서버, 또는 내 OHLCV로 돌리는 로컬 Docker 서버.
- 패리티를 측정하는 방법: 현재 결과와 그 출처.