UNPKG

gateio-api

Version:

Complete & Robust Node.js SDK for Gate.com's REST APIs, WebSockets & WebSocket APIs, with TypeScript declarations.

1,460 lines (1,424 loc) 337 kB
This file is a merged representation of a subset of the codebase, containing files not matching ignore patterns, combined into a single document by Repomix. The content has been processed where content has been compressed (code blocks are separated by ⋮---- delimiter). ================================================================ File Summary ================================================================ Purpose: -------- This file contains a packed representation of a subset of the repository's contents that is considered the most important context. It is designed to be easily consumable by AI systems for analysis, code review, or other automated processes. File Format: ------------ The content is organized as follows: 1. This summary section 2. Repository information 3. Directory structure 4. Repository files (if enabled) 5. Multiple file entries, each consisting of: a. A separator line (================) b. The file path (File: path/to/file) c. Another separator line d. The full contents of the file e. A blank line Usage Guidelines: ----------------- - This file should be treated as read-only. Any changes should be made to the original repository files, not this packed version. - When processing this file, use the file path to distinguish between different files in the repository. - Be aware that this file may contain sensitive information. Handle it with the same level of security as you would the original repository. Notes: ------ - Some files may have been excluded based on .gitignore rules and Repomix's configuration - Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files - Files matching these patterns are excluded: .github/, examples/apidoc/, docs/images/, docs/endpointFunctionList.md, test/, src/util/ - Files matching patterns in .gitignore are excluded - Files matching default ignore patterns are excluded - Content has been compressed - code blocks are separated by ⋮---- delimiter - Files are sorted by Git change count (files with more changes are at the bottom) ================================================================ Directory Structure ================================================================ examples/ futures/ getBalances.ts getOrders.ts getTickers.ts submitLimitOrder.ts submitMarketOrder.ts testnet.ts spot/ getBalances.ts getCandles.ts getOrders.ts getTickers.ts submitLimitOrder.ts submitMarketOrder.ts futures-balance-trade.ts README.md ws-api-client.ts ws-private-perp-futures-wsapi.ts ws-private-perp-futures.ts ws-private-spot-wsapi.ts ws-private-spot.ts ws-public.ts src/ lib/ websocket/ websocket-util.ts WsStore.ts WsStore.types.ts BaseRestClient.ts BaseWSClient.ts logger.ts misc-util.ts requestUtils.ts webCryptoAPI.ts types/ request/ account.ts collateralLoan.ts delivery.ts earn.ts earnuni.ts flashswap.ts futures.ts margin.ts marginuni.ts multicollateralLoan.ts options.ts rebate.ts spot.ts subaccount.ts unified.ts wallet.ts withdrawal.ts response/ account.ts collateralloan.ts delivery.ts earn.ts earnuni.ts flashswap.ts futures.ts margin.ts marginuni.ts multicollateralLoan.ts options.ts rebate.ts spot.ts subaccount.ts unified.ts wallet.ts withdrawal.ts websockets/ client.ts events.ts requests.ts wsAPI.ts shared.ts index.ts RestClient.ts WebsocketAPIClient.ts WebsocketClient.ts .eslintrc.cjs .gitignore .nvmrc .prettierrc jest.config.ts LICENSE.md package.json postBuild.sh README.md tea.yaml tsconfig.cjs.json tsconfig.esm.json tsconfig.json tsconfig.linting.json ================================================================ Files ================================================================ ================ File: examples/futures/getBalances.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function getFuturesBalances() ⋮---- // Fetch the futures account balance for USDT settlement ⋮---- console.log('Response: ', result); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to get futures balances ================ File: examples/futures/getOrders.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key or use environment variables secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret or use environment variables ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function getFuturesOrders() ⋮---- // Fetch open futures orders with USDT settlement ⋮---- settle: 'usdt', // Specify the settlement currency status: 'open', // Specify the status of the orders to fetch ⋮---- console.log('openOrders: ', openOrders); // Log the response to the console ⋮---- // Fetch finished futures orders with USDT settlement ⋮---- settle: 'usdt', // Specify the settlement currency status: 'finished', // Specify the status of the orders to fetch ⋮---- console.log('finishedOrders: ', finishedOrders); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to get futures orders ================ File: examples/futures/getTickers.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function getFuturesTicker() ⋮---- // Fetch all futures tickers with USDT settlement ⋮---- settle: 'usdt', // Specify the settlement currency ⋮---- console.log('allTickers: ', allTickers); // Log the response to the console ⋮---- // Fetch a specific futures ticker with USDT settlement ⋮---- settle: 'usdt', // Specify the settlement currency contract: 'BTC_USDT', // Specify the contract ⋮---- console.log('ticker: ', ticker); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to get futures tickers ================ File: examples/futures/submitLimitOrder.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function submitFuturesOrder() ⋮---- // Submit a limit order for futures trading ⋮---- settle: 'usdt', // Specify the settlement currency contract: 'BTC_USDT', // Specify the contract size: 10, // Order size: positive for long, negative for short price: '45000', // Limit price for the order tif: 'gtc', // Time in force: 'gtc' (Good Till Cancelled) ⋮---- console.log('Response: ', result); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to submit a futures order ================ File: examples/futures/submitMarketOrder.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function submitFuturesOrder() ⋮---- // Submit a market order for futures trading ⋮---- settle: 'usdt', // Specify the settlement currency contract: 'BTC_USDT', // Specify the contract size: 20, // Order size: positive for long, negative for short price: '0', // Market order, so price is set to '0' tif: 'ioc', // Time in force: 'ioc' (Immediate Or Cancel) ⋮---- console.log('Response: ', result); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to submit a futures order ================ File: examples/futures/testnet.ts ================ import { RestClient } from '../../src/index.js'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- /** * To use a different base URL, use the baseUrl key. The SDK uses the live environment by default: * baseUrlKey: 'live', *'https://api.gateio.ws/api/v4' * But you can force it to use any of the available environments. Examples below. */ ⋮---- /* * Futures TestNet trading: * 'https://fx-api-testnet.gateio.ws/api/v4' */ ⋮---- /** * Futures live trading alternative (futures only): * 'https://fx-api.gateio.ws/api/v4' */ // baseUrlKey: 'futuresLiveAlternative' ⋮---- async function submitFuturesOrder() ⋮---- // Submit a market order for futures trading ⋮---- settle: 'usdt', // Specify the settlement currency contract: 'BTC_USDT', // Specify the contract size: 20, // Order size: positive for long, negative for short price: '0', // Market order, so price is set to '0' tif: 'ioc', // Time in force: 'ioc' (Immediate Or Cancel) ⋮---- console.log('Response: ', result); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to submit a futures order ================ File: examples/spot/getBalances.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function getSpotBalances() ⋮---- // Fetch the spot account balances ⋮---- console.log('Response: ', balances); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to get spot balances ================ File: examples/spot/getCandles.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function getSpotCandles() ⋮---- // Fetch the spot account balances ⋮---- console.log('Response: ', balances); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to get spot balances ================ File: examples/spot/getOrders.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function getSpotOrders() ⋮---- // Fetch open spot orders for the BTC_USDT currency pair ⋮---- currency_pair: 'BTC_USDT', // Specify the currency pair status: 'open', // Specify the status of the orders to fetch ⋮---- console.log('openOrders: ', openOrders); // Log the response to the console ⋮---- // Fetch finished spot orders for the BTC_USDT currency pair ⋮---- currency_pair: 'BTC_USDT', // Specify the currency pair status: 'finished', // Specify the status of the orders to fetch ⋮---- console.log('finishedOrders: ', finishedOrders); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to get spot orders ================ File: examples/spot/getTickers.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function getSpotTicker() ⋮---- // Fetch the ticker for a specific currency pair (BTC_USDT) ⋮---- currency_pair: 'BTC_USDT', // Specify the currency pair ⋮---- console.log('Response: ', ticker); // Log the response to the console ⋮---- // Fetch all tickers ⋮---- console.log('Response: ', allTickers); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to get spot tickers ================ File: examples/spot/submitLimitOrder.ts ================ import { RestClient } from '../../src'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function submitSpotOrder() ⋮---- // Submit a limit order for spot trading ⋮---- currency_pair: 'BTC_USDT', // Specify the currency pair side: 'buy', // Specify the order side: 'buy' or 'sell' type: 'limit', // Specify the order type: 'limit' amount: '0.001', // Specify the amount to buy price: '45000', // Specify the limit price time_in_force: 'gtc', // Time in force: 'gtc' (Good Till Cancelled) ⋮---- console.log('Response: ', result); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to submit a spot order ================ File: examples/spot/submitMarketOrder.ts ================ import { RestClient } from '../../src/index.js'; // For an easy demonstration, import from the src dir. Normally though, see below to import from the npm installed version instead. // import { RestClient } from 'gateio-api'; // Import the RestClient from the published version of this SDK, installed via NPM (npm install gateio-api) ⋮---- // Define the account object with API key and secret ⋮---- key: process.env.API_KEY || 'yourApiHere', // Replace 'yourApiHere' with your actual API key secret: process.env.API_SECRET || 'yourSecretHere', // Replace 'yourSecretHere' with your actual API secret ⋮---- // Initialize the RestClient with the API credentials ⋮---- async function submitSpotOrder() ⋮---- // Submit a market order for spot trading ⋮---- currency_pair: 'BTC_USDT', // Specify the currency pair side: 'buy', // Specify the order side: 'buy' or 'sell' type: 'market', // Specify the order type: 'market' amount: '10', // Specify the amount to buy time_in_force: 'ioc', // Time in force: 'ioc' (Immediate Or Cancel) ⋮---- console.log('Response: ', result); // Log the response to the console ⋮---- console.error(`Error in execution: `, e); // Log any errors that occur ⋮---- // Execute the function to submit a spot order ================ File: examples/futures-balance-trade.ts ================ /** * This example demonstrates a simple commented workflow of: * - initialising the RestClient and WebsocketClient for Gate.io exchange * - connecting to an account’s private websockets (to receive updates asynchronously) * - checking if connection is successful * - fetching available futures balance * - placing an order using 50% of the available balance **/ ⋮---- // Import the RestClient and WebsocketClient from the published version of this SDK, installed via NPM (npm install gateio-api) import { RestClient, WebsocketClient } from 'gateio-api'; ⋮---- // Define the account object with API key and secret ⋮---- // Replace 'yourApiHere' with your actual API key or use environment variables ⋮---- // Replace 'yourSecretHere' with your actual API secret or use environment variables ⋮---- // Initialize the RestClient with the API credentials ⋮---- // initialise websocket client - if you want only public data, you can initialise the client without the apiKey and apiSecret, just WebsocketClient() ⋮---- // Data received ⋮---- async function subscribePrivateWs() ⋮---- // Enter your user ID here ⋮---- //sub to balances updates ⋮---- //sub to trades updates ⋮---- /** * Either send one topic (with params) at a time */ // client.subscribe({ // topic: 'futures.usertrades', // payload: [myUserID, '!all'], // }, 'perpFuturesUSDTV4'); ⋮---- /** * Or send multiple topics in a batch (grouped by ws connection (WsKey)) * You can also use strings for topics that don't have any parameters, even if you mix multiple requests into one function call: */ ⋮---- async function main() ⋮---- // Get futures account balance via REST ⋮---- // total usdt balance ⋮---- // available usdt balance ⋮---- // submit market order with 50% of the balance ⋮---- // Submit a market order with 50% of the balance ⋮---- settle: 'usdt', // Specify the settlement currency contract: 'BTC_USDT', // Specify the contract size: orderAmount, // Order size: positive for long, negative for short, in USDT price: '0', // Market order, so price is set to '0' tif: 'ioc', // Time in force: 'ioc' (Immediate Or Cancel) ⋮---- // for more detailed ws connection, you can use a lot more listeners like below: ⋮---- // Something happened, attempting to reconnect ⋮---- // Reconnect successful ⋮---- // Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- // Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" ================ File: examples/README.md ================ # Examples These samples can be executed using `ts-node` or `tsx`: ``` ts-node ./examples/ws-public.ts ``` Most examples also have minimal typescript, so if you rename them to "js" they should execute fine with just node. TypeScript is recommended but completely optional: ``` node ./examples/spot/getTickers.js ``` ================ File: examples/ws-api-client.ts ================ import { WebsocketAPIClient, WS_KEY_MAP } from '../src/index.js'; // import { LogParams, WebsocketClient } from 'gateio-api'; // normally you should install this module via npm: `npm install gateio-api` ⋮---- async function start() ⋮---- /** * Optional: authenticate in advance. This will prepare and authenticate a connection. * Useful to save time for the first request but completely optional. It will also happen automatically when you make your first request. */ // console.log(new Date(), 'Authenticating in advance...'); // await client.getWSClient().connectWSAPI('spotV4'); // console.log(new Date(), 'Authenticating in advance...OK!'); ⋮---- /* ============ SPOT TRADING EXAMPLES ============ */ ⋮---- // SPOT ORDER PLACE - Submit a new spot order ⋮---- // SPOT ORDER CANCEL - Cancel a specific spot order ⋮---- // SPOT ORDER CANCEL BY IDS - Cancel orders by ID list ⋮---- // SPOT ORDER CANCEL BY CURRENCY PAIR - Cancel all orders for a currency pair ⋮---- // SPOT ORDER AMEND - Update an existing spot order ⋮---- // SPOT ORDER STATUS - Get status of a specific spot order ⋮---- // SPOT ORDER LIST - Get list of spot orders ⋮---- /* ============ FUTURES TRADING EXAMPLES ============ */ ⋮---- /** * Gate has different websocket groups depending on the futures product. * * This affects which connection your command is sent to, so make sure to pass one matching your request. Look at WS_KEY_MAP (or the examples below) for details on the available product groups. */ ⋮---- /** * Also optional, as for spot. Keep in mind the first parameter (wsKey) might vary depending on which WS URL is needed. */ ⋮---- // console.log(new Date(), 'Authenticating in advance...'); // await client.getWSClient().connectWSAPI(futuresConnectionGroup); // await client.getWSClient().connectWSAPI('perpFuturesUSDTV4'); // await client.getWSClient().connectWSAPI('perpFuturesBTCV4'); // await client.getWSClient().connectWSAPI('deliveryFuturesUSDTV4'); // await client.getWSClient().connectWSAPI('perpFuturesBTCV4'); // console.log(new Date(), 'Authenticating in advance...OK!'); ⋮---- // FUTURES ORDER PLACE - Submit a new futures order ⋮---- // FUTURES ORDER BATCH PLACE - Submit multiple futures orders ⋮---- // FUTURES ORDER CANCEL - Cancel a specific futures order ⋮---- // FUTURES ORDER CANCEL BY IDS - Cancel futures orders by ID list ⋮---- // FUTURES ORDER CANCEL ALL - Cancel all open futures orders ⋮---- // FUTURES ORDER AMEND - Update an existing futures order ⋮---- // FUTURES ORDER LIST - Get list of futures orders ⋮---- // FUTURES ORDER STATUS - Get status of a specific futures order ================ File: examples/ws-private-perp-futures-wsapi.ts ================ /* eslint-disable @typescript-eslint/no-unused-vars */ ⋮---- import { LogParams, WebsocketClient } from '../src/index.js'; // import { LogParams, WebsocketClient } from 'gateio-api'; // normally you should install this module via npm: `npm install gateio-api` ⋮---- // Define a custom logger object to handle logging at different levels ⋮---- // Trace level logging: used for detailed debugging information ⋮---- // Uncomment the line below to enable trace logging // console.log(new Date(), 'trace', ...params); ⋮---- // Info level logging: used for general informational messages ⋮---- // Error level logging: used for error messages ⋮---- async function start() ⋮---- // See comments below about event-driven vs promise-driven. Not needed if using the promise-driven approach // client.on('update', (data) => { // // console.info(new Date(), 'ws data received: ', JSON.stringify(data)); // console.info(new Date(), 'ws data received: ', JSON.stringify(data, null, 2)); // }); ⋮---- // Something happened, attempting to reconnect ⋮---- // Reconnect successful ⋮---- // Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- // Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" // See comments below about event-driven vs promise-driven. Not needed if using the promise-driven approach // client.on('response', (data) => { // console.info( // new Date(), // 'ws server reply ', // JSON.stringify(data, null, 2), // '\n', // ); // }); ⋮---- // Optional, listen to this event if you prefer the event-driven approach. // See below comments on event-driven vs promise-driven. // client.on('authenticated', (data) => { // console.error(new Date(), 'ws authenticated: ', data); // }); ⋮---- /** * All WebSocket API (WS API) messaging should be done via the sendWSAPIRequest method. * * You have two ways to handle responses on the WS API. You can either: * - event-driven: process async `response` and `update` events from the websocket client, OR * - promise-driven: await every call to `client.sendWSAPIRequest`, this can behave similar to using a REST API (successful responses resolve, exceptions reject). */ ⋮---- /** * To authenticate, send an empty request to "futures.login". The SDK will handle all the parameters. * * Optional - you can inject rich types to set the response type * const loginResult = await client.sendWSAPIRequest<WSAPIResponse<WSAPILoginResponse>>('perpFuturesUSDTV4', 'futures.login'); */ ⋮---- /** * For other channels, the 3rd parameter should have any parameters for the request (the payload). * * Note that internal parameters such as "signature" etc are all handled automatically by the SDK. * */ ⋮---- /** * Submit futures order */ ⋮---- size: 20, // positive for long, negative for short ⋮---- /** * Submit batch futures order */ ⋮---- size: 10, // positive for long, negative for short ⋮---- size: 10, // positive for long, negative for short ⋮---- /** * Cancel futures order */ ⋮---- /** * Cancel all futures orders */ ⋮---- /** * Update/Amend Futures order */ ⋮---- /** * Get orders list */ ⋮---- /** * Get order status */ ================ File: examples/ws-private-perp-futures.ts ================ /* eslint-disable @typescript-eslint/no-unused-vars */ import { LogParams, WebsocketClient, WsTopicRequest } from '../src/index.js'; // import { LogParams, WebsocketClient, WsTopicRequest } from 'gateio-api'; // normally you should install this module via npm: `npm install gateio-api` ⋮---- // Define a custom logger object to handle logging at different levels ⋮---- // Trace level logging: used for detailed debugging information ⋮---- // Uncomment the line below to enable trace logging // console.log(new Date(), 'trace', ...params); ⋮---- // Info level logging: used for general informational messages ⋮---- // Error level logging: used for error messages ⋮---- async function start() ⋮---- // console.log('auth with: ', account); ⋮---- // Data received ⋮---- // Something happened, attempting to reconnect ⋮---- // Reconnect successful ⋮---- // Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- // Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" ⋮---- // TODO: many private topics use your user ID ⋮---- /** * Either send one topic (with params) at a time */ // client.subscribe({ // topic: 'futures.usertrades', // payload: [myUserID, '!all'], // }, 'perpFuturesUSDTV4'); ⋮---- /** * Or send multiple topics in a batch (grouped by ws connection (WsKey)) * You can also use strings for topics that don't have any parameters, even if you mix multiple requests into one function call: */ ================ File: examples/ws-private-spot-wsapi.ts ================ /* eslint-disable @typescript-eslint/no-unused-vars */ ⋮---- import { LogParams, WebsocketClient } from '../src/index.js'; // import { LogParams, WebsocketClient } from 'gateio-api'; // normally you should install this module via npm: `npm install gateio-api` ⋮---- // eslint-disable-next-line @typescript-eslint/no-unused-vars ⋮---- // Define a custom logger object to handle logging at different levels ⋮---- // Trace level logging: used for detailed debugging information ⋮---- // Uncomment the line below to enable trace logging // console.log(new Date(), 'trace', ...params); ⋮---- // Info level logging: used for general informational messages ⋮---- // Error level logging: used for error messages ⋮---- async function start() ⋮---- // See comments below about event-driven vs promise-driven. Not needed if using the promise-driven approach // client.on('update', (data) => { // // console.info(new Date(), 'ws data received: ', JSON.stringify(data)); // console.info(new Date(), 'ws data received: ', JSON.stringify(data, null, 2)); // }); ⋮---- // Something happened, attempting to reconnect ⋮---- // Reconnect successful ⋮---- // Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- // Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" // See comments below about event-driven vs promise-driven. Not needed if using the promise-driven approach // client.on('response', (data) => { // console.info( // new Date(), // 'ws server reply ', // JSON.stringify(data, null, 2), // '\n', // ); // }); ⋮---- // Optional, listen to this event if you prefer the event-driven approach. // See below comments on event-driven vs promise-driven. // client.on('authenticated', (data) => { // console.error(new Date(), 'ws authenticated: ', data); // }); ⋮---- /** * All WebSocket API (WS API) messaging should be done via the sendWSAPIRequest method. * * You have two ways to handle responses on the WS API. You can either: * - event-driven: process async `response` and `update` events from the websocket client, OR * - promise-driven: await every call to `client.sendWSAPIRequest`, this can behave similar to using a REST API (successful responses resolve, exceptions reject). */ ⋮---- /** * No need to authenticate first - the SDK will automatically authenticate for you when you send your first request. * * Unless you want to prepare the connection before your first request, to speed up your first request. */ ⋮---- /** * For other channels, the 3rd parameter should have any parameters for the request (the payload that goes in req_param in the docs). * * See WsAPIRequestsTopicMap for a topic->parameter map. * * Note that internal parameters such as "signature" etc are all handled automatically by the SDK. */ ⋮---- /** * Submit spot order */ ⋮---- /** * Cancel spot order */ ⋮---- /** * Batch cancel spot order */ ⋮---- /** * Amend/Update spot order */ ⋮---- /** * Get spot order status */ ⋮---- /** * If you don't want to use await (and prefer the async event emitter), make sure to still include a catch block. * * The response will come async via the event emitter in the WS Client. */ ⋮---- // client // .sendWSAPIRequest('spotV4', 'spot.order_status', { // order_id: '600995435390', // currency_pair: 'BTC_USDT', // }) // .catch((e) => { // console.error(`exception ws api call, get spot order status: `, e); // }); ================ File: examples/ws-private-spot.ts ================ /* eslint-disable @typescript-eslint/no-unused-vars */ import { LogParams, WebsocketClient, WsTopicRequest } from '../src/index.js'; // import { LogParams, WebsocketClient, WsTopicRequest } from 'gateio-api'; // normally you should install this module via npm: `npm install gateio-api` ⋮---- // eslint-disable-next-line @typescript-eslint/no-unused-vars ⋮---- // Define a custom logger object to handle logging at different levels ⋮---- // Trace level logging: used for detailed debugging information ⋮---- // Uncomment the line below to enable trace logging // console.log(new Date(), 'trace', ...params); ⋮---- // Info level logging: used for general informational messages ⋮---- // Error level logging: used for error messages ⋮---- async function start() ⋮---- // console.log('auth with: ', account); ⋮---- // Data received ⋮---- // Something happened, attempting to reconnect ⋮---- // Reconnect successful ⋮---- // Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- // Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" ⋮---- // client.subscribe(topics, 'spotV4'); ⋮---- // This has the same effect as above, it's just a different way of messaging which topic this is for // const topicWithoutParamsAsObject: WsTopicRequest = { // topic: 'spot.balances', // }; ⋮---- /** * Either send one topic (with optional params) at a time */ // client.subscribe(topicWithoutParamsAsObject, 'spotV4'); ⋮---- /** * Or send multiple topics in a batch (grouped by ws connection (WsKey)) * You can also use strings for topics that don't have any parameters, even if you mix multiple requests into one function call: */ ⋮---- /** * You can also subscribe in separate function calls as you wish. * * Any duplicate requests should get filtered out (e.g. here we subscribed to "spot.balances" twice, but the WS client will filter this out) */ ================ File: examples/ws-public.ts ================ // eslint-disable-next-line @typescript-eslint/no-unused-vars import { WebsocketClient, WsTopicRequest } from '../src/index.js'; // import { LogParams, WebsocketClient, WsTopicRequest } from 'gateio-api'; // normally you should install this module via npm: `npm install gateio-api` ⋮---- // const customLogger = { // // eslint-disable-next-line @typescript-eslint/no-unused-vars // trace: (...params: LogParams): void => { // console.log('trace', ...params); // }, // info: (...params: LogParams): void => { // console.log('info', ...params); // }, // error: (...params: LogParams): void => { // console.error('error', ...params); // }, // }; ⋮---- async function start() ⋮---- // Optional, inject a custom logger // const client = new WebsocketClient({}, customLogger); ⋮---- // Data received ⋮---- // Something happened, attempting to reconnect ⋮---- // Reconnect successful ⋮---- // Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- // Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" ⋮---- // const topicWithoutParamsAsString = 'spot.balances'; ⋮---- // This has the same effect as above, it's just a different way of messaging which topic this is for // const topicWithoutParamsAsObject: WsTopicRequest = { // topic: 'spot.balances', // }; ⋮---- /** * Either send one topic (with optional params) at a time */ // client.subscribe(tickersRequestWithParams, 'spotV4'); ⋮---- /** * Or send multiple topics in a batch (grouped by ws connection (WsKey)) */ ⋮---- // /** // * You can also use strings for topics that don't have any parameters, even if you mix multiple requests into one function call: // */ // client.subscribe( // [tickersRequestWithParams, rawTradesRequestWithParams, topicWithoutParamsAsString], // 'spotV4', // ); ================ File: src/lib/websocket/websocket-util.ts ================ import WebSocket from 'isomorphic-ws'; ⋮---- import { WSAPIRequest } from '../../types/websockets/requests.js'; import { FuturesWSAPITopic, SpotWSAPITopic, } from '../../types/websockets/wsAPI.js'; ⋮---- /** * Should be one WS key per unique URL. Some URLs may need a suffix. */ ⋮---- /** * Spot & Margin * https://www.gate.io/docs/developers/apiv4/ws/en/ */ ⋮---- /** * Perpetual futures (USDT) * https://www.gate.io/docs/developers/futures/ws/en/#gate-io-futures-websocket-v4 */ ⋮---- /** * Perpetual futures (BTC) * https://www.gate.io/docs/developers/futures/ws/en/#gate-io-futures-websocket-v4 */ ⋮---- /** * Delivery Futures (USDT) * https://www.gate.io/docs/developers/delivery/ws/en/ */ ⋮---- /** * Delivery Futures (BTC) * https://www.gate.io/docs/developers/delivery/ws/en/ */ ⋮---- /** * Options * https://www.gate.io/docs/developers/options/ws/en/ */ ⋮---- /** * Announcements V4 * https://www.gate.io/docs/developers/options/ws/en/ */ ⋮---- /** This is used to differentiate between each of the available websocket streams */ export type WsKey = (typeof WS_KEY_MAP)[keyof typeof WS_KEY_MAP]; ⋮---- export type FuturesWsKey = | typeof WS_KEY_MAP.perpFuturesUSDTV4 | typeof WS_KEY_MAP.perpFuturesBTCV4 | typeof WS_KEY_MAP.deliveryFuturesUSDTV4 | typeof WS_KEY_MAP.deliveryFuturesBTCV4; ⋮---- export type WsMarket = 'all'; ⋮---- /** * Normalised internal format for a request (subscribe/unsubscribe/etc) on a topic, with optional parameters. * * - Topic: the topic this event is for * - Payload: the parameters to include, optional. E.g. auth requires key + sign. Some topics allow configurable parameters. */ export interface WsTopicRequest< TWSTopic extends string = string, TWSPayload = any, > { topic: TWSTopic; payload?: TWSPayload; } ⋮---- /** * Conveniently allow users to request a topic either as string topics or objects (containing string topic + params) */ export type WsTopicRequestOrStringTopic< TWSTopic extends string, TWSPayload = any, > = WsTopicRequest<TWSTopic, TWSPayload> | string; ⋮---- /** * Some exchanges have two livenet environments, some have test environments, some dont. This allows easy flexibility for different exchanges. * Examples: * - One livenet and one testnet: NetworkMap<'livenet' | 'testnet'> * - One livenet, sometimes two, one testnet: NetworkMap<'livenet' | 'testnet', 'livenet2'> * - Only one livenet, no other networks: NetworkMap<'livenet'> */ type NetworkMap< TRequiredKeys extends string, TOptionalKeys extends string | undefined = undefined, > = Record<TRequiredKeys, string> & (TOptionalKeys extends string ? Record<TOptionalKeys, string | undefined> : Record<TRequiredKeys, string>); ⋮---- export function neverGuard(x: never, msg: string): Error ⋮---- /** * WS API promises are stored using a primary key. This key is constructed using * properties found in every request & reply. */ export function getPromiseRefForWSAPIRequest( requestEvent: WSAPIRequest, ): string ⋮---- export function getPrivateSpotTopics(): string[] ⋮---- // Consumeable channels for spot ⋮---- // WebSocket API for spot ⋮---- export function getPrivateFuturesTopics(): string[] ⋮---- // These are the same for perps vs delivery futures ⋮---- export function getPrivateOptionsTopics(): string[] ⋮---- /** * ws.terminate() is undefined in browsers. * This only works in node.js, not in browsers. * Does nothing if `ws` is undefined. Does nothing in browsers. */ export function safeTerminateWs( ws?: WebSocket | any, fallbackToClose?: boolean, ): boolean ================ File: src/lib/websocket/WsStore.ts ================ import WebSocket from 'isomorphic-ws'; ⋮---- import { DefaultLogger } from '../logger.js'; import { DeferredPromise, WSConnectedResult, WsConnectionStateEnum, WsStoredState, } from './WsStore.types.js'; ⋮---- /** * Simple comparison of two objects, only checks 1-level deep (nested objects won't match) */ export function isDeepObjectMatch(object1: unknown, object2: unknown): boolean ⋮---- type DeferredPromiseRef = (typeof DEFERRED_PROMISE_REF)[keyof typeof DEFERRED_PROMISE_REF]; ⋮---- export class WsStore< WsKey extends string, ⋮---- constructor(logger: DefaultLogger) ⋮---- /** Get WS stored state for key, optionally create if missing */ get( key: WsKey, createIfMissing?: true, ): WsStoredState<TWSTopicSubscribeEventArgs>; ⋮---- get( key: WsKey, createIfMissing?: false, ): WsStoredState<TWSTopicSubscribeEventArgs> | undefined; ⋮---- get( key: WsKey, createIfMissing?: boolean, ): WsStoredState<TWSTopicSubscribeEventArgs> | undefined ⋮---- getKeys(): WsKey[] ⋮---- create(key: WsKey): WsStoredState<TWSTopicSubscribeEventArgs> | undefined ⋮---- delete(key: WsKey): void ⋮---- // TODO: should we allow this at all? Perhaps block this from happening... ⋮---- /* connection websocket */ ⋮---- hasExistingActiveConnection(key: WsKey): boolean ⋮---- getWs(key: WsKey): WebSocket | undefined ⋮---- setWs(key: WsKey, wsConnection: WebSocket): WebSocket ⋮---- /** * deferred promises */ ⋮---- getDeferredPromise<TSuccessResult = any>( wsKey: WsKey, promiseRef: string | DeferredPromiseRef, ): DeferredPromise<TSuccessResult> | undefined ⋮---- createDeferredPromise<TSuccessResult = any>( wsKey: WsKey, promiseRef: string | DeferredPromiseRef, throwIfExists: boolean, ): DeferredPromise<TSuccessResult> ⋮---- // console.log('existing promise'); ⋮---- // console.log('create promise'); ⋮---- // TODO: Once stable, use Promise.withResolvers in future ⋮---- resolveDeferredPromise( wsKey: WsKey, promiseRef: string | DeferredPromiseRef, value: unknown, removeAfter: boolean, ): void ⋮---- rejectDeferredPromise( wsKey: WsKey, promiseRef: string | DeferredPromiseRef, value: unknown, removeAfter: boolean, ): void ⋮---- removeDeferredPromise( wsKey: WsKey, promiseRef: string | DeferredPromiseRef, ): void ⋮---- // Just in case it's pending ⋮---- rejectAllDeferredPromises(wsKey: WsKey, reason: string): void ⋮---- // Skip reserved keys, such as the connection promise ⋮---- /** Get promise designed to track a connection attempt in progress. Resolves once connected. */ getConnectionInProgressPromise( wsKey: WsKey, ): DeferredPromise<WSConnectedResult> | undefined ⋮---- getAuthenticationInProgressPromise( wsKey: WsKey, ): DeferredPromise<WSConnectedResult & ⋮---- /** * Create a deferred promise designed to track a connection attempt in progress. * * Will throw if existing promise is found. */ createConnectionInProgressPromise( wsKey: WsKey, throwIfExists: boolean, ): DeferredPromise<WSConnectedResult> ⋮---- createAuthenticationInProgressPromise( wsKey: WsKey, throwIfExists: boolean, ): DeferredPromise<WSConnectedResult & ⋮---- /** Remove promise designed to track a connection attempt in progress */ removeConnectingInProgressPromise(wsKey: WsKey): void ⋮---- removeAuthenticationInProgressPromise(wsKey: WsKey): void ⋮---- /* connection state */ ⋮---- isWsOpen(key: WsKey): boolean ⋮---- getConnectionState(key: WsKey): WsConnectionStateEnum ⋮---- setConnectionState(key: WsKey, state: WsConnectionStateEnum) ⋮---- isConnectionState(key: WsKey, state: WsConnectionStateEnum): boolean ⋮---- /** * Check if we're currently in the process of opening a connection for any reason. Safer than only checking "CONNECTING" as the state * @param key * @returns */ isConnectionAttemptInProgress(key: WsKey): boolean ⋮---- const stateChangeTimeout = 15000; // allow a max 15 second timeout since the last state change before assuming stuck; ⋮---- /* subscribed topics */ ⋮---- getTopics(key: WsKey): Set<TWSTopicSubscribeEventArgs> ⋮---- getTopicsByKey(): Record<string, Set<TWSTopicSubscribeEventArgs>> ⋮---- /** * Find matching "topic" request from the store * @param key * @param topic * @returns */ getMatchingTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) ⋮---- addTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) ⋮---- // Check for duplicate topic. If already tracked, don't store this one ⋮---- deleteTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) ⋮---- // Check if we're subscribed to a topic like this ================ File: src/lib/websocket/WsStore.types.ts ================ /* eslint-disable @typescript-eslint/no-explicit-any */ import WebSocket from 'isomorphic-ws'; ⋮---- export enum WsConnectionStateEnum { INITIAL = 0, CONNECTING = 1, CONNECTED = 2, CLOSING = 3, RECONNECTING = 4, // ERROR_RECONNECTING = 5, ERROR = 5, } ⋮---- // ERROR_RECONNECTING = 5, ⋮---- export interface DeferredPromise<TSuccess = any, TError = any> { resolve?: (value: TSuccess) => TSuccess; reject?: (value: TError) => TError; promise?: Promise<TSuccess>; } ⋮---- export interface WSConnectedResult { wsKey: string; ws: WebSocket; } ⋮---- export interface WsStoredState<TWSTopicSubscribeEvent extends string | object> { /** The currently active websocket connection */ ws?: WebSocket; /** The current lifecycle state of the connection (enum) */ connectionState?: WsConnectionStateEnum; connectionStateChangedAt?: Date; /** A timer that will send an upstream heartbeat (ping) when it expires */ activePingTimer?: ReturnType<typeof setTimeout> | undefined; /** A timer tracking that an upstream heartbeat was sent, expecting a reply before it expires */ activePongTimer?: ReturnType<typeof setTimeout> | undefined; /** If a reconnection is in progress, this will have the timer for the delayed reconnect */ activeReconnectTimer?: ReturnType<typeof setTimeout> | undefined; /** * When a connection attempt is in progress (even for reconnect), a promise is stored here. * * This promise will resolve once connected (and will then get removed); */ // connectionInProgressPromise?: DeferredPromise | undefined; deferredPromiseStore: Record<string, DeferredPromise>; /** * All the topics we are expected to be subscribed to on this connection (and we automatically resubscribe to if the connection drops) * * A "Set" and a deep-object-match are used to ensure we only subscribe to a * topic once (tracking a list of unique topics we're expected to be connected to) */ subscribedTopics: Set<TWSTopicSubscribeEvent>; /** Whether this connection has completed authentication (only applies to private connections) */ isAuthenticated?: boolean; /** * Whether this connection has completed authentication before for the Websocket API, so it k * nows to automatically reauth if reconnected */ didAuthWSAPI?: boolean; /** To reauthenticate on the WS API, which channel do we send to? */ WSAPIAuthChannel?: string; } ⋮---- /** The currently active websocket connection */ ⋮---- /** The current lifecycle state of the connection (enum) */ ⋮---- /** A timer that will send an upstream heartbeat (ping) when it expires */ ⋮---- /** A timer tracking that an upstream heartbeat was sent, expecting a reply before it expires */ ⋮---- /** If a reconnection is in progress, this will have the timer for the delayed reconnect */ ⋮---- /** * When a connection attempt is in progress (even for reconnect), a promise is stored here. * * This promise will resolve once connected (and will then get removed); */ // connectionInProgressPromise?: DeferredPromise | undefined; ⋮---- /** * All the topics we are expected to be subscribed to on this connection (and we automatically resubscribe to if the connection drops) * * A "Set" and a deep-object-match are used to ensure we only subscribe to a * topic once (tracking a list of unique topics we're expected to be connected to) */ ⋮---- /** Whether this connection has completed authentication (only applies to private connections) */ ⋮---- /** * Whether this connection has completed authentication before for the Websocket API, so it k * nows to automatically reauth if reconnected */ ⋮---- /** To reauthenticate on the WS API, which channel do we send to? */ ================ File: src/lib/BaseRestClient.ts ================ import axios, { AxiosRequestConfig, AxiosResponse, Method } from 'axios'; import https from 'https'; ⋮---- import { neverG