← 아카이브
자금흐름2026-08-18· 67분 분석

코인 거래소 서버 시간 실측 — 요청 타임스탬프가 뒤로 60,000밀리초, 앞으로 1,000밀리초에서 잘린 자리

열두 개 해외 거래소의 열세 개 공개 시각 창구를 번갈아 불러 시계 차이를 재고, 문서가 적어 둔 요청 타임스탬프 허용 창을 축자로 맞대 봤습니다. 바이낸스는 늦은 쪽을 60,000밀리초까지 열어 주지만 빠른 쪽은 recvWindow 를 키워도 1,000밀리초에서 잘렸습니다.

altnara 자금흐름 데스크는 시장 데이터가 어느 창구에서 어떤 모양으로 나오는지를 점검합니다. 이번 노트의 주제는 거래소 서버 시간입니다. 운영자 보유 가능성: 본 매체는 비트코인·주요 알트 및 스테이블코인 보유 가능성을 명시합니다.

서명이 필요한 요청에는 거의 예외 없이 요청 시각이 들어갑니다. 거래소는 그 시각이 자기 서버 시각과 얼마나 벌어져도 되는지를 문서에 적어 두고, 그 창을 벗어난 요청은 거절합니다. 그러니 이 자리에서 갈리는 것은 두 가지입니다. 하나는 내 시계가 거래소 시계와 얼마나 어긋나 있는가이고, 다른 하나는 거래소가 허용하는 창이 얼마나 넓은가입니다.

이번 노트는 그 둘을 각각 직접 쟀습니다. 앞의 것은 열두 개 해외 거래소가 열어 둔 인증 없이 열리는 공개 시각 창구 열세 곳을 번갈아 호출해서, 뒤의 것은 더미 열쇠로 시각을 일부러 어긋내 부르는 방식으로 확인했습니다. 호출 시각은 본문 각 절에 그대로 적었습니다.

짙은 남색 배경 앞 어두운 슬레이트 판 위에 놋쇠 소리굽쇠들이 나란히 서 있고 왼쪽 위에 흐릿한 빛이 번져 있다

결론부터 — 이번 조회에서 갈라진 것은 세 가지입니다

첫째, 왕복이 짧은 아홉 창구의 시각은 서로 ±1.5밀리초 안에 모였고, 어긋난 것은 이쪽 시계였습니다. 2026년 8월 18일 11시 23분(KST)에 잰 오프셋의 중앙값은 -245.1밀리초였습니다. 부호가 음수라는 것은 거래소 시계가 늦다는 뜻이 아니라 측정에 쓴 PC 시계가 그만큼 앞서 있었다는 뜻입니다. 서로 무관한 아홉 창구가 같은 방향으로 0.245초씩 어긋날 수는 없으므로 공통 성분은 이쪽에 있습니다. 9분 뒤에 한 번 더 재서 이 판단을 직접 확인했습니다.

둘째, 문서가 적어 둔 허용 창은 앞뒤가 대칭이 아니었습니다. 바이낸스는 늦은 쪽(서버보다 과거인 타임스탬프)을 recvWindow 로 60,000밀리초까지 늘려 주지만, 빠른 쪽은 recvWindow 를 아무리 키워도 1,000밀리초에서 잘립니다. 더미 열쇠로 잰 경계가 문서와 같은 자리에 있었습니다. 반면 OKX 는 같은 조건에서 앞뒤가 모두 30초 근처였습니다.

셋째, 같은 응답 한 덩어리 안에 초·밀리초·마이크로초·나노초가 섞여 있었고, 초 단위로 잘린 필드를 쓰면 최대 1초 가까이를 버립니다. 바이비트 한 응답의 timetimeSecond 를 열여덟 번 맞대 보니 두 값의 차이가 4밀리초에서 946밀리초까지 벌어졌습니다. 이 차이는 오차가 아니라 초 아래를 버려서 생긴 몫입니다.

이 노트가 재는 자리와 재지 않는 자리

같은 주제어로 묶이기 쉬운 자리를 먼저 갈라 둡니다.

첫째, 열쇠를 다루는 글이 아닙니다. API 키를 어떻게 발급받는지, 어떤 권한을 켜고 끄는지, 접속 IP 허용 목록을 어떻게 거는지, 출금 화이트리스트를 어떻게 등록하는지, 2단계 인증을 어떻게 설정하는지는 이 노트에서 다루지 않습니다. 그런 보안 설정은 이번 조회의 범위 밖입니다. 이 노트가 보는 것은 인증 없이 열리는 공개 시각 창구가 돌려주는 값문서가 적어 둔 요청 타임스탬프 허용 오차 창 둘뿐입니다.

둘째, 실계정으로 주문을 넣어 보지 않았습니다. 허용 창 경계는 전부 더미 열쇠로 쟀습니다. 시각 검사를 통과하면 그다음 열쇠 검사에서 걸리는 응답이 오고, 그 응답이 갈리는 자리를 경계로 읽었습니다. 실계정 열쇠로 같은 경계가 나오는지, 검사 순서가 계정 상태에 따라 달라지는지는 확인하지 않았습니다.

셋째, 어느 거래소가 낫다는 판단을 하지 않습니다. 창이 넓다고 좋은 것도 좁다고 나쁜 것도 아닙니다. 창이 좁으면 오래된 요청이 뒤늦게 도착해 체결되는 일을 막고, 넓으면 회선이 흔들려도 요청이 살아남습니다. 이 노트가 하는 일은 각 창구가 어디에 선을 그어 두었는지를 같은 방식으로 재서 나란히 놓는 것까지입니다.

넷째, 절대 시각을 재지 않았습니다. 여기서 말하는 오프셋은 전부 측정 PC 시계를 기준으로 한 상대값입니다. 별도의 시각 서버와 대조하지 않았으므로 어느 쪽이 참값에 가까운지는 이 방법으로 알 수 없습니다.

같은 시각 열세 창구에서 받은 서버 시각

2026년 8월 18일 11시 23분 02초부터 11시 23분 22초(KST), 협정세계시로는 8월 18일 2시 23분입니다. 열세 개 창구를 번갈아 아홉 회전 호출했습니다. 인증 헤더는 어디에도 붙이지 않았습니다. 이 열세 곳을 연 거래소는 열둘입니다. 바이낸스만 현물과 선물이 서로 다른 주소로 갈리기 때문에 창구 수와 거래소 수가 하나 어긋납니다.

재는 방법은 이렇습니다. 요청을 보내기 직전과 응답을 다 받은 직후의 로컬 시각을 적어 두고 그 중점을 요청이 서버에 닿은 시점으로 봅니다. 여기서 서버가 준 시각을 빼면 오프셋이 나옵니다. 이 추정의 불확실도는 왕복시간의 절반이므로, 회선이 짧은 창구일수록 값이 촘촘해집니다. 그래서 아래 값은 창구마다 아홉 회전 중 왕복시간이 가장 짧았던 회전을 골라 적었습니다.

