npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ygcc/ygcc

v2.9.0

Published

Lightweight cryptocurrency exchange library — unified REST & WebSocket API for 30+ exchanges

Readme

YGCC — Cryptocurrency Exchange Library

npm version Node.js License: MIT Tests Exchanges

Lightweight, unified REST & WebSocket API for cryptocurrency exchanges. One interface, 33 exchanges.

Overview

YGCC is a JavaScript library for cryptocurrency trading that provides a unified API across multiple exchanges. Write your trading logic once — it works on every supported exchange without modification.

Built from 5+ years of production trading experience across 30+ exchanges.

Features

  • Unified API — Same method signatures across all exchanges (fetchTicker, createOrder, watchOrderBook, etc.)
  • REST + WebSocket — Full market data, trading, and real-time streaming support
  • Weight-Aware Rate Limiting — Token-bucket limiter that syncs with exchange response headers
  • Auto-Reconnect WebSocket — Exponential backoff with jitter, automatic resubscription
  • Typed Error HierarchyAuthenticationError, InsufficientFunds, RateLimitExceeded, etc.
  • Minimal Dependencies — Only ws for WebSocket support
  • Multi-Auth Support — HMAC-SHA256/384/512 (hex, Base64), SHA512 content hash (Kraken/Gate.io/Bittrex), JWT/ES256 (Coinbase), UUID nonce (Bitstamp), MD5+HMAC-SHA256 (LBank), Base64-decoded HMAC-SHA256 (Phemex), HMAC-SHA256+memo (BitMart), HMAC-SHA256+URL-signature (Bitrue), HMAC-SHA256+path-signing (Bitforex), HMAC-SHA256+header-signing (Pionex), dual V3 HmacMD5 + V4 HmacSHA256 (Bibox), Base64+HMAC-SHA512 (WhiteBit), HMAC-SHA512 timestamp+method+path (VALR), HMAC-SHA256 uppercase 4-credential (Bitexen), Base64-decoded HMAC-SHA256 (BtcTurk), HMAC-SHA384 path-signing (BTSE), HMAC-SHA512 form-encoded (EXMO), double-layer HMAC-SHA256 (CoinTR), Huobi-style query-string HMAC-SHA256 Base64 (HotCoin), Base64-decoded HMAC-SHA256 ICX headers (iCrypex), Binance-compatible HMAC-SHA256 (JBEX/Trubit), HMAC-SHA512 payload-based (PointPay), HTTP Basic Auth (TradeOgre)
  • Testnet Support — Built-in sandbox mode for safe testing

Supported Exchanges

CEX (Centralized)

| # | Exchange | ID | REST | WebSocket | Status | |---|----------|-----|------|-----------|--------| | 1 | Binance | binance | ✅ | ✅ | Ready | | 2 | Bybit | bybit | ✅ | ✅ | Ready | | 3 | OKX | okx | ✅ | ✅ | Ready | | 4 | Kraken | kraken | ✅ | ✅ | Ready | | 5 | Gate.io | gateio | ✅ | ✅ | Ready | | 6 | Coinbase | coinbase | ✅ | ✅ | Ready | | 7 | KuCoin | kucoin | ✅ | ✅ | Ready | | 8 | Bitfinex | bitfinex | ✅ | ✅ | Ready | | 9 | Bitstamp | bitstamp | ✅ | ✅ | Ready | | 10 | Bittrex | bittrex | ✅ | ✅ | Ready | | 11 | Bitrue | bitrue | ✅ | ✅ | Ready | | 12 | LBANK | lbank | ✅ | ✅ | Ready | | 13 | BitMart | bitmart | ✅ | ✅ | Ready | | 14 | Bitforex | bitforex | ✅ | ✅ | Ready | | 15 | Phemex | phemex | ✅ | ✅ | Ready | | 16 | Pionex | pionex | ✅ | ✅ | Ready | | 17 | Bibox | bibox | ✅ | ✅ | Ready | | 18 | WhiteBit | whitebit | ✅ | ✅ | Ready | | 19 | VALR | valr | ✅ | ✅ | Ready | | 20 | Bitexen | bitexen | ✅ | ✅ | Ready | | 21 | BtcTurk | btcturk | ✅ | ✅ | Ready | | 22 | BTSE | btse | ✅ | ✅ | Ready | | 23 | EXMO | exmo | ✅ | ✅ | Ready | | 24 | CoinTR | cointr | ✅ | ✅ | Ready | | 25 | HotCoin | hotcoin | ✅ | ✅ | Ready | | 26 | iCrypex | icrypex | ✅ | ✅ | Ready | | 27 | JBEX | jbex | ✅ | ✅ | Ready | | 28 | PointPay | pointpay | ✅ | ✅ | Ready | | 29 | TruBit | trubit | ✅ | ✅ | Ready | | 30 | TradeOgre | tradeogre | ✅ | ❌ | Ready |

DEX (Decentralized)

| # | Exchange | ID | REST | WebSocket | Status | |---|----------|-----|------|-----------|--------| | 31 | Pollymarket | pollymarket | 🔜 | 🔜 | Planned | | 32 | Hyperliquid | hyperliquid | 🔜 | 🔜 | Planned | | 33 | ZKLighter | zklighter | 🔜 | 🔜 | Planned |

✅ = Implemented    🔜 = Coming Soon

Installation

npm install @ygcc/ygcc

Or clone directly:

git clone https://github.com/yuzgecoguz/ygcc.git
cd ygcc
npm install

Quick Start

Fetch Market Data (Public — No API Key Needed)

const { Binance } = require('@ygcc/ygcc');

const exchange = new Binance();

(async () => {
  // Load all trading pairs
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Get BTC price
  const ticker = await exchange.fetchTicker('BTCUSDT');
  console.log(`BTC: $${ticker.last} (${ticker.percentage}%)`);

  // Order book (top 5 levels)
  const book = await exchange.fetchOrderBook('BTCUSDT', 5);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);

  // OHLCV candlesticks
  const candles = await exchange.fetchOHLCV('BTCUSDT', '1h', undefined, 5);
  console.log(`Last 5 hourly candles:`, candles);
})();

Place Orders (Private — API Key Required)

const { Binance } = require('@ygcc/ygcc');

const exchange = new Binance({
  apiKey: process.env.BINANCE_API_KEY,
  secret: process.env.BINANCE_SECRET,
  enableRateLimit: true,
});

