같은 종목인데 프로그램은 다른 종목으로 알고 있었다
화면에 종목은 떠 있는데 가격이 갱신되지 않았다. 에러도 없고 통신도 정상이었다. 원인은 같은 종목이 거래소에 따라 다른 이름표를 달고 온다는 것을 몰랐던 것.
이번 버그는 화면이 비는 것보다 고약했다. 화면은 멀쩡해 보였다. 종목도 떠 있고, 이름도 맞고, 섹터 색깔도 제대로 칠해져 있었다.
그런데 가격이 안 움직였다. 10분이 지나도 아까 그 숫자였다.
먼저 상황 설명
내 대시보드에는 “편입 풀”이라는 게 있다. 당일에 한 번이라도 4% 이상 오른 종목을 기억해 두는 목록이다. 4%를 찍었다가 나중에 3%로 밀려도 목록에는 남겨두고 계속 추적한다. 장중에 뭐가 강했는지 보려는 것이다.
이 목록은 종목코드를 이름표로 삼는 명부라고 생각하면 된다. 새 데이터가 들어오면 같은 이름표를 찾아서 최신 값으로 덮어쓴다.
문제는 “같은 이름표”가 같지 않았다는 것이다.
08시와 10시의 이름표가 달랐다
내 프로그램은 시간대에 따라 조회하는 거래소를 바꾼다. 오전 8시부터 9시 50분까지는 NXT라는 대체거래소를, 그 이후에는 KRX와 NXT를 합친 통합 시장을 본다.
그런데 키움이 보내주는 종목코드가 이렇게 왔다.
통합 조회 → 042660_AL
NXT 조회 → 042660_NX
같은 종목이다. 앞의 여섯 자리 042660이 진짜 종목코드고, 뒤에 붙은 _AL과 _NX는 어느 거래소에서 온 데이터인지를 표시하는 꼬리표다.
내 프로그램은 이걸 꼬리표까지 통째로 이름표로 썼다. 그래서 이런 일이 벌어졌다.
-
08:30 — NXT로 조회한다
명부에
042660_NX라는 이름으로 등록된다 -
09:50 — 통합 시장으로 전환한다
이제 같은 종목이
042660_AL로 들어온다 - 프로그램은 이걸 새 종목으로 본다 명부에 없는 이름표니까 새로 등록한다
- 옛 이름표는 아무도 갱신하지 않는다 그런데 화면은 명부에 있는 걸 전부 그린다 — 08:30 가격 그대로 남는다
에러가 안 났던 이유가 여기 있다. 프로그램 입장에서는 잘못한 게 하나도 없다. 이름표가 다르면 다른 사람인 게 맞다. 시킨 대로 한 것이다.
이게 왜 찾기 어려웠나
특히 짜증났던 건 시간대에 따라 증상이 다르게 나타났기 때문이다.
- 09:50 이전에 켜면: 잘 된다
- 09:50 이후에 켜면: 잘 된다 (통합으로만 조회하니 이름표가 하나로 통일됨)
- 09:50을 걸쳐서 켜두면: 그 시점 이전에 편입된 종목만 멈춘다
즉 재현이 안 됐다. “아까는 이상했는데 지금은 되네?“를 며칠 반복했다. 그러다 멈춘 종목과 정상인 종목을 나란히 놓고 명부 내용을 통째로 찍어보고 나서야 _AL과 _NX가 눈에 들어왔다.
재현이 안 되는 버그는 대개 상태가 시간에 따라 달라지기 때문이다. 이럴 땐 화면을 들여다볼 게 아니라 프로그램이 안에 들고 있는 것을 통째로 꺼내 봐야 한다.
고친 방법
이름표를 만들 때 숫자만 남기기로 했다. 042660_AL이든 042660_NX든 숫자만 뽑으면 둘 다 042660이 된다.
여기서 한 가지 선택이 있었다. “앞에서 여섯 글자만 자른다”는 더 간단한 방법도 있다. 그렇게 안 한 이유는, 꼬리표가 항상 _AL과 _NX 두 가지뿐이라는 보장이 없기 때문이다. 문서에 없는 꼬리표가 나중에 생겨도, 심지어 앞에 붙어도, 숫자만 골라내는 방식은 안 깨진다. 앞에서 자르는 방식은 꼬리표가 앞에 붙는 순간 무너진다.
그리고 명부를 건드리는 모든 자리를 이 규칙으로 통일했다.
“모든 자리”가 중요하다. 나는 처음에 등록하는 곳만 고쳤다가 또 당했다. 아침에 전날 데이터로 명부를 미리 채워두는 부분이 따로 있었는데, 거기서는 여전히 꼬리표째 이름표를 쓰고 있었다. 결국 네 군데였다.
한 군데라도 빠뜨리면 그 경로로 들어온 종목만 다시 멈춘다. 그리고 그건 또 특정 시간대에만 나타난다.
남은 교훈
- 바깥에서 온 이름표를 그대로 쓰지 마라. 내 방식으로 다듬는 규칙을 하나 만들어서 무조건 거기를 통과시키는 게 낫다.
- 다듬는 건 한 군데가 아니라 전부여야 한다. 이름표를 만드는 자리가 여기저기 흩어져 있으면 반드시 하나를 빠뜨린다.
- 에러가 안 난다고 정상이 아니다. 이 버그는 경고 한 줄 없었다. 데이터가 조용히 낡아갈 뿐이었다. “마지막으로 갱신된 시각”을 화면에 띄워뒀다면 훨씬 빨리 잡았을 것이다.
- 재현되는 조건을 먼저 찾아라. “09:50을 걸쳐야 재현된다”를 알아낸 순간, 원인 후보가 거래소 전환 하나로 좁혀졌다.
고친 결과는 10줄 추가, 4줄 삭제였다. 원인을 찾는 데 며칠, 고치는 데 5분. 대개 이렇다.
이 글은 개인 프로젝트의 개발 기록입니다. 투자 자문이나 종목 추천이 아니며, 글에 등장하는 종목명은 프로그램의 동작을 설명하기 위한 예시입니다. 투자 판단과 그 결과에 대한 책임은 투자자 본인에게 있습니다.