binance-futures-wrapper
Version:
A comprehensive TypeScript wrapper for Binance USDT-M Futures API with full REST and WebSocket support
298 lines • 8.83 kB
JavaScript
;
/**
* Utility functions for Binance Futures API
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReconnectionManager = exports.RateLimiter = exports.Logger = void 0;
exports.createSignature = createSignature;
exports.getTimestamp = getTimestamp;
exports.objectToQueryString = objectToQueryString;
exports.addSignature = addSignature;
exports.getBaseUrls = getBaseUrls;
exports.validateConfig = validateConfig;
exports.generateClientOrderId = generateClientOrderId;
exports.formatNumber = formatNumber;
exports.sleep = sleep;
exports.retry = retry;
exports.convertKlineData = convertKlineData;
exports.convertKlinesData = convertKlinesData;
const crypto = __importStar(require("crypto"));
/**
* Create HMAC SHA256 signature for Binance API
*/
function createSignature(queryString, apiSecret) {
return crypto
.createHmac('sha256', apiSecret)
.update(queryString)
.digest('hex');
}
/**
* Get current timestamp in milliseconds
*/
function getTimestamp() {
return Date.now();
}
/**
* Convert object to query string
*/
function objectToQueryString(obj) {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(obj)) {
if (value !== undefined && value !== null) {
if (Array.isArray(value)) {
params.append(key, JSON.stringify(value));
}
else {
params.append(key, String(value));
}
}
}
return params.toString();
}
/**
* Add signature to parameters
*/
function addSignature(params, apiSecret, timestamp) {
const finalParams = {
...params,
timestamp: timestamp || getTimestamp()
};
const queryString = objectToQueryString(finalParams);
const signature = createSignature(queryString, apiSecret);
return {
...finalParams,
signature
};
}
/**
* Get base URLs based on testnet configuration
*/
function getBaseUrls(testnet = false) {
if (testnet) {
return {
rest: 'https://testnet.binancefuture.com',
ws: 'wss://stream.binancefuture.com'
};
}
return {
rest: 'https://fapi.binance.com',
ws: 'wss://fstream.binance.com'
};
}
/**
* Validate Binance configuration
*/
function validateConfig(config) {
// Allow empty API key/secret for public endpoints only
if (!config.apiKey && !config.apiSecret) {
// This is OK for public endpoints
return;
}
if (!config.apiKey) {
throw new Error('API key is required');
}
if (!config.apiSecret) {
throw new Error('API secret is required');
}
if (config.recvWindow && (config.recvWindow < 1000 || config.recvWindow > 60000)) {
throw new Error('recvWindow must be between 1000 and 60000 milliseconds');
}
}
/**
* Generate random string for client order ID
*/
function generateClientOrderId(prefix = 'x-') {
const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).substring(2, 8);
return `${prefix}${timestamp}${random}`;
}
/**
* Format number to string with proper precision
*/
function formatNumber(num, precision) {
if (precision !== undefined) {
return num.toFixed(precision);
}
return num.toString();
}
/**
* Sleep function for delays
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Retry function with exponential backoff
*/
async function retry(fn, maxRetries = 3, baseDelay = 1000) {
let lastError;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
}
catch (error) {
lastError = error;
if (attempt === maxRetries - 1) {
throw lastError;
}
const delay = baseDelay * Math.pow(2, attempt);
await sleep(delay);
}
}
throw lastError;
}
/**
* Logger utility
*/
class Logger {
constructor(enabled = false, prefix = '[Binance]') {
this.enabled = enabled;
this.prefix = prefix;
}
log(message, ...args) {
if (this.enabled) {
console.log(`${this.prefix} ${message}`, ...args);
}
}
error(message, ...args) {
if (this.enabled) {
console.error(`${this.prefix} ERROR: ${message}`, ...args);
}
}
warn(message, ...args) {
if (this.enabled) {
console.warn(`${this.prefix} WARN: ${message}`, ...args);
}
}
debug(message, ...args) {
if (this.enabled) {
console.debug(`${this.prefix} DEBUG: ${message}`, ...args);
}
}
}
exports.Logger = Logger;
/**
* Rate limiter utility
*/
class RateLimiter {
constructor(maxRequests = 1200, timeWindow = 60000) {
this.requests = [];
this.maxRequests = maxRequests;
this.timeWindow = timeWindow;
}
async checkLimit() {
const now = Date.now();
// Remove old requests outside the time window
this.requests = this.requests.filter(time => now - time < this.timeWindow);
if (this.requests.length >= this.maxRequests) {
const oldestRequest = Math.min(...this.requests);
const waitTime = this.timeWindow - (now - oldestRequest);
await sleep(waitTime);
return this.checkLimit();
}
this.requests.push(now);
}
}
exports.RateLimiter = RateLimiter;
/**
* WebSocket reconnection utility
*/
class ReconnectionManager {
constructor(maxAttempts = 10, baseDelay = 1000, maxDelay = 30000) {
this.attempts = 0;
this.maxAttempts = maxAttempts;
this.baseDelay = baseDelay;
this.maxDelay = maxDelay;
}
async getDelay() {
if (this.attempts >= this.maxAttempts) {
throw new Error('Max reconnection attempts reached');
}
const delay = Math.min(this.baseDelay * Math.pow(2, this.attempts), this.maxDelay);
this.attempts++;
return delay;
}
reset() {
this.attempts = 0;
}
canReconnect() {
return this.attempts < this.maxAttempts;
}
}
exports.ReconnectionManager = ReconnectionManager;
/**
* REST Data Converters
*/
/**
* Convert raw kline array to Kline object
* Binance returns klines as arrays in this format:
* [
* 1499040000000, // Open time
* "0.01634790", // Open
* "0.80000000", // High
* "0.01575800", // Low
* "0.01577100", // Close
* "148976.11427815", // Volume
* 1499644799999, // Close time
* "2434.19055334", // Quote asset volume
* 308, // Number of trades
* "1756.87402397", // Taker buy base asset volume
* "28.46694368", // Taker buy quote asset volume
* "17928899.62484339" // Ignore
* ]
*/
function convertKlineData(rawKline) {
return {
openTime: rawKline[0],
open: rawKline[1],
high: rawKline[2],
low: rawKline[3],
close: rawKline[4],
volume: rawKline[5],
closeTime: rawKline[6],
quoteAssetVolume: rawKline[7],
count: rawKline[8],
takerBuyBaseAssetVolume: rawKline[9],
takerBuyQuoteAssetVolume: rawKline[10]
};
}
/**
* Convert array of raw klines to array of Kline objects
*/
function convertKlinesData(rawKlines) {
return rawKlines.map(convertKlineData);
}
//# sourceMappingURL=index.js.map