(async () => {
  // Check balance
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Place a limit order
  const order = await exchange.createLimitOrder('BTCUSDT', 'BUY', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel it
  const canceled = await exchange.cancelOrder(order.id, 'BTCUSDT');
  console.log(`Canceled: ${canceled.status}`);
})();

WebSocket Streaming (Real-Time)

const { Binance } = require('@ygcc/ygcc');

const exchange = new Binance();

// Real-time ticker updates
exchange.watchTicker('BTCUSDT', (ticker) => {
  console.log(`BTC: $${ticker.last} | Bid: $${ticker.bid} | Ask: $${ticker.ask}`);
});

// Real-time trades
exchange.watchTrades('ETHUSDT', (trade) => {
  console.log(`${trade.side.toUpperCase()} ${trade.amount} ETH @ $${trade.price}`);
});

// Real-time order book
exchange.watchOrderBook('BTCUSDT', (book) => {
  const spread = book.asks[0][0] - book.bids[0][0];
  console.log(`Spread: $${spread.toFixed(2)}`);
}, 5);

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using Bybit

const { Bybit } = require('@ygcc/ygcc');

const exchange = new Bybit();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  const ticker = await exchange.fetchTicker('BTCUSDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTCUSDT', 50);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Bybit Trading (Private)

const { Bybit } = require('@ygcc/ygcc');

const exchange = new Bybit({
  apiKey: process.env.BYBIT_API_KEY,
  secret: process.env.BYBIT_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Bybit V5 uses POST for orders (not query string like Binance)
  const order = await exchange.createLimitOrder('BTCUSDT', 'Buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses POST too (not DELETE like Binance)
  const canceled = await exchange.cancelOrder(order.id, 'BTCUSDT');
  console.log(`Canceled: ${canceled.status}`);
})();

Using OKX

const { Okx } = require('@ygcc/ygcc');

const exchange = new Okx();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // OKX uses dash-separated symbols: BTC-USDT (not BTCUSDT)
  const ticker = await exchange.fetchTicker('BTC-USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC-USDT', 5);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

OKX Trading (Private)

const { Okx } = require('@ygcc/ygcc');

const exchange = new Okx({
  apiKey: process.env.OKX_API_KEY,
  secret: process.env.OKX_SECRET,
  passphrase: process.env.OKX_PASSPHRASE, // OKX requires passphrase!
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // OKX uses lowercase side/type, Base64 signature, POST for all trades
  const order = await exchange.createLimitOrder('BTC-USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id, 'BTC-USDT');
  console.log(`Canceled: ${canceled.status}`);
})();

Using Kraken

const { Kraken } = require('@ygcc/ygcc');

const exchange = new Kraken();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Kraken uses slash-separated symbols: BTC/USD
  const ticker = await exchange.fetchTicker('BTC/USD');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USD', 10);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Kraken Trading (Private)

const { Kraken } = require('@ygcc/ygcc');

const exchange = new Kraken({
  apiKey: process.env.KRAKEN_API_KEY,
  secret: process.env.KRAKEN_SECRET, // Base64-encoded secret
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USD:', balance.USD);

  // Kraken uses form-urlencoded POST, SHA256+HMAC-SHA512 signing
  const order = await exchange.createLimitOrder('BTC/USD', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Using Gate.io

const { Gateio } = require('@ygcc/ygcc');

const exchange = new Gateio();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Gate.io uses underscore-separated symbols: BTC_USDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 10);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Gate.io Trading (Private)

const { Gateio } = require('@ygcc/ygcc');

const exchange = new Gateio({
  apiKey: process.env.GATEIO_API_KEY,
  secret: process.env.GATEIO_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Gate.io uses HMAC-SHA512 hex signing with SHA512 body hash
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.status}`);
})();

Using KuCoin

const { KuCoin } = require('@ygcc/ygcc');

const exchange = new KuCoin();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // KuCoin uses hyphen-separated symbols: BTC-USDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 20);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

KuCoin Trading (Private)

const { KuCoin } = require('@ygcc/ygcc');

const exchange = new KuCoin({
  apiKey: process.env.KUCOIN_API_KEY,
  secret: process.env.KUCOIN_SECRET,
  passphrase: process.env.KUCOIN_PASSPHRASE, // KuCoin requires passphrase (encrypted automatically)
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // KuCoin auto-generates clientOid (UUID) for every order
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Using Coinbase

const { Coinbase } = require('@ygcc/ygcc');

const exchange = new Coinbase();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Coinbase uses hyphen-separated symbols: BTC-USD (note: USD, not USDT)
  const ticker = await exchange.fetchTicker('BTC/USD');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USD', 10);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Coinbase Trading (Private)

const { Coinbase } = require('@ygcc/ygcc');

const exchange = new Coinbase({
  apiKey: process.env.COINBASE_API_KEY,    // organizations/{org_id}/apiKeys/{key_id}
  secret: process.env.COINBASE_SECRET,      // EC private key (PEM format)
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USD:', balance.USD);

  // Coinbase uses JWT/ES256 auth, nested order_configuration, auto-generated client_order_id
  const order = await exchange.createLimitOrder('BTC/USD', 'BUY', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses POST batch_cancel (not DELETE)
  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Using Bitfinex

const { Bitfinex } = require('@ygcc/ygcc');

const exchange = new Bitfinex();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Bitfinex uses tBTCUSD format internally, accepts BTC/USD
  const ticker = await exchange.fetchTicker('BTC/USD');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USD', 25);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Bitfinex Trading (Private)

const { Bitfinex } = require('@ygcc/ygcc');

const exchange = new Bitfinex({
  apiKey: process.env.BITFINEX_API_KEY,
  secret: process.env.BITFINEX_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USD:', balance.USD);

  // Bitfinex uses HMAC-SHA384, EXCHANGE LIMIT/MARKET types, amount sign for side
  const order = await exchange.createLimitOrder('BTC/USD', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Using Bitstamp

const { Bitstamp } = require('@ygcc/ygcc');

const exchange = new Bitstamp();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Bitstamp uses slash-separated symbols: BTC/USD
  const ticker = await exchange.fetchTicker('BTC/USD');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USD', 10);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Bitstamp Trading (Private)

const { Bitstamp } = require('@ygcc/ygcc');

const exchange = new Bitstamp({
  apiKey: process.env.BITSTAMP_API_KEY,
  secret: process.env.BITSTAMP_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USD:', balance.USD);

  // Bitstamp uses HMAC-SHA256 + UUID nonce, side is in the URL path (buy/sell)
  const order = await exchange.createLimitOrder('BTC/USD', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Using Bittrex

const { Bittrex } = require('@ygcc/ygcc');

const exchange = new Bittrex();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Bittrex uses hyphen-separated uppercase symbols: BTC-USDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 25);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Bittrex Trading (Private)

const { Bittrex } = require('@ygcc/ygcc');

const exchange = new Bittrex({
  apiKey: process.env.BITTREX_API_KEY,
  secret: process.env.BITTREX_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Bittrex uses HMAC-SHA512 + SHA512 content hash, JSON POST body, DELETE for cancel
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses DELETE method (unique among exchanges)
  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Bittrex WebSocket (SignalR V3)

const { Bittrex } = require('@ygcc/ygcc');

const exchange = new Bittrex();

// Real-time ticker via SignalR V3 hub "c3"
exchange.watchTicker('BTC/USDT', (ticker) => {
  console.log(`BTC: $${ticker.last} | Bid: $${ticker.bid} | Ask: $${ticker.ask}`);
});

// Real-time order book deltas
exchange.watchOrderBook('BTC/USDT', (book) => {
  console.log(`Bids: ${book.bids.length} | Asks: ${book.asks.length} | Seq: ${book.nonce}`);
}, 25);

// Real-time trades
exchange.watchTrades('ETH/USD', (trade) => {
  console.log(`${trade.side.toUpperCase()} ${trade.amount} ETH @ $${trade.price}`);
});

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using LBank

const { LBank } = require('@ygcc/ygcc');

const exchange = new LBank();

(async () => {
  await exchange.loadMarkets();
  console.log(`${Object.keys(exchange.markets).length} symbols loaded`);

  // LBank uses underscore-separated lowercase symbols: btc_usdt
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 50);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

LBank Trading (Private)

const { LBank } = require('@ygcc/ygcc');

const exchange = new LBank({
  apiKey: process.env.LBANK_API_KEY,
  secret: process.env.LBANK_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // LBank uses MD5+HMAC-SHA256 two-step signing, POST params in query string
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.id}`);
})();

LBank WebSocket (V3 JSON)

const { LBank } = require('@ygcc/ygcc');

const exchange = new LBank();

// Real-time ticker via V3 JSON subscribe
exchange.watchTicker('BTC/USDT', (ticker) => {
  console.log(`BTC: $${ticker.last} | Bid: $${ticker.bid} | Ask: $${ticker.ask}`);
});

// Real-time order book depth
exchange.watchOrderBook('BTC/USDT', (book) => {
  console.log(`Bids: ${book.bids.length} | Asks: ${book.asks.length}`);
}, 50);

// Real-time trades
exchange.watchTrades('ETH/USDT', (trades) => {
  trades.forEach(t => console.log(`${t.side.toUpperCase()} ${t.amount} ETH @ $${t.price}`));
});

// Real-time klines
exchange.watchKlines('BTC/USDT', '1m', (kline) => {
  console.log(`Open: ${kline.open} | Close: ${kline.close} | Vol: ${kline.volume}`);
});

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using Phemex

const { Phemex } = require('@ygcc/ygcc');

const exchange = new Phemex();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Phemex uses s-prefix format internally: sBTCUSDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT');
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Phemex Trading (Private)

const { Phemex } = require('@ygcc/ygcc');

const exchange = new Phemex({
  apiKey: process.env.PHEMEX_API_KEY,
  secret: process.env.PHEMEX_SECRET, // Base64-encoded secret key
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Phemex uses HMAC-SHA256 with Base64-decoded secret, Ep/Ev 10^8 scaling
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses DELETE method with query params
  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.id}`);
})();

Phemex WebSocket (JSON-RPC)

const { Phemex } = require('@ygcc/ygcc');

const exchange = new Phemex();

// Real-time ticker via JSON-RPC subscribe
exchange.watchTicker('BTC/USDT', (ticker) => {
  console.log(`BTC: $${ticker.last} | Bid: $${ticker.bid} | Ask: $${ticker.ask}`);
});

// Real-time order book (snapshot + incremental)
exchange.watchOrderBook('BTC/USDT', (book) => {
  console.log(`Bids: ${book.bids.length} | Asks: ${book.asks.length} | Type: ${book.type}`);
});

// Real-time trades
exchange.watchTrades('ETH/USDT', (trades) => {
  trades.forEach(t => console.log(`${t.side.toUpperCase()} ${t.amount} ETH @ $${t.price}`));
});

// Real-time klines
exchange.watchKlines('BTC/USDT', '1h', (klines) => {
  klines.forEach(k => console.log(`Open: ${k.open} | Close: ${k.close}`));
});

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using BitMart

const { BitMart } = require('@ygcc/ygcc');

const exchange = new BitMart();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // BitMart uses underscore-separated symbols: BTC_USDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 20);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

BitMart Trading (Private)

const { BitMart } = require('@ygcc/ygcc');

const exchange = new BitMart({
  apiKey: process.env.BITMART_API_KEY,
  secret: process.env.BITMART_SECRET,
  memo: process.env.BITMART_MEMO, // BitMart requires memo (3rd credential)
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // BitMart uses HMAC-SHA256 with memo in signature: timestamp#memo#body
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.status}`);
})();

BitMart WebSocket (zlib compressed)

const { BitMart } = require('@ygcc/ygcc');

const exchange = new BitMart();

// Real-time ticker via zlib-compressed subscribe
exchange.watchTicker('BTC/USDT', (ticker) => {
  console.log(`BTC: $${ticker.last} | Bid: $${ticker.bid} | Ask: $${ticker.ask}`);
});

// Real-time order book (depth5 or depth20)
exchange.watchOrderBook('BTC/USDT', (book) => {
  console.log(`Bids: ${book.bids.length} | Asks: ${book.asks.length}`);
}, 20);

// Real-time trades
exchange.watchTrades('ETH/USDT', (trades) => {
  trades.forEach(t => console.log(`${t.side.toUpperCase()} ${t.amount} ETH @ $${t.price}`));
});

// Real-time klines
exchange.watchKlines('BTC/USDT', '1h', (klines) => {
  klines.forEach(k => console.log(`Open: ${k.open} | Close: ${k.close}`));
});

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using Bitrue

const { Bitrue } = require('@ygcc/ygcc');

const exchange = new Bitrue();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Bitrue uses Binance-style symbols: BTCUSDT (no separator)
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 20);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Bitrue Trading (Private)

