본문 바로가기
업비트 트레이더

7편: "매수 성공"이라는데 내 잔고는 왜 0원일까? (유령 매수 사건과 해결책)

by WELab74 2026. 3. 24.
반응형
서버를 올리고 나서 처음으로 매수 신호가 떴다. 텔레그램에 "[매수] KRW-BTC" 알림이 왔고, "[보유중] 수익률 +X%" 메시지도 왔다. 그런데 업비트 앱을 열어보니 실제로 매수된 게 없었다.

1. 상황 파악: 안 샀는데 샀다고 했다

텔레그램으로 이런 메시지들이 왔다.

[매수] KRW-BTC
가격: XXX,XXX,XXX KRW
금액: 700,000 KRW
[보유중] KRW-BTC
현재가: XXX,XXX,XXX KRW
수익률: +X.XX%

그런데 업비트 앱에서 확인하니 체결 내역이 없었다. BTC 잔고도 그대로였다.


2. 원인 분석: 두 가지 문제가 겹쳤다

문제 1: 봇이 2개 동시에 실행 중이었다

로그를 확인하니 텔레그램 getUpdates API에서 409 Conflict 에러가 수백 개 찍혀 있었다.

ERROR | 텔레그램 업데이트 조회 실패: 409 Client Error: Conflict

409 Conflict는 텔레그램이 "같은 봇 토큰으로 두 곳에서 동시에 연결하려 한다"는 뜻이다. 즉, main.py 프로세스가 2개 떠 있었던 것이다.

두 봇이 동시에 같은 신호를 감지했다.

결과
봇 1번 업비트에 매수 주문 → 성공 (잔고 소진)
봇 2번 잔고 부족으로 실패

문제 2: 주문 실패 여부를 확인하지 않았다

당시 코드는 이랬다.

# 문제의 코드
buy_market(symbol, invest_krw)

# 주문 실패해도 아래가 무조건 실행됨
on_buy(symbol, sig['price'])

# 성공으로 상태 저장
send_buy(...)                        

# 매수 알림 발송

buy_market()이 실패해서 빈 {}를 반환해도, 바로 아래 on_buy()send_buy()무조건 실행됐다.

결과적으로:

① 실제 매수는 실패
② 봇 내부 상태는 "BTC 보유 중"으로 저장
③ 텔레그램엔 매수 성공 알림 발송
④ 이후 체크마다 "보유중, 수익률 +X%" 메시지 반복 발송


3. 해결: 즉시 조치 + 코드 개선

즉시 조치: 중복 프로세스 제거

# 서비스 중지
sudo systemctl stop upbit-trader

# 남은 프로세스 강제 종료
sudo pkill -f main.py

# 재시작
sudo systemctl start upbit-trader

코드 개선: 주문 응답 확인 후 알림

매수/매도 모두 업비트 응답을 먼저 확인하고 알림을 보내도록 수정했다.

# 개선된 코드
order = buy_market(symbol, invest_krw)

# 성공했을 때만
if order:
    on_buy(symbol, sig['price'])
    send_buy(...)

# 실패하면 실패 알림
else:
    send(f'[매수 실패] {symbol}\n업비트 주문이 실패했습니다.')

4. 개선 결과

이제 주문 실패 시 텔레그램으로 아래 메시지가 온다.

[매수 실패] KRW-BTC
업비트 주문이 실패했습니다. 로그를 확인하세요.

성공했을 때만 기존 알림이 발송된다. 실패를 성공으로 착각하는 일은 없다.


5. 배운 것

첫째, 외부 API 호출은 항상 실패할 수 있다. 응답 결과를 확인하지 않고 다음 로직을 실행하면 안 된다.

둘째, 알림이 온다고 실제 거래가 됐다는 보장이 없다. 초기엔 반드시 업비트 앱에서 직접 체결 내역을 교차 확인해야 한다.

셋째, 봇이 살아있다는 것과 봇이 제대로 작동한다는 것은 다른 말이다. 서버가 돌아가고 알림이 와도 실제 주문이 정상 체결됐는지는 별도로 확인해야 한다.

 

# 자동매매 트러블슈팅: 409 Conflict 에러와 주문 상태 동기화 오류 개선

# 업비트 자동매매 7편: 첫 매수 신호와 뼈아픈 실패 (원인 분석 및 코드 개선)

반응형