Ключевые выводы/sapi/v1/system/status сообщает нормальное состояние или maintenance, но не доказывает исправность каждого Spot, Futures, WebSocket, account или trading-компонента.
/sapi/v1/system/statusсообщает нормальное состояние или maintenance, но не доказывает исправность каждого Spot, Futures, WebSocket, account или trading-компонента.- Диагностируйте по слоям: различайте отсутствие HTTP-ответа, не-Binance content, JSON-ошибку Binance и успешный, но устаревший поток данных.
5XXили-1007могут оставить исполнение ордера неизвестным: сохраняйтеnewClientOrderId, проверяйте User Data Stream и запрашивайте состояние перед ретраем.- Проверяйте symbol через
exchangeInfo, включая status, permissions, order types и filters; delist schedule используйте как предварительное предупреждение.
Краткое содержание подготовлено с помощью ИИ.
Что на самом деле подтверждает эндпоинт системного статуса
GET /sapi/v1/system/status расходует 1 единицу IP weight, не требует API-ключа в актуальной документации глобального Wallet API и возвращает два поля:
{
"status": 0,
"msg": "normal"
}
Значение 0 означает, что этот эндпоинт не сообщает об общем обслуживании системы. Значение 1 означает, что он сообщает о system maintenance. Ответ не уточняет, плановая ли это работа, какие продукты затронуты и когда восстановится нормальная работа.
Область проверки важна. Нормальный ответ не доказывает исправность Spot trading, Futures, WebSocket Streams, User Data Stream, отдельного REST-кластера или аккаунта. Эндпоинт полезен как первый сигнал, но каждая следующая проверка подтверждает только один слой:
| Проверка | Что она подтверждает |
|---|---|
| DNS, TCP и TLS | До выбранного hostname можно установить сетевое соединение |
/sapi/v1/system/status |
Эндпоинт сообщает или не сообщает об общем maintenance |
/api/v3/ping |
Конкретный Spot REST host отвечает на публичный запрос |
/api/v3/time |
Хост возвращает корректный JSON Spot API |
/api/v3/exchangeInfo |
Отвечает публичный слой метаданных Spot |
| Подписанный account request | Работают ключ, подпись, timestamp, permissions и account path |
| User Data Stream | Клиент получает приватные события аккаунта |
| Order query или test order | Доступен конкретный торговый путь |
| Проверка Futures или WebSocket | Доступен отдельный продукт или транспорт |
Binance публикует несколько базовых адресов Spot REST: api.binance.com, api-gcp.binance.com и api1–api4.binance.com. Документация предупреждает, что api1–api4 могут давать лучшую производительность при меньшей стабильности. Поэтому сбой на одном хосте и успех на другом указывают на различие конкретного хоста или маршрута, но сами по себе не доказывают общий сбой Binance.
Следующий скрипт выполняет публичные проверки без ретраев и доступа к аккаунту. Он записывает задержку, content type, HTTP-статус, Retry-After и код Binance, если тело действительно является Binance JSON:
from __future__ import annotations
import json
import time
from dataclasses import asdict, dataclass
from typing import Any
import requests
SYSTEM_STATUS_URL = "https://api.binance.com/sapi/v1/system/status"
SPOT_HOSTS = [
"https://api.binance.com",
"https://api-gcp.binance.com",
"https://api1.binance.com",
]
@dataclass
class ProbeResult:
url: str
latency_ms: float | None = None
http_status: int | None = None
content_type: str | None = None
retry_after: str | None = None
binance_code: int | None = None
message: str | None = None
exception: str | None = None
def probe(url: str, timeout: float = 5.0) -> ProbeResult:
started = time.monotonic_ns()
try:
response = requests.get(
url,
timeout=timeout,
headers={"Accept": "application/json"},
)
except requests.RequestException as exc:
return ProbeResult(
url=url,
latency_ms=(time.monotonic_ns() - started) / 1_000_000,
exception=type(exc).__name__,
message=str(exc),
)
result = ProbeResult(
url=url,
latency_ms=(time.monotonic_ns() - started) / 1_000_000,
http_status=response.status_code,
content_type=response.headers.get("Content-Type"),
retry_after=response.headers.get("Retry-After"),
)
try:
payload: Any = response.json()
except ValueError:
result.message = response.text[:300].strip() or "<empty body>"
return result
if isinstance(payload, dict):
code = payload.get("code")
result.binance_code = code if isinstance(code, int) else None
result.message = str(payload.get("msg", payload))
else:
result.message = json.dumps(payload)[:300]
return result
def get_egress_ip(timeout: float = 3.0) -> str:
try:
response = requests.get("https://api.ipify.org", timeout=timeout)
response.raise_for_status()
return response.text.strip()
except requests.RequestException as exc:
return f"unavailable ({type(exc).__name__})"
def triage() -> None:
print("egress_ip:", get_egress_ip())
urls = [SYSTEM_STATUS_URL]
for host in SPOT_HOSTS:
urls.extend([
f"{host}/api/v3/ping",
f"{host}/api/v3/time",
])
for url in urls:
print(json.dumps(asdict(probe(url)), ensure_ascii=False))
if __name__ == "__main__":
triage()
Запускайте его с того же хоста, контейнера и исходящего маршрута, где работает проблемное приложение. Успешный тест с ноутбука разработчика не доказывает, что production worker использует те же DNS, routing, proxy и условия доступности.
Как классифицировать ответ до чтения кода ошибки
Отрицательный код Binance существует только тогда, когда вы получили распознаваемую JSON-ошибку Binance. Инцидент может оборваться раньше или вернуть другое тело, поэтому сначала определите уровень ответа:
| Результат | Что обычно означает | Следующий шаг |
|---|---|---|
| Нет HTTP-ответа | Ошибка DNS, подключения, TLS, proxy, timeout или disconnect | Записать исключение и проверить маршрут |
| HTTP с HTML или некорректным JSON | Ответ CDN, WAF, неверный маршрут, посредник или нестандартная ошибка | Записать статус, content type и короткий фрагмент тела |
Binance JSON с отрицательным code |
API классифицировал запрос | Ветвить обработку по числовому коду |
| HTTP 200 при устаревших данных | Доступность и свежесть данных — разные свойства | Проверить event time и целостность последовательности |
Если Binance JSON получен, начните с HTTP-статуса:
| HTTP | Документированный смысл | Рабочая реакция |
|---|---|---|
| 4XX | Запрос сформирован некорректно или отклонён по вине отправителя | Читать код Binance и параметры запроса |
| 403 | Сработало правило WAF; возможны rate-limit или security enforcement | Проверить частоту, payload, параметры, SQL-подобные строки и общий IP |
| 409 | Запрос cancelReplace выполнился частично |
Свести результат отмены и создания нового ордера |
| 429 | Превышен лимит запросов или ордеров | Остановить отправку, соблюдать Retry-After, синхронизировать workers |
| 418 | IP автоматически заблокирован после продолжения запросов вслед за 429 | Остановить трафик до срока Retry-After и исправить limiter |
| 5XX | Внутренняя ошибка Binance | Для изменяющей состояние операции считать исполнение неизвестным |
Последняя строка критична. 5XX на ордерной операции не доказывает, что Matching Engine отклонил ордер. Слепой повтор запроса способен создать вторую позицию.
Как сверить ордер после 5XX или -1007
Механизм reconciliation нужно подготовить до первого production-ордера. Передавайте уникальный newClientOrderId и сохраняйте его вместе с намерением создать ордер. Если timeout или 5XX оставил результат неизвестным, не создавайте новый ордер немедленно.
Последовательность:
1. Остановить автоматические ретраи этого логического ордера.
2. Проверить User Data Stream на executionReport с client order ID.
3. Если события нет, вызвать GET /api/v3/order с origClientOrderId.
4. Свести status, executedQty, cumulative quote quantity и fills.
5. Повторять отправку только после подтверждения, что исходного ордера нет.
Binance документирует десятисекундный timeout обработки Spot API. Ошибка -1007 прямо сообщает, что send status и execution status неизвестны. Официальная рекомендация — сначала проверить User Data Stream, а при отсутствии события запросить статус через API.
Client order ID не заменяет reconciliation, но даёт приложению стабильный идентификатор, когда HTTP-клиент не получил Binance orderId. Сохраняйте его до отправки вместе с symbol, side, quantity, ожидаемой ценой, временем запроса и worker.
Как использовать коды ошибок Binance без чрезмерной классификации диапазонов
В актуальной Spot-документации сказано, что коды универсальны, а сообщения могут различаться. Здесь «универсальны» относится к текущим Spot-интерфейсам, описанным на этой странице. Нельзя автоматически переносить тот же список на отдельную региональную платформу или другой продукт Binance.
Официальная документация группирует 10xx как общие серверные и сетевые проблемы, а 11xx — как проблемы запроса. Для production-обработки удобнее группировать ошибки по требуемому действию:
| Категория | Примеры | Типичное действие |
|---|---|---|
| Transport или неизвестное исполнение | -1001, -1006, -1007, 5XX |
Переподключиться или сверить состояние до ретрая |
| Лимиты запросов и соединений | -1003, -1015, -1034, HTTP 429/418 |
Общий backoff и исправление limiter |
| Аутентификация и подпись | -1002, -1021, -1022, -2014, -2015 |
Проверить часы, подпись, ключ, IP и permissions |
| Валидация запроса | -1100, -1102, -1111, -1121, -1130 |
Исправить параметры по актуальным метаданным |
| Matching и состояние ордера | -2010, -2011, -2013, -2026, -2039 |
Проверить состояние ордера и сообщение Matching Engine |
Записывайте числовой код отдельным полем. Вместе с ним сохраняйте HTTP-статус, endpoint, host и текст сообщения: число определяет ветку обработки, а текст даёт контекст, когда у одного кода несколько документированных вариантов.
Что означает invalid symbol
Код -1121 означает BAD_SYMBOL: переданный symbol недопустим для этого endpoint. Не создавайте API-символ простым удалением / или - из отображаемой пары. Используйте точное значение из exchangeInfo на том продукте и хосте, куда обращается код.
Для Spot проверяйте не только имя:
curl -sS \
"https://api.binance.com/api/v3/exchangeInfo?symbol=BTCUSDT" \
| jq '.symbols[0] | {
symbol,
status,
orderTypes,
permissionSets,
quoteOrderQtyMarketAllowed,
filters
}'
Проверьте:
- точную строку symbol;
- текущий
status; - соответствие аккаунта требуемым
permissionSets; - поддержку нужного order type;
- применимые
PRICE_FILTER,LOT_SIZE,MIN_NOTIONAL,NOTIONALи другие filters; - какой именно рынок вызывается: Spot, Futures, Binance.US или другая платформа.
Корректное имя ещё не означает, что символ подходит для конкретной операции. В актуальном списке ошибок есть отдельный код -1220 SYMBOL_DOES_NOT_MATCH_STATUS.
Для будущих удалений Binance предоставляет GET /sapi/v1/spot/delist-schedule. Эндпоинт требует X-MBX-APIKEY и расходует IP weight 100. Запрашивайте его по расписанию, соответствующему вашему торговому universe, например раз в сутки, и кешируйте ответ вместо вызова внутри торгового цикла:
curl -sS \
"https://api.binance.com/sapi/v1/spot/delist-schedule" \
-H "X-MBX-APIKEY: $BINANCE_API_KEY" \
| jq '.[] | {delistTime, symbols}'
Это источник предварительного предупреждения. Runtime-источником текущих символов и фильтров Spot остаётся exchangeInfo.
Почему HTTP 200 недостаточно для здоровья маркет-данных
API может принимать соединения, пока клиент уже не обрабатывает актуальные маркет-данные. В WebSocket-системе свежесть нужно контролировать отдельно от доступности:
- возраст последнего event time;
- время с момента последнего сообщения;
- ожидаемую частоту обновлений выбранного stream;
- непрерывность sequence или update ID, если она определена протоколом;
- число reconnect и resynchronization;
- возраст локального order-book snapshot;
- расхождение REST и локального состояния при восстановлении.
Открытый socket без свежих событий нельзя считать исправным только потому, что TCP-сессия не закрылась. Успешный REST ping также ничего не доказывает о текущем состоянии WebSocket consumer.
Какие поля писать в журнал инцидента
Запись должна содержать достаточно контекста для воспроизведения маршрута:
timestamp
product
host
endpoint
method
HTTP status
Binance code
message
request latency
response content type
Retry-After
X-MBX-USED-WEIGHT-*
X-MBX-ORDER-COUNT-*
clientOrderId
egress IP
exception type
latest market-event age
Явно сохраняйте product и host. Сбой fapi.binance.com, api.binance.com и региональной платформы нельзя объединять в одну метрику binance_api_down.
Полезные метрики:
binance_http_errors_total{product,host,status}
binance_api_errors_total{product,host,code}
binance_request_latency_ms{product,host,endpoint}
binance_unknown_execution_total{endpoint}
binance_market_event_age_ms{stream}
binance_stream_reconnect_total{stream}
binance_egress_ip_info{worker,ip}
Где проверять официальные уведомления
В общем центре анонсов Binance могут публиковаться уведомления об обслуживании, но это не компонентная машиночитаемая status page. Binance также направляет API-разработчиков в официальный канал API announcements, где выходят уведомления о сервисе, изменениях API, обновлениях и deprecation.
Используйте уведомления как дополнительный контекст к собственным компонентным проверкам. Сторонние outage trackers агрегируют пользовательские жалобы: они могут показать массовость проблемы, но не определяют, какой компонент Binance неисправен и затрагивает ли проблема ваш маршрут.
Прокси не исправляет обслуживание Binance, устаревшее состояние приложения, WAF enforcement или сломанный rate limiter. Его уместная роль здесь — стабильный исходящий адрес для IP whitelisting и точной атрибуции инцидента. Наши прокси для Binance включают выделенные IPv4, зарезервированные только для вас на срок плана, поэтому после redeploy worker может сохранить ожидаемый адрес в правилах IP whitelisting и в логах.