창구오프셋(밀리초)최소 왕복시간(밀리초)
바이낸스 현물-246.650.5
바이낸스 선물-246.353.7
HTX-246.250.4
바이비트-245.486.2
쿠코인-245.158.0
비트마트-245.058.3
OKX-244.557.6
MEXC-243.856.7
비트겟-243.760.6
코인베이스-238.1220.4
데리비트-228.6265.3
게이트-200.4143.2
크라켄-551.6278.1

왕복시간이 100밀리초 미만인 창구는 아홉이었고, 그 아홉의 오프셋 중앙값은 -245.1밀리초입니다. 크라켄이 혼자 300밀리초 넘게 떨어져 있는데, 이것은 크라켄 시계가 이상해서가 아니라 크라켄이 초 단위로 잘린 값만 주기 때문입니다. 그 사정은 뒤에서 따로 봅니다.

열세 곳이 한 방향으로 어긋난 것은 거래소가 아니라 이쪽 시계입니다

중앙값 -245.1밀리초를 기준선으로 놓고 각 창구가 거기서 얼마나 떨어져 있는지 적으면 이렇습니다.

창구중앙값 대비 편차(밀리초)최소 왕복시간(밀리초)
쿠코인0.058.0
비트마트+0.158.3
바이비트-0.386.2
OKX+0.657.6
바이낸스 선물-1.253.7
MEXC+1.356.7
HTX-1.150.4
비트겟+1.460.6
바이낸스 현물-1.550.5

아홉 창구가 전부 ±1.5밀리초 안에 들어옵니다. 서로 다른 회사가 서로 다른 대륙에서 굴리는 아홉 개 시계가 우연히 같은 방향으로 0.245초씩 어긋날 수는 없으므로, 이 공통 성분은 거래소가 아니라 측정에 쓴 PC 시계에 있습니다.

말로만 그렇게 읽지 않고 한 번 더 재서 확인했습니다. 9분 14초 뒤인 11시 32분 16초(KST)에 같은 스크립트를 그대로 돌렸습니다.

창구11시 23분 오프셋11시 32분 오프셋11시 23분 편차11시 32분 편차
바이낸스 현물-246.6-216.5-1.5-2.3
바이낸스 선물-246.3-214.9-1.2-0.7
HTX-246.2-217.3-1.1-3.1
바이비트-245.4-217.0-0.3-2.8
쿠코인-245.1-213.40.0+0.8
비트마트-245.0-213.0+0.1+1.2
OKX-244.5-214.2+0.60.0
MEXC-243.8-213.2+1.3+1.0
비트겟-243.7-209.8+1.4+4.4
중앙값-245.1-214.2

중앙값만 30.9밀리초 움직였고, 각 창구의 상대 위치는 거의 그대로입니다. 아홉 창구가 손잡고 같이 움직였다고 보기보다 기준선 하나가 움직였다고 보는 편이 훨씬 자연스럽습니다. 두 측정의 중점 사이는 554초이므로 기울기는 분당 3.34밀리초, 비율로는 약 55.7피피엠입니다.

이 기울기가 무엇을 뜻하는지는 뒤에 나올 허용 창 숫자와 맞대면 분명해집니다. 이 속도가 그대로 이어진다고 두고 나눠 보면 1,000밀리초를 쌓는 데 약 5시간, 5,000밀리초에는 약 25시간, 60,000밀리초에는 약 12일 반이 걸립니다. 다만 이 세 값은 관측이 아니라 두 점에서 얻은 기울기를 그대로 늘린 산술입니다. 기울기가 이 상태로 유지되는지는 두 번만 재서는 알 수 없습니다.

왕복시간이 긴 세 창구는 편차가 더 큽니다. 게이트는 두 측정에서 각각 +44.7·+46.5밀리초, 데리비트는 +16.5·+16.4밀리초로 두 번 모두 같은 자리에 있었습니다. 값이 반복된다는 점은 눈에 띄지만, 게이트의 왕복시간이 143147밀리초, 데리비트가 265266밀리초였으므로 이 방법의 불확실도(왕복시간의 절반)만 각각 72밀리초·133밀리초입니다. 편차가 통째로 불확실도 안에 들어가므로 시계 차이인지 경로가 한쪽으로 기운 탓인지는 이 방법으로 갈라내지 못했습니다. 코인베이스는 두 측정에서 +7.0과 -3.6으로 부호까지 바뀌었는데, 왕복시간이 220~235밀리초인 것을 생각하면 이 흔들림도 같은 자리에서 나옵니다.

초 단위로 잘린 필드를 쓰면 최대 1초 가까이를 버립니다

바이비트 응답에는 같은 시각이 세 가지 모양으로 들어 있습니다. 그래서 세 필드를 각각 오프셋으로 환산해 아홉 회전 동안 값이 얼마나 흩어지는지 봤습니다.

필드11시 23분 측정 흩어짐(밀리초)11시 32분 측정 흩어짐(밀리초)
time (밀리초 정수)68.413.0
timeNano 를 100만으로 나눈 값67.913.1
timeSecond 에 1,000을 곱한 값760.9929.6

timetimeNano 는 같이 움직이는데 timeSecond 만 열 배 넘게 흩어집니다. 이 흩어짐은 바이비트 시계가 흔들려서 생긴 것이 아닙니다. 한 응답 안에서 직접 빼 보면 바로 확인됩니다. 같은 응답의 time 에서 timeSecond 에 1,000을 곱한 값을 빼면 초 아래로 버려진 몫이 그대로 나오는데, 열여덟 번의 응답에서 그 값이 4밀리초에서 946밀리초까지 나왔습니다. 초 단위 필드는 요청이 초의 어느 지점에 걸리느냐에 따라 그만큼 과거로 밀립니다.

timeNano 쪽도 확인했습니다. timeNano 를 100만으로 나눈 값과 time 의 차이는 열여덟 번 모두 0.86밀리초 미만이었습니다. 곧 time 은 나노초 값을 밀리초 아래에서 자른 값이고, 두 필드가 가리키는 시각은 같습니다.

크라켄도 같은 모양입니다. unixtime 은 초 단위 정수여서 여기에 1,000을 곱한 값의 흩어짐이 두 측정에서 각각 786.5밀리초·866.0밀리초였습니다. 앞의 표에서 크라켄만 -551.6밀리초로 혼자 떨어져 보였던 것은 이 때문입니다. 크라켄 시계가 0.3초 늦은 것이 아니라, 초 아래를 안 주는 값을 밀리초처럼 읽으면 평균적으로 반 초쯤 과거로 보이는 것입니다.