const { Bitrue } = require('@ygcc/ygcc');

const exchange = new Bitrue({
  apiKey: process.env.BITRUE_API_KEY,
  secret: process.env.BITRUE_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Bitrue uses HMAC-SHA256 with signature in URL, JSON POST body, GTT timeInForce
  const order = await exchange.createLimitOrder('BTC/USDT', 'BUY', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.status}`);
})();

Bitrue WebSocket (gzip compressed)

const { Bitrue } = require('@ygcc/ygcc');

const exchange = new Bitrue();

// Real-time ticker via gzip-compressed subscribe
exchange.watchTicker('BTC/USDT', (ticker) => {
  console.log(`BTC: $${ticker.last} | Bid: $${ticker.bid} | Ask: $${ticker.ask}`);
});

// Real-time order book (depth_step0)
exchange.watchOrderBook('BTC/USDT', (book) => {
  console.log(`Bids: ${book.bids.length} | Asks: ${book.asks.length}`);
}, 20);

// Real-time trades
exchange.watchTrades('ETH/USDT', (trade) => {
  console.log(`${trade.side.toUpperCase()} ${trade.amount} ETH @ $${trade.price}`);
});

// Real-time klines
exchange.watchKlines('BTC/USDT', '1h', (kline) => {
  console.log(`Open: ${kline.open} | Close: ${kline.close} | Vol: ${kline.volume}`);
});

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using Bitforex

const { Bitforex } = require('@ygcc/ygcc');

const exchange = new Bitforex();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Bitforex uses unique coin-quote-base format: coin-usdt-btc
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 10);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Bitforex Trading (Private)

const { Bitforex } = require('@ygcc/ygcc');

const exchange = new Bitforex({
  apiKey: process.env.BITFOREX_API_KEY,
  secret: process.env.BITFOREX_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Bitforex uses HMAC-SHA256 with path in signing string, limit orders only (no market orders)
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.status}`);
})();

