UNPKG

node-twstock

Version:

A client library for scraping Taiwan stock market data

458 lines (457 loc) 22.1 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TwStock = void 0; const lodash_1 = require("lodash"); const scrapers_1 = require("./scrapers"); const enums_1 = require("./enums"); class TwStock { constructor(options) { this._stocks = new Map(); this._indices = new Map(); this._futopt = new Map(); this._scraper = new scrapers_1.ScraperFactory(options); } get stocks() { return { list: this.fetchStocksList.bind(this), quote: this.fetchStocksQuote.bind(this), historical: this.fetchStocksHistorical.bind(this), institutional: this.fetchStocksInstitutional.bind(this), values: this.fetchStocksValues.bind(this), finiHoldings: this.fetchStocksFiniHoldings.bind(this), marginTrades: this.fetchStocksMarginTrades.bind(this), shortSales: this.fetchStocksShortSales.bind(this), shareholders: this.fetchStocksShareholders.bind(this), eps: this.fetchStocksEps.bind(this), revenue: this.fetchStocksRevenue.bind(this), dividends: this.fetchStocksDividends.bind(this), capitalReductions: this.fetchStocksCapitalReductions.bind(this), splits: this.fetchStocksSplits.bind(this), etfSplits: this.fetchStocksEtfSplits.bind(this), }; } get indices() { return { list: this.getIndicesList.bind(this), quote: this.getIndicesQuote.bind(this), historical: this.getIndicesHistorical.bind(this), trades: this.getIndicesTrades.bind(this), }; } get market() { return { trades: this.getMarketTrades.bind(this), breadth: this.getMarketBreadth.bind(this), institutional: this.getMarketInstitutional.bind(this), marginTrades: this.getMarketMarginTrades.bind(this), }; } get futopt() { return { list: this.getFutOptList.bind(this), quote: this.getFutOptQuote.bind(this), historical: this.getFutOptHistorical.bind(this), institutional: this.getFutOptInstitutional.bind(this), largeTraders: this.getFutOptLargeTraders.bind(this), mxfRetailPosition: this.getFutOptMxfRetailPosition.bind(this), tmfRetailPosition: this.getFutOptTmfRetailPosition.bind(this), txoPutCallRatio: this.getFutOptTxoPutCallRatio.bind(this), exchangeRates: this.getFutOptExchangeRates.bind(this), }; } async loadStocks(options) { const { symbol } = options !== null && options !== void 0 ? options : {}; const isinScraper = this._scraper.getIsinScraper(); const stocks = (symbol) ? await isinScraper.fetchListed({ symbol }) : await Promise.all([ isinScraper.fetchListedStocks({ exchange: enums_1.Exchange.TWSE }), isinScraper.fetchListedStocks({ exchange: enums_1.Exchange.TPEx }), ]).then(results => results.flat()); stocks.forEach((_a) => { var { symbol } = _a, ticker = __rest(_a, ["symbol"]); return this._stocks.set(symbol, Object.assign({ symbol }, ticker)); }); return stocks; } async loadIndices() { const misScraper = this._scraper.getMisTwseScraper(); const data = await Promise.all([ misScraper.fetchListedIndices({ exchange: enums_1.Exchange.TWSE }), misScraper.fetchListedIndices({ exchange: enums_1.Exchange.TPEx }), ]).then(results => results.flat()); const indices = data .filter((_a) => { var { symbol } = _a, ticker = __rest(_a, ["symbol"]); const isExist = this._indices.has(symbol); if (!isExist) this._indices.set(symbol, Object.assign({ symbol }, ticker)); return !isExist; }) .map(ticker => (0, lodash_1.omit)(ticker, 'ex_ch')); return indices; } async loadFutOpt(options) { const { type } = options !== null && options !== void 0 ? options : {}; const misTaifexScraper = this._scraper.getMisTaifexScraper(); const futopt = await (() => { switch (type) { case 'F': return misTaifexScraper.fetchListedFutOpt({ type: 'F' }); case 'O': return misTaifexScraper.fetchListedFutOpt({ type: 'O' }); default: return misTaifexScraper.fetchListedFutOpt(); } })(); futopt.forEach((_a) => { var { symbol } = _a, ticker = __rest(_a, ["symbol"]); return this._futopt.set(symbol, Object.assign({ symbol }, ticker)); }); return futopt; } async loadFutOptContracts(options) { const { symbol, type } = options; const isinScraper = this._scraper.getIsinScraper(); const futopt = (symbol) ? await isinScraper.fetchListed({ symbol }) : await isinScraper.fetchListedFutOpt({ type }); futopt.forEach((_a) => { var { symbol } = _a, ticker = __rest(_a, ["symbol"]); return this._futopt.set(symbol, Object.assign({ symbol }, ticker)); }); return futopt; } async fetchStocksList(options) { const { exchange } = options !== null && options !== void 0 ? options : {}; const data = await this.loadStocks(); return exchange ? data.filter(ticker => ticker.exchange === exchange) : data; } async fetchStocksQuote(options) { const { symbol, odd } = options; if (!this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); return this._scraper.getMisTwseScraper().fetchStocksQuote({ ticker, odd }); } async fetchStocksHistorical(options) { const { date, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksHistorical({ date, symbol }) : await this._scraper.getTwseScraper().fetchStocksHistorical({ date, symbol }); } async fetchStocksInstitutional(options) { const { date, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksInstitutional({ date, symbol }) : await this._scraper.getTwseScraper().fetchStocksInstitutional({ date, symbol }); } async fetchStocksValues(options) { const { date, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksValues({ date, symbol }) : await this._scraper.getTwseScraper().fetchStocksValues({ date, symbol }); } async fetchStocksSplits(options) { const { startDate, endDate, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksSplits({ symbol, startDate, endDate }) : await this._scraper.getTwseScraper().fetchStocksSplits({ symbol, startDate, endDate }); } async fetchStocksEtfSplits(options) { const { startDate, endDate, symbol, reverseSplit } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await (reverseSplit ? this._scraper.getTpexScraper().fetchStocksEtfReverseSplits({ symbol, startDate, endDate }) : this._scraper.getTpexScraper().fetchStocksEtfSplits({ symbol, startDate, endDate })) : await this._scraper.getTwseScraper().fetchStocksEtfSplits({ symbol, startDate, endDate, reverseSplit }); } async fetchStocksCapitalReductions(options) { const { symbol, startDate, endDate } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksCapitalReductions({ symbol, startDate, endDate }) : await this._scraper.getTwseScraper().fetchStocksCapitalReductions({ symbol, startDate, endDate }); } async fetchStocksDividends(options) { const { symbol, startDate, endDate } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksDividends({ symbol, startDate, endDate }) : await this._scraper.getTwseScraper().fetchStocksDividends({ symbol, startDate, endDate }); } async fetchStocksFiniHoldings(options) { const { date, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksFiniHoldings({ date, symbol }) : await this._scraper.getTwseScraper().fetchStocksFiniHoldings({ date, symbol }); } async fetchStocksMarginTrades(options) { const { date, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksMarginTrades({ date, symbol }) : await this._scraper.getTwseScraper().fetchStocksMarginTrades({ date, symbol }); } async fetchStocksShortSales(options) { const { date, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchStocksShortSales({ date, symbol }) : await this._scraper.getTwseScraper().fetchStocksShortSales({ date, symbol }); } async fetchStocksShareholders(options) { if (!options) return this._scraper.getTdccScraper().fetchStocksShareholdersRecentWeek(); const { date, symbol } = options; if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } return (!date) ? this._scraper.getTdccScraper().fetchStocksShareholdersRecentWeek({ symbol }) : this._scraper.getTdccScraper().fetchStocksShareholders({ date, symbol }); } async fetchStocksEps(options) { const { symbol, year, quarter } = options; if (!options.exchange && !options.symbol) { throw new Error('Either "exchange" or "symbol" options must be specified'); } if (options.exchange && options.symbol) { throw new Error('One and only one of the "exchange" or "symbol" options must be specified'); } if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return this._scraper.getMopsScraper().fetchStocksEps({ exchange, year, quarter, symbol }); } async fetchStocksRevenue(options) { const { symbol, year, month, foreign } = options; if (!options.exchange && !options.symbol) { throw new Error('Either "exchange" or "symbol" options must be specified'); } if (options.exchange && options.symbol) { throw new Error('One and only one of the "exchange" or "symbol" options must be specified'); } if (symbol && !this._stocks.has(symbol)) { const stocks = await this.loadStocks({ symbol }); if (!stocks.length) throw new Error('symbol not found'); } const ticker = this._stocks.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return this._scraper.getMopsScraper().fetchStocksRevenue({ exchange, year, month, foreign, symbol }); } async getIndicesList(options) { const { exchange } = options !== null && options !== void 0 ? options : {}; const data = await this.loadIndices(); return exchange ? data.filter(ticker => ticker.exchange === exchange) : data; } async getIndicesQuote(options) { const { symbol } = options; if (!this._indices.has(symbol)) { const indices = await this.loadIndices(); if (!(0, lodash_1.map)(indices, 'symbol').includes(symbol)) throw new Error('symbol not found'); } const ticker = this._indices.get(symbol); return this._scraper.getMisTwseScraper().fetchIndicesQuote({ ticker }); } async getIndicesHistorical(options) { const { date, symbol } = options; if (symbol && !this._indices.has(symbol)) { const indices = await this.loadIndices(); if (!(0, lodash_1.map)(indices, 'symbol').includes(symbol)) throw new Error('symbol not found'); } const ticker = this._indices.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchIndicesHistorical({ date, symbol }) : await this._scraper.getTwseScraper().fetchIndicesHistorical({ date, symbol }); } async getIndicesTrades(options) { const { date, symbol } = options; if (symbol && !this._indices.has(symbol)) { const indices = await this.loadIndices(); if (!(0, lodash_1.map)(indices, 'symbol').includes(symbol)) throw new Error('symbol not found'); } const ticker = this._indices.get(symbol); const exchange = symbol ? ticker.exchange : options.exchange; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchIndicesTrades({ date, symbol }) : await this._scraper.getTwseScraper().fetchIndicesTrades({ date, symbol }); } async getMarketTrades(options) { const { date, exchange } = options; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchMarketTrades({ date }) : await this._scraper.getTwseScraper().fetchMarketTrades({ date }); } async getMarketBreadth(options) { const { date, exchange } = options; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchMarketBreadth({ date }) : await this._scraper.getTwseScraper().fetchMarketBreadth({ date }); } async getMarketInstitutional(options) { const { date, exchange } = options; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchMarketInstitutional({ date }) : await this._scraper.getTwseScraper().fetchMarketInstitutional({ date }); } async getMarketMarginTrades(options) { const { date, exchange } = options; return (exchange === enums_1.Exchange.TPEx) ? await this._scraper.getTpexScraper().fetchMarketMarginTrades({ date }) : await this._scraper.getTwseScraper().fetchMarketMarginTrades({ date }); } async getFutOptList(options) { const { type, availableContracts } = options !== null && options !== void 0 ? options : {}; return availableContracts ? await this.loadFutOptContracts({ type }) : await this.loadFutOpt({ type }); } async getFutOptQuote(options) { const { symbol, afterhours } = options; if (!this._futopt.has(symbol)) { const futopt = (symbol.length === 3) ? await this.loadFutOpt() : await this.loadFutOptContracts({ symbol }); // @ts-ignore if (!(0, lodash_1.map)(futopt, 'symbol').includes(symbol)) throw new Error('symbol not found'); } const ticker = this._futopt.get(symbol); return (ticker.symbol.length === 3) ? this._scraper.getMisTaifexScraper().fetchFutOptQuoteList({ ticker, afterhours }) : this._scraper.getMisTaifexScraper().fetchFutOptQuoteDetail({ ticker, afterhours }); } async getFutOptHistorical(options) { const { date, symbol, afterhours } = options; if (symbol && !this._futopt.has(symbol)) { const futopt = await this.loadFutOpt(); if (!(0, lodash_1.map)(futopt, 'symbol').includes(symbol)) throw new Error('symbol not found'); } const ticker = this._futopt.get(symbol); const type = symbol ? ticker.type : options.type; return (type === 'O') ? this._scraper.getTaifexScraper().fetchOptionsHistorical({ date, symbol, afterhours }) : this._scraper.getTaifexScraper().fetchFuturesHistorical({ date, symbol, afterhours }); } async getFutOptInstitutional(options) { const { date, symbol } = options; const type = (symbol.charAt(2) === 'O') ? 'O' : 'F'; return (type === 'O') ? this._scraper.getTaifexScraper().fetchOptionsInstitutional({ date, symbol }) : this._scraper.getTaifexScraper().fetchFuturesInstitutional({ date, symbol }); } async getFutOptLargeTraders(options) { const { date, symbol } = options; const type = (symbol.charAt(2) === 'O') ? 'O' : 'F'; return (type === 'O') ? this._scraper.getTaifexScraper().fetchOptionsLargeTraders({ date, symbol }) : this._scraper.getTaifexScraper().fetchFuturesLargeTraders({ date, symbol }); } async getFutOptMxfRetailPosition(options) { const { date } = options; return this._scraper.getTaifexScraper().fetchMxfRetailPosition({ date }); } async getFutOptTmfRetailPosition(options) { const { date } = options; return this._scraper.getTaifexScraper().fetchTmfRetailPosition({ date }); } async getFutOptTxoPutCallRatio(options) { const { date } = options; return this._scraper.getTaifexScraper().fetchTxoPutCallRatio({ date }); } async getFutOptExchangeRates(options) { const { date } = options; return this._scraper.getTaifexScraper().fetchExchangeRates({ date }); } } exports.TwStock = TwStock;