Integración API

¿Cómo conectar la API de Binance con Node.js? Firma crypto y node-binance-api

Práctica real completa de la API de Binance con Node.js: firma nativa con crypto, encapsulamiento de peticiones con axios, librería oficial node-binance-api, suscripción WebSocket con ws, manejo de excepciones y definiciones de tipos en TypeScript.

La ruta estándar para conectarse a la API de Binance con Node.js es: generar una firma HMAC-SHA256 utilizando el módulo nativo crypto junto con axios o undici para enviar peticiones, o utilizar directamente librerías de la comunidad como node-binance-api o binance-api-node. Este artículo proporciona código completo para el encapsulamiento nativo, comparación de SDKs populares, suscripciones WebSocket y tipos de TypeScript, todo listo para ser ejecutado con npm install. Si aún no tienes una cuenta de Binance, puedes completar el registro en el sitio oficial de Binance; los nuevos usuarios pueden abrir una cuenta mediante el registro gratuito.

I. Tabla comparativa de SDKs para Node.js

Nombre de la librería Autor Descargas semanales Características Escenario recomendado
node-binance-api jaggedsoft 30k+ Funcionalidades completas, estilo callback Validación rápida de scripts
binance-api-node Ashlar 50k+ Basado en Promises, amigable con TypeScript Entornos de producción con TypeScript
@binance/connector Oficial 40k+ Encapsulamiento ligero y delgado Seguir de cerca las actualizaciones de la API
ccxt Comunidad 80k+ Unificado para múltiples exchanges Trading algorítmico multiplataforma
Desarrollo propio axios + crypto Control total y extremo Market making de alta frecuencia

II. Firma nativa con crypto + encapsulamiento con axios

1. Inicialización del proyecto

mkdir binance-node && cd binance-node
npm init -y
npm install axios dotenv

Archivo .env:

BINANCE_API_KEY=tu_api_key_aqui
BINANCE_SECRET_KEY=tu_secret_key_aqui

2. Encapsulamiento del núcleo de firma

src/client.js:

const crypto = require('crypto');
const axios = require('axios');
require('dotenv').config();

const API_KEY = process.env.BINANCE_API_KEY;
const SECRET_KEY = process.env.BINANCE_SECRET_KEY;
const BASE_URL = 'https://api.binance.com';

function sign(params) {
  const query = new URLSearchParams(params).toString();
  return crypto
    .createHmac('sha256', SECRET_KEY)
    .update(query)
    .digest('hex');
}

async function request(method, path, params = {}, signed = false) {
  const headers = {};
  if (signed) {
    params.timestamp = Date.now();
    params.recvWindow = 5000;
    params.signature = sign(params);
    headers['X-MBX-APIKEY'] = API_KEY;
  }

  try {
    const config = {
      method,
      url: `${BASE_URL}${path}`,
      headers,
      timeout: 10000,
    };
    if (method === 'GET' || method === 'DELETE') {
      config.params = params;
    } else {
      config.data = new URLSearchParams(params).toString();
      config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
    }
    const r = await axios(config);
    return r.data;
  } catch (err) {
    if (err.response) {
      const { code, msg } = err.response.data;
      throw new Error(`Binance ${code}: ${msg}`);
    }
    throw err;
  }
}

module.exports = { request, sign };

3. Llamadas a cuenta y mercado

src/account.js:

const { request } = require('./client');

async function getAccount() {
  return request('GET', '/api/v3/account', {}, true);
}

async function getPrice(symbol) {
  const r = await request('GET', '/api/v3/ticker/price', { symbol });
  return parseFloat(r.price);
}

async function getDepth(symbol, limit = 20) {
  return request('GET', '/api/v3/depth', { symbol, limit });
}

async function placeLimitOrder(symbol, side, quantity, price) {
  return request('POST', '/api/v3/order', {
    symbol,
    side,
    type: 'LIMIT',
    timeInForce: 'GTC',
    quantity,
    price,
  }, true);
}

async function cancelOrder(symbol, orderId) {
  return request('DELETE', '/api/v3/order', { symbol, orderId }, true);
}

module.exports = { getAccount, getPrice, getDepth, placeLimitOrder, cancelOrder };

4. Ejemplo de ejecución

index.js:

const { getAccount, getPrice, placeLimitOrder } = require('./src/account');