Bitforex WebSocket (plain text JSON)

const { Bitforex } = require('@ygcc/ygcc');

const exchange = new Bitforex();

// Real-time ticker via plain text JSON subscribe
exchange.watchTicker('BTC/USDT', (ticker) => {
  console.log(`BTC: $${ticker.last} | Bid: $${ticker.bid} | Ask: $${ticker.ask}`);
});

// Real-time order book (depth10)
exchange.watchOrderBook('BTC/USDT', (book) => {
  console.log(`Bids: ${book.bids.length} | Asks: ${book.asks.length}`);
}, 10);

// Real-time trades
exchange.watchTrades('ETH/USDT', (trade) => {
  console.log(`${trade.side.toUpperCase()} ${trade.amount} ETH @ $${trade.price}`);
});

// Real-time klines
exchange.watchKlines('BTC/USDT', '1m', (kline) => {
  console.log(`Open: ${kline.open} | Close: ${kline.close} | Vol: ${kline.volume}`);
});

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using Pionex

const { Pionex } = require('@ygcc/ygcc');

const exchange = new Pionex();

(async () => {
  // Pionex has NO REST market data — only loadMarkets is available publicly
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // No fetchTicker, fetchOrderBook, fetchTrades, or fetchOHLCV!
  // Use WebSocket for real-time market data instead
})();

Pionex Trading (Private)

const { Pionex } = require('@ygcc/ygcc');

const exchange = new Pionex({
  apiKey: process.env.PIONEX_API_KEY,
  secret: process.env.PIONEX_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Pionex MARKET BUY uses amount (quote currency), SELL uses size (base currency)
  const order = await exchange.createLimitOrder('BTC/USDT', 'BUY', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses DELETE with JSON body (unique to Pionex)
  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.status}`);

  // Cancel all open orders for a symbol
  await exchange.cancelAllOrders('BTC/USDT');
})();

Pionex WebSocket (Real-Time)

const { Pionex } = require('@ygcc/ygcc');

const exchange = new Pionex();

// Real-time order book (server PING → client PONG heartbeat)
exchange.watchOrderBook('BTC/USDT', (book) => {
  const spread = book.asks[0][0] - book.bids[0][0];
  console.log(`Spread: $${spread.toFixed(2)}`);
}, 100);

// Real-time trades
exchange.watchTrades('BTC/USDT', (trades) => {
  trades.forEach(t => console.log(`${t.side} ${t.amount} @ $${t.price}`));
});

process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using Bibox

const { Bibox } = require('@ygcc/ygcc');

const exchange = new Bibox();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Bibox uses underscore-separated symbols: BTC_USDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 10);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

Bibox Trading (Private)

const { Bibox } = require('@ygcc/ygcc');

const exchange = new Bibox({
  apiKey: process.env.BIBOX_API_KEY,
  secret: process.env.BIBOX_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // Bibox uses dual auth: V3 HmacMD5 for trading, V4 HmacSHA256 for account
  // Only limit orders supported (no market orders)
  const order = await exchange.createLimitOrder('BTC/USDT', 'BUY', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses POST (not DELETE like Pionex)
  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Bibox WebSocket (zlib compressed)

const { Bibox } = require('@ygcc/ygcc');

const exchange = new Bibox();

// Real-time order book via zlib-compressed binary data
exchange.watchOrderBook('BTC/USDT', (book) => {
  const spread = book.asks[0][0] - book.bids[0][0];
  console.log(`Spread: $${spread.toFixed(2)}`);
}, 10);

// Graceful shutdown
process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using WhiteBit

const { WhiteBit } = require('@ygcc/ygcc');

const exchange = new WhiteBit();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // WhiteBit uses underscore-separated symbols: BTC_USDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 10);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

WhiteBit Trading (Private)

const { WhiteBit } = require('@ygcc/ygcc');

const exchange = new WhiteBit({
  apiKey: process.env.WHITEBIT_API_KEY,
  secret: process.env.WHITEBIT_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // WhiteBit uses Base64+HMAC-SHA512 signing, all private endpoints are POST
  const order = await exchange.createLimitOrder('BTC/USDT', 'BUY', 0.001, 50000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

WhiteBit WebSocket (zlib compressed)

const { WhiteBit } = require('@ygcc/ygcc');

const exchange = new WhiteBit();

// Real-time order book via zlib-compressed binary data (Z_SYNC_FLUSH)
exchange.watchOrderBook('BTC/USDT', (book) => {
  const spread = book.asks[0][0] - book.bids[0][0];
  console.log(`Spread: $${spread.toFixed(2)}`);
}, 50);

process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using VALR

const { Valr } = require('@ygcc/ygcc');

const exchange = new Valr();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // VALR uses concatenated symbols: BTCZAR (South African exchange, ZAR quote)
  const ticker = await exchange.fetchTicker('BTC/ZAR');
  console.log(`BTC: R${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/ZAR', 10);
  console.log(`Best bid: R${book.bids[0][0]} | Best ask: R${book.asks[0][0]}`);
})();

VALR Trading (Private)

const { Valr } = require('@ygcc/ygcc');

const exchange = new Valr({
  apiKey: process.env.VALR_API_KEY,
  secret: process.env.VALR_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('ZAR:', balance.ZAR);

  // VALR uses HMAC-SHA512(timestamp+method+path+body) signing
  const order = await exchange.createLimitOrder('BTC/ZAR', 'BUY', 0.001, 500000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses DELETE with JSON body (like Pionex)
  const canceled = await exchange.cancelOrder(order.id, 'BTC/ZAR');
  console.log(`Canceled: ${canceled.status}`);
})();

Using Bitexen

const { Bitexen } = require('@ygcc/ygcc');

const exchange = new Bitexen();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // Bitexen uses concatenated symbols: BTCTRY (Turkish exchange, TRY quote)
  const ticker = await exchange.fetchTicker('BTC/TRY');
  console.log(`BTC: ₺${ticker.last}`);
})();

Bitexen Trading (Private)

const { Bitexen } = require('@ygcc/ygcc');

