node-twstock
Version:
A client library for scraping Taiwan stock market data
458 lines (457 loc) • 22.1 kB
JavaScript
"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;