UNPKG

@seedalpha/ticker

Version:
186 lines (144 loc) 5 kB
var Queue = require('@seedalpha/queue'); var log = require('./utils/log'); var data = require('./data/index'); var ticker = { parse: function(str) { var pattern = /^([0-9a-z]{1,5}|[0-9]{6})[\s]*[\s\.:][\s]*([a-z]{1,2})$/i; var matches = str.trim().match(pattern); // CapIQ style pattern var pattern2 = /^([a-z]{3,6}):A?([0-9]{1,6})$/i; var matches2 = str.trim().match(pattern2); if ((!matches || matches.length !== 3) && (!matches2 || matches2.length !== 3)) { log.trace('input does not match ticker pattern'); return null; } var stockCode, exchangeCode; if (matches) { stockCode = matches[1].replace(/^[0]+/g, '').toUpperCase(); exchangeCode = matches[2].toUpperCase(); } else if (matches2) { stockCode = matches2[2].replace(/^[0]+/g, '').toUpperCase(); exchangeCode = matches2[1].toUpperCase(); } log.trace('ticker pattern matched, code: %s, exchange: %s', stockCode, exchangeCode); return { code: stockCode, exchange: exchangeCode } }, _findPossibleExchanges: function(obj) { return data.exchanges.filter(function(exchange) { return exchange.codes.indexOf(obj.exchange.toUpperCase()) > -1; }); }, lookup: function(obj, callback) { var stock = null; var exchange = null; ticker._findPossibleExchanges(obj).some(function(ex) { if (stock = data.stocks[ex.key][obj.code.toUpperCase()]) { exchange = ex; return true; } }); log.debug('stock found: ', stock); if (!stock) return callback('stock not found'); callback(null, { stock: stock, exchange: exchange }); }, getTerms: function(info, includeNoLeadingZeros, withKeywords, callback) { if (typeof includeNoLeadingZeros === 'function') { callback = includeNoLeadingZeros; includeNoLeadingZeros = false; withKeywords = false; } else if (typeof withKeywords === 'function') { callback = withKeywords; withKeywords = false; } log.trace('includeNoLeadingZeros: %s, with keywords: %s', includeNoLeadingZeros, withKeywords); var terms = []; var stock = info.stock; var exchange = info.exchange; var separators = [' ', '.', ':']; exchange.codes.forEach(function(exchangeCode) { var stockCode = stock.code; if (isInt(stock.code) && isInt(exchange.numericLength)) { stockCode = padZeros(stock.code, exchange.numericLength); } terms = terms.concat(separators.map(function(sep) { return [stockCode, exchangeCode].join(sep); })); if (isInt(stock.code) && includeNoLeadingZeros) { terms = terms.concat(separators.map(function(sep) { return [stock.code, exchangeCode].join(sep); })); } }); terms.push(stock.name); log.trace('terms got: %o', terms); // TODO: add more related keywords to the dataset and support withKeywords argument /*if (withKeywords) { }*/ callback(null, terms); }, findTickers: function(contentText, callback) { try { var pattern1 = /(?:[^0-9a-z]|^)([0-9a-z]{1,4}|[0-9]{6})[\.:]([a-z]{1,2})(?:[^0-9a-z]|$)/ig; var pattern2 = /(?:[^0-9a-z]|^)([0-9]{4,6})[\s]([a-z]{2})(?:[^0-9a-z]|$)/ig; var objs = []; var i = 0; var extract = function(matches, objs) { if (matches.length === 3) { var stockCode = matches[1].replace(/^[0]+/g, '').toUpperCase(); var exchangeCode = matches[2].toUpperCase(); var obj = { code: stockCode, exchange: exchangeCode }; if (ticker._findPossibleExchanges(obj).length) { objs.push(obj); } } } var matches; while ((matches = pattern1.exec(contentText)) !== null) { extract(matches, objs); } while ((matches = pattern2.exec(contentText)) !== null) { extract(matches, objs); } var lookups = objs.map(function(obj) { return function(results, next) { ticker.lookup(obj, function(err, result) { if (err) return next(); results.push(result); next(); }); } }); Queue([]).add(lookups) .end(function(err, results) { callback(null, results.map(function(result) { return [result.stock.code.toString().toUpperCase(), result.exchange.codes[0].toUpperCase()].join('.'); })); }); } catch(err) { callback(err); } } } exports = module.exports = ticker; function isInt(value) { return !isNaN(value) && parseInt(Number(value)) == value && !isNaN(parseInt(value, 10)); } function padZeros(str, len) { var padded = str; while(padded.length < len) { padded = '0' + padded; } return padded; }