const exchange = new Bitexen({
  apiKey: process.env.BITEXEN_API_KEY,
  secret: process.env.BITEXEN_SECRET,
  passphrase: process.env.BITEXEN_PASSPHRASE, // Bitexen requires 4 credentials
  uid: process.env.BITEXEN_USERNAME,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('TRY:', balance.TRY);

  // Bitexen uses HMAC-SHA256 uppercase, only limit orders, buy_sell: B/S
  const order = await exchange.createLimitOrder('BTC/TRY', 'BUY', 0.001, 750000);
  console.log(`Order ${order.id}: ${order.status}`);

  // Cancel uses POST with orderId in URL path
  const canceled = await exchange.cancelOrder(order.id);
  console.log(`Canceled: ${canceled.status}`);
})();

Bitexen WebSocket (Socket.IO v2)

const { Bitexen } = require('@ygcc/ygcc');

const exchange = new Bitexen();

// Real-time ticker via Socket.IO v2 (SID handshake, Engine.IO keepalive)
exchange.watchTicker('BTC/TRY', (ticker) => {
  console.log(`BTC: ₺${ticker.last}`);
});

// Real-time order book
exchange.watchOrderBook('BTC/TRY', (book) => {
  const spread = book.asks[0][0] - book.bids[0][0];
  console.log(`Spread: ₺${spread.toFixed(2)}`);
});

process.on('SIGINT', async () => {
  await exchange.closeAllWs();
  process.exit(0);
});

Using BtcTurk

const { BtcTurk } = require('@ygcc/ygcc');

const exchange = new BtcTurk();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // BtcTurk uses concatenated symbols: BTCTRY (Turkish exchange)
  const ticker = await exchange.fetchTicker('BTC/TRY');
  console.log(`BTC: ₺${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/TRY', 5);
  console.log(`Best bid: ₺${book.bids[0][0]} | Best ask: ₺${book.asks[0][0]}`);
})();

BtcTurk Trading (Private)

const { BtcTurk } = require('@ygcc/ygcc');

const exchange = new BtcTurk({
  apiKey: process.env.BTCTURK_API_KEY,
  secret: process.env.BTCTURK_SECRET, // Base64-encoded secret
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('TRY:', balance.TRY);

  // BtcTurk uses HMAC-SHA256 with Base64-decoded secret key
  const order = await exchange.createLimitOrder('BTC/TRY', 'buy', 0.001, 2500000);
  console.log(`Order ${order.id}: ${order.status}`);

  // cancelOrder uses DELETE with id in query params
  const canceled = await exchange.cancelOrder(order.id, 'BTC/TRY');
  console.log(`Canceled: ${canceled.status}`);
})();

BtcTurk WebSocket

const { BtcTurk } = require('@ygcc/ygcc');

const exchange = new BtcTurk();

// Real-time order book via JSON array protocol [type, payload]
exchange.watchOrderBook('BTC/TRY', (book) => {
  const spread = book.asks[0][0] - book.bids[0][0];
  console.log(`Spread: ₺${spread.toFixed(2)}`);
});

Using BTSE

const { Btse } = require('@ygcc/ygcc');

const exchange = new Btse();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // BTSE uses hyphen-separated symbols: BTC-USDT
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 5);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

BTSE Trading (Private)

const { Btse } = require('@ygcc/ygcc');

const exchange = new Btse({
  apiKey: process.env.BTSE_API_KEY,
  secret: process.env.BTSE_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // BTSE uses HMAC-SHA384, numeric order types (76=limit, 77=market)
  const order = await exchange.createLimitOrder('BTC/USDT', 'BUY', 0.001, 65000);
  console.log(`Order ${order.id}: ${order.status}`);

  // cancelOrder uses DELETE with JSON body
  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.status}`);
})();

Using EXMO

const { Exmo } = require('@ygcc/ygcc');

const exchange = new Exmo();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // EXMO uses underscore-separated symbols: BTC_USD
  const ticker = await exchange.fetchTicker('BTC/USD');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USD', 5);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

EXMO Trading (Private)

const { Exmo } = require('@ygcc/ygcc');

const exchange = new Exmo({
  apiKey: process.env.EXMO_API_KEY,
  secret: process.env.EXMO_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USD:', balance.USD);

  // EXMO uses HMAC-SHA512 with form-encoded POST, nonce in body
  const order = await exchange.createLimitOrder('BTC/USD', 'buy', 0.001, 65000);
  console.log(`Order ${order.id}: ${order.status}`);

  // cancelOrder also uses POST (all private endpoints are POST)
  const canceled = await exchange.cancelOrder(order.id, 'BTC/USD');
  console.log(`Canceled: ${canceled.status}`);
})();

Using CoinTR

const { Cointr } = require('@ygcc/ygcc');

const exchange = new Cointr();

(async () => {
  await exchange.loadMarkets();
  console.log(`${exchange.symbols.length} symbols loaded`);

  // CoinTR uses concatenated symbols: BTCUSDT (OKX-style API)
  const ticker = await exchange.fetchTicker('BTC/USDT');
  console.log(`BTC: $${ticker.last}`);

  const book = await exchange.fetchOrderBook('BTC/USDT', 5);
  console.log(`Best bid: $${book.bids[0][0]} | Best ask: $${book.asks[0][0]}`);
})();

CoinTR Trading (Private)

const { Cointr } = require('@ygcc/ygcc');

const exchange = new Cointr({
  apiKey: process.env.COINTR_API_KEY,
  secret: process.env.COINTR_SECRET,
});

(async () => {
  const balance = await exchange.fetchBalance();
  console.log('USDT:', balance.USDT);

  // CoinTR uses double-layer HMAC-SHA256, auto-generates clOrdId (UUID)
  const order = await exchange.createLimitOrder('BTC/USDT', 'buy', 0.001, 65000);
  console.log(`Order ${order.id}: ${order.status}`);

  const canceled = await exchange.cancelOrder(order.id, 'BTC/USDT');
  console.log(`Canceled: ${canceled.status}`);
})();

Testnet / Sandbox Mode

// Binance testnet
const binance = new Binance({
  apiKey: 'testnet-key',
  secret: 'testnet-secret',
  options: { sandbox: true }, // Uses testnet.binance.vision
});

// Bybit testnet
const bybit = new Bybit({
  apiKey: 'testnet-key',
  secret: 'testnet-secret',
  options: { sandbox: true }, // Uses api-testnet.bybit.com
});

// OKX demo trading
const okx = new Okx({
  apiKey: 'demo-key',
  secret: 'demo-secret',
  passphrase: 'demo-pass',
  options: { sandbox: true }, // Adds x-simulated-trading header
});

Unified API Reference

All exchanges implement the same method signatures:

Market Data (Public)

