Binance TypeScript SDK example: rest-spot-exchange-info.ts

Binance REST Spot REST spot exchange info example for the Siebly Binance SDK, with TypeScript source for exchange REST API and WebSocket integration, setup, and production SDK docs.

What This Example Covers

  • Binance REST API example in TypeScript.
  • Uses the Siebly Binance SDK package binance instead of hand-written HTTP request plumbing.
  • Source path: Binance/Rest/Spot/rest-spot-exchange-info.ts.
  • Example category: REST Spot.
  • Imports SDK symbols including MainClient.
  • Calls SDK methods such as getExchangeInfo(), submitNewOrder().

How To Use This Example

  • Start here for the specific request or stream pattern, then check the matching SDK guide for install, credentials, and operational notes.
  • Open the repository source when you need the latest committed version: GitHub source file.

Example Path

Binance/Rest/Spot/rest-spot-exchange-info.ts

Source Link

Repository source: https://github.com/sieblyio/crypto-api-examples/blob/master/examples/Binance/Rest/Spot/rest-spot-exchange-info.ts

Related SDK Docs

Example Source

import {
  ExchangeInfo,
  MainClient,
  numberInString,
  roundToStepSize,
  roundToTickSize,
} from 'binance';

const client = new MainClient({
  // Optional (default: false) - when true, response strings are parsed to floats (only for known keys).
  // beautifyResponses: true,
});

interface SymbolInfo {
  tickSize?: numberInString;
  qtyStepSize?: numberInString;
  minOrderQty?: numberInString;
  maxOrderQty?: numberInString;
  maxMarketQty?: numberInString;
  maxNumOfOrders?: number;
  minNotional?: numberInString;
  maxNotional?: numberInString;
  maxBasePrecisionDecimals: number;
  maxQuotePrecisionDecimals: number;
}

// Get full exchange info so we can cache it and use it for other functions without making request every time
async function fetchExchangeInfo() {
  try {
    const exchangeInfo = await client.getExchangeInfo();
    return exchangeInfo;
  } catch (error) {
    throw new Error(
      `Failed to get exchange info: ${error instanceof Error ? error.message : String(error)}`,
    );
  }
}

const symbol = 'SOLUSDT';

async function getSymbolInfo(
  exchangeInfo: ExchangeInfo,
  symbol: string,
): Promise<SymbolInfo> {
  try {
    // Find the symbol information once
    const symbolInfo = exchangeInfo.symbols.find((s) => s.symbol === symbol);
    // console.log(symbolInfo);

    if (!symbolInfo) {
      throw new Error(`Symbol ${symbol} not found in exchange info`);
    }

    // Extract filters from the symbol info
    const priceFilter = symbolInfo.filters.find(
      (f) => f.filterType === 'PRICE_FILTER',
    );
    const lotSizeFilter = symbolInfo.filters.find(
      (f) => f.filterType === 'LOT_SIZE',
    );
    const marketLotSizeFilter = symbolInfo.filters.find(
      (f) => f.filterType === 'MARKET_LOT_SIZE',
    );
    const maxNumOrdersFilter = symbolInfo.filters.find(
      (f) => f.filterType === 'MAX_NUM_ORDERS',
    );
    const notionalFilter = symbolInfo.filters.find(
      (f) => f.filterType === 'NOTIONAL',
    );

    const symbolFilters = {
      tickSize: priceFilter?.tickSize,
      qtyStepSize: lotSizeFilter?.stepSize,
      minOrderQty: lotSizeFilter?.minQty,
      maxOrderQty: lotSizeFilter?.maxQty,
      maxMarketQty: marketLotSizeFilter?.maxQty,
      maxNumOfOrders: maxNumOrdersFilter?.maxNumOrders,
      minNotional: notionalFilter?.minNotional,
      maxNotional: notionalFilter?.maxNotional,
      maxBasePrecisionDecimals: symbolInfo.baseAssetPrecision,
      maxQuotePrecisionDecimals: symbolInfo.quoteAssetPrecision,
    };
    console.log(symbolFilters);

    return symbolFilters;
  } catch (error) {
    throw new Error(
      `Failed to get symbol info: ${error instanceof Error ? error.message : String(error)}`,
    );
  }
}

/**
 * Validates and formats an order based on symbol constraints
 */
function formatOrderParams(
  symbol: string,
  price: number,
  quantity: number,
  symbolInfo: any,
): { symbol: string; price: number; quantity: number } {
  try {
    // Check if price is within allowed range
    const minPrice = parseFloat(symbolInfo.tickSize || '0');
    if (price < minPrice) {
      throw new Error(`Price ${price} is below minimum ${minPrice}`);
    }

    // Check if quantity is within allowed range
    const minQty = parseFloat(symbolInfo.minOrderQty || '0');
    const maxQty = parseFloat(symbolInfo.maxOrderQty || Infinity);

    if (quantity < minQty) {
      throw new Error(`Quantity ${quantity} is below minimum ${minQty}`);
    }

    if (quantity > maxQty) {
      throw new Error(`Quantity ${quantity} exceeds maximum ${maxQty}`);
    }

    // Check notional value (price * quantity)
    const notional = price * quantity;
    const minNotional = parseFloat(symbolInfo.minNotional || '0');

    if (notional < minNotional) {
      throw new Error(
        `Order value ${notional} is below minimum ${minNotional}`,
      );
    }

    // Format price and quantity according to exchange requirements
    if (!symbolInfo.tickSize || !symbolInfo.qtyStepSize) {
      throw new Error('Missing required symbol info: tickSize or qtyStepSize');
    }
    const formattedPrice = roundToTickSize(price, symbolInfo.tickSize);
    const formattedQty = roundToStepSize(quantity, symbolInfo.qtyStepSize);

    return {
      symbol,
      price: formattedPrice,
      quantity: formattedQty,
    };
  } catch (error) {
    throw new Error(
      `Failed to format order: ${error instanceof Error ? error.message : String(error)}`,
    );
  }
}

// Example usage
async function testSymbolUtils() {
  const exchangeInfo = await fetchExchangeInfo();
  if (!exchangeInfo) return;

  const symbolFilters = await getSymbolInfo(exchangeInfo, symbol);
  if (!symbolFilters) return;

  // Test price formatting
  if (!symbolFilters.tickSize) {
    console.log('tickSize not available for this symbol');
    return;
  }
  const testPrice = 23.45678;
  console.log(
    `Original price: ${testPrice}`,
    `Formatted price: ${roundToTickSize(testPrice, symbolFilters.tickSize.toString())}`,
  );

  // Test quantity formatting
  if (!symbolFilters.qtyStepSize) {
    console.log('qtyStepSize not available for this symbol');
    return;
  }
  const testQty = 1.23456;
  console.log(
    `Original quantity: ${testQty}`,
    `Formatted quantity: ${roundToStepSize(
      testQty,
      symbolFilters.qtyStepSize.toString(),
    )}`,
  );

  // Test full order formatting
  const orderParams = formatOrderParams(
    symbol,
    testPrice,
    testQty,
    symbolFilters,
  );
  console.log('Formatted order parameters:', orderParams);

  // example how to use the order params
  const order = await client.submitNewOrder({
    symbol: orderParams.symbol,
    side: 'BUY',
    type: 'LIMIT',
    quantity: Number(orderParams.quantity),
    price: Number(orderParams.price),
    timeInForce: 'GTC',
  });

  console.log(order);
}

testSymbolUtils();