백테스트 결과를 받아 보다가 또 그걸 봤습니다. 장 마감 동시호가에 판 돈으로, 같은 동시호가에 다른 종목을 사고 있더군요.
처음이 아닙니다. 솔직히 몇 번째인지 모르겠습니다. 수십 번은 됩니다. 지적할 때마다 AI는 «맞습니다, 실제로는 불가능한 매수입니다»라고 하고, 기록해 두겠다고 하고, 다음 실험에서 또 합니다.
오늘은 한마디 더 했습니다. «맨날 이야기해도 맨날 어기니, 막을 방법을 찾아봐. 기록은 되어 있나 모르겠군.»
이 글은 그 뒤에 벌어진 일입니다.

뭐가 문제냐면
장 마지막 10분, 15시 20분부터 30분까지는 동시호가입니다. 주문을 받아만 두고 15시 30분에 한꺼번에 체결합니다. 그러니 15시 25분에 판 주식의 돈은 15시 30분에야 들어옵니다. 그때는 장이 끝나 있죠. 그 돈으로 그날 다른 걸 살 방법이 없습니다. 이 얘기는 예전에 동시호가에 판 돈은 그날 못 씁니다에 자세히 썼습니다.
그런데 백테스트는 하루를 한 덩어리로 봅니다. «오늘 팔았다»와 «오늘 샀다» 사이에 시각이 없어요. 그래서 판 돈이 그 자리에서 생기고, 그 돈으로 바로 삽니다. 실제 계좌였으면 돈이 없어서 못 샀을 매수가 결과에 들어가는 겁니다. 그 매수가 수익을 냈다면 수익률이 그만큼 부풀려지고요.
아침 9시에 사는 전략이 그날 오후에 판 돈을 쓰는 경우도 있었습니다. 뿌리는 같습니다. 그 시각에 없던 돈을 쓴 거죠.
전방참조는 아닌데, 그래서 더 고약합니다
백테스트 하면 제일 먼저 조심하는 게 전방참조입니다. 그날 종가를 보고 그날 아침에 사는 식으로, 그 시점엔 알 수 없던 가격을 쓰는 거요. 저도 점검표까지 만들어 두고 씁니다.
이번 건은 엄밀히 따지면 전방참조가 아닙니다. 미래 가격은 하나도 안 썼거든요. 판 가격도 산 가격도 그 시각에 알 수 있는 값입니다. 훔친 건 가격이 아니라 돈이 들어오는 시각입니다.
그래서 전방참조 검사에는 안 걸립니다. 그런데 결과가 부풀려지는 건 똑같습니다. 검사는 통과하고 숫자는 좋게 나오니, 제가 눈으로 보고 짚기 전까지는 아무도 모릅니다.
기록은 다 되어 있었습니다
AI(백테스트 전체를 관리하는 창이라 저는 «마스터»라고 부릅니다)에게 기록이 있는지부터 확인하게 했습니다. 있었습니다. AI의 기억에도, 백테스트 규칙서에도 원리와 검사법까지 적혀 있었어요. 엔진에는 막는 장치도 달려 있었고요.
빠져 있던 건 두 군데였습니다. 백테스트 결과를 판정할 때 보는 지침에 이 항목이 없었고, 결과를 내는 도구는 위반이 있어도 아무 말 없이 숫자를 냈습니다.
더 큰 이유는 따로 있었습니다. 엔진의 막는 장치가 정해진 길에만 걸려 있었던 겁니다. 그런데 실험은 늘 길을 바꿉니다. 아침에 사던 걸 장 마감에 사 보고, 다른 전략에 자리를 내주려고 파는 매도를 끼워 보고, 신용으로 사 보고. 새 길이 생길 때마다 막는 장치는 따라오지 않았습니다.
마스터가 스스로 정리한 말이 정확했습니다.
대책이 매번 «기록해 두기»에 그쳤습니다. 새 실험을 짤 때마다 기억해서 챙겨야 하는 구조라 계속 새어 나갔습니다. 지적은 매번 사용자님이 하셨고, 제가 스스로 잡은 적은 없습니다.
AI는 규칙을 물으면 정확하게 설명합니다. 그런데 새 코드를 짜는 순간에 그걸 떠올려서 새 길에 다시 걸어 주는 건 다른 일이더군요. 사람도 마찬가지지만, 적어 둔다고 지켜지진 않습니다.
그래서 도구에 박았습니다
제 백테스트는 여러 AI 창이 각자 실험을 짜도, 돌릴 때는 같은 실행기를 거칩니다. 마스터가 여기에 감시 장치를 달았습니다.
하는 일은 단순합니다. 매수가 일어날 때마다 «이 돈이 그 시각에 있었나»를 셉니다. 아침에 사는 매수는 아침 9시에 있던 현금과 시초가에 판 돈까지만 쓸 수 있습니다. 장 마감에 사는 매수가 그날 판 돈을 쓰려면, 그 매도가 장중에 미리 팔린 것으로 처리돼 있어야 합니다. 이걸 어기면 한 건으로 셉니다.
판이 끝나면 결과 바로 밑에 «현금 시각 위반 몇 건»이 찍힙니다. 이 장치는 끄는 스위치가 없습니다. 끌 수 있으면 언젠가는 꺼진 채로 돌 테니까요. 그리고 0건이 아닌 판의 숫자는 저한테 보고하지도, 채택에 쓰지도 않기로 했습니다.
매수 시각을 바꾸는 실험은 «이 매수는 이제 장 마감이다»라고 코드에 적어야 합니다. 안 적으면 원래 시각 기준으로 검사합니다. 기억에 맡기던 걸 코드가 대신 묻게 한 겁니다.
정말 잡는지 일부러 망가뜨려 봤습니다
검사 장치는 «0건»이라고 말할 때가 제일 위험합니다. 진짜 깨끗해서 0건인지, 검사가 아무것도 못 봐서 0건인지 구분이 안 되거든요. 그래서 일부러 망가뜨린 판을 넣어 봤습니다.
| 돌린 판 | 위반 |
|---|---|
| 지금 쓰는 백테스트 14판 그대로 (결과도 기존과 한 자리도 안 다름) | 모두 0건 |
| 아침 매수가 그날 판 돈을 못 쓰게 막던 장치를 풀어 버린 판 | 25건 |
| 장 마감 매도를 장중에 판 것으로 고치는 처리를 꺼 버린 판 | 118건 |
멀쩡한 판은 0건, 망가뜨린 판은 잡아냈습니다. 여기까지 보고 나서야 적용했습니다.
그런데 구멍이 하나 더 있었습니다
같은 날 저녁, 결과를 뜯어보는 검증용 AI를 한 번 더 돌렸는데 거기서 구멍이 나왔습니다.
감시 장치는 «장 마감 매도를 장중에 판 것으로 고쳐 뒀나»를 믿고 넘어갑니다. 그런데 그 고치는 처리가, 코드에서 매도가 일어나는 25군데마다 «이건 장 마감 체결»이라고 손으로 달아 둔 표시에 기대고 있었습니다. 새 매도 자리를 만들다 표시 하나를 빠뜨리면? 그 매도는 안 고쳐진 채 조용히 결과를 바꿉니다.
실제로 표시를 지운 판을 돌려 보니 결과 숫자는 달라졌는데 감시 장치는 «0건»이라고 했습니다. 방금 만든 장치가 못 보는 결함이었던 거죠.
그래서 장치를 하나 더 달았습니다. 매도가 일어날 때마다 «줄어든 주식 수 = 장 마감 표시 수량 + 장 마감 아님 표시 수량»이 맞는지, 그리고 장 마감이라고 표시한 매도가 정말 종가로 팔렸는지를 맞춰 봅니다.
처음엔 «체결가가 종가와 같으면 장 마감 매도로 보자»는 방법도 나왔는데, 시가나 지정가가 우연히 종가와 같은 날이 있어서 멀쩡한 판 네 개에서 여섯 건을 위반으로 잘못 잡았습니다. 멀쩡한 판을 자꾸 무효로 만드는 검사는 결국 누군가 끄게 됩니다. 그래서 추정하지 않고 표시를 직접 맞춰 보는 쪽으로 갔습니다.
| 돌린 판 | 매도 표시 위반 |
|---|---|
| 지금 쓰는 백테스트 14판 (한 판에서 매도 1,261건 검사) | 모두 0건 |
| 표시를 지운 판 (첫 장치가 0건이라고 했던 그 판) | 833건 |
| 장중 매도까지 전부 장 마감으로 잘못 표시한 판 | 390건 |
이것도 끄는 스위치 없이 걸었습니다. 이제 백테스트 결과 밑에는 두 줄이 같이 붙어 옵니다. 현금 시각 위반 0건, 매도 표시 위반 0건.
아직 못 보는 것도 있습니다
이걸로 끝났다고 생각하진 않습니다. 공용 실행기를 안 거치고 따로 짠 스크립트로 돌리면 이 검사를 건너뜁니다. 장 마감 순자산으로 다음 날 매수 비중을 정하는, 같은 뿌리의 다른 변형도 이 장치는 세지 않습니다. 신용으로 사는 실험은 현금이 아닌 돈을 쓰니 위반으로 잡히는데, 그런 판은 따로 봐야 합니다.
마치며
AI는 설명을 참 잘합니다. 이번 오류도 물으면 저보다 더 정확하게 설명합니다. 그런데 설명할 줄 아는 것과, 새 코드를 짤 때마다 빠짐없이 지키는 건 다른 일이었습니다. 그리고 그 차이를 메우는 건 기록이 아니라 도구였습니다.
같은 말을 세 번 하게 되면, 그땐 적어 둘 게 아니라 막아야 합니다. 저는 그걸 수십 번째에야 했네요.
'자동매매 일지 > 전략 개선' 카테고리의 다른 글
| 백테스트가 미래를 훔쳐보는 여섯 가지 길 — 전방참조 점검표 (0) | 2026.08.20 |
|---|