API 연동

바이낸스 API Node.js 연결 방법: crypto 서명 및 node-binance-api 가이드

바이낸스 Node.js API 전체 실전 가이드: 네이티브 crypto 서명, axios 요청 캡슐화, node-binance-api 공식 라이브러리, WebSocket ws 구독, 예외 처리, TypeScript 타입 정의 및 실행 가능한 전체 코드 포함.

바이낸스 Node.js API 연결의 표준 경로는 네이티브 crypto 모듈을 사용하여 HMAC-SHA256 서명을 생성하고 axios 또는 undici로 요청을 보내거나, node-binance-api 또는 binance-api-node와 같은 커뮤니티 라이브러리를 직접 사용하는 것입니다. 이 글에서는 네이티브 캡슐화, 인기 SDK 비교, WebSocket 구독, TypeScript 타입 정의의 4개 모듈에 대한 전체 코드를 제공하며, 모두 npm install 후 즉시 실행 가능합니다. 아직 바이낸스 계정이 없다면 바이낸스 공식 사이트에서 가입을 완료할 수 있으며, 신규 사용자는 무료 회원가입을 통해 계정을 개설할 수 있습니다.

1. Node.js SDK 비교표

라이브러리명 개발자 주간 다운로드 특징 추천 시나리오
node-binance-api jaggedsoft 30k+ 포괄적인 기능, 콜백 방식 스크립트 빠른 검증
binance-api-node Ashlar 50k+ Promise 기반, TypeScript 친화적 운영 환경 TypeScript
@binance/connector 공식 40k+ 가볍고 얇은 캡슐화 최신 API 업데이트 반영
ccxt 커뮤니티 80k+ 여러 거래소 통합 지원 거래소 간 양적 매매
자체 개발 axios + crypto 극도의 제어 가능성 고빈도 마켓 메이킹

2. 네이티브 crypto 서명 + axios 캡슐화

1. 프로젝트 초기화

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

.env 파일:

BINANCE_API_KEY=your_key_here
BINANCE_SECRET_KEY=your_secret_here

2. 핵심 서명 캡슐화

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. 계정 및 시세 호출

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. 실행 예제

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('0이 아닌 잔고:');
    nonZero.forEach(b => console.log(`  ${b.asset}: ${b.free}`));

    const btc = await getPrice('BTCUSDT');
    console.log(`BTC 최신가: $${btc}`);

    // 한도 주문 (체결 방지를 위해 현재가 대비 -10% 설정)
    const testPrice = (btc * 0.9).toFixed(2);
    const order = await placeLimitOrder('BTCUSDT', 'BUY', '0.001', testPrice);
    console.log(`주문 ${order.orderId} 생성됨`);
  } catch (e) {
    console.error('실패:', e.message);
  }
})();

실행:

node index.js

3. node-binance-api 빠른 솔루션

1. 설치

npm install node-binance-api

2. 사용 예제

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,  // 서버 시간 자동 동기화
  recvWindow: 10000,
  test: false,  // true 설정 시 테스트넷 사용
});

