백테는 반드시 두 개의 엔진으로 돌려야 한다
AI로 백테 돌리는 법을 다루는 글은 많다. 그런데 거의 전부가 "돌리는 법"에서 끝난다. 정작 중요한 건 그 코드가 맞는지 어떻게 아느냐다.
혼자서는 못 찾는다. 코드를 짠 쪽과 검토하는 쪽이 같으면 같은 착각을 반복하기 때문이다. 그래서 나는 이렇게 한다.
방법
- 룰을 자연어 명세로 먼저 확정한다. 진입 조건, 손절, 사이징, 비중 한도까지 전부 문장으로.
- 서로 다른 AI 둘에게 그 명세만 주고 각자 백테 엔진을 짜게 한다. 서로의 코드를 보여주지 않는다.
- 같은 데이터로 돌린다.
- 결과가 아니라 중간 산출물을 대조한다.
4번이 전부다. 최종 수익률만 비교하면 "비슷하네" 하고 넘어가게 된다. 대조해야 하는 건 그 앞 단계다.
- 후보 종목 원장 (어느 날 어떤 종목이 걸렀나)
- 진입 자리별 건수
- 체결 건수
실제로 나온 것
이 방법으로 내 엔진에서 버그 세 개가 나왔다. 전부 나 혼자서는 못 찾았을 것들이다.
하나. 거래대금 상위 3분의 1을 자르는 단계에서, RS 값이 없는 신규 상장주를 모집단에서 미리 빼고 있었다. 실전 봇은 넣고 계산했다. 컷 기준선 자체가 달라진다.
둘. 백분위를 66.667로 하드코딩해 놨다. 실전 봇은 정확한 2/3을 썼다.
소수점 셋째 자리 차이인데, 경계에 걸린 종목이 매일 몇 개씩 갈렸다.
셋. 특정 조건을 거르는 루프에 break가 들어가 있었다.
그래서 피벗 하나당 하루만 막고 끝났다. 실전 봇은 조건이 맞는 날마다 막았다.
셋 다 고치고 나니 후보 종목이 상대 엔진과 99.50% 일치했다. (공통 3,617개 / 내 쪽 3,629개 / 상대 3,635개)
99.5%가 같아도 결과는 다르다
여기가 재미있는 부분이다. 후보가 99.5% 같은데 연복리는 2.5%p 차이가 났다. 남은 원인은 시뮬레이션 단계다 — 같은 날 여러 신호가 떴을 때 무엇을 먼저 사느냐, 슬리피지를 어떻게 잡느냐 같은 것들.
이건 버그가 아니라 실제 운용의 불확실성이다. 그래서 지금은 백테 결과를 점 하나로 적지 않고 분포로 적는다. 같은 룰, 같은 데이터인데도 "무엇을 먼저 사는가"만으로 연복리가 몇 %p씩 움직인다면, 그 폭까지가 정직한 답이다.
정리
AI에게 백테를 짜게 하는 건 쉬워졌다. 문제는 그 결과를 믿어도 되는지다. 엔진 하나로 나온 숫자는 검증된 숫자가 아니라 아직 반증되지 않은 숫자다.
두 번째 엔진을 짜는 비용은 생각보다 싸다. 명세가 이미 문장으로 있으면 반나절이면 된다. 그 반나절이 몇 달치 잘못된 결론을 막는다.