한 줄로
9/30 개장 직후 자동매매가 7종목을 판 원인은 손절이 아니었다. 전날 #90에서 버그를 고치면서 되살아난 점수 기반 매도가 원인이었다. 그 버그는 한 달 넘게 이 매도 규칙을 막고 있었다. 그래서 틱 하나로 판다는 약점이 그동안 드러나지 않았다. 매도 규칙은 그대로 두고, 3분봉 2연속 확인과 09:18 이전 봉 제외를 넣어 #91로 재배포했다.
이번에 확인한 매도 경로
이번에 확인한 매도 경로는 다음과 같다.
- 손절: -15%에서 판다.
- 본전 보호: 산 값 밑으로 내려가지 않게 지킨다.
- 점수 기반 매도: 지표 점수가 매도 쪽으로 기울면 판다. 단 8/26에 넣은 규칙이 하나 붙어 있다. 「산 뒤 최소 5봉은 점수로 팔지 않는다」.
이번 사건은 세 번째 경로에서 일어났다. 정확히는 세 번째 경로를 묶어 두던 「최소 5봉」 조건이 원래대로 돌아오면서 일어났다.
한 달 동안 규칙이 막힌 이유
재시작할 때마다 이전 세션의 entry_index=249가 그대로 복원됐다. 그래서 보유 봉 수(산 뒤 지난 봉의 개수)가 항상 0으로 계산됐다. 5봉을 넘길 수가 없으니 점수 기반 매도는 늘 막혀 있었다.
결과는 기록에 그대로 남아 있다. 8/26부터 9/29까지 점수 기반 매도가 한 번도 나가지 않았고, 이 기간 매도 체결은 0건이다.
이 기록에서 확인할 수 있는 것은 8/26부터 9/29까지 점수 기반 매도가 나가지 않았다는 점이다.
버그를 고친 다음 날 일어난 일
9/29에 #90으로 이 복원 버그를 고쳤다. 보유 봉 수가 제대로 세어지기 시작했고, 점수 기반 매도도 다시 나갈 수 있게 됐다.
다음 날인 9/30 09:00~09:04, 개장 직후의 흔들림에서 RSI·볼린저 지표가 극단으로 튀었다. 틱 신호 하나에 6종목이 팔렸고, 10:57에 1종목이 더 팔렸다. 합쳐서 7종목이다.
처음에는 손절을 의심할 만한 모양이었다. 하지만 원인은 되살아난 점수 기반 매도였다. 노트에 기록된 순손익은 +33,210원이다. 개별 종목의 손익과 별개로, 개장 직후 몇 분의 노이즈에 보유 종목이 한꺼번에 정리됐다는 것 자체가 문제였다.
#90의 수정은 맞았다. 다만 그 수정으로 막혀 있던 경로가 풀렸고, 틱 하나로 매도하는 약점이 개장 직후에 드러났다.
수정: PR #91
고른 안은 매도 규칙은 그대로 두고 확인만 강화하는 것이다.
- 이익 구간이든 손실 구간이든 틱 하나로는 팔지 않는다.
- 3분봉 종가가 두 번 연속 매도 신호여야 판다.
- 09:18 전에 마감한 봉은 세지 않는다. 그래서 점수 기반 매도는 가장 빨라도 09:21에 나간다.
- 폴링 모드에도 같은 규칙을 적용했다.
- 손절(-15%)과 본전 보호는 그대로 뒀다.
9/30의 경우에 대 보면, 09:00~09:04 사이에 튄 지표는 이제 매도로 이어지지 않는다. 그 구간의 봉은 아예 세지 않고, 그 뒤에도 틱 하나가 아니라 3분봉 종가 두 번이 연속으로 확인돼야 한다.
검증은 다음과 같이 했다.
- 전체 테스트 3226개가 통과했다.
- Opus 리뷰에서 나온 지적 사항을 모두 반영했다.
- 19:48에 재기동했다. 재기동 뒤 경고는 없고, WS는 27종목을 구독하고 있다.
같은 날 밤: 자가개선 루프는 롤백됐다
같은 시스템에는 21:30에 도는 자가개선 루프가 있다. 이날 루프가 맡은 결함은 SIGNAL_FILTER 사유로 매수가 너무 많이 막힌 16건이었다.
루프에는 울타리가 쳐져 있다.
- 고쳐도 되는 파일은
risk/trailing_stop.py와strategies/hybrid_quant_ai.py두 개뿐이다. -
buy_threshold는 고칠 수 없다. 8월 실거래에서 -271,574원 손실이 난 뒤 사람이 0.15에서 올린 값이기 때문이다.
이날 루프가 만든 수정은 테스트 게이트에서 막혀 롤백됐다. 이 사실은 cron 점검에서 autotrading-improve가 비정상 종료한 것을 보고 확인했다. 같은 날 사람이 고친 #91은 테스트를 통과해 배포됐고, 루프가 만든 수정은 테스트 게이트에서 롤백됐다.
남은 교훈
버그를 고치면 그 버그가 막고 있던 경로가 다시 실행될 수 있다. 이번에는 entry_index 복원 버그가 점수 기반 매도를 한 달 넘게 가리고 있었다. 이 기간의 매도 체결 0건은 점수 기반 매도가 막혀 있던 기록이다. 비슷한 수정을 할 때는 고친 코드만 볼 게 아니라, 그 코드 뒤에서 이제 풀려날 경로가 어떤 조건에서 다시 실행될지까지 봐야 한다.