(async () => {
  try {
    const account = await getAccount();
    const nonZero = account.balances.filter(b => parseFloat(b.free) > 0);
    console.log('Saldos no nulos:');
    nonZero.forEach(b => console.log(`  ${b.asset}: ${b.free}`));

    const btc = await getPrice('BTCUSDT');
    console.log(`Precio actual de BTC: $${btc}`);

    // Colocar una orden limitada (un -10% del precio actual para evitar ejecución inmediata en test)
    const testPrice = (btc * 0.9).toFixed(2);
    const order = await placeLimitOrder('BTCUSDT', 'BUY', '0.001', testPrice);
    console.log(`Orden ${order.orderId} creada con éxito`);
  } catch (e) {
    console.error('Fallo:', e.message);
  }
})();

Ejecución:

node index.js

III. Solución rápida con node-binance-api

1. Instalación

npm install node-binance-api

2. Ejemplo de uso

const Binance = require('node-binance-api');

const binance = new Binance().options({
  APIKEY: process.env.BINANCE_API_KEY,
  APISECRET: process.env.BINANCE_SECRET_KEY,
  useServerTime: true,  // Sincronización automática con la hora del servidor
  recvWindow: 10000,
  test: false,  // true para habilitar la Testnet
});

// Consultar saldos
binance.balance((error, balances) => {
  if (error) return console.error(error);
  Object.keys(balances).forEach(asset => {
    const available = parseFloat(balances[asset].available);
    if (available > 0) {
      console.log(`${asset}: ${available}`);
    }
  });
});

// Compra a mercado
binance.marketBuy('BTCUSDT', 0.001, (error, response) => {
  if (error) return console.error(error.body);
  console.log('Compra a mercado exitosa:', response);
});

// Orden limitada
binance.buy('BTCUSDT', 0.001, 60000, { type: 'LIMIT' }, (error, response) => {
  if (error) return console.error(error.body);
  console.log('Orden limitada colocada:', response.orderId);
});

// Estilo Promise
(async () => {
  const ticker = await binance.prices('BTCUSDT');
  console.log('Precio actual:', ticker.BTCUSDT);

  const candles = await binance.candlesticks('BTCUSDT', '1h', false, { limit: 100 });
  console.log('K-lines recientes:', candles.length);
})();

IV. binance-api-node (Promise / TypeScript)

1. Instalación

npm install binance-api-node
npm install -D typescript @types/node

2. Ejemplo en TypeScript

import Binance, { Binance as BinanceClient, OrderType, OrderSide } from 'binance-api-node';

const client: BinanceClient = Binance({
  apiKey: process.env.BINANCE_API_KEY!,
  apiSecret: process.env.BINANCE_SECRET_KEY!,
});

async function main() {
  // Inferencia automática de tipos
  const time = await client.time();
  console.log('Hora del servidor:', new Date(time));

  const account = await client.accountInfo();
  const nonZero = account.balances.filter(b => parseFloat(b.free) > 0);
  console.log(`Posees ${nonZero.length} tipos de activos`);

  const depth = await client.book({ symbol: 'BTCUSDT', limit: 20 });
  console.log(`Bid 1: ${depth.bids[0].price}, Ask 1: ${depth.asks[0].price}`);

  // Orden con verificación de tipos
  const order = await client.order({
    symbol: 'BTCUSDT',
    side: OrderSide.BUY,
    type: OrderType.LIMIT,
    timeInForce: 'GTC',
    quantity: '0.001',
    price: '60000.00',
  });
  console.log('ID de la orden:', order.orderId);
}

main().catch(console.error);

V. Suscripción en tiempo real con WebSocket (librería ws)

const WebSocket = require('ws');

function subscribeTickers(symbols) {
  const streams = symbols.map(s => `${s.toLowerCase()}@ticker`).join('/');
  const url = `wss://stream.binance.com:9443/stream?streams=${streams}`;

  function connect() {
    const ws = new WebSocket(url);

    ws.on('open', () => console.log(`Suscrito a ${symbols.length} pares de trading`));

    ws.on('message', (raw) => {
      const { stream, data } = JSON.parse(raw);
      console.log(`${data.s}: Último precio ${data.c}, cambio 24h ${data.P}%`);
    });

    ws.on('pong', () => console.log('Pong recibido'));

    ws.on('close', () => {
      console.log('Conexión perdida, reconectando en 5s');
      setTimeout(connect, 5000);
    });

    ws.on('error', (err) => console.error('Error de WS:', err.message));

    // Enviar ping cada 3 minutos para mantener la conexión activa
    setInterval(() => {
      if (ws.readyState === WebSocket.OPEN) ws.ping();
    }, 180000);
  }

  connect();
}