HTX 문서도 같은 자리를 건드립니다. 자주 묻는 질문의 Q6:Why the signature authentication always fail? 아래 목록 다섯째 줄이 서명에 쓰는 시각의 형식을 5.The Timestamp should be UTC time and the format should be YYYY-MM-DDTHH:mm:ss. 라고 적어 두었는데, 이 형식에는 초 아래 자리가 없습니다. 바로 다음 줄이 허용 오차를 6.The time difference between your timestamp and standard should be less than 1 minute. 로 적어 두었습니다. 창이 1분이라면 초 단위 표기로도 여유가 남습니다. 다만 같은 문서의 다른 절은 같은 값을 5분으로 적어 두었는데, 그 자리는 뒤에서 따로 봅니다.

옅은 회색 회벽 사이로 난 좁고 긴 세로 틈에서 따뜻한 빛이 들어와 어두운 돌바닥에 닿아 있다

한 응답 안에 초·밀리초·마이크로초·나노초가 섞여 있습니다

같은 회전에서 받은 응답을 그대로 옮깁니다. 바이비트는 한 덩어리 안에 세 가지 단위를 담습니다.

{"retCode":0,"retMsg":"OK","result":{"timeSecond":"1787019782","timeNano":"1787019782304651444"},"retExtInfo":{},"time":1787019782304}

timeSecond 는 10자리 문자열이고, timeNano 는 19자리 문자열이며, time 은 13자리 정수입니다. 세 값이 같은 시각을 가리키는데 자료형도 자릿수도 다릅니다.

데리비트는 밀리초와 마이크로초를 함께 줍니다.

{"jsonrpc":"2.0","result":1787019783000,"usIn":1787019783000449,"usOut":1787019783000503,"usDiff":54,"testnet":false}

result 가 13자리 밀리초, usInusOut 이 16자리 마이크로초입니다. usDiff 는 서버가 이 요청을 처리하는 데 쓴 시간인데, 열여덟 번의 응답에서 47마이크로초에서 80마이크로초 사이였습니다.

코인베이스는 초 단위 실수입니다.

{"iso":"2026-08-18T02:23:03.607Z","epoch":1787019783.607}

epoch 가 정수가 아니라 소수점이 붙은 초입니다. 정수로 받는다고 가정하고 파싱하는 코드는 이 자리에서 소수부를 잃습니다.

비트겟은 같은 시각을 두 자리에 둡니다.

{"code":"00000","msg":"success","requestTime":1787019782755,"data":{"serverTime":"1787019782755"}}

바깥의 requestTime 은 정수이고 안쪽의 data.serverTime 은 문자열입니다. 위 응답에서는 두 값이 같은데, 항상 같지는 않았습니다. 서른 번을 연속으로 불러 두 값을 비교해 보니 스물두 번은 같았고 여덟 번은 data.serverTime 이 정확히 1밀리초 컸습니다. 차이는 여덟 번 모두 1밀리초였습니다. 어느 쪽을 읽느냐에 따라 값이 1밀리초 갈릴 수 있다는 뜻입니다.

게이트는 이름이 함정입니다. 응답은 이렇게 옵니다.

{"server_time":1787019782635}

이름은 server_time 인데 값은 13자리 밀리초입니다. 이름만 보고 초로 읽기 쉬운 자리입니다. 실제로 이번 측정용 스크립트를 처음 짤 때 이 필드에 1,000을 곱하도록 써 두었고, 게이트 값만 자릿수가 통째로 어긋나서 그제야 알아챘습니다. 필드 이름은 단위를 알려 주지 않습니다.

바이낸스는 헤더 한 줄로 응답 단위가 바뀝니다

같은 GET /api/v3/time 을 헤더만 바꿔 여섯 번 불렀습니다.

보낸 헤더결과응답
없음HTTP 200 · 13자리"serverTime":1787019856215
X-MBX-TIME-UNIT: MICROSECONDHTTP 200 · 16자리"serverTime":1787019856415954
X-MBX-TIME-UNIT: microsecondHTTP 200 · 16자리소문자도 같은 동작
X-MBX-TIME-UNIT: MILLISECONDHTTP 200 · 13자리기본과 같음
X-MBX-TIME-UNIT: NANOSECONDHTTP 400아래 오류
X-MBX-TIME-UNIT: SECONDHTTP 400아래 오류

거절된 두 경우의 본문은 같았습니다.

{"code":-1194,"msg":"Invalid value for time unit; expected either MILLISECOND or MICROSECOND."}

문서는 이 동작을 이렇게 적어 두었습니다. All time and timestamp related fields in the JSON responses are in milliseconds by default. To receive the information in microseconds, please add the header X-MBX-TIME-UNIT:MICROSECOND or X-MBX-TIME-UNIT:microsecond. 대문자와 소문자를 둘 다 적어 둔 대로 둘 다 동작했습니다.

작은 어긋남이 하나 있습니다. 공식 오류 코드 문서는 같은 오류를 ### -1194 INVALID_TIME_UNIT 아래에 Invalid value for time unit; expected either MICROSECOND or MILLISECOND. 로 적어 두었는데, 실제 응답은 두 단어의 순서가 반대인 expected either MILLISECOND or MICROSECOND. 였습니다. 오류 메시지 문자열을 그대로 비교하는 코드를 두셨다면 이런 자리에서 어긋납니다.

문서가 적어 둔 허용 오차 창을 축자로 옮기면

각 거래소 공식 문서에서 요청 타임스탬프 허용 창을 다루는 대목을 그대로 옮깁니다. 문서를 받은 시각과 응답 크기는 맨 아래 출처 절에 적었습니다.

바이낸스. 공식 저장소의 rest-api.md 는 다음 네 줄을 나란히 둡니다. An additional optional parameter, recvWindow, specifies for how long the request stays valid and may only be specified in milliseconds. · recvWindow supports up to three decimal places of precision (e.g., 6000.346) so that microseconds may be specified. · If recvWindow is not sent, it defaults to 5000 milliseconds. · Maximum recvWindow is 60000 milliseconds. 그리고 처리 논리를 의사코드로 적어 두었습니다.

serverTime = getCurrentTime()
if (timestamp < (serverTime + 1 second) && (serverTime - timestamp) <= recvWindow) {
  // begin processing request
  serverTime = getCurrentTime()
  if (serverTime - timestamp) <= recvWindow {
    // forward request to Matching Engine
  } else {
    // reject request
  }
  // finish processing request
} else {
  // reject request
}

여기가 이 노트의 핵심입니다. 조건이 두 개인데 둘의 모양이 다릅니다. 뒤쪽은 (serverTime - timestamp) <= recvWindowrecvWindow 값에 따라 늘어나는데, 앞쪽은 timestamp < (serverTime + 1 second)recvWindow 가 어디에도 나오지 않습니다. 곧 앞쪽 1초는 고정값입니다. 게다가 요청을 받아들인 뒤에도 recvWindow 를 한 번 더 검사합니다. 같은 문서는 It is recommended to use a small recvWindow of 5000 or less! The max cannot go beyond 60,000! 도 함께 적어 두었습니다.

