바이낸스 선물 자동매매

바이낸스 봇 청산 실패 -2022 오류, 고쳤는데 다음날 또 터졌다

creator88837 2026. 7. 10. 09:00

바이낸스 선물 자동매매 봇 청산 오류 -2022를 정리했다.
고쳐서 테스트까지 통과했는데, 다음날 같은 오류가 재발했다.
이 글에서는 -2022 오류의 두 가지 원인과 헤지 모드에서의 진짜 해결법을 코드와 함께 정리한다.

5월 25일에 -4509 오류를 잡았다.
진입 직후 OCO 주문 실패 문제였다.
sleep(5)를 추가해서 해결했고, 테스트에서 정상 작동을 확인했다.

다음날인 5월 26일 오후 1시.
EXIT_SIGNAL이 나왔다.
봇이 BTC 롱 포지션 청산을 시도했다.
이번엔 청산이 안 됐다.
로그에 찍힌 오류는 -2022였다.

{"code": -2022, "msg": "ReduceOnly Order is rejected."}



 

바이낸스 -2022 오류가 청산 주문을 거부하는 원인


-2022는 reduceOnly 주문이 거부됐다는 뜻이다.
reduceOnly는 직역하면 "포지션을 줄이는 용도로만 써라"는 조건이다.

선물 거래에서 청산 주문을 낼 때 이 조건을 붙이면 바이낸스가 해당 주문을 반드시 포지션 청산 목적으로만 처리한다.
실수로 포지션이 반대 방향으로 늘어나는 것을 막기 위한 안전장치다.

예를 들어 BTC 롱 0.001을 보유 중일 때,
청산 주문(매도)에 reduceOnly를 붙이면 0.001을 초과하는 매도는 자동으로 거부된다.
포지션을 줄이는 것만 허용한다는 뜻이다.

이 조건이 거부(-2022)됐다는 건 뭔가 이 조건을 충족하지 못하는 상황이 발생했다는 의미다.

 

OCO가 취소된 뒤 청산까지 실패하면 포지션이 무방비 상태가 된다 


봇의 청산 절차는 두 단계로 진행된다.

1단계 — 기존 OCO(SL/TP) 주문을 취소한다.
2단계 — 시장가 청산 주문을 전송한다.

이날은 1단계(OCO 취소)는 성공했다.
그런데 2단계(시장가 청산)에서 -2022가 반환됐다.

결과적으로 SL/TP는 이미 취소됐고, 청산 주문도 실패한 상태가 됐다.
손절도 익절도 없고 청산 명령도 통하지 않는 무방비 상태로 포지션이 고착됐다.
봇은 정상 작동 중으로 표시되지만 포지션은 방치된 것이다.

 

처음에는 청산 수량 불일치가 -2022의 원인이라고 생각했다


로그를 분석했다.
봇이 JSON 파일에 저장한 포지션 수량은 0.001 BTC였다.
그런데 봇이 처음 진입했을 때 주문이 일부만 체결되는 경우가 있다.
0.001을 주문했는데 0.0009만 체결된 상태라면 실제 잔여 수량은 JSON과 다르다.

reduceOnly 조건이 붙어 있으면 바이낸스는 실제 보유량(0.0009)을 초과하는 수량의 청산 주문을 거부한다.
봇은 JSON에 저장된 0.001로 청산을 시도하고, 실제 보유량 0.0009와 불일치하니 -2022가 난 것이다.

AI에게 이렇게 요청했다.

"청산 시 봇이 JSON에 저장된 수량으로 주문을 내고 있다. 실제 바이낸스 포지션에서 현재 수량을 직접 조회해서 그 수량으로 청산하도록 수정해줘."

수정 전 코드:

```python
# JSON 저장값으로 청산
amount = self.position['amount']
self.exchange.create_market_sell_order(self.symbol, amount,
                                       params={'reduceOnly': True})
```



수정 후 코드:

```python
# 거래소 실제 수량 조회
positions = self.exchange.fetch_positions([self.symbol])
actual_amount = None
for p in positions:
    if float(p['contracts']) > 0:
        actual_amount = float(p['contracts'])
        break

if actual_amount is None:
    logging.warning("거래소 포지션 없음 — 상태 초기화")
    self.position = None
    return False

# 실제 수량으로 청산
self.exchange.create_market_sell_order(self.symbol, actual_amount,
                                       params={'reduceOnly': True})
```



