@fugle/node-twstock 3.0.0-alpha.1 → 3.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/lib/scrapers/twse-scraper.d.ts +2 -1
- package/lib/scrapers/twse-scraper.js +16 -6
- package/lib/twstock.d.ts +2 -2
- package/lib/twstock.js +15 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -928,7 +928,7 @@ twstock.stocks.splitAnnouncement({ symbol: '1234' })
|
|
|
928
928
|
* `endDate`: {string} 結束日期 (`'YYYY-MM-DD'`)
|
|
929
929
|
* `exchange` (optional): {string} 市場別 (`'TWSE'`:上市;`'TPEx'`:上櫃)
|
|
930
930
|
* `symbol` (optional): {string} ETF 代號
|
|
931
|
-
* `
|
|
931
|
+
* `splitType` (optional): {string} 分割類型,可選值: `'split'` (分割)、`'reverse-split'` (反分割)、`'all'` (全部,預設值)
|
|
932
932
|
* Returns: {Promise} 成功時以 {Object[]} 履行,其中 `Object` 包含以下屬性:
|
|
933
933
|
* `resumeDate`: {string} 恢復買賣日期
|
|
934
934
|
* `exchange`: {string} 市場別
|
|
@@ -941,8 +941,17 @@ twstock.stocks.splitAnnouncement({ symbol: '1234' })
|
|
|
941
941
|
* `openingReferencePrice`: {number} 開盤競價基準
|
|
942
942
|
|
|
943
943
|
```js
|
|
944
|
+
// 查詢所有類型(預設)
|
|
944
945
|
twstock.stocks.etfSplits({ startDate: '2024-12-01', endDate: '2024-12-31', exchange: 'TWSE' })
|
|
945
946
|
.then(data => console.log(data));
|
|
947
|
+
|
|
948
|
+
// 只查詢分割
|
|
949
|
+
twstock.stocks.etfSplits({ startDate: '2024-12-01', endDate: '2024-12-31', exchange: 'TWSE', splitType: 'split' })
|
|
950
|
+
.then(data => console.log(data));
|
|
951
|
+
|
|
952
|
+
// 只查詢反分割
|
|
953
|
+
twstock.stocks.etfSplits({ startDate: '2024-12-01', endDate: '2024-12-31', exchange: 'TWSE', splitType: 'reverse-split' })
|
|
954
|
+
.then(data => console.log(data));
|
|
946
955
|
```
|
|
947
956
|
|
|
948
957
|
### `.stocks.etfSplitAnnouncement([options])`
|
|
@@ -952,7 +961,7 @@ twstock.stocks.etfSplits({ startDate: '2024-12-01', endDate: '2024-12-31', excha
|
|
|
952
961
|
* `options`: {Object}
|
|
953
962
|
* `exchange` (optional): {string} 市場別 (`'TWSE'`:上市;`'TPEx'`:上櫃,預設為 `'TWSE'`)
|
|
954
963
|
* `symbol` (optional): {string} ETF 代號
|
|
955
|
-
* `splitType` (optional): {string}
|
|
964
|
+
* `splitType` (optional): {string} 分割類型,可選值: `'split'` (分割)、`'reverse-split'` (反分割)、`'all'` (全部,預設值)
|
|
956
965
|
* Returns: {Promise} 成功時以 {Object[]} 履行,其中 `Object` 包含以下屬性:
|
|
957
966
|
* `symbol`: {string} ETF 代號
|
|
958
967
|
* `name`: {string} ETF 名稱
|
|
@@ -66,7 +66,7 @@ export declare class TwseScraper extends Scraper {
|
|
|
66
66
|
startDate: string;
|
|
67
67
|
endDate: string;
|
|
68
68
|
symbol?: string;
|
|
69
|
-
|
|
69
|
+
splitType?: 'split' | 'reverse-split' | 'all';
|
|
70
70
|
}): Promise<StockSplits[]>;
|
|
71
71
|
fetchStocksSplitAnnouncement(options?: {
|
|
72
72
|
symbol?: string;
|
|
@@ -74,6 +74,7 @@ export declare class TwseScraper extends Scraper {
|
|
|
74
74
|
}): Promise<StocksSplitAnnouncement[]>;
|
|
75
75
|
fetchStocksEtfSplitAnnouncement(options?: {
|
|
76
76
|
symbol?: string;
|
|
77
|
+
splitType?: 'split' | 'reverse-split' | 'all';
|
|
77
78
|
}): Promise<StocksEtfSplitAnnouncement[]>;
|
|
78
79
|
fetchStocksListingApplicants(options?: {
|
|
79
80
|
symbol?: string;
|
|
@@ -591,7 +591,7 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
591
591
|
return symbol ? data.filter((data) => data.symbol === symbol) : data;
|
|
592
592
|
}
|
|
593
593
|
async fetchStocksEtfSplits(options) {
|
|
594
|
-
const { startDate, endDate, symbol } = options;
|
|
594
|
+
const { startDate, endDate, symbol, splitType = 'all' } = options;
|
|
595
595
|
const query = new URLSearchParams({
|
|
596
596
|
startDate: luxon_1.DateTime.fromISO(startDate).toFormat('yyyyMMdd'),
|
|
597
597
|
endDate: luxon_1.DateTime.fromISO(endDate).toFormat('yyyyMMdd'),
|
|
@@ -615,7 +615,11 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
615
615
|
data.openingReferencePrice = (0, utils_1.parseNumeric)(values[4]);
|
|
616
616
|
return data;
|
|
617
617
|
})
|
|
618
|
-
.filter((row) =>
|
|
618
|
+
.filter((row) => {
|
|
619
|
+
if (splitType === 'all')
|
|
620
|
+
return true;
|
|
621
|
+
return splitType === 'split' ? row.type === '分割' : row.type === '反分割';
|
|
622
|
+
})
|
|
619
623
|
.map((row) => _.omit(row, ['type']));
|
|
620
624
|
return symbol ? data.filter((data) => data.symbol === symbol) : data;
|
|
621
625
|
}
|
|
@@ -679,6 +683,7 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
679
683
|
}
|
|
680
684
|
async fetchStocksEtfSplitAnnouncement(options) {
|
|
681
685
|
var _a;
|
|
686
|
+
const { symbol: filterSymbol, splitType = 'all' } = options || {};
|
|
682
687
|
const query = new URLSearchParams({
|
|
683
688
|
response: 'json',
|
|
684
689
|
_: Date.now().toString(),
|
|
@@ -688,19 +693,24 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
688
693
|
const json = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.stat) === 'OK' && response.data;
|
|
689
694
|
if (!json || !json.data)
|
|
690
695
|
return [];
|
|
691
|
-
|
|
692
|
-
const [haltDate, symbol, name,
|
|
696
|
+
let data = json.data.map((row) => {
|
|
697
|
+
const [haltDate, symbol, name, splitTypeValue, resumeDate, splitRatio] = row;
|
|
693
698
|
const data = {};
|
|
694
699
|
data.symbol = symbol.trim();
|
|
695
700
|
data.name = name.trim();
|
|
696
701
|
data.exchange = enums_1.Exchange.TWSE;
|
|
697
702
|
data.haltDate = (0, utils_1.rocToWestern)(haltDate);
|
|
698
703
|
data.resumeDate = (0, utils_1.rocToWestern)(resumeDate);
|
|
699
|
-
data.splitType =
|
|
704
|
+
data.splitType = splitTypeValue.trim();
|
|
700
705
|
data.splitRatio = (0, utils_1.parseNumeric)(splitRatio);
|
|
701
706
|
return data;
|
|
702
707
|
});
|
|
703
|
-
|
|
708
|
+
// Apply splitType filter if specified
|
|
709
|
+
if (splitType !== 'all') {
|
|
710
|
+
const targetType = splitType === 'split' ? '分割' : '反分割';
|
|
711
|
+
data = data.filter(item => item.splitType === targetType);
|
|
712
|
+
}
|
|
713
|
+
return filterSymbol ? data.filter((item) => item.symbol === filterSymbol) : data;
|
|
704
714
|
}
|
|
705
715
|
async fetchStocksListingApplicants(options) {
|
|
706
716
|
var _a;
|
package/lib/twstock.d.ts
CHANGED
|
@@ -100,12 +100,12 @@ export declare class TwStock {
|
|
|
100
100
|
startDate: string;
|
|
101
101
|
endDate: string;
|
|
102
102
|
symbol?: string | undefined;
|
|
103
|
-
|
|
103
|
+
splitType?: "split" | "reverse-split" | "all" | undefined;
|
|
104
104
|
}) => Promise<import("./interfaces").StockSplits[]>;
|
|
105
105
|
etfSplitAnnouncement: (options?: {
|
|
106
106
|
exchange?: "TWSE" | "TPEx" | undefined;
|
|
107
107
|
symbol?: string | undefined;
|
|
108
|
-
splitType?: "
|
|
108
|
+
splitType?: "split" | "reverse-split" | "all" | undefined;
|
|
109
109
|
} | undefined) => Promise<import("./interfaces").StocksEtfSplitAnnouncement[]>;
|
|
110
110
|
listingApplicants: (options?: {
|
|
111
111
|
exchange?: "TWSE" | "TPEx" | undefined;
|
package/lib/twstock.js
CHANGED
|
@@ -203,7 +203,7 @@ class TwStock {
|
|
|
203
203
|
: await this._scraper.getTwseScraper().fetchStocksSplits({ symbol, startDate, endDate });
|
|
204
204
|
}
|
|
205
205
|
async fetchStocksEtfSplits(options) {
|
|
206
|
-
const { startDate, endDate, symbol,
|
|
206
|
+
const { startDate, endDate, symbol, splitType = 'all' } = options;
|
|
207
207
|
if (symbol && !this._stocks.has(symbol)) {
|
|
208
208
|
const stocks = await this.loadStocks({ symbol });
|
|
209
209
|
if (!stocks.length)
|
|
@@ -212,10 +212,15 @@ class TwStock {
|
|
|
212
212
|
const ticker = this._stocks.get(symbol);
|
|
213
213
|
const exchange = symbol ? ticker.exchange : options.exchange;
|
|
214
214
|
return (exchange === enums_1.Exchange.TPEx)
|
|
215
|
-
? await (
|
|
215
|
+
? await (splitType === 'reverse-split'
|
|
216
216
|
? this._scraper.getTpexScraper().fetchStocksEtfReverseSplits({ symbol, startDate, endDate })
|
|
217
|
-
:
|
|
218
|
-
|
|
217
|
+
: splitType === 'split'
|
|
218
|
+
? this._scraper.getTpexScraper().fetchStocksEtfSplits({ symbol, startDate, endDate })
|
|
219
|
+
: [
|
|
220
|
+
...await this._scraper.getTpexScraper().fetchStocksEtfSplits({ symbol, startDate, endDate }),
|
|
221
|
+
...await this._scraper.getTpexScraper().fetchStocksEtfReverseSplits({ symbol, startDate, endDate })
|
|
222
|
+
])
|
|
223
|
+
: await this._scraper.getTwseScraper().fetchStocksEtfSplits({ symbol, startDate, endDate, splitType });
|
|
219
224
|
}
|
|
220
225
|
async fetchStocksDividendsAnnouncement(options) {
|
|
221
226
|
const { exchange = enums_1.Exchange.TWSE, symbol, includeDetail } = options || {};
|
|
@@ -236,12 +241,12 @@ class TwStock {
|
|
|
236
241
|
: await this._scraper.getTwseScraper().fetchStocksSplitAnnouncement({ symbol, includeDetail });
|
|
237
242
|
}
|
|
238
243
|
async fetchStocksEtfSplitAnnouncement(options) {
|
|
239
|
-
const { exchange = enums_1.Exchange.TWSE, symbol, splitType } = options || {};
|
|
244
|
+
const { exchange = enums_1.Exchange.TWSE, symbol, splitType = 'all' } = options || {};
|
|
240
245
|
if (exchange === enums_1.Exchange.TPEx) {
|
|
241
246
|
// TPEx has separate endpoints for split and reverse split
|
|
242
|
-
const data = splitType === '
|
|
247
|
+
const data = splitType === 'reverse-split'
|
|
243
248
|
? await this._scraper.getTpexScraper().fetchStocksEtfReverseSplitAnnouncement({ symbol })
|
|
244
|
-
: splitType === '
|
|
249
|
+
: splitType === 'split'
|
|
245
250
|
? await this._scraper.getTpexScraper().fetchStocksEtfSplitAnnouncement({ symbol })
|
|
246
251
|
: [
|
|
247
252
|
...await this._scraper.getTpexScraper().fetchStocksEtfSplitAnnouncement({ symbol }),
|
|
@@ -250,8 +255,9 @@ class TwStock {
|
|
|
250
255
|
return data;
|
|
251
256
|
}
|
|
252
257
|
// TWSE returns all split types in one call, filter by splitType if specified
|
|
253
|
-
const
|
|
254
|
-
|
|
258
|
+
const targetType = splitType === 'split' ? '分割' : splitType === 'reverse-split' ? '反分割' : undefined;
|
|
259
|
+
const data = await this._scraper.getTwseScraper().fetchStocksEtfSplitAnnouncement({ symbol, splitType });
|
|
260
|
+
return targetType ? data.filter(item => item.splitType === targetType) : data;
|
|
255
261
|
}
|
|
256
262
|
async fetchStocksCapitalReductions(options) {
|
|
257
263
|
const { symbol, startDate, endDate, includeDetail } = options;
|