La méthode standard pour accéder à l'API Binance avec Node.js consiste à utiliser le module natif crypto pour générer une signature HMAC-SHA256, couplé à axios ou undici pour envoyer les requêtes, ou à utiliser directement des bibliothèques communautaires comme node-binance-api ou binance-api-node. Cet article fournit le code complet pour l'encapsulation native, une comparaison des SDK populaires, l'abonnement WebSocket et les types TypeScript, le tout prêt à être exécuté après un npm install. Si vous n'avez pas encore de compte Binance, vous pouvez vous inscrire sur le site officiel de Binance ; les nouveaux utilisateurs peuvent ouvrir un compte via l' inscription gratuite.
I. Tableau comparatif des SDK Node.js
| Nom de la bibliothèque | Auteur | Téléchargements hebdo | Caractéristiques | Scénario recommandé |
|---|---|---|---|---|
| node-binance-api | jaggedsoft | 30k+ | Fonctionnalités complètes, style callback | Validation rapide de scripts |
| binance-api-node | Ashlar | 50k+ | Promise + Compatible TypeScript | Environnement de production TypeScript |
| @binance/connector | Officiel | 40k+ | Encapsulation légère | Suivi étroit des mises à jour API |
| ccxt | Communauté | 80k+ | Unifié pour plusieurs échanges | Trading quantitatif multi-plateformes |
| Sur mesure axios + crypto | — | — | Contrôle total | Market making haute fréquence |
II. Signature crypto native + Encapsulation axios
1. Initialisation du projet
mkdir binance-node && cd binance-node
npm init -y
npm install axios dotenv
Fichier .env :
BINANCE_API_KEY=votre_cle_ici
BINANCE_SECRET_KEY=votre_secret_ici
2. Encapsulation de la signature de base
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. Appels de compte et de marché
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. Exemple d'exécution
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('Soldes non nuls :');
nonZero.forEach(b => console.log(` ${b.asset}: ${b.free}`));
const btc = await getPrice('BTCUSDT');
console.log(`Dernier prix BTC : $${btc}`);
// Passer un ordre limité (à -10% du prix actuel pour éviter l'exécution immédiate)
const testPrice = (btc * 0.9).toFixed(2);
const order = await placeLimitOrder('BTCUSDT', 'BUY', '0.001', testPrice);
console.log(`Ordre ${order.orderId} créé`);
} catch (e) {
console.error('Échec :', e.message);
}
})();
Lancer :
node index.js
III. Solution rapide node-binance-api
1. Installation
npm install node-binance-api
2. Exemple d'utilisation
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, // Synchronisation automatique de l'heure du serveur
recvWindow: 10000,
test: false, // Mettre à true pour activer le testnet
});
// Consulter les soldes
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}`);
}
});
});
// Achat au prix du marché
binance.marketBuy('BTCUSDT', 0.001, (error, response) => {
if (error) return console.error(error.body);
console.log('Achat au marché réussi :', response);
});
// Ordre limité
binance.buy('BTCUSDT', 0.001, 60000, { type: 'LIMIT' }, (error, response) => {
if (error) return console.error(error.body);
console.log('Ordre limité placé :', response.orderId);
});
// Style Promise
(async () => {
const ticker = await binance.prices('BTCUSDT');
console.log('Prix actuel :', ticker.BTCUSDT);
const candles = await binance.candlesticks('BTCUSDT', '1h', false, { limit: 100 });
console.log('Derniers chandeliers :', candles.length);
})();
IV. binance-api-node (Promise / TypeScript)
1. Installation
npm install binance-api-node
npm install -D typescript @types/node
2. Exemple 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() {
// Inférence de type automatique
const time = await client.time();
console.log('Heure du serveur :', new Date(time));
const account = await client.accountInfo();
const nonZero = account.balances.filter(b => parseFloat(b.free) > 0);
console.log(`Détient ${nonZero.length} types d'actifs`);
const depth = await client.book({ symbol: 'BTCUSDT', limit: 20 });
console.log(`Achat 1 : ${depth.bids[0].price}, Vente 1 : ${depth.asks[0].price}`);
// Passage d'ordre avec vérification de type
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 l\'ordre :', order.orderId);
}
main().catch(console.error);
V. Abonnement WebSocket en temps réel (bibliothèque 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(`Abonné à ${symbols.length} paires de trading`));
ws.on('message', (raw) => {
const { stream, data } = JSON.parse(raw);
console.log(`${data.s}: Dernier prix ${data.c}, Variation 24h ${data.P}%`);
});
ws.on('pong', () => console.log('Pong reçu'));
ws.on('close', () => {
console.log('Connexion interrompue, reconnexion dans 5s');
setTimeout(connect, 5000);
});
ws.on('error', (err) => console.error('Erreur WS :', err.message));
// Envoyer un ping toutes les 3 minutes pour maintenir la connexion
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) ws.ping();
}, 180000);
}
connect();
}
subscribeTickers(['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT']);
VI. Exemple Node.js pour l'API Futures (Contrats)
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. Questions Fréquentes FAQ
Q1 : La précision de Date.now() dans Node.js est-elle suffisante ?
R : Oui. Date.now() de Node.js renvoie un horodatage en millisecondes (13 chiffres), ce qui est exactement ce que requiert l'API Binance. Cependant, dans un environnement de conteneur, assurez-vous que l'horloge de l'hôte est précise (utilisez chronyd ou systemd-timesyncd).
Q2 : Entre axios et node-fetch, lequel est le plus adapté à l'API Binance ?
R : axios est adapté par défaut pour le REST (analyse JSON automatique, tentatives d'erreur, pool de connexions) ; fetch (natif dans Node 18+) est plus léger mais nécessite une gestion manuelle des erreurs. Pour les scénarios à haute fréquence, préférez undici ou http.Agent natif, 30 % plus performant qu'axios.
Q3 : Comment éviter as any en TypeScript ?
R : Utilisez binance-api-node avec des définitions de type complètes ; ou générez vos propres types avec openapi-typescript basés sur les spécifications OpenAPI officielles. Évitez l'encapsulation générique de type request<any>.
Q4 : À quoi faut-il faire attention avec le daemon pm2 ?
R : La boucle d'événements Node ne s'arrête pas lors de la perte d'une connexion WebSocket, pm2 ne redémarrera donc pas automatiquement. Il est conseillé d'implémenter la reconnexion au sein du code (voir section V) ; configurez pm2 avec max_memory_restart: '500M' pour prévenir les fuites de mémoire.
Q5 : Comment limiter le débit (rate limit) dans Node.js ?
R : Utilisez la bibliothèque bottleneck :
const Bottleneck = require('bottleneck');
const limiter = new Bottleneck({
minTime: 10, // Intervalle minimum de 10ms
maxConcurrent: 20, // Maximum 20 requêtes simultanées
});
const wrappedGet = limiter.wrap(axios.get);
Après avoir exploré la solution Node.js, retournez à la Navigation par catégorie pour consulter les tutoriels sur les SDK d'autres langues dans la catégorie « Intégration API ».