subscribeTickers(['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT']);

VI. Ejemplo en Node.js para la API de Futuros (Futures)

const crypto = require('crypto');
const axios = require('axios');

const FAPI = 'https://fapi.binance.com';

function signFutures(params, secret) {
  const query = new URLSearchParams(params).toString();
  return crypto.createHmac('sha256', secret).update(query).digest('hex');
}

async function futuresPlaceOrder(apiKey, secret, symbol, side, quantity, price) {
  const params = {
    symbol,
    side,
    type: 'LIMIT',
    timeInForce: 'GTC',
    quantity: quantity.toString(),
    price: price.toString(),
    timestamp: Date.now(),
  };
  params.signature = signFutures(params, secret);

  const r = await axios.post(
    `${FAPI}/fapi/v1/order`,
    new URLSearchParams(params).toString(),
    {
      headers: {
        'X-MBX-APIKEY': apiKey,
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    }
  );
  return r.data;
}

async function futuresSetLeverage(apiKey, secret, symbol, leverage) {
  const params = { symbol, leverage, timestamp: Date.now() };
  params.signature = signFutures(params, secret);

  const r = await axios.post(
    `${FAPI}/fapi/v1/leverage`,
    new URLSearchParams(params).toString(),
    { headers: { 'X-MBX-APIKEY': apiKey } }
  );
  return r.data;
}

VII. Preguntas frecuentes FAQ

P1: ¿Es suficiente la precisión de Date.now() en Node.js?

R: Sí. Date.now() en Node.js devuelve un timestamp en milisegundos (13 dígitos), que es exactamente lo que requiere la API de Binance. Sin embargo, en entornos de contenedores, asegúrate de que el reloj del host esté sincronizado (se recomienda usar chronyd o systemd-timesyncd).

P2: ¿Qué es mejor para la API de Binance, axios o node-fetch?

R: Axios es ideal para REST por defecto (análisis JSON automático, reintentos de errores, pool de conexiones); fetch (nativo en Node 18+) es más ligero pero requiere manejo manual de errores. Para escenarios de alta frecuencia, se recomienda undici o http.Agent nativo, ya que el rendimiento es un 30% superior al de axios.

P3: ¿Cómo evitar el uso de as any en TypeScript?

R: Utiliza binance-api-node, que incluye definiciones de tipos completas; o genera tus propios tipos basados en la especificación OpenAPI oficial usando openapi-typescript. Evita encapsulamientos genéricos como request<any>.

P4: ¿Qué precauciones debo tomar con el demonio pm2?

R: Si se pierde la conexión WebSocket, el bucle de eventos de Node no se cerrará y pm2 no reiniciará automáticamente el proceso. Se recomienda implementar la reconexión interna en el código (ver sección V) y configurar pm2 con max_memory_restart: '500M' para prevenir fugas de memoria.

P5: ¿Cómo limitar la frecuencia (rate limit) en Node.js?

R: Utiliza la librería bottleneck:

const Bottleneck = require('bottleneck');
const limiter = new Bottleneck({
  minTime: 10,        // Intervalo mínimo de 10ms
  maxConcurrent: 20,  // Máximo 20 peticiones concurrentes
});
const wrappedGet = limiter.wrap(axios.get);

Después de revisar la solución para Node.js, vuelve a la navegación de categorías para ver tutoriales de SDK en otros lenguajes en la sección de «Integración API».

Continuar explorando

¿Sigues con dudas sobre el uso de Binance? Vuelve a la página de categorías para encontrar otros tutoriales sobre el mismo tema.

Categorías

Tutoriales relacionados

¿Cómo solicitar la API de Binance? Guía para generar claves y firmas 2026-04-14 ¿Cómo usar la API Spot de Binance? Código listo para ejecutar desde cero hasta tu primera orden 2026-04-14 ¿Cuál es la diferencia entre la API de Binance Futures y Spot? Comparativa de endpoints, parámetros y pesos 2026-04-14 ¿Banearán mi IP de la API de Binance? Estrategias de límite de frecuencia y pesos explicadas 2026-04-14