포지션 대사(Reconciliation) — 봇이 아는 수량과 거래소 실제 수량이 갈라질 때
자동매매에서 가장 조용하고 가장 비싼 사고는 전략이 틀리는 게 아닙니다. 봇이 기억하는 포지션과 거래소에 실제로 잡혀 있는 포지션이 다른 상태로 계속 도는 것입니다. 봇은 자기 장부만 보고 판단하므로, 어긋난 줄 모른 채 몇 시간을 더 굴립니다.
둘이 갈라지는 건 예외가 아니라 기본값이다
봇 안에는 "지금 롱 0.1을 들고 있다" 같은 상태값이 있습니다. 거래소에도 같은 정보가 있습니다. 이 둘은 원래 같아야 하지만, 네트워크를 사이에 두고 있는 한 언제든 갈라집니다.
① 응답 유실
주문은 접수됐는데 응답을 못 받음
② 봇 재시작
메모리 상태는 날아가고 포지션은 남음
③ 부분 체결
0.1 주문 중 0.04만 체결
④ 수동 개입
사람이 앱에서 일부를 닫음
⑤ 강제 청산·ADL
거래소가 봇 몰래 포지션을 줄임
─────────────
다섯 중 넷은 봇 코드가 멀쩡해도 발생한다
그래서 대사(reconciliation)는 "버그가 있을 때 켜는 디버그 기능"이 아니라 상시 돌아야 하는 구성요소입니다. 접속이 끊겨도 포지션은 거래소 서버에 그대로 남는다는 구조는 접속이 끊기면 포지션은 어떻게 되나에 정리돼 있습니다. 봇 입장에서는 그 "그대로 남아 있는 것"이 문제의 시작입니다.
타임아웃은 실패가 아니다
가장 흔한 사고 원인은 단순합니다. 주문 요청을 보냈는데 응답이 안 오면 대부분 "실패했나 보다" 하고 다시 보냅니다. 그런데 타임아웃은 결과를 모른다는 뜻이지 실패했다는 뜻이 아닙니다.
의도한 진입 = 롱 0.1
1차 요청 → 응답 타임아웃
(실제로는 거래소에 체결 완료)
2차 요청 → 성공 응답
─────────────
봇 장부: 0.1
거래소 실제: 0.2
명목이 2배 → 계좌 위험도 2배
봇은 0.1 기준으로 손절을 건다
→ 손절이 나가도 0.1이 남는다
여기서 진짜 무서운 건 노출이 2배가 된 것보다 손절이 절반만 닫는다는 점입니다. 봇은 자기가 아는 0.1을 청산하고 "정리 완료"라고 기록한 뒤 다음 신호를 기다립니다. 남은 0.1은 아무도 관리하지 않는 포지션이 되어 방치됩니다. 이 상태로 방향이 반대로 가면 손실은 계획에 없던 크기로 커집니다.
멱등성 — 재시도를 안전하게 만드는 장치
해법은 재시도를 없애는 게 아닙니다. 재시도는 통신 환경상 반드시 필요합니다. 대신 같은 요청을 두 번 보내도 한 번만 실행되게 만듭니다. 이걸 멱등성이라고 부르고, 실무에서는 클라이언트 주문 ID로 구현합니다.
주문을 만들 때 봇이 먼저 ID를 정한다
예: btc-20260905-1412-a7
1차 요청: 이 ID로 전송 → 타임아웃
2차 요청: 같은 ID로 재전송
─────────────
거래소 응답
· 이미 접수됨 → 중복 거부
· 접수 안 됨 → 정상 접수
어느 쪽이든 최종 수량은 0.1
ID는 매 주문마다 새로 만들되, 재시도할 때는 절대 새로 만들지 않습니다. 재시도마다 새 ID를 붙이면 멱등성이 사라지고 중복 주문이 그대로 들어갑니다. 거래소별로 필드 이름과 길이 제한이 다르므로 연동 문서를 먼저 확인해야 합니다 — 연동 구조 자체는 거래소 API 자동매매 연동 가이드에 있습니다. 요청이 아예 거부되는 경우의 원인 분류는 주문이 거부되는 8가지 이유 쪽이 빠릅니다.
대사는 무엇을 무엇과 비교하나
대사에서 가장 먼저 정할 것은 누가 권위인가입니다. 답은 항상 거래소입니다. 봇 장부가 아무리 그럴듯해도, 실제로 돈이 걸려 있는 건 거래소 쪽 숫자입니다.
① 방향 롱/숏/없음
다르면 → 즉시 경보
② 수량 절대값 비교
차이 > 허용오차 → 경보
③ 평단 참고용
수수료·부분체결로 소수점 차이는 정상
④ 미체결 주문 개수·수량
장부에 없는 주문이 살아 있으면 → 경보
─────────────
허용오차 예시
최소 주문단위의 10% 이내는 무시
(반올림·표시 자릿수 차이 흡수)
허용오차를 0으로 두면 소수점 표기 차이만으로 하루에도 수십 번 경보가 울립니다. 반대로 너무 넉넉하게 잡으면 진짜 누락을 놓칩니다. 최소 주문 단위를 기준으로 잡는 편이 종목이 바뀌어도 그대로 쓰입니다. 부분 체결 때문에 수량이 어중간하게 남는 상황 자체는 부분 체결(Partial Fill)에 따로 정리돼 있습니다.
수량이 어긋나면 계좌 숫자가 전부 틀어진다
불일치는 노출만 바꾸는 게 아닙니다. 봇이 계산하는 거의 모든 숫자가 함께 틀어집니다.
진입가 $80,000 · 계좌 $2,000
봇이 믿는 값
명목 = 0.1 × 80,000 = $8,000
1% 역행 시 손실 = $80
계좌 대비 = 4.0%
실제 값
명목 = 0.2 × 80,000 = $16,000
1% 역행 시 손실 = $160
계좌 대비 = 8.0%
─────────────
· 청산까지 여유 = 절반
· 손절 1회 리스크 = 2배
· 봇의 사이징 계산 = 전부 무효
봇은 이 상태에서도 "리스크 4%로 잘 관리 중"이라고 로그를 남깁니다. 위험 관리 로직이 있어도 입력값이 틀리면 결과는 의미가 없습니다. 계좌 전체가 실제로 얼마나 노출돼 있는지를 세는 방법은 포트폴리오 히트 쪽 계산이 그대로 적용됩니다.
재시작 직후의 순서
봇을 다시 켤 때 순서 하나만 지켜도 사고 대부분이 사라집니다.
1) 거래소 포지션 조회
2) 거래소 미체결 주문 조회
3) 로컬 장부와 대사
4) 불일치가 있으면 → 여기서 멈춤
5) 일치할 때만 → 신규 주문 허용
─────────────
흔한 실수
· 조회 없이 빈 상태로 시작
→ 이미 있는 포지션 위에 또 진입
· 조회 실패를 포지션 없음으로 처리
→ 같은 결과
4번과 5번이 핵심입니다. 불일치를 발견하고도 "일단 돌리면서 고치자"로 넘어가면 어긋난 상태 위에 새 거래가 쌓입니다. 조회 실패를 "포지션 없음"으로 해석하는 것도 같은 사고입니다 — 모른다와 없다는 다른 상태이고, 코드에서 이 둘을 같은 값으로 표현하면 언젠가 반드시 사고가 납니다. 조회가 실패하는 흔한 원인인 요청 한도 문제는 API 요청 한도(레이트리밋)와 429 에러에 있습니다.
주기와 오탐 — 스테일 데이터를 조심한다
대사를 자주 돌릴수록 좋지만, 조회 데이터가 오래됐을 때 잘못 판단하면 오히려 위험합니다.
· 방금 진입 주문이 체결됨
· 대사가 10초 전 캐시를 조회
· 결과: 거래소 0 · 장부 0.1
· 판정: "장부에만 있는 유령 포지션"
· 자동 정정: 장부를 0으로 리셋
─────────────
실제로는 포지션이 살아 있다
→ 관리되지 않는 포지션이 생김
방어
· 조회 시각이 N초보다 오래되면 판정 보류
· 불일치는 연속 2~3회 관측될 때만 확정
· 주문 직후 수 초는 대사 유예
연속 관측 조건 하나만 넣어도 오탐이 크게 줄어듭니다. 한 번 어긋나 보이는 건 대부분 타이밍 문제이고, 세 번 연속 같은 방향으로 어긋나면 그건 진짜입니다. 판정 근거가 "조회 실패"인지 "실제 불일치"인지도 로그에 구분해 남겨야 나중에 원인을 찾을 수 있습니다.
자동으로 고칠 것과 알리기만 할 것
불일치를 발견했을 때 봇이 알아서 정리하게 할지, 사람에게 넘길지는 미리 정해둡니다.
자동 정정해도 되는 것
· 장부 메모를 거래소 값으로 덮어쓰기
· 유령 미체결 주문 취소
· 소수점 오차 흡수
사람에게 넘길 것
· 방향이 반대인 경우
· 실제 수량이 장부보다 많은 경우
· 조회가 계속 실패하는 경우
─────────────
원칙
기록을 고치는 것은 자동
돈을 움직이는 것은 확인 후
봇이 스스로 시장가 청산을 날려 정리하게 만드는 설계는 편해 보이지만, 조회가 잘못됐을 때 멀쩡한 포지션을 닫아버립니다. 잘못된 데이터로 실행하는 자동 청산은 불일치보다 더 비싼 사고가 될 수 있습니다. 자동화가 어디까지 스스로 판단하게 두는 게 합리적인지에 대한 감각은 자동매매 환상과 현실 쪽 정리와 같이 보면 잡힙니다.
정리
② 타임아웃 = 실패가 아니라 결과를 모름 — 그냥 재시도하면 수량이 2배
③ 수량 2배는 손절이 절반만 닫는다는 뜻이라 더 위험하다
④ 재시도는 클라이언트 주문 ID로 멱등하게 — 재시도 시 ID를 새로 만들지 않는다
⑤ 권위는 항상 거래소, 장부는 사본이다
⑥ 비교 항목 = 방향 · 수량 · 미체결 주문 (평단은 참고)
⑦ 허용오차는 최소 주문단위 기준으로 잡는다
⑧ 기동 순서 = 조회 → 대사 → 일치할 때만 신규 주문
⑨ "조회 실패"를 "포지션 없음"으로 처리하지 않는다
⑩ 불일치는 연속 관측으로 확정 — 기록 수정은 자동, 청산은 확인 후
한 줄로 줄이면 이렇습니다. 봇이 믿는 숫자는 사본이고, 원본은 거래소에 있습니다. 사본과 원본을 주기적으로 맞춰보는 절차가 없으면, 전략이 아무리 좋아도 어긋난 수량 위에서 계산된 결과를 받게 됩니다. 대사는 수익을 늘리는 기능이 아니라 이미 벌어진 것을 잃지 않게 하는 기능입니다.
NOONOO TRADING 무료 채팅방에서 실시간 트레이딩을 같이 보세요.
무료 채팅방 입장 →📈 OKX 신규 가입 시 거래 수수료 할인
OKX 수수료 할인 가입 →