UNPKG

betfair-node

Version:

A comprehensive Node.js TypeScript library for the Betfair Exchange API, providing both JSON-RPC API integration and real-time Exchange Stream API support for automated betting and trading applications.

202 lines 7.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getNearestValidPrice = exports.getPreviousTick = exports.getNextTick = exports.generatePriceLadder = exports.getTickSize = exports.safeJsonParse = exports.delay = exports.isValidSelectionId = exports.convertCurrency = exports.formatBetfairPrice = exports.isValidMarketId = exports.generatePacketId = void 0; /** * Generates a random packet ID for API requests * @returns A random number between 100000000 and 999999999 */ const generatePacketId = () => { const min = 100000000; const max = 999999999; return Math.floor(Math.random() * (max - min + 1) + min); }; exports.generatePacketId = generatePacketId; /** * Validates if a string is a valid market ID format * @param marketId - The market ID to validate * @returns True if valid, false otherwise */ const isValidMarketId = (marketId) => { // Market IDs are typically in format like "1.123456789" return /^1\.\d+$/.test(marketId); }; exports.isValidMarketId = isValidMarketId; /** * Converts a price to the Betfair price format * @param price - The price to convert * @returns The formatted price */ const formatBetfairPrice = (price) => { return Math.round(price * 100) / 100; }; exports.formatBetfairPrice = formatBetfairPrice; /** * Converts currency amount using the provided rate * @param amount - The amount to convert * @param rate - The currency conversion rate * @returns The converted amount */ const convertCurrency = (amount, rate) => { return amount * rate; }; exports.convertCurrency = convertCurrency; /** * Validates if a selection ID is valid * @param selectionId - The selection ID to validate * @returns True if valid, false otherwise */ const isValidSelectionId = (selectionId) => { return Number.isInteger(selectionId) && selectionId > 0; }; exports.isValidSelectionId = isValidSelectionId; /** * Creates a delay promise * @param ms - Milliseconds to delay * @returns Promise that resolves after the delay */ const delay = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); }; exports.delay = delay; /** * Safely parses JSON with error handling * @param json - JSON string to parse * @returns Parsed object or null if invalid */ const safeJsonParse = (json) => { try { return JSON.parse(json); } catch { return null; } }; exports.safeJsonParse = safeJsonParse; /** * Price ladder tick size definitions based on Betfair's price ranges */ const PRICE_TICK_RANGES = [ { min: 1.01, max: 2, increment: 0.01 }, { min: 2, max: 3, increment: 0.02 }, { min: 3, max: 4, increment: 0.05 }, { min: 4, max: 6, increment: 0.1 }, { min: 6, max: 10, increment: 0.2 }, { min: 10, max: 20, increment: 0.5 }, { min: 20, max: 30, increment: 1 }, { min: 30, max: 50, increment: 2 }, { min: 50, max: 100, increment: 5 }, { min: 100, max: 1000, increment: 10 } ]; /** * Cache for generated price ladders */ const priceLadderCache = new Map(); /** * Finds the appropriate tick size for a given price * @param price - The price to find the tick size for * @returns The tick increment for the price range */ const getTickSize = (price) => { for (const range of PRICE_TICK_RANGES) { if (price >= range.min && price < range.max) { return range.increment; } } // For prices >= 1000, use the largest increment return PRICE_TICK_RANGES[PRICE_TICK_RANGES.length - 1].increment; }; exports.getTickSize = getTickSize; /** * Generates a complete price ladder for a given range with memoization * @param minPrice - Minimum price (default: 1.01) * @param maxPrice - Maximum price (default: 1000) * @returns Array of valid prices in the ladder */ const generatePriceLadder = (minPrice = 1.01, maxPrice = 1000) => { const cacheKey = `${minPrice}-${maxPrice}`; if (priceLadderCache.has(cacheKey)) { return priceLadderCache.get(cacheKey); } const ladder = []; let currentPrice = minPrice; while (currentPrice <= maxPrice) { // Round to avoid floating point precision issues const roundedPrice = Math.round(currentPrice * 100) / 100; ladder.push(roundedPrice); const tickSize = (0, exports.getTickSize)(currentPrice); currentPrice += tickSize; } priceLadderCache.set(cacheKey, ladder); return ladder; }; exports.generatePriceLadder = generatePriceLadder; /** * Gets the next valid tick price from a given price * @param price - The current price * @returns The next valid price in the ladder, or null if at maximum */ const getNextTick = (price) => { const tickSize = (0, exports.getTickSize)(price); const nextPrice = price + tickSize; // Round to avoid floating point precision issues const roundedNext = Math.round(nextPrice * 100) / 100; // Check if we've exceeded the maximum price if (roundedNext > 1000) { return null; } return roundedNext; }; exports.getNextTick = getNextTick; /** * Gets the previous valid tick price from a given price * @param price - The current price * @returns The previous valid price in the ladder, or null if at minimum */ const getPreviousTick = (price) => { // Find the tick size for the price we're moving to const tickSize = (0, exports.getTickSize)(price); const prevPrice = price - tickSize; // Round to avoid floating point precision issues const roundedPrev = Math.round(prevPrice * 100) / 100; // Check if we've gone below the minimum price if (roundedPrev < 1.01) { return null; } return roundedPrev; }; exports.getPreviousTick = getPreviousTick; /** * Finds the nearest valid price in the ladder * @param price - The price to find the nearest valid price for * @param direction - 'up' to round up, 'down' to round down, 'nearest' for closest * @returns The nearest valid price in the ladder */ const getNearestValidPrice = (price, direction = 'nearest') => { if (price < 1.01) return 1.01; if (price > 1000) return 1000; const tickSize = (0, exports.getTickSize)(price); const range = PRICE_TICK_RANGES.find(r => price >= r.min && price < r.max); if (!range) { // For prices >= 1000, use the last range const lastRange = PRICE_TICK_RANGES[PRICE_TICK_RANGES.length - 1]; const steps = Math.floor((price - lastRange.min) / lastRange.increment); return Math.round((lastRange.min + steps * lastRange.increment) * 100) / 100; } // Calculate steps from the range minimum const stepsFromMin = (price - range.min) / range.increment; let validPrice; if (direction === 'up') { validPrice = range.min + Math.ceil(stepsFromMin) * range.increment; } else if (direction === 'down') { validPrice = range.min + Math.floor(stepsFromMin) * range.increment; } else { validPrice = range.min + Math.round(stepsFromMin) * range.increment; } return Math.round(validPrice * 100) / 100; }; exports.getNearestValidPrice = getNearestValidPrice; //# sourceMappingURL=utils.js.map