| Method | Description | Binance | Bybit | OKX | Kraken | Gate.io | KuCoin | Coinbase | Bitfinex | Bitstamp | Bittrex | LBank | Phemex | BitMart | Bitrue | Bitforex | Pionex | Bibox | WhiteBit | VALR | Bitexen | BtcTurk | BTSE | EXMO | CoinTR | |--------|-------------|---------|-------|-----|--------|---------|--------|----------|----------|----------|---------|-------|--------|---------|--------|----------|--------|-------|----------|------|---------|---------|------|------|--------| | loadMarkets() | Load trading pairs, filters, precision rules | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | fetchTicker(symbol) | 24hr price statistics | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | fetchTickers(symbols?) | All tickers at once | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | | fetchOrderBook(symbol, limit?) | Bids & asks depth | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | | fetchTrades(symbol, since?, limit?) | Recent public trades | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | fetchOHLCV(symbol, timeframe?, since?, limit?) | Candlestick / kline data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | fetchAvgPrice(symbol) | Current average price | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | fetchPrice(symbol?) | Quick price lookup (lightweight) | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | fetchBookTicker(symbol?) | Best bid/ask only | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | fetchTime() | Server time | | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

Trading (Private — Signed)

| Method | Description | Binance | Bybit | OKX | Kraken | Gate.io | KuCoin | Coinbase | Bitfinex | Bitstamp | Bittrex | LBank | Phemex | BitMart | Bitrue | Bitforex | Pionex | Bibox | WhiteBit | VALR | Bitexen | BtcTurk | BTSE | EXMO | CoinTR | |--------|-------------|---------|-------|-----|--------|---------|--------|----------|----------|----------|---------|-------|--------|---------|--------|----------|--------|-------|----------|------|---------|---------|------|------|--------| | createOrder(symbol, type, side, amount, price?, params?) | Place any order type | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | createLimitOrder(symbol, side, amount, price) | Limit order shortcut | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | createMarketOrder(symbol, side, amount) | Market order shortcut | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | | cancelOrder(id, symbol) | Cancel single order | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | cancelAllOrders(symbol) | Cancel all open orders | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ✅ | | ❌ | ❌ | ❌ | | | | | | amendOrder(id, symbol, params) | Modify existing order | ✅ | ✅ | ✅ | | | | | | | | | | | | | | | | | | | | | | | createOCO(symbol, side, qty, price, stopPrice) | One-Cancels-Other | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | createOTO(...) | One-Triggers-Other | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | createOTOCO(...) | One-Triggers-OCO | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | testOrder(...) | Validate without placing | ✅ | | | | | | | | | | | | | | | | | | | | | | | |

Account (Private — Signed)

| Method | Description | Binance | Bybit | OKX | Kraken | Gate.io | KuCoin | Coinbase | Bitfinex | Bitstamp | Bittrex | LBank | Phemex | BitMart | Bitrue | Bitforex | Pionex | Bibox | WhiteBit | VALR | Bitexen | BtcTurk | BTSE | EXMO | CoinTR | |--------|-------------|---------|-------|-----|--------|---------|--------|----------|----------|----------|---------|-------|--------|---------|--------|----------|--------|-------|----------|------|---------|---------|------|------|--------| | fetchBalance() | Account balances (free, used, total) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | fetchOrder(id, symbol) | Single order status | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | fetchOpenOrders(symbol?) | All open orders | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | | fetchClosedOrders(symbol, ...) | Closed order history | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | fetchMyTrades(symbol, ...) | Trade history with fees | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ✅ | ✅ | ✅ | | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | fetchTradingFees(symbol) | Maker/taker fee rates | | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅ | | | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | fetchCommission(symbol) | Maker/taker commission rates | ✅ | | | | | | | | | | | | | | | | | | | | | | | |

WebSocket Streams

| Method | Description | Binance | Bybit | OKX | Kraken | Gate.io | KuCoin | Coinbase | Bitfinex | Bitstamp | Bittrex | LBank | Phemex | BitMart | Bitrue | Bitforex | Pionex | Bibox | WhiteBit | VALR | Bitexen | BtcTurk | BTSE | EXMO | CoinTR | |--------|-------------|---------|-------|-----|--------|---------|--------|----------|----------|----------|---------|-------|--------|---------|--------|----------|--------|-------|----------|------|---------|---------|------|------|--------| | watchTicker(symbol, callback) | Real-time ticker | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | | watchAllTickers(callback) | All tickers stream | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | watchOrderBook(symbol, callback, levels?) | Real-time order book | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | watchTrades(symbol, callback) | Real-time trades | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | watchKlines(symbol, interval, callback) | Real-time candlesticks | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | watchBookTicker(symbol, callback) | Real-time best bid/ask | ✅ | | | | | | | | | | | | | | | | | | | | | | | | | watchBalance(callback) | Balance updates (private) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | | | | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | watchOrders(callback) | Order updates (private) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | | | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

Unified Response Formats

Ticker

{
  symbol: 'BTCUSDT',
  last: 97500.00,
  bid: 97499.50,  bidVolume: 1.5,
  ask: 97500.50,  askVolume: 0.8,
  high: 98200.00, low: 96800.00,
  open: 97000.00, close: 97500.00,
  volume: 12345.678,
  quoteVolume: 1204567890.12,
  change: 500.00,
  percentage: 0.515,
  timestamp: 1700000000000,
  datetime: '2023-11-14T22:13:20.000Z',
}

Order Book

{
  symbol: 'BTCUSDT',
  bids: [[97500.00, 1.5], [97499.00, 2.0], ...],  // [price, quantity]
  asks: [[97501.00, 0.8], [97502.00, 1.2], ...],
  timestamp: 1700000000000,
  nonce: 123456789,
}

Order

{
  id: '12345678',
  clientOrderId: 'myOrder1',
  symbol: 'BTCUSDT',
  type: 'LIMIT',
  side: 'BUY',
  price: 95000.00,
  amount: 0.01,
  filled: 0.005,
  remaining: 0.005,
  cost: 475.00,
  average: 95000.00,
  status: 'PARTIALLY_FILLED',  // NEW, FILLED, CANCELED, EXPIRED, REJECTED
  timestamp: 1700000000000,
  trades: [{ price, amount, commission, commissionAsset }],
}

Balance

{
  BTC:  { free: 0.50, used: 0.10, total: 0.60 },
  USDT: { free: 5000, used: 1000, total: 6000 },
  timestamp: 1700000000000,
}

Error Handling

YGCC provides typed errors for precise error handling:

const {
  Binance,
  AuthenticationError,
  InsufficientFunds,
  RateLimitExceeded,
  InvalidOrder,
  OrderNotFound,
  BadSymbol,
  NetworkError,
} = require('@ygcc/ygcc');

try {
  await exchange.createOrder('BTCUSDT', 'LIMIT', 'BUY', 0.001, 95000);
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Check your API key and secret');
  } else if (error instanceof InsufficientFunds) {
    console.error('Not enough balance');
  } else if (error instanceof RateLimitExceeded) {
    console.error('Slow down — rate limited');
  } else if (error instanceof InvalidOrder) {
    console.error('Order rejected:', error.message);
  } else if (error instanceof NetworkError) {
    console.error('Connection issue — retry');
  }
}