오류 코드 문서는 이 두 조건에 걸린 경우를 한 항목 아래 두 줄로 나눠 둡니다. ### -1021 INVALID_TIMESTAMP 아래에 Timestamp for this request is outside of the recvWindow.Timestamp for this request was 1000ms ahead of the server's time. 입니다. 같은 오류 번호인데 문구가 갈립니다.

바이비트. V5 가이드는 헤더를 X-BAPI-TIMESTAMP - UTC timestamp in milliseconds 로 적고, 창을 We also provide X-BAPI-RECV-WINDOW (unit in millisecond and default value is 5,000) to specify how long an HTTP request is valid. 로 설명한 뒤 규칙을 부등식으로 못 박습니다. Please make sure that the timestamp parameter adheres to the following rule : server_time - recv_window <= timestamp < server_time + 1000 이고, 바로 다음 줄이 같은 말을 구간으로 다시 씁니다. which means your timestamp should lie in range: [server_time - recv_window; server_time + 1000) 바이낸스와 같은 모양의 비대칭입니다. 뒤쪽은 recv_window 로 열리고 앞쪽은 1000 이 박혀 있습니다. 같은 문서는 시계를 어떻게 맞출지도 권합니다. Keep in mind it's highly recommended that you use local device time for timestamp and keep it NTP-synchronized at all times.

OKX. REST 인증 절이 헤더 설명 안에 창을 함께 적습니다. OK-ACCESS-TIMESTAMP Request timestamp in ISO 8601 UTC format with millisecond precision, e.g. 2020-12-08T09:08:57.715Z . The server rejects requests where this differs from server time by more than 30 seconds (error 50102). Always use UTC — local timezone offset is the most common cause of error 50102. Synchronise with GET /api/v5/public/time before placing orders. 여기서 differs from server time 은 방향을 나누지 않은 표현입니다. 오류 코드 표에는 50102 401 Timestamp request expired. 로 실려 있습니다.

MEXC. Spot V3 문서는 바이낸스와 거의 같은 의사코드를 Timing security 절에 적어 두었습니다.

if (timestamp < (serverTime + 1000) && (serverTime - timestamp) <= recvWindow)
{
  // process request
}
else
{
  // reject request
}

그리고 If recvWindow is not sent, it defaults to 5000. 이 붙습니다. 앞쪽 1000 이 고정인 모양도 같습니다.

HTX. 여기는 같은 문서가 두 곳에서 다른 값을 적습니다. 자주 묻는 질문 Q6:Why the signature authentication always fail? Please check whether you follow below rules: 아래 목록의 여섯 번째 줄은 6.The time difference between your timestamp and standard should be less than 1 minute. 로 1분입니다. 그런데 Authentication 아래 Signature Method 절의 서명 만들기 네 번째 단계는 같은 값을 이렇게 적습니다. The 'timestamp' should be formated as 'YYYY-MM-DDThh:mm:ss' and URL encoded. The value is valid within 5 minutes. 한쪽은 1분, 다른 쪽은 5분입니다. 둘 다 앞뒤를 나누지 않았고, 어느 쪽이 실제로 걸리는 값인지는 이번에 실측하지 않았습니다.

비트마트. 처음에는 공식 SDK README(13,001바이트)만 열어 timestamp 가 0건이라 못 찾았는데, 공식 개발자 문서 쪽에 그대로 실려 있었습니다. About recvWindow, timestamp 절이 적용 범위를 Currently only applicable to v4 interfaces 로 먼저 못 박고, 이어지는 Time synchronization security 항목이 창을 적습니다. Signed interfaces require the timestamp parameter to be passed, whose value should be the Unix timestamp (in milliseconds) at the time the request is sent, set in the X-BM-TIMESTAMP header of the request. When the server receives the request, it will check the timestamp in the request. If it was sent more than 5000 milliseconds ago, the request will be considered invalid. This time window value can be defined by sending the optional parameter recvWindow. 뒤따르는 의사코드도 같은 모양입니다.

if ( timestamp < ( serverTime + 1000 ) && ( serverTime - timestamp ) <= recvWindow )
{
  // process request
}
else
{
  // reject request
}

상한과 권장값도 같은 자리에 있습니다. It is recommended to use a recvWindow of less than 5 seconds! It cannot exceed 60 seconds at most! 앞쪽에 1000 을 박아 둔 문서가 이로써 넷째입니다(바이낸스·바이비트·MEXC·비트마트).

비트겟. 현행 문서 주소에서는 못 찾았는데, 별도 도메인에 있는 정적 문서에는 실려 있었습니다. Standard SpecificationTimestamp 항목입니다. The unit of ACCESS-TIMESTAMP in the request signature is milliseconds. The timestamp of the request must be within 30 seconds of the API service time, otherwise the request will be considered expired and rejected. If there is a large deviation between the local server time and the API server time, we recommend that you update the timestamp by query and compare the time difference between API server time and the time in your code. 앞뒤를 나누지 않은 30초라 OKX 와 같은 모양입니다. 현행 문서 두 주소(www.bitget.com/api-doc/common/signature 와 같은 사이트의 다른 문서 주소)는 HTTP 200 인데 응답이 둘 다 23,627바이트로 같았고 태그를 걷어 낸 본문이 좌측 메뉴 목록 3,742자뿐이었으므로, 같은 거래소라도 어느 주소를 여느냐에 따라 문구가 있고 없고가 갈립니다.

크라켄. 크라켄은 아예 다른 방식입니다. 인증 파라미터를 nonce payload parameter: always increasing, unsigned 64-bit integer. 로 적고, 그 값을 만드는 방법을 이렇게 설명합니다. While a simple counter would provide a valid nonce, a more usual method of generating a valid nonce is to use e.g. a UNIX timestamp in milliseconds.시각과 비교하는 것이 아니라 직전 값보다 크기만 하면 되는 구조입니다. 그래서 이 문서는 시계 문제를 창이 아니라 순서 문제로 적습니다. Problems can arise from requests arriving out of order due to API keys being shared across processes, or from system clock drift/recalibration. An optional "nonce window" can be configured to specify a tolerance between nonce values. 이 문서 안에서 server time 이라는 문자열은 검색되지 않았습니다.

형제 문서를 세면 OKX 는 두 자리가 다릅니다

문서를 읽을 때 같은 주제를 다루는 자리가 여러 개 있으면 하나만 보고 정리하면 어긋납니다. 이번에도 그런 자리가 있었습니다.

