본문 바로가기
자동매매 일지/시스템 운영

동시호가에 판 돈은 그날 못 씁니다 — 파는 건 장중에, 사는 건 마지막에

by 아트스탁 2026. 8. 26.
한눈에
  • 장 마지막 10분(15:20~15:30)은 주문을 모으기만 합니다. 체결은 15:30에 한꺼번에 일어납니다.
  • 그 시간에 팔면 돈이 15:30에 들어오는데, 그때는 장이 끝납니다. 그날 그 돈으로 살 수가 없습니다.
  • 제 프로그램은 「팔면 돈이 생긴다」고 계산하고 있었습니다. 그래서 돈이 있는 줄 알고 사려다 못 샀습니다.
  • 답은 순서였습니다 — 파는 건 장중에 먼저, 사는 건 마지막에.
  • 덤으로 배운 것: 거래정지된 종목은 날짜가 멈춰 있습니다. 한 종목만 보고 「오늘이 며칠인지」를 정하면 안 됩니다.

자동매매를 돌리다 보면 이해가 안 되는 날이 있습니다. 계좌에 돈이 있는데 아무것도 안 사는 날입니다.

로그를 보면 프로그램은 사려고 했습니다. 돈이 있다고 계산했고, 주문을 내려고 했습니다. 그런데 안 샀습니다.

원인은 제 코드가 아니라 시장이 돌아가는 방식이었습니다.

동시호가란 — 마지막 10분은 주문만 모읍니다

장은 3시 30분에 끝납니다. 그런데 마지막 10분은 다르게 돌아갑니다.

시간 무슨 일이
~ 15:20 주문이 들어오는 대로 바로바로 체결됩니다
15:20 ~ 15:30 주문을 받아만 둡니다. 아무것도 체결되지 않습니다
15:30 모인 주문을 하나의 값으로 한꺼번에 체결합니다 — 이게 종가입니다

이걸 동시호가라고 부릅니다. 마지막 순간에 몇 주 던져서 종가를 흔드는 걸 막으려고 만든 장치입니다. 아침에 장이 열릴 때도 같은 방식으로 시가를 정합니다.

여기까지는 아는 분이 많습니다. 문제는 그다음입니다.

판 돈이 들어오는 순간, 장이 끝나 있습니다

동시호가에는 파는 주문도 사는 주문도 똑같이 15:30에 체결됩니다. 여기서 함정이 생깁니다.

3시 25분에 팔아서 그 돈으로 다른 걸 사려고 하면 — 안 됩니다. 파는 것도 15:30, 사는 것도 15:30이라 돈이 들어오는 순간이 이미 장이 끝나는 순간입니다.

사람이 손으로 매매할 때는 잘 안 부딪힙니다. 팔고 나서 「어, 돈이 아직 없네」 하고 다음 날 사면 되니까요.

그런데 프로그램은 계산부터 합니다. 「이걸 팔면 얼마가 생기니까 저걸 살 수 있겠다」고 판단하고 주문을 냅니다. 그 계산이 시각을 안 보고 금액만 봤습니다.

시뮬레이션은 이걸 모릅니다

이 문제가 고약한 이유가 있습니다. 과거 데이터로 미리 돌려보는 시뮬레이션에서는 이게 안 보입니다.

시뮬레이션은 하루치 자료를 한 덩어리로 다룹니다. 「이날 팔았다」와 「이날 샀다」 사이에 시간이 없습니다. 그래서 판 돈이 그 자리에서 생기고, 그 돈으로 바로 삽니다.

실제로는 그 사이에 「장이 끝난다」는 사건이 끼어 있습니다.

얼마나 차이가 나는지 세어봤습니다. 시뮬레이션이 「샀다」고 기록한 매수 중에서 여섯 건에 한 건꼴로 실제로는 살 수 없는 것이었습니다. 돈이 제때 없어서입니다.

이건 프로그램이 고장 난 게 아닙니다. 시뮬레이션이 낙관적이었던 것입니다. 그래서 저는 시뮬레이션 결과를 그대로 기대치로 읽지 않습니다.

답은 순서였습니다