Error Hierarchy

Error
  └── ExchangeError
        ├── AuthenticationError    // Invalid API key, signature, or timestamp
        ├── RateLimitExceeded      // 429 / 418 responses
        ├── InsufficientFunds      // Not enough balance
        ├── InvalidOrder           // Filter violations, bad params
        ├── OrderNotFound          // Order doesn't exist
        ├── BadSymbol              // Invalid trading pair
        ├── BadRequest             // Malformed request
        ├── ExchangeNotAvailable   // Exchange maintenance
        └── NetworkError
              └── RequestTimeout   // Request exceeded timeout

Rate Limiting

YGCC automatically tracks and respects exchange rate limits:

const exchange = new Binance({ enableRateLimit: true }); // Default: true

// Monitor rate limit usage
exchange.on('rateLimitWarning', ({ used, limit }) => {
  console.warn(`Rate limit: ${used}/${limit} weight used`);
});

Binance uses a weight-based system (6000 weight/minute). Each endpoint has a different weight cost. YGCC tracks the X-MBX-USED-WEIGHT-1M response header and automatically throttles requests when approaching the limit.

Architecture

ygcc/
├── index.js                    # Entry point: const { Binance, Bybit, Okx, ..., HotCoin, Icrypex, Jbex, PointPay, Trubit, TradeOgre } = require('@ygcc/ygcc')
├── lib/
│   ├── BaseExchange.js         # Abstract base class — unified interface
│   ├── binance.js              # Binance implementation (1369 lines, 59 methods)
│   ├── bybit.js                # Bybit V5 implementation (1021 lines, 45 methods)
│   ├── okx.js                  # OKX V5 implementation (690 lines, 42 methods)
│   ├── kraken.js               # Kraken implementation (680 lines, 40 methods)
│   ├── gateio.js               # Gate.io V4 implementation (700 lines, 40 methods)
│   ├── kucoin.js               # KuCoin V1 implementation (1033 lines, 42 methods)
│   ├── coinbase.js             # Coinbase Advanced Trade implementation (780 lines, 42 methods)
│   ├── bitfinex.js             # Bitfinex V2 implementation (750 lines, 42 methods)
│   ├── bitstamp.js             # Bitstamp V2 implementation (580 lines, 38 methods)
│   ├── bittrex.js              # Bittrex V3 implementation (976 lines, 44 methods)
│   ├── lbank.js                # LBank V2 implementation (530 lines, 40 methods)
│   ├── phemex.js               # Phemex Spot implementation (580 lines, 42 methods)
│   ├── bitmart.js              # BitMart Spot implementation (600 lines, 48 methods)
│   ├── bitrue.js               # Bitrue Spot implementation (600 lines, 42 methods)
│   ├── bitforex.js             # Bitforex Spot implementation (500 lines, 35 methods)
│   ├── pionex.js               # Pionex — HMAC-SHA256 header-signing, DELETE with JSON body
│   ├── bibox.js                # Bibox — dual V3 HmacMD5 + V4 HmacSHA256, zlib WS, limit orders only
│   ├── whitebit.js             # WhiteBit — Base64+HMAC-SHA512, zlib Z_SYNC_FLUSH WS, all private POST
│   ├── valr.js                 # VALR — HMAC-SHA512 timestamp+method+path, DELETE with JSON body, ZAR pairs
│   ├── bitexen.js              # Bitexen — 4-credential HMAC-SHA256 uppercase, Socket.IO v2 WS, TRY pairs
│   ├── btcturk.js              # BtcTurk exchange
│   ├── btse.js                 # BTSE exchange
│   ├── exmo.js                 # EXMO exchange
│   ├── cointr.js               # CoinTR exchange
│   ├── hotcoin.js              # HotCoin — Huobi-style query-string HMAC-SHA256 Base64, GZIP WS
│   ├── icrypex.js              # iCrypex — Base64-decoded HMAC-SHA256, ICX headers, pipe-delimited WS
│   ├── jbex.js                 # JBEX — Binance-compatible HMAC-SHA256, Galactic-Tech white-label
│   ├── pointpay.js             # PointPay — HMAC-SHA512 payload-based, all private POST
│   ├── trubit.js               # Trubit — Binance-compatible, same platform as JBEX
│   ├── tradeogre.js            # TradeOgre — HTTP Basic Auth, no WS, limit orders only
│   └── utils/
│       ├── crypto.js           # HMAC-SHA256/384/512 + JWT/ES256 + MD5 + HmacMD5 + Base64-decoded + memo + path + Base64 + uppercase signing
│       ├── errors.js           # Typed error classes
│       ├── helpers.js          # Safe value extraction, query builders
│       ├── throttler.js        # Token-bucket rate limiter
│       └── ws.js               # WebSocket with auto-reconnect
├── examples/
│   ├── fetch-ticker.js         # Public market data demo
│   ├── place-order.js          # Trading demo
│   └── websocket-stream.js     # Real-time streaming demo
└── tests/
    ├── binance.test.js         # 82 tests — Binance implementation
    ├── bybit.test.js           # 83 tests — Bybit V5 implementation
    ├── okx.test.js             # 91 tests — OKX V5 implementation
    ├── kraken.test.js          # 86 tests — Kraken implementation
    ├── gateio.test.js          # 84 tests — Gate.io V4 implementation
    ├── kucoin.test.js          # 86 tests — KuCoin V1 implementation
    ├── coinbase.test.js        # 93 tests — Coinbase Advanced Trade implementation
    ├── bitfinex.test.js        # 97 tests — Bitfinex V2 implementation
    ├── bitstamp.test.js        # 91 tests — Bitstamp V2 implementation
    ├── bittrex.test.js         # 112 tests — Bittrex V3 implementation
    ├── lbank.test.js           # 110 tests — LBank V2 implementation
    ├── phemex.test.js          # 106 tests — Phemex Spot implementation
    ├── bitmart.test.js         # 108 tests — BitMart Spot implementation
    ├── bitrue.test.js          # 108 tests — Bitrue Spot implementation
    ├── bitforex.test.js        # 101 tests — Bitforex Spot implementation
    ├── pionex.test.js          # 101 tests — Pionex implementation
    ├── bibox.test.js           # 98 tests — Bibox dual-auth implementation
    ├── whitebit.test.js        # 94 tests — WhiteBit Base64+HMAC-SHA512 implementation
    ├── valr.test.js            # 97 tests — VALR HMAC-SHA512 implementation
    ├── bitexen.test.js         # 101 tests — Bitexen 4-credential implementation
    ├── btcturk.test.js         # 97 tests — BtcTurk tests (97 tests, 16 sections)
    ├── btse.test.js            # 94 tests — BTSE tests (94 tests, 16 sections)
    ├── exmo.test.js            # 93 tests — EXMO tests (93 tests, 16 sections)
    ├── cointr.test.js          # 92 tests — CoinTR tests (92 tests, 16 sections)
    ├── hotcoin.test.js         # 95 tests — HotCoin tests (16 sections)
    ├── icrypex.test.js         # 95 tests — iCrypex tests (16 sections)
    ├── jbex.test.js            # 93 tests — JBEX tests (16 sections)
    ├── pointpay.test.js        # 95 tests — PointPay tests (16 sections)
    ├── trubit.test.js          # 93 tests — Trubit tests (16 sections)
    └── tradeogre.test.js       # 91 tests — TradeOgre tests (15 sections, no WS)