수정 후 테스트에서는 정상 작동했다.
이걸로 해결됐다고 생각했다.

 

-2022 오류가 수정 후에도 다음날 재발했다


5월 27일 새벽 1시 10분.
또 -2022가 떴다.
이번에는 청산 시도가 있을 때마다 반복됐다.

수량을 확인했다.
실제 수량과 JSON 저장값이 동일했다. 0.001 = 0.001.
수량 불일치가 원인이 아니었다.
어제 수정한 게 원인이 아니었다는 뜻이다.

처음부터 다시 생각해야 했다.

 

헤지 모드에서 시장가 청산에 reduceOnly를 쓰면 -2022가 난다


2봇~5봇의 청산 로직과 비교했다.
4개 봇은 모두 정상적으로 청산이 되고 있었다.
그 코드를 확인했더니 차이가 바로 보였다.

봇 청산 주문 방식 비교



2봇~5봇은 청산 시장가 주문에 별도 파라미터를 붙이지 않는다.

```python
# 2봇~5봇 청산 방식
self.exchange.create_market_sell_order(self.symbol, amount)
```



1봇은 `params={'reduceOnly': True}`가 붙어 있었다.

```python
# 1봇 청산 방식 (문제)
self.exchange.create_market_sell_order(self.symbol, amount,
                                       params={'reduceOnly': True})
```



이 한 줄 차이가 원인이었다.

헤지 모드(Hedge Mode) 계정에서는 시장가 주문에 reduceOnly 파라미터를 지원하지 않는다.
reduceOnly는 OCO(SL/TP) 같은 조건부 주문에 쓰는 파라미터다.
청산 시장가 주문에는 붙일 필요가 없다.
헤지 모드에서는 포지션 방향(positionSide)이 이미 LONG/SHORT으로 구분되어 있어서 반대 방향 진입과 청산이 자동으로 분리된다.
따로 reduceOnly를 붙이지 않아도 청산 주문은 청산으로만 처리된다.

쉽게 설명하면 이렇다.
봇이 바이낸스에 이렇게 말한 셈이다.
"0.001 BTC 팔게. 근데 이 주문, 절대로 포지션 늘리는 데 쓰면 안 돼."
바이낸스가 "그 조건은 여기서 처리 못 해. 거부(-2022)"라고 응답한 것이다.
그냥 "0.001 BTC 팔게"라고만 했으면 됐는데, 불필요한 조건이 오류를 만들었다.

1차 진단에서 수량 불일치를 원인으로 봤던 것은 잘못된 진단이었다.
fetch_positions로 수량을 다시 조회하는 수정 후에도 reduceOnly는 그대로 남아 있었으니 -2022가 재발한 것이다.

 

reduceOnly 파라미터 제거로 청산 오류를 해결했다


AI에게 이렇게 요청했다.

"청산 시장가 주문에서 params={'reduceOnly': True}를 제거해줘. 2봇~5봇처럼 파라미터 없이 일반 시장가 주문으로 변경해줘."

수정 전:

```python
self.exchange.create_market_sell_order(self.symbol, amount,
                                       params={'reduceOnly': True})
```



수정 후:

```python
self.exchange.create_market_sell_order(self.symbol, amount)
```



두 글자 차이다.
수정 후 모든 청산이 정상 작동했다.

 

결론 


-2022 오류가 나면 두 가지를 확인해야 한다.

첫째, 청산 수량이 실제 보유량과 일치하는지 확인한다.
JSON 저장값을 그대로 쓰면 부분 체결 시 불일치가 생길 수 있다.

둘째, 청산 시장가 주문에 불필요한 파라미터가 붙어 있는지 확인한다.
헤지 모드에서 시장가 청산 주문에 reduceOnly를 쓰면 -2022로 거부된다.

이번 경험에서 배운 것은 오류 진단을 단정 짓지 말아야 한다는 점이다.
같은 오류 코드라도 원인이 두 개 이상일 수 있다.
한 가지를 고쳐서 됐다고 해도, 재발하면 처음부터 다시 살펴봐야 한다.
그리고 같은 기능을 하는 다른 봇의 코드와 비교하는 게 빠른 해결 방법이다.

📈 백테스트