// 잔고 확인
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}`);
    }
  });
});

// 시장가 매수
binance.marketBuy('BTCUSDT', 0.001, (error, response) => {
  if (error) return console.error(error.body);
  console.log('시장가 매수 성공:', response);
});

// 지정가 주문
binance.buy('BTCUSDT', 0.001, 60000, { type: 'LIMIT' }, (error, response) => {
  if (error) return console.error(error.body);
  console.log('지정가 주문 완료:', response.orderId);
});

// Promise 스타일
(async () => {
  const ticker = await binance.prices('BTCUSDT');
  console.log('현재가:', ticker.BTCUSDT);

  const candles = await binance.candlesticks('BTCUSDT', '1h', false, { limit: 100 });
  console.log('최근 K라인 수:', candles.length);
})();

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

1. 설치

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

2. 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() {
  // 자동 타입 추론 지원
  const time = await client.time();
  console.log('서버 시간:', new Date(time));

  const account = await client.accountInfo();
  const nonZero = account.balances.filter(b => parseFloat(b.free) > 0);
  console.log(`${nonZero.length}종의 자산 보유 중`);

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

  // 타입 체크가 포함된 주문
  const order = await client.order({
    symbol: 'BTCUSDT',
    side: OrderSide.BUY,
    type: OrderType.LIMIT,
    timeInForce: 'GTC',
    quantity: '0.001',
    price: '60000.00',
  });
  console.log('주문 ID:', order.orderId);
}

main().catch(console.error);

5. WebSocket 실시간 구독 (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(`${symbols.length}개 거래쌍 구독 시작`));

    ws.on('message', (raw) => {
      const { stream, data } = JSON.parse(raw);
      console.log(`${data.s}: 최신가 ${data.c}, 24h 변동률 ${data.P}%`);
    });

    ws.on('pong', () => console.log('pong 수신'));

    ws.on('close', () => {
      console.log('연결 끊김, 5초 후 재연결');
      setTimeout(connect, 5000);
    });

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

    // 3분마다 ping을 보내 연결 유지
    setInterval(() => {
      if (ws.readyState === WebSocket.OPEN) ws.ping();
    }, 180000);
  }

  connect();
}

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

6. 선물 API (Futures) Node.js 예제

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;
}

7. 자주 묻는 질문 (FAQ)

Q1: Node.js의 Date.now() 정밀도가 충분한가요?

A: 네, 충분합니다. Node.js의 Date.now()는 밀리초 정밀도의 타임스탬프(13자리)를 반환하며, 바이낸스 API가 요구하는 밀리초 수준을 완전히 충족합니다. 다만 컨테이너 환경에서는 호스트 시계가 정확해야 합니다(chronyd 또는 systemd-timesyncd 권장).

Q2: axios와 node-fetch 중 어느 것이 바이낸스 API에 더 적합한가요?

A: axios의 기본 동작이 REST에 더 적합합니다(자동 JSON 파싱, 오류 재시도, 커넥션 풀 지원). fetch(Node 18+ 네이티브 지원)는 더 가볍지만 오류 처리를 수동으로 해야 합니다. 고빈도 시나리오에서는 axios보다 성능이 30%가량 높은 undici 또는 네이티브 http.Agent를 권장합니다.

Q3: TypeScript에서 as any를 피하려면 어떻게 하나요?

A: 전체 타입 정의가 포함된 binance-api-node를 사용하거나, 공식 OpenAPI 사양을 기반으로 openapi-typescript를 사용하여 직접 타입을 생성하세요. request<any>와 같은 범용 캡슐화는 피하는 것이 좋습니다.

Q4: pm2 프로세스 관리자 사용 시 주의사항은?

A: WebSocket 연결이 끊겨도 Node 이벤트 루프가 종료되지 않으므로 pm2가 자동으로 재시작되지 않습니다. 코드 내부에서 재연결 로직을 구현해야 하며(5절 참조), 메모리 누수 방지를 위해 pm2 설정에서 max_memory_restart: '500M'를 추가하는 것이 좋습니다.

Q5: Node.js에서 요청 속도를 제한(Rate Limit)하려면?

A: bottleneck 라이브러리를 사용하세요:

const Bottleneck = require('bottleneck');
const limiter = new Bottleneck({
  minTime: 10,        // 최소 10ms 간격
  maxConcurrent: 20,  // 최대 20개 동시 요청
});
const wrappedGet = limiter.wrap(axios.get);

Node.js 솔루션을 확인하셨다면, 카테고리로 돌아가 「API 연동」 분류에서 다른 언어의 SDK 튜토리얼을 확인해 보세요.

계속 둘러보기

바이낸스 사용에 대한 추가 질문이 있으신가요? 카테고리 페이지로 돌아가 같은 주제의 다른 가이드를 찾아보세요.

카테고리

관련 가이드

바이낸스 API 신청 방법? 키 및 서명 생성 가이드 2026-04-14 바이낸스 현물(Spot) API 사용법: 첫 주문까지 가능한 실행 코드 가이드 2026-04-14 바이낸스 선물(Futures)과 현물(Spot) API의 차이점은? 엔드포인트와 가중치 비교 2026-04-14 바이낸스 API 사용 시 IP 차단될까? 제한 정책 및 가중치 계산법 총정리 2026-04-14