내 트레이딩 봇은 4일 동안 거래 중이라고 말했다... 그는 거짓말을 하고 있었다
요약
LLM 보조 암호화폐 트레이딩 봇 'ziom trader'의 실제 실행 과정에서 발생하는 데이터 불일치와 계층별 오류를 분석합니다. 백테스트(Shadow)와 실제 시장(Live) 사이의 격차를 관리하고, P&L의 귀속 문제를 해결하는 프레임워크를 다룹니다.
핵심 포인트
- P&L은 전략, 실행 래퍼, 모니터링 계층의 합계로 구성됨
- 백테스트 데이터와 실제 라이브 데이터 간의 격차 분석 필요
- 계층별 귀속(Attribution) 정보가 없는 데이터는 신뢰하기 어려움
- 시스템 오류를 식별하기 위한 다층적 모니터링 구조의 중요성
Hyperliquid에서의 25일. 65번의 종료된 거래. P&L(손익): -$9.21.
알고 보니 그것은 가장 사소한 잘못이었다.
랜딩 페이지에는 -$7.72가 표시되었는데, 이는 다른 P&L 공식을 사용하고 두 개의 오픈 포지션(open positions)을 제외했기 때문이다. 어느 쪽 숫자든 작다. 하지만 두 숫자 모두 나에게 전달하고 있는 내용에 있어 틀린 것이었다.
나는 어제 모든 거래를 감사(auditing)하는 데 시간을 보냈다. 감사 결과 예상치 못한 세 가지 발견 사항이 나왔다. 각각은 서로 다른 종류의 오류였다.
이 글은 나의 작은 AI 보조 암호화폐 트레이딩 봇인 ziom trader에 관한 시리즈의 첫 번째 포스트이다. "Ziom"은 말하는 사람에 따라 친구, 동료, 또는 녀석을 뜻하는 폴란드어이다. 이름은 의도적으로 진지하지 않게 지었다. 하지만 시스템은 그렇지 않다.
이것은 "내가 돈을 찍어내는 것을 지켜보라"는 식의 시리즈가 아니다. 숫자는 마이너스다. 좋다.
이 시리즈의 목적은 LLM(대규모 언어 모델) 보조 트레이딩 시스템이 백테스트(backtests)와 대시보드(dashboards)를 넘어 실제 실행(live execution) 단계로 넘어갈 때 어떤 일이 발생하는지 추적하는 것이다. 즉, 봇이 어디서 틀리는지, 대시보드가 어디서 틀리는지, 내가 어디서 틀리는지, 그리고 어느 계층(layer)이 이를 증명하게 되는지를 다룬다.
프레임 (Frame)
-$9.21이라는 숫자를 처음 접했을 때 자연스러운 해석은 "전략이 돈을 잃고 있다"는 것이다. 그 해석은 표시된 P&L이 전략의 탓이라고 가정한다. 하지만 그렇지 않다.
표면에 나타나는 숫자는 최소 세 가지의 서로 다른 계층의 합계이다: 전략 그 자체, 그 주변을 감싸는 실행 래퍼(execution wrapper), 그리고 둘 다를 관찰하는 모니터링 계층(monitoring layer)이다. 각 계층은 자신만의 종류의 실패를 만들어낼 수 있다. 표시된 숫자는 이 세 가지를 단일 달러 수치로 압축하며, 그 과정에서 귀속(attribution) 정보를 잃어버린다.
Daniel Nevoigt로부터 얻은 나의 프레임은, 향후 상관관계(forward-correlation)에 대한 공개 없이 방법론 개요만 제공하는 것은 선의만 있는 로그(log)라는 것이다. P&L에도 동일하게 적용된다: 계층별 귀속에 대한 공개 없이 총 P&L만 보여주는 것은 선의만 있는 로그이다. 당신은 숫자를 보지만, 그것이 어디에서 왔는지는 보지 못한다.
내가 귀속을 강제했을 때 발견한 내용은 다음과 같다.
계층 1: 섀도우(Shadow)는 라이브(live)와 같지 않다
어떤 레인(lane)을 배포하기 전, 시스템은 백테스트(backtested) 데이터에 대해 실행됩니다. 섀도우(shadow)는 "이 전략은 Y번의 거래 동안 X의 수익을 낸다"라고 말합니다. 배포 결정은 섀도우가 건강해 보일 때 내려집니다. 그 후 라이브(live)가 실행되며 다른 숫자를 만들어냅니다.
그 차이에 대한 라벨(label)은 "전략이 실망스러웠다"가 아닙니다. 섀도우는 하나의 권위(authority)입니다. 라이브는 또 다른 권위입니다. 실패 기준을 작성한 것은 전략이 아니라 시장입니다.
이것은 Christopher Maher가 명명한 이음새(seam)의 버전입니다. 즉, 바이트 체크(bite check)가 스스로를 잡아내지 못했고, 다른 레일(rail)이 그것을 잡아낸 것입니다. 섀도우 데이터는 스스로의 실패를 작성할 수 없습니다. 오직 라이브 시장만이 그럴 수 있습니다. 그리고 라이브 시장은 그 격차의 어느 부분이 변동성(variance)인지, 어느 부분이 체제 변화(regime drift)인지, 그리고 어느 부분이 당신이 튜닝(tune)하는 것을 잊어버린 파라미터(parameter)인지 알려주지 않습니다.
이 구간에서 funding_divergence_long 레인은 n=660의 백테스트 거래 동안 거래당 +0.355%의 섀도우 우위(edge)를 가졌으며, 95% 신뢰 구간(CI95)은 [+0.085, +0.625]였습니다. 동일한 레인의 라이브는 29번의 라이브 거래 동안 거래당 -1.10%였습니다. 그 격차는 1.46 퍼센트 포인트입니다. 거래당 시그마(sigma)가 약 2%이고 n=29일 때, 그 격차는 3.9 표준 오차(standard errors)에 해당합니다. 통계적으로 유의미한 음수입니다.
이것이 전략이 망가졌음을 증명하는 것은 아닙니다. 그것은 섀도우와 라이브가 변동성으로 설명할 수 있는 수준 이상으로 불일치했음을 증명합니다. 세 가지 설명이 여전히 유효하며, 감사(audit)를 통해 범위를 좁힐 수는 있지만 해결할 수는 없습니다:
- 6월 15일 ADA 이상치(outlier)는 -$2.25, -5.64%였으며, 이는 섀도우 평균에서 3.6 시그마 떨어져 있습니다. 작은 표본 내에서 단 하나의 거래가 구조적인 영향을 미치고 있습니다.
- 우위(edge)가 이 BTC 구간 동안 지속되지 않습니다. 6월은 회복에서 반전(reversal)으로 이어졌습니다.
- 청산(exit) 설정 선택이 손실을 키웠습니다.
이것들을 구분하기 위해서는 50~100번의 거래가 더 필요합니다. 저는 오늘 이것들을 구분하지 않을 것입니다. 이 섹션의 라벨은 AMBIGUOUS(모호함)이며, 표본이 두 배가 될 때까지 이 라벨을 유지하겠습니다.
계층 2: 표시된 라이브가 전략의 진실과 일치하지는 않는다
-$9.21 내부에서 60%는 전략의 문제가 아닙니다. 그것은 git 커밋 참조(git commit refs)를 포함한 시스템 오버헤드(system overhead)입니다.
상세 내역:
| 원인 | 거래 횟수 | 손실 | 커밋 참조 (Commit ref) |
|---|---|---|---|
| regime gate 없이 bear 시장에서 실행된 oi_surge LONG | 3 | -$1.45 | 6월 11일 gate 추가 2d10e326 |
| ... | |||
| 총 시스템 오버헤드 (Total system overhead): 36번의 거래에서 -$5.49 발생, 손실의 60% 차지. |
손실의 60%는 감사 추적 (audit trail)이 가능합니다. 그 대부분은 git 커밋 (git commit)을 가지고 있습니다. 이 모든 것은 "신호(signal)가 실패했다"는 것과는 다른 종류의 오류입니다.
각 행에는 격차를 메우는 커밋 해시 (commit hash)가 있거나, 감사를 통해 드러난 이음새 (seam)가 있습니다. 이 중 어느 것도 "신호가 틀렸다"는 의미에서의 전략 (strategy)이 아닙니다. 이 모든 것은 "이를 막았어야 할 레일(rail)이 아직 존재하지 않았다"는 의미에서의 시스템 (system)입니다.
Sean Burn은 이를 정확하게 명명했습니다: 이음새를 보여주되, 숨기지 마십시오. 이 손실의 60%가 현재는 존재하지만 6월 6일에는 존재하지 않았던 커밋들에 의해 해결되었음을 보여주십시오. "시스템"과 "전략"을 "봇이 돈을 잃었다"라는 하나의 바구니로 통합하지 마십시오. 이들은 동일한 달러(손실)를 만들어낸 서로 다른 저자들입니다.
나머지 40%는 funding_divergence_long (-32번의 거래에서 -$4.15)와 oi_surge_fade (2번의 거래에서 +$0.13)입니다. funding_long 라인은 Layer 1의 shadow-vs-live 격차가 발생하는 라인입니다. ADA 이상치 (outlier)와 다음에 설명할 실행 격차 (execution gap)가 없었다면, 이 경로는 28번의 거래에서 -$1.47, 즉 거래당 -$0.05를 기록했을 것입니다. 이는 이 표본 크기에서의 노이즈 플로어 (noise floor)이지, 전략의 품질이 아닙니다. 그렇게 취급하십시오.
Layer 3: 가시적인 라이브(live) 상태가 운전자가 시도한 것과 일치하지는 않는다
세 번째 발견에는 경고가 없었습니다. 처음 두 가지는 인벤토리 작업이었습니다. 이번 것은 구조적인 것이었습니다.
6월 18일 10:01 UTC부터 6월 22일 16:01 UTC 사이, funding_divergence_long 드라이버(driver)는 무장(armed) 상태였습니다. 데이터베이스의 run_summary 이벤트는 약 20~30 사이클 동안 4일 전체 기간에 대해 armed=true, placed=1을 보여줍니다. 동일한 기간의 포지션 테이블(positions table)은 새로운 체결(fills)이 0임을 보여줍니다. 이벤트 테이블(events table)은 execution_error 이벤트가 0임을 보여줍니다.
대시보드는 placed=1로 읽었습니다. 거래소 확인 계층(exchange acknowledgement layer)은 placed_ok=0을 기록했습니다. execution_error 행을 기록했을 오류 경로(error path)는 실행되지 않았는데, 예외(exception)를 던지는 코드가 상위 단계(upstream) 어딘가에서 에러 카운터를 증가시키지 않은 채 포착되었기 때문입니다.
4일 동안 드라이버(driver)는 거래 중이라고 말했습니다. 거래소는 아니라고 말했습니다.
이벤트 테이블(events table)은 아무 말도 하지 않았습니다.
감사 추적(audit trail) 자체가 거짓을 말하고 있었습니다.
L. Cordero의 프레임워크가 적용됩니다: 검색(retrieval)을 신뢰하고, 회상(recall)을 검증하라. placed=1 카운터는 시스템이 자신의 신념을 검색(retrieving)한 것이었습니다. 실제 포지션 상태는 회상(recall)이었으며, 회상 경로가 끊어져 있었습니다. 두 계층이 조용히 갈라졌고, 대시보드는 잘못된 계층을 읽고 있었습니다.
Todd Hendricks의 프레임워크가 적용됩니다: 큰 숫자, 잘못된 지표(big number, wrong metric). placed=1은 큰 숫자입니다. placed_ok=0이 의미 있는 숫자입니다. 시스템은 큰 숫자를 표시했습니다. 저는 잘못된 대시보드를 배포했습니다.
감사(audit) 이후, 다른 온체인 읽기(read-the-chain) 제품을 운영하는 동료가 시도된 읽기(attempted read)와 검증된 읽기(verified read) 사이의 경계가 바로 이러한 종류의 버그가 발생하는 지점임을 독립적으로 확인한 후, 오늘 수정 사항이 반영되었습니다. 그가 제안한 올바른 기본값(default)은 다음과 같습니다: 기본적으로 불완전할 것(incomplete by default). 명시적으로 검증된 결과로 분류되지 않은 모든 것은 '0'이 아니라 '알 수 없음(unknown)'입니다. '0'과 '알 수 없음'은 시각적으로 뚜렷하게 구분되어야 합니다. 파이프라인은 이 구분을 표면(surface)까지 그대로 전달합니다.
영향(Impact) 추정치: 20~30개의 신호 누락, 각각 약 $15의 명목 가치(notional). 만약 샤도우 엣지(shadow edge)가 유지되었다면, 이익이든 손실이든 양방향으로 $1에서 $1.50 정도의 차이가 발생했을 것이며, 이는 표시된 손익(P&L)에는 보이지 않았을 것입니다. 놓친 거래가 어느 방향으로 흘러갔을지 알 수 없기 때문에, 정직한 라벨은 '추정치(ESTIMATED)'입니다.
감사가 변화시키는 것
표시된 손실은 -$9.21입니다. 시스템 오버헤드(system overhead), 실행 격차(execution gap), 그리고 단일 3.6-시그마(3.6-sigma) 이상치(outlier)를 제외한 해당 손실에 대한 전략 기여도는 28번의 거래 동안 약 -$1.47, 즉 거래당 -$0.05입니다. 이것은 노이즈(noise)입니다. 샘플이 너무 적어 전략이 좋거나 나쁘다고 판단하기에는 부족합니다. 포워드 테스트(Forward-test) 예산: 전략 품질에 대한 어떠한 판결을 내리기 전까지 50~100회의 거래를 더 진행해야 합니다.
시스템 오버헤드는 해결되었습니다. 커밋(commits)은 존재합니다. 다음 50~100번의 거래는 레짐 게이트(regime gate), 코인당 최대 제한(max_per_coin cap), 비활성화된 데드 레인(dead lanes), 수정된 검증 레일(verification rail), 그리고 현재의 활성 레인(active lane) 구성과 함께 실행될 것입니다. 만약 이 거래들이 실행되었음에도 레인이 거래당 -$0.10 이하로 나타난다면, 문제는 레일(rails)이 아니라 전략입니다. 만약 실행 후 레인이 거래당 +$0.05 이상으로 나타난다면, 섀도우 엣지(shadow edge)가 유지된 것이며 이전의 손실은 레일 때문이었던 것입니다.
저는 테스트 예산을 미리 확정해 둡니다. 만약 다음 50번의 거래가 거래당 -$0.10 이하로 나타난다면, 이 포스트에서 보여준 수정 후의 낙관론을 철회하겠습니다. 베팅은 신호(signal)가 아니라 레일이 문제라는 쪽에 걸려 있습니다. 어떤 결과가 나오든 다음 분석 내용을 게시하겠습니다.
사후 감사 점검 (Post-audit check)
감사가 시작된 후 약 12시간 뒤인 2026-06-25 19:15 CEST경에 추가되었습니다. 확인을 마쳤습니다.
첫 번째 사후 감사 윈도우(post-audit window)에서는 이전의 실패 패턴이 재현되지 않았습니다.
oi_surge_fade_live SHORT 레인은 사후 감사 후 12번의 거래 동안 약 +$1.38를 기록했으며, 12번 중 10번이 수익(green)이었습니다.
여기에는 AVAX, UNI, ADA, ATOM, FIL, TIA가 포함됩니다. 중요한 점은 수치가 수익이라는 것이 아닙니다. 중요한 점은 감사를 통해 '시도된 배치(attempted placement)'와 '거래소에서 확인된 배치(exchange-confirmed placement)'를 분리한 후에 결과가 나왔다는 점입니다.
초기 분석은 긍정적이지만 제한적입니다.
이것은 "수정이 성공했다"는 뜻이 아닙니다. "첫 번째 사후 감사 윈도우에서 이전의 버그 형태가 즉시 반복되지 않았으며, 새로운 보고 레일(reporting rail) 하에서 활성 레인이 초기 윈도우 동안 수익을 냈다"는 뜻입니다.
이 두 가지는 서로 다른 주장입니다.
저는 오직 이 제한적인 주장만을 하고 있습니다.
이것이 아닌 것 (What this is not)
이것은 제가 돈을 벌었다는 글이 아닙니다. 숫자는 마이너스입니다. 크지 않습니다. 전략도 검증되지 않았습니다. 감사는 커밋 참조를 통해 실제 버그들을 발견했지만, 이 전략이 작동한다는 것을 증명하지는 못했습니다.
또한 이것은 AI가 제 봇을 코딩했다는 글도 아닙니다. Claude Code가 이 시스템의 상당 부분을 작성했습니다. 감사 과정에서 동일한 저자(모델의 도움을 받은 나)가 액션 레이어와 그 액션을 검증해야 하는 레이어를 모두 작성한 여러 곳이 발견되었습니다. 단일 저자 감사 추적은 거짓입니다. 그 부분은 모델에 관한 것이 아니라 시스템 설계에 관한 것입니다.
진짜 이것은 모든 알고리즘 트레이딩 또는 자율 에이전트 시스템에서 표시되는 작은 숫자 아래에 위치해야 할 분석입니다. 세 가지 종류의 오류가 있습니다. 같은 달러를 만든 세 명의 다른 저자입니다. 표시된 숫자는 그중 하나일 뿐입니다. 나머지 두 개는 기본적으로 보이지 않습니다.
시리즈 계약 (Series contract)
이 시리즈는 ziom trader를 성과 주장으로가 아니라 살아있는 시스템으로서 추적할 것입니다.
저는 지루한 부분들을 게시할 것입니다: 작은 손실, 체결 실패(missed fills), 고장 난 카운터, 구식 가정, 대시보드의 거짓말, 감사 수정 사항, 그리고 다음 샘플이 이전의 읽기와 모순될 때의 철회입니다.
알파 주장은 없습니다. 미래 샘플이 그 문장을 벌기 전까지는
- Daniel Nevoigt: "전방 상관관계 (forward-correlation) 공개 없는 방법론 개요는 선의만 가득한 기록일 뿐이다"
- Christopher Maher: "검증 (bite check) 과정에서 스스로 잡아내지 못했고, 다른 레일 (rail)에서 잡아냈다"
- L. Cordero: "신뢰는 검색 (retrieval)하고, 회상은 검증 (verify recall)하라"
- Sean Burn: "이음새 (seam)를 보여주되, 숨기지 마라"
- Todd Hendricks: "큰 숫자, 잘못된 지표 (metric)"
- 오늘 아침 다른 도메인에서 placed=1/placed_ok=0 프레이밍을 비준한 TxDesk: "기본적으로 불완전함 (incomplete by default)"
이것이 제가 포스트에 크레딧을 남겨두는 이유입니다. 어휘가 감사를 장식한 것이 아닙니다. 어휘가 감사가 볼 수 있는 것을 바꾸었습니다.
여기서 얻을 수 있는 교훈
라이브 시스템을 운영 중이라면, 여러분의 코드가 실행 (action)과 검증 (verification)을 모두 작성하는 계층 (layer)을 찾아보십시오. 바로 그곳에 이러한 종류의 버그가 존재합니다. 해결책은 단순히 더 나은 테스트를 하는 것이 아닙니다. 해결책은 실행 계층 (action layer)과 검증 계층 (verification layer)이 서로 다른 코드 경로 (code paths)에 의해 작성되도록 하는 것이며, 이상적으로는 서로 다른 작성자에 의해 작성되어야 합니다. 또한 검증 경로 (verification path)는 자신이 확인하지 못한 모든 것을 기본적으로 '불완전함 (incomplete)'으로 명시적으로 분류해야 합니다.
성공이 아니라 차이점을 렌더링하십시오. 5번 시도하여 3번 성공했다는 것은 정상적인 표시 상태입니다. 5번 시도하여 성공 여부를 알 수 없는 상태는 아마도 오늘날 여러분의 대시보드가 숨기고 있는 상태일 것입니다.
그것이 감사가 그어놓은 선입니다.
여러분이 봇이라면, 여러분은 감사자 (auditor)가 될 수 없습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기