고친 방법은 새 기능이 아니라 순서였습니다.

파는 건 장중에 먼저, 사는 건 마지막에.

어차피 오늘 팔기로 되어 있는 것이라면, 동시호가까지 기다리지 않고 장중에 미리 팝니다. 그러면 그 돈이 장중에 손에 들어와서 마지막에 살 때 쓸 수 있습니다.

치르는 값은 있습니다. 장중에 팔면 종가가 아니라 그 순간 값에 팔립니다. 조금 손해 볼 수도 있고 이득일 수도 있습니다. 그래도 「사려던 걸 아예 못 사는 것」보다는 낫습니다.

제 기록을 세어보니 매도 186건 중 177건이 장중에 나갔고, 동시호가로 나간 건 9건뿐이었습니다. 원칙이 실제로 지켜지고 있다는 뜻입니다.

고치면서 조심한 것 두 가지

하나. 판단하는 코드를 복사하지 않았습니다.

「장중에 판다」를 만들려면 기존 매도 기능을 하나 더 만드는 게 빠릅니다. 그런데 그러면 「무엇을 팔지 정하는 규칙」이 두 벌이 됩니다. 나중에 한쪽만 고치면 두 코드가 조용히 달라집니다.

그래서 기존 매도 기능에 「지금 팔아도 되나」를 묻는 문 하나만 달았습니다. 무엇을 팔지 정하는 부분은 한 글자도 건드리지 않았습니다.

둘. 기록에 구분을 남겼습니다.

장중에 미리 판 것도, 마지막에 판 것도 결과는 똑같이 「팔았다」입니다. 그래서 처음엔 기록을 하나로 남겼습니다.

그런데 나중에 「이건 미리 판 건가, 원래 순서대로 판 건가」를 물었을 때 답할 수가 없었습니다. 기록에 그 구분이 없으니까요. 지금은 나눠서 적습니다.

나중에 물어볼 것 같은 질문은 지금 기록에 넣어두어야 합니다. 지나간 일은 다시 만들 수 없습니다.

번외 — 거래정지 종목은 날짜가 멈춰 있습니다

시간과 관련해 하나 더 걸렸던 게 있습니다.

프로그램이 「지금이 며칠인가」를 알아야 할 때가 있습니다. 달력 날짜가 아니라 장이 열린 날 기준으로요. 주말과 공휴일이 있으니 달력으로는 셀 수 없습니다.

그래서 종목의 일봉 데이터에서 마지막 날짜를 읽는 방법을 썼습니다. 어제 장이 섰으면 어제 날짜가 찍혀 있을 테니까요.

그런데 거래정지된 종목이 있습니다. 거래가 멈추면 일봉도 멈춥니다. 정지된 날짜에서 더 이상 안 늘어납니다.

하필 그 종목을 보고 날짜를 정하면, 프로그램은 몇 달 전을 「오늘」이라고 믿습니다.

고친 방법은 간단합니다. 한 종목만 보지 않고 여러 종목을 본 뒤, 그중 가장 최근 날짜를 씁니다. 멈춘 종목이 섞여 있어도 살아 있는 종목이 하나만 있으면 맞는 날짜가 나옵니다.

하나만 보고 정하는 값은, 그 하나가 고장 나면 통째로 틀립니다.

정리

겪은 것 배운 것
판 돈이 그날 안 들어왔다 파는 건 장중에 먼저, 사는 건 마지막에
시뮬레이션은 이걸 못 본다 하루를 한 덩어리로 보면 그 안의 순서가 사라진다
기능을 하나 더 만들 뻔했다 판단하는 코드는 복사하지 말고 문만 연다
나중에 구분할 수가 없었다 물어볼 것 같은 질문은 지금 기록에 넣는다
거래정지 종목이 날짜를 오염시켰다 하나만 보고 정하지 말고 여럿 중 최신을 쓴다

다섯 개가 다 「시장은 하루 종일 같은 방식으로 돌아가지 않는다」는 한 가지에서 나왔습니다. 프로그램은 시간을 그냥 흘러가는 숫자로 보지만, 시장에는 성격이 다른 구간이 있고 멈추는 종목이 있습니다.