Adding a New Exchange

Every exchange extends BaseExchange and implements:

const BaseExchange = require('./BaseExchange');

class MyExchange extends BaseExchange {
  describe() {
    return {
      id: 'myexchange',
      name: 'My Exchange',
      version: 'v1',
      rateLimit: 100,
      urls: { api: 'https://api.myexchange.com' },
      has: { fetchTicker: true, createOrder: true, ... },
    };
  }

  _sign(path, method, params) {
    // Exchange-specific authentication
  }

  async loadMarkets() { /* ... */ }
  async fetchTicker(symbol) { /* ... */ }
  async createOrder(symbol, type, side, amount, price) { /* ... */ }
  // ... implement all supported methods
}

Tests

npm test
▶ Module Exports (4 tests)
▶ Binance Constructor (7 tests)
▶ BaseExchange (1 test)
▶ Binance Authentication (5 tests)
▶ Binance Parsers (8 tests)
▶ Binance Error Mapping (9 tests)
▶ Binance Rate Limit Header Handling (2 tests)
▶ Binance API Methods — mocked (16 tests)
▶ Utility Functions (18 tests)
▶ Crypto Utilities (4 tests)
▶ Throttler (5 tests)
▶ Error Classes (4 tests)
▶ Binance market() lookup (3 tests)
▶ Module Exports — Bybit (3 tests)
▶ Bybit Constructor (10 tests)
▶ Bybit Authentication (6 tests)
▶ Bybit Response Unwrapping (4 tests)
▶ Bybit Parsers (10 tests)
▶ Bybit Helper Methods (3 tests)
▶ Bybit Error Mapping (13 tests)
▶ Bybit HTTP Error Handling (5 tests)
▶ Bybit Rate Limit Header Handling (3 tests)
▶ Bybit API Methods — mocked (20 tests)
▶ Bybit market() lookup (3 tests)
▶ Bybit vs Binance Differences (5 tests)
▶ Module Exports — OKX (3 tests)
▶ OKX Constructor (12 tests)
▶ OKX Authentication (9 tests)
▶ OKX Response Unwrapping (4 tests)
▶ OKX Parsers (9 tests)
▶ OKX Helper Methods (4 tests)
▶ OKX Error Mapping (12 tests)
▶ OKX HTTP Error Handling (5 tests)
▶ OKX Rate Limit Header Handling (3 tests)
▶ OKX API Methods — mocked (18 tests)
▶ OKX market() lookup (3 tests)
▶ OKX vs Binance/Bybit Differences (7 tests)
▶ Crypto — hmacSHA256Base64 (2 tests)
▶ Module Exports — Kraken (3 tests)
▶ Kraken Constructor (10 tests)
▶ Kraken Authentication (8 tests)
▶ Kraken Response Unwrapping (4 tests)
▶ Kraken Parsers (10 tests)
▶ Kraken Helper Methods (4 tests)
▶ Kraken Error Mapping (12 tests)
▶ Kraken HTTP Error Handling (5 tests)
▶ Kraken Rate Limit Headers (3 tests)
▶ Kraken Mocked API Calls (20 tests)
▶ Kraken Market Lookup (3 tests)
▶ Kraken vs Other Exchanges (7 tests)
▶ Crypto — krakenSign (3 tests)
▶ Module Exports — Gate.io (3 tests)
▶ Gateio Constructor (10 tests)
▶ Gate.io Authentication (8 tests)
▶ Gate.io Response Handling (4 tests)
▶ Gate.io Parsers (9 tests)
▶ Gate.io Helper Methods (4 tests)
▶ Gate.io Error Mapping (10 tests)
▶ Gate.io HTTP Error Handling (5 tests)
▶ Gate.io Rate Limit Headers (3 tests)
▶ Gate.io Mocked API Calls (17 tests)
▶ Gate.io Market Lookup (3 tests)
▶ Gate.io vs Others Differences (5 tests)
▶ Crypto — sha512 & hmacSHA512Hex (3 tests)
▶ Module Exports — KuCoin (3 tests)
▶ KuCoin Constructor (10 tests)
▶ KuCoin Authentication (8 tests)
▶ KuCoin Response Handling (4 tests)
▶ KuCoin Parsers (10 tests)
▶ KuCoin Helper Methods (4 tests)
▶ KuCoin Error Mapping (10 tests)
▶ KuCoin HTTP Error Handling (5 tests)
▶ KuCoin Rate Limit Handling (3 tests)
▶ KuCoin Mocked API Calls (18 tests)
▶ KuCoin Market Lookup (3 tests)
▶ KuCoin vs Others Differences (6 tests)
▶ Crypto — hmacSHA256Base64 for KuCoin (3 tests)
▶ Module Exports — Coinbase (3 tests)
▶ Coinbase Constructor (10 tests)
▶ Coinbase Authentication — JWT/ES256 (10 tests)
▶ Coinbase Response Handling (4 tests)
▶ Coinbase Parsers (10 tests)
▶ Coinbase Helper Methods (8 tests)
▶ Coinbase Error Mapping (10 tests)
▶ Coinbase HTTP Error Handling (5 tests)
▶ Coinbase Rate Limit Handling (3 tests)
▶ Coinbase Mocked API Calls (16 tests)
▶ Coinbase Market Lookup (3 tests)
▶ Coinbase vs Others Differences (8 tests)
▶ Crypto — signJWT + base64UrlEncode (3 tests)
▶ Module Exports — Bitfinex (3 tests)
▶ Bitfinex Constructor (10 tests)
▶ Bitfinex Authentication — HMAC-SHA384 (10 tests)
▶ Bitfinex Response Handling (5 tests)
▶ Bitfinex Parsers (12 tests)
▶ Bitfinex Helper Methods (13 tests)
▶ Bitfinex Error Mapping (10 tests)
▶ Bitfinex HTTP Error Handling (6 tests)
▶ Bitfinex Rate Limit Handling (3 tests)
▶ Bitfinex Mocked API Calls (16 tests)
▶ Bitfinex Market Lookup (3 tests)
▶ Bitfinex vs Other Exchanges (8 tests)
▶ Crypto — hmacSHA