OKX 문서는 REST 인증과 웹소켓 로그인을 서로 다른 절에서 다루는데, 두 절이 적어 둔 시각의 형식과 표현이 다릅니다. REST 절은 위에 옮긴 대로 ISO 8601 UTC format with millisecond precision 에 30초입니다. 웹소켓 로그인 절은 예시를 Example of timestamp : const timestamp = '' + Date.now() / 1,000 로 적고 창을 The request will expire 30 seconds after the timestamp. 로 적습니다. 한쪽은 밀리초 정밀 ISO 문자열이고 다른 한쪽은 초 단위 숫자입니다. REST 절만 읽고 "OKX 타임스탬프는 ISO 8601 밀리초"라고 정리하면 웹소켓 쪽에서 어긋납니다. 이번 실측은 REST 쪽만 했고, 웹소켓 로그인의 창은 재지 않았습니다.

HTX 도 같은 함정입니다. 위 절에 옮긴 대로 자주 묻는 질문 목록은 허용 오차를 1분으로 적고, Signature Method 절은 같은 값을 5분으로 적습니다. 한 문서 안의 두 절이 같은 값을 다섯 배 차이로 적어 둔 셈입니다. 이 노트도 처음에는 자주 묻는 질문 쪽 한 곳만 보고 1분으로 정리했다가, 같은 문서에서 형제 문장을 다시 세고 나서야 두 값이 갈린다는 것을 알았습니다. 형제 문서를 센다면서 정작 한 곳을 못 센 자리가 이 노트 안에 있었다는 뜻입니다. 어느 쪽이 실제로 걸리는 값인지는 실측하지 않았으므로, 여기서 말할 수 있는 것은 문서가 갈려 있다는 것까지입니다.

시각을 일부러 어긋내 불러 보니 문서 자리에서 잘렸습니다

2026년 8월 18일 11시 25분~11시 28분(KST) 사이에 더미 열쇠로 잰 결과입니다. 매 호출마다 서버 시각을 새로 받아 거기에 스큐를 얹었고, 시각을 받은 시점과 요청을 보낸 시점 사이의 간격도 함께 기록했습니다. 이 간격은 51밀리초에서 106밀리초 사이였습니다.

먼저 OKX 인데, 여기서 예상 밖의 자리가 하나 나왔습니다. 처음 쓴 더미 열쇠로는 시각 검사에 닿지도 못했습니다. 66자짜리 임의 문자열을 열쇠로 넣었더니 스큐를 0초로 두든 하루치인 86,400초로 두든 응답이 똑같았습니다.

{"msg":"Invalid OK-ACCESS-KEY","code":"50111"}

OKX 열쇠는 하이픈이 들어간 UUID 모양입니다. 그래서 형식만 맞춘 가짜 UUID 로 바꿔 다시 불렀더니 그때부터 시각 검사가 돌기 시작했습니다. 열쇠 형식 검사가 시각 검사보다 앞에 있습니다. 형식이 맞는 열쇠로 부르면 응답이 두 갈래로 갈립니다.

{"msg":"API key doesn't exist","code":"50119"}
{"msg":"Timestamp request expired","code":"50102"}

창 안에서는 앞의 50119 가 오고 창 밖에서는 뒤의 50102 가 옵니다. 이 두 응답이 갈리는 자리를 경계로 읽었습니다.

넣은 스큐간격을 뺀 실효 스큐응답 코드
-32.0초-32.07초50102 거절
-31.0초-31.08초50102 거절
-30.5초-30.57초50102 거절
-30.0초-30.11초50119 통과
-29.5초-29.59초50119 통과
+29.5초+29.40초50119 통과
+30.0초+29.90초50119 통과
+30.5초+30.40초50119 통과
+31.0초+30.92초50102 거절
+31.5초+31.43초50102 거절
+35.0초+34.93초50102 거절

확인된 것은 점이 아니라 구간입니다. 뒤쪽 경계는 30.11초와 30.57초 사이, 앞쪽 경계는 30.40초와 30.92초 사이입니다. 문서가 적어 둔 30초와 같은 자리이고, 여기서 눈여겨볼 것은 두 경계가 서로 같은 자리에 있다는 점입니다. OKX 는 앞뒤가 대칭입니다.

뒤쪽 창은 늘어나는데 앞쪽 창은 늘어나지 않습니다

바이낸스는 같은 방식으로 GET /api/v3/account 를 더미 열쇠로 불렀습니다. 시각 검사를 통과하면 "code":-2014"msg":"API-key format invalid." 가 담긴 응답이 오고, 걸리면 -1021 이 옵니다. recvWindow 를 5,000과 60,000 두 값으로 나눠 각각 잰 결과입니다.

넣은 스큐recvWindow=5000recvWindow=60000
-60,500밀리초-1021 거절-1021 거절
-60,000밀리초-1021 거절-1021 거절
-59,900밀리초-1021 거절-2014 통과
-59,000밀리초-1021 거절-2014 통과
-5,200밀리초-1021 거절-2014 통과
-5,000밀리초-1021 거절-2014 통과
-4,900밀리초-2014 통과-2014 통과
-4,000밀리초-2014 통과-2014 통과
+900밀리초-2014 통과-2014 통과
+1,000밀리초-2014 통과-2014 통과
+1,050밀리초-2014 통과-2014 통과
+1,100밀리초-1021 거절-1021 거절
+1,500밀리초-1021 거절-1021 거절
+3,000밀리초-1021 거절
+5,000밀리초-1021 거절
+60,000밀리초-1021 거절

두 열을 위아래로 읽으면 이 노트의 제목이 그대로 나옵니다.

뒤쪽은 recvWindow 를 따라 열두 배로 늘어났습니다. recvWindow 가 5,000일 때 경계는 4,900밀리초와 5,000밀리초 사이였고, 60,000으로 올리자 경계가 59,900밀리초와 60,000밀리초 사이로 옮겨 갔습니다. 여기에 시각을 받은 시점과 요청을 보낸 시점 사이의 간격(51~63밀리초)을 얹어 보면 두 경계 모두 문서가 적은 값과 같은 자리에 있습니다.

앞쪽은 두 열이 완전히 같습니다. recvWindow 를 열두 배로 키워도 경계는 그대로 1,050밀리초와 1,100밀리초 사이였습니다. 거절 문구도 recvWindow 를 말하지 않고 이렇게 옵니다.

{"code":-1021,"msg":"Timestamp for this request was 1000ms ahead of the server's time."}

recvWindow 자체에도 상한이 걸려 있습니다. 60,001과 100,000을 넣어 보니 둘 다 HTTP 400 이었고 본문에 "code":-1131'recvWindow' must be less than 60000. 가 실려 왔습니다. 반대로 0을 넣으면 스큐를 주지 않아도 -1021 로 거절됩니다.

이 비대칭이 실제로 무엇을 뜻하는지는 앞 절의 오프셋과 맞대면 보입니다. 이번 측정에서 PC 시계는 거래소보다 0.245초 앞서 있었습니다. 앞쪽 창이 1,000밀리초이므로 남은 여유는 약 755밀리초입니다. 뒤쪽은 기본값 5,000밀리초가 통째로 남아 있고 recvWindow 를 올리면 60,000까지 열립니다. 창의 크기로 견주면 앞쪽은 기본값에서 뒤쪽의 다섯 분의 일이고, recvWindow 를 상한까지 올리면 예순 분의 일까지 벌어집니다. 좁은 쪽은 설정으로 넓힐 수 없으므로 이 비는 벌어지는 방향으로만 움직입니다.

짙은 남색 벽 앞에 가느다란 검은 실에 매달린 놋쇠 다림추가 어두운 돌 선반 가까이까지 내려와 있다

거절 사유를 응답으로 말해 주지 않는 창구가 있습니다

바이비트는 같은 방식으로 재려 했는데 응답이 갈리지 않았습니다. GET /v5/account/wallet-balance 를 더미 열쇠와 스큐 여섯 종(0·+500·+2,000·+60,000·-10,000·-600,000밀리초)으로 불렀더니 전부 HTTP 401 이고 Content-Length 가 0, 본문이 0바이트였습니다. Content-Typeapplication/json; charset=utf-8 인데 정작 JSON 이 없습니다.

여기서 멈추지 않고 무엇이 이 응답을 바꾸는지 더 찾아봤습니다.

바꿔 본 것넣은 값응답
열쇠 형식18자 영숫자HTTP 401 · 본문 0바이트
열쇠 형식20자 영숫자HTTP 401 · 본문 0바이트
열쇠 형식66자 임의 문자열HTTP 401 · 본문 0바이트
열쇠 형식UUID 모양HTTP 401 · 본문 0바이트
열쇠 형식빈 문자열HTTP 401 · 본문 0바이트
X-BAPI-RECV-WINDOW5000 · 60000 · 120000HTTP 401 · 본문 0바이트
헤더타임스탬프 헤더만 뺌HTTP 401 · 본문 0바이트
헤더열쇠 헤더만 뺌HTTP 401 · 본문 0바이트
헤더인증 헤더를 전부 뺌HTTP 401 · 본문 0바이트

인증 헤더를 하나도 붙이지 않은 요청까지 같은 응답이 왔습니다. 그러니 이 응답으로는 시계에서 걸렸는지 열쇠에서 걸렸는지 헤더가 빠져서 걸렸는지를 갈라낼 수 없었습니다. 앞선 8월 17일 노트에서 바이비트가 인증이 필요한 다른 엔드포인트에 대해 HTTP 200 에 본문의 retCode 만 10001 로 바꿔 주던 것과도 다른 모양입니다. 같은 거래소 안에서도 거절을 알리는 방식이 엔드포인트마다 갈립니다.

문자열을 잘라 밀리초를 읽으면 어긋나는 자리

코인베이스의 iso 필드는 소수부 자릿수가 일정하지 않습니다. 서른 번 불러 소수부 길이를 세어 보니 세 자리가 스물여덟 건, 두 자리가 두 건이었습니다. 두 자리로 온 두 건은 이렇습니다.

{"iso":"2026-08-18T02:24:28.18Z","epoch":1787019868.18}

.18Z 는 18밀리초가 아니라 180밀리초입니다. 소수부를 고정 폭으로 두 자리만 떼어 정수로 읽는 코드는 이 자리에서 180을 18로 읽어 162밀리초를 잃습니다. 다만 isoepoch 가 서로 어긋난 것은 아닙니다. 서른 번 모두 두 필드가 1밀리초 안에서 일치했으므로, 이 자리에서 어긋나는 것은 응답이 아니라 읽는 쪽입니다.

크라켄의 rfc1123 필드도 비슷한 자리가 있습니다. 값이 Tue, 18 Aug 26 02:23:03 +0000 인데 연도가 두 자리입니다. 그래서 네 자리 연도를 기대하는 %a, %d %b %Y %H:%M:%S %z 로 파싱하면 값 오류가 나고, 두 자리 연도인 %a, %d %b %y %H:%M:%S %z 로 바꿔야 통과합니다. 같은 응답의 unixtime 을 쓰면 이 자리를 지나갈 수 있습니다.

HTTP Date 헤더로는 초까지만 확인됩니다

응답 본문 대신 HTTP Date 헤더를 쓰면 안 되는지도 재 봤습니다. 열 개 창구를 여섯 회전, 모두 예순 번 호출해서 본문 시각의 초와 Date 헤더의 초를 맞대 봤습니다.

이 예순 번에서 두 값이 어긋난 경우는 0건이었고, 본문 시각에서 Date 헤더 시각을 뺀 값은 +0.009초에서 +0.978초까지 흩어졌습니다. Date 헤더에는 초 아래 자리가 없기 때문입니다.

다만 여기서 "Date 헤더는 늘 본문과 같은 초를 가리킨다"로 넘어가면 안 됩니다. 같은 날 12시 33분 54초부터 12시 34분 05초(KST) 에 열두 창구를 여덟 회전, 모두 아흔여섯 번 다시 불러 보니 데리비트에서 두 번 초가 어긋났습니다. 두 번 다 본문 시각의 초가 Date 헤더의 초보다 1 작았고, 본문에서 Date 를 뺀 값은 각각 -0.065초와 -0.007초로 부호까지 반대였습니다. 어긋난 두 응답의 본문 시각은 초의 끝자락인 .935.993 이었습니다. Date 헤더는 응답을 내보내는 시점에 찍히므로, 본문 시각이 초 경계에 가까우면 그 사이에 초가 넘어가 두 값이 갈립니다.

그러니 앞의 0건은 이번 예순 번이 그랬다는 기록이지 규칙이 아닙니다. +0.009초에서 +0.978초까지라는 한쪽 방향 범위도 마찬가지여서, 다시 재니 음수가 나왔습니다. 밀리초가 필요한 자리에서는 본문 필드를 읽어야 하고, 초만 필요한 자리에서도 Date 헤더는 1초 어긋날 수 있다고 두셔야 합니다.

직접 부를 창구와 필드 이름

같은 값을 다시 재실 수 있게 이번에 쓴 주소와 읽은 필드, 그리고 그 필드의 모양을 그대로 옮깁니다. 전부 인증 없이 열렸습니다.

창구요청읽은 필드필드 모양
바이낸스 현물GET https://api.binance.com/api/v3/timeserverTime밀리초 정수 13자리
바이낸스 선물GET https://fapi.binance.com/fapi/v1/timeserverTime밀리초 정수 13자리
바이비트GET https://api.bybit.com/v5/market/timetime밀리초 정수 13자리
OKXGET https://www.okx.com/api/v5/public/timedata 배열 첫 항목의 ts밀리초 문자열
게이트GET https://api.gateio.ws/api/v4/spot/timeserver_time밀리초 정수 13자리
비트겟GET https://api.bitget.com/api/v2/public/timedata.serverTime밀리초 문자열
데리비트GET https://www.deribit.com/api/v2/public/get_timeresult밀리초 정수 13자리
크라켄GET https://api.kraken.com/0/public/Timeresult.unixtime초 정수 10자리
코인베이스GET https://api.exchange.coinbase.com/timeepoch초 단위 실수
쿠코인GET https://api.kucoin.com/api/v1/timestampdata밀리초 정수 13자리
MEXCGET https://api.mexc.com/api/v3/timeserverTime밀리초 정수 13자리
비트마트GET https://api-cloud.bitmart.com/system/timedata.server_time밀리초 정수 13자리
HTXGET https://api.huobi.pro/v1/common/timestampdata밀리초 정수 13자리

열세 창구 가운데 밀리초를 주는 곳이 열하나, 초 단위로 주는 곳이 둘(크라켄·코인베이스)입니다. 다만 그 둘의 모양이 다릅니다. 코인베이스의 epoch 는 소수부가 붙은 초라 밀리초를 그대로 되살릴 수 있고, 초 아래를 실제로 버리는 것은 크라켄의 unixtime입니다. 그리고 이 표의 열세 줄 가운데 바이낸스 현물과 선물은 같은 회사의 서로 다른 주소이므로, 거래소로 세면 열둘이고 창구로 세면 열셋입니다.

같은 방식으로 공개 응답을 열어 값을 대조하는 절차는 코인 마진 차입 이자율을 잰 노트에 정리해 두었습니다. 응답 파라미터 표기와 한 번에 받아지는 개수를 세는 방법은 코인 과거 시세 데이터 소급 한계를 잰 노트에 있고, 응답의 시각 필드를 함께 저장하지 않으면 어떤 일이 벌어지는지는 거래소 보험기금 풀 구조를 잰 노트에서 다뤘습니다.

이 글이 확인하지 못한 것

거래소 서버 시각 자가 점검 7단계

  1. 옮겨 적은 필드의 단위를 문서나 자릿수로 확인하셨습니까. 이번 열세 창구에서 초·밀리초·마이크로초·나노초가 모두 나왔고, 게이트의 server_time 처럼 이름이 초로 읽히는데 값은 밀리초인 자리도 있었습니다.
  2. 초 단위로 잘린 필드를 쓰고 계시지 않습니까. 바이비트 timeSecond 와 크라켄 unixtime 이 그렇습니다. 이번 측정에서 버려진 몫이 최대 946밀리초였습니다.
  3. 앞쪽 여유가 고정값이라는 것을 알고 계십니까. 바이낸스·바이비트·MEXC·비트마트 문서가 모두 앞쪽에 1000 을 박아 두었고, 실측에서도 recvWindow 를 열두 배로 키워도 앞쪽 경계는 그대로였습니다.
  4. recvWindow 를 키우는 것으로 시계 문제를 덮고 계시지 않습니까. 늘어나는 것은 뒤쪽뿐입니다. 내 시계가 앞서 있다면 이 값은 도움이 되지 않습니다.
  5. 내 시계가 앞선 것인지 뒤처진 것인지 부호를 확인하셨습니까. 여러 창구에서 같은 방향으로 나온다면 원인은 이쪽에 있습니다.
  6. 왕복 중점으로 재고 왕복시간이 긴 경로에는 불확실도를 함께 적으셨습니까. 이번에도 왕복시간이 긴 세 창구(게이트·코인베이스·데리비트)는 편차를 좁히지 못했습니다. 크라켄은 왕복시간이 그보다도 길지만 초 절삭 때문에 따로 읽었습니다.
  7. HTTP 상태와 오류 문구를 함께 보고 계십니까. 바이비트는 본문 0바이트 401 이라 사유가 안 실리고, OKX 는 열쇠 형식이 틀리면 시각 검사에 닿지도 않습니다.

FAQ

Q. 서명할 때 서버 시각을 매번 불러와야 하나요? A. 바이비트 문서는 그렇게 권하지 않습니다. Keep in mind it's highly recommended that you use local device time for timestamp and keep it NTP-synchronized at all times. 라고 적어 두었습니다. 곧 매 요청마다 서버에 시각을 물으라는 것이 아니라, 로컬 시계를 시각 서버에 맞춰 두고 그 값을 쓰라는 쪽입니다. 서버 시각을 매번 부르면 그 호출 자체가 요청 한도를 먹고 왕복시간만큼 값이 낡습니다. 다만 OKX 문서는 주문을 넣기 전에 Synchronise with GET /api/v5/public/time before placing orders. 라고 적어 두었으므로, 창구마다 권하는 바가 같지 않습니다.

Q. recvWindow 를 60,000으로 두면 시각 문제가 사라지나요? A. 뒤쪽만 넓어집니다. 이번 실측에서 recvWindow 를 5,000에서 60,000으로 올리자 뒤쪽 경계는 약 4,950밀리초에서 약 59,950밀리초로 옮겨 갔지만, 앞쪽 경계는 1,050밀리초와 1,100밀리초 사이로 두 경우가 같았습니다. 내 시계가 서버보다 앞서 있는 경우라면 recvWindow 를 아무리 키워도 그 자리는 그대로입니다. 바이낸스 문서 자체가 It is recommended to use a small recvWindow of 5000 or less! 로 작은 값을 권하기도 합니다.

Q. 크라켄에는 왜 시각 창이 없나요? A. 크라켄은 시각을 비교하지 않고 직전 값보다 큰지를 봅니다. 문서가 nonce payload parameter: always increasing, unsigned 64-bit integer. 로 적어 두었고, 그 값으로 밀리초 타임스탬프를 쓰는 것이 흔한 방법이라고 덧붙입니다. 그래서 이 문서는 시계 문제를 창이 아니라 순서 문제로 설명하고 system clock drift/recalibration 을 원인 중 하나로 적어 두었습니다. 시계가 뒤로 조정되면 새 값이 직전 값보다 작아질 수 있기 때문입니다.

Q. 나노초 필드를 그대로 쓰면 더 정확한가요? A. 자릿수는 더 깁니다. 다만 이번 측정에서 바이비트 timeNano 를 100만으로 나눈 값과 time 의 차이는 열여덟 번 모두 0.86밀리초 미만이었고, 두 필드를 오프셋으로 환산한 흩어짐도 사실상 같았습니다. 그리고 timeNano 는 19자리 문자열로 옵니다. 언어에 따라 이 값을 배정밀도 실수로 읽으면 아래 자리가 잘리므로, 정수로 다룰 수 있는 자료형을 쓰셔야 합니다.

Q. 코인베이스 iso 값의 소수부가 두 자리로 올 때가 있던데 응답이 잘못된 것인가요? A. 응답끼리는 어긋나지 않았습니다. 서른 번 모두 isoepoch 가 1밀리초 안에서 일치했습니다. 어긋나는 것은 읽는 쪽입니다. .18Z 는 18밀리초가 아니라 180밀리초인데, 소수부를 고정 폭으로 잘라 정수로 읽으면 162밀리초를 잃습니다. 소수부는 길이를 세어 자릿수를 맞추거나, 아예 epoch 쪽을 쓰는 편이 안전합니다.

Q. 바이비트에서 401 만 오고 본문이 비어 있는데 시계 문제인가요? A. 이번 조회로는 그렇게 말할 수 없습니다. 스큐 여섯 종, 열쇠 형식 다섯 종, X-BAPI-RECV-WINDOW 세 값, 그리고 인증 헤더를 아예 붙이지 않은 경우까지 전부 같은 HTTP 401 에 본문 0바이트가 왔습니다. 응답이 갈리지 않으므로 사유를 이 응답만으로 좁히지 못합니다. 시각 쪽을 확인하시려면 공개 시각 창구로 오프셋부터 재 보시는 편이 빠릅니다.

Q. 오프셋이 음수로 나왔다는 것은 거래소 시계가 늦다는 뜻인가요? A. 반대입니다. 여기서 오프셋은 서버가 준 시각에서 로컬 왕복 중점을 뺀 값이므로, 음수는 로컬 시계가 그만큼 앞서 있다는 뜻입니다. 이번 측정에서 서로 무관한 아홉 창구가 모두 -245밀리초 근처로 모였고 9분 뒤 다시 재니 아홉 개의 상대 위치는 그대로인 채 중앙값만 -214밀리초로 옮겨 갔습니다. 공통으로 움직인 성분은 이쪽 시계에 있습니다.

Q. Date 헤더만 보고 서버 시각을 맞춰도 되나요? A. 대체로 맞지만 늘 그렇지는 않습니다. 예순 번 호출에서는 본문 시각의 초와 Date 헤더의 초가 어긋난 경우가 0건이었는데, 뒤에 아흔여섯 번을 다시 부르니 데리비트에서 두 번 어긋났습니다. Date 는 응답을 내보낼 때 찍히므로 본문 시각이 초 경계에 걸리면 그 사이에 초가 넘어갑니다. 게다가 Date 헤더에는 초 아래 자리가 없어서, 본문 시각에서 Date 를 빼면 예순 번 측정에서 +0.009초부터 +0.978초까지 흩어졌습니다. 밀리초가 필요한 자리에서는 본문 필드를 읽으셔야 합니다.

함께 보면 좋은 글

데이터·개념 출처

본 노트의 수치는 2026년 8월 18일에 직접 호출해 받은 응답을 읽은 것입니다. 호출 시각은 다섯 덩어리입니다. 열세 창구 아홉 회전 측정이 11시 23분 02초~11시 23분 22초(KST, 협정세계시 2시 23분), 같은 스크립트의 두 번째 측정이 11시 32분 16초~11시 32분 37초(KST), 응답 형식·헤더 단위·Date 헤더 대조가 11시 24분~11시 25분(KST), 더미 열쇠 스큐 측정이 11시 25분~11시 28분(KST), 그리고 Date 헤더를 다시 확인한 아흔여섯 번 호출이 12시 33분 54초~12시 34분 05초(KST) 입니다. 더미 열쇠 덩어리만 실제 계정과 무관한 더미 열쇠를 붙였고, 나머지 넷은 인증 헤더를 붙이지 않은 공개 호출입니다.

부른 주소는 본문의 창구 표에 적은 열세 개 공개 시각 엔드포인트와, 허용 창 경계를 재는 데 쓴 GET https://www.okx.com/api/v5/account/balance·GET https://api.binance.com/api/v3/account·GET https://api.bybit.com/v5/account/wallet-balance 세 개입니다. 오프셋·편차·흩어짐·기울기와 각 자릿수 계수는 모두 응답을 받은 스크립트 안에서 계산했습니다.

문서 문구는 각 거래소 공식 문서를 2026년 8월 18일 11시 30분(KST) 에 직접 받아 축자로 확인했습니다. 바이낸스는 공식 저장소의 rest-api.md(181,189바이트)의 ### Timing security 절과 errors.md(20,321바이트)의 ### -1021 INVALID_TIMESTAMP·### -1194 INVALID_TIME_UNIT·### -2014 BAD_API_KEY_FMT 항목에서 옮겼습니다. 바이비트는 V5 가이드 문서(57,280바이트)의 인증 헤더 절에서, OKX 는 v5 문서(5,242,376바이트)의 REST 인증 절과 오류 코드 표, 그리고 웹소켓 로그인 절에서 옮겼습니다. MEXC 는 Spot V3 문서(445,494바이트)의 Timing security 절에서, HTX 는 Spot v1 문서(830,811바이트)의 자주 묻는 질문 Q6 목록 다섯째·여섯째 줄과 Signature Method 절의 네 번째 단계 두 곳에서, 크라켄은 Spot REST Authentication 문서(559,478바이트)의 인증 파라미터 절과 nonce 설명 절에서 옮겼습니다.

비트겟과 비트마트는 처음 아홉 주소에서 못 찾았다가 12시 33분(KST) 에 다른 주소를 열어 찾았습니다. 비트겟은 bitgetlimited.github.io/apidoc/en/spot/(HTTP 200 · 611,442바이트)의 Standard SpecificationTimestamp 항목, 비트마트는 developer-pro.bitmart.com/en/spot/(HTTP 200 · 614,112바이트)의 About recvWindow, timestamp 절입니다. 본문에 "확인하지 못했다"로 적은 세 거래소에 대해서는 시도한 주소와 받은 응답 크기를 위 절에 그대로 남겼습니다.

이 글은 공개 API 응답과 개발자 문서를 정리한 정보 제공 목적의 자료이며 특정 종목이나 거래소의 이용 권유가 아닙니다. 본 노트는 진입가나 정리 가격을 제시하지 않고, 어떤 자산도 매수 또는 매도 대상으로 지목하지 않으며, 어느 창구가 더 낫다는 판단도 하지 않습니다. 가상자산은 원금 손실이 발생할 수 있습니다. 위 오프셋과 왕복시간은 특정 시각에 특정 회선에서 잰 한 번의 스냅샷이라 다시 부르시면 달라질 수 있고, 허용 창 경계도 각 거래소가 바꿀 수 있는 값이라 이후에도 같은 자리에 있는지는 이 글에서 확인하지 않았습니다. 투자 판단과 그 결과는 전적으로 본인 책임입니다.

관련 평가 리포트

자금흐름2026-08-17

코인 마진 차입 이자율 실측 — 공개 창구에서 받은 값과 기간 단위 표기

자금흐름2026-08-16

코인 과거 시세 데이터 소급 한계 — 창구마다 다른 첫 기록 날짜와 한 번에 받아지는 개수

자금흐름2026-08-15

무기한 계약 최소 주문 금액 — 비트코인과 도지코인에서 하한 순서가 뒤집힌 자리