@fugle/node-twstock 2.2.1-alpha.1 → 3.0.0-alpha.1
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/lib/scrapers/twse-scraper.js +37 -18
- package/package.json +1 -1
|
@@ -293,7 +293,7 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
293
293
|
return symbol ? data.find(data => data.symbol === symbol) : data;
|
|
294
294
|
}
|
|
295
295
|
async fetchStocksDividends(options) {
|
|
296
|
-
const { startDate, endDate, symbol, includeDetail =
|
|
296
|
+
const { startDate, endDate, symbol, includeDetail = false } = options;
|
|
297
297
|
const query = new URLSearchParams({
|
|
298
298
|
startDate: luxon_1.DateTime.fromISO(startDate).toFormat('yyyyMMdd'),
|
|
299
299
|
endDate: luxon_1.DateTime.fromISO(endDate).toFormat('yyyyMMdd'),
|
|
@@ -350,7 +350,7 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
350
350
|
const url = `https://www.twse.com.tw/rwd/zh/exRight/TWT49UDetail?${query}`;
|
|
351
351
|
const response = await this.httpService.get(url);
|
|
352
352
|
const json = response.data.stat === 'ok' && response.data;
|
|
353
|
-
if (!json)
|
|
353
|
+
if (!json || !json.data || !json.data.length)
|
|
354
354
|
return null;
|
|
355
355
|
const [, name, ...values] = json.data[0];
|
|
356
356
|
const data = {};
|
|
@@ -417,8 +417,8 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
417
417
|
return filterSymbol ? data.filter((item) => item.symbol === filterSymbol) : data;
|
|
418
418
|
}
|
|
419
419
|
async fetchStocksCapitalReductions(options) {
|
|
420
|
-
const { startDate, endDate, symbol } = options;
|
|
421
|
-
// Note:
|
|
420
|
+
const { startDate, endDate, symbol, includeDetail = false } = options;
|
|
421
|
+
// Note: Default false for performance, set true to include detail fields
|
|
422
422
|
const query = new URLSearchParams({
|
|
423
423
|
startDate: luxon_1.DateTime.fromISO(startDate).toFormat('yyyyMMdd'),
|
|
424
424
|
endDate: luxon_1.DateTime.fromISO(endDate).toFormat('yyyyMMdd'),
|
|
@@ -443,16 +443,19 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
443
443
|
data.openingReferencePrice = (0, utils_1.parseNumeric)(values[4]);
|
|
444
444
|
data.exrightReferencePrice = (0, utils_1.parseNumeric)(values[5]);
|
|
445
445
|
data.reason = values[6].trim();
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
446
|
+
if (includeDetail) {
|
|
447
|
+
try {
|
|
448
|
+
const [, detailDate] = values[7].split(',');
|
|
449
|
+
const detail = await this.fetchStockCapitalReductionDetail({ symbol, date: detailDate });
|
|
450
|
+
return Object.assign(Object.assign({}, data), detail);
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
// If detail fetch fails, return main data without detail
|
|
454
|
+
console.warn(`Failed to fetch capital reduction detail for ${symbol}:`, error);
|
|
455
|
+
return data;
|
|
456
|
+
}
|
|
455
457
|
}
|
|
458
|
+
return data;
|
|
456
459
|
}));
|
|
457
460
|
return symbol ? data.filter((data) => data.symbol === symbol) : data;
|
|
458
461
|
}
|
|
@@ -466,7 +469,7 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
466
469
|
const url = `https://www.twse.com.tw/rwd/zh/reducation/TWTAVUDetail?${query}`;
|
|
467
470
|
const response = await this.httpService.get(url);
|
|
468
471
|
const json = response.data.stat === 'OK' && response.data;
|
|
469
|
-
if (!json)
|
|
472
|
+
if (!json || !json.data || !json.data.length)
|
|
470
473
|
return null;
|
|
471
474
|
const [, name, ...values] = json.data[0];
|
|
472
475
|
const data = {};
|
|
@@ -494,7 +497,7 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
494
497
|
const url = `https://www.twse.com.tw/rwd/zh/change/TWTB7UDetail?${query}`;
|
|
495
498
|
const response = await this.httpService.get(url);
|
|
496
499
|
const json = response.data.stat === 'OK' && response.data;
|
|
497
|
-
if (!json)
|
|
500
|
+
if (!json || !json.data || !json.data.length)
|
|
498
501
|
return null;
|
|
499
502
|
const [, name, ...values] = json.data[0];
|
|
500
503
|
const data = {};
|
|
@@ -629,7 +632,10 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
629
632
|
if (!json || !json.data)
|
|
630
633
|
return [];
|
|
631
634
|
const data = await Promise.all(json.data.map(async (row) => {
|
|
632
|
-
const [haltDate, symbol, name, resumeDate, splitRatio, oldFaceValue, newFaceValue
|
|
635
|
+
const [haltDate, symbol, name, resumeDate, splitRatio, oldFaceValue, newFaceValue, detailField1, // row[7]: "7780 ,20251230"
|
|
636
|
+
detailField2, // row[8]: "7780 ,20260109,20260119"
|
|
637
|
+
detailField3 // row[9]: ",10.00,1.00"
|
|
638
|
+
] = row;
|
|
633
639
|
const data = {};
|
|
634
640
|
data.symbol = symbol.trim();
|
|
635
641
|
data.name = name.trim();
|
|
@@ -639,12 +645,25 @@ class TwseScraper extends scraper_1.Scraper {
|
|
|
639
645
|
data.splitRatio = (0, utils_1.parseNumeric)(splitRatio);
|
|
640
646
|
data.oldFaceValue = (0, utils_1.parseNumeric)(oldFaceValue);
|
|
641
647
|
data.newFaceValue = (0, utils_1.parseNumeric)(newFaceValue);
|
|
648
|
+
// Extract detail query date from detailField1 (format: "symbol,date")
|
|
649
|
+
// Example: "7780 ,20251230" → extract "20251230"
|
|
650
|
+
let detailQueryDate;
|
|
651
|
+
if (detailField1) {
|
|
652
|
+
const parts = detailField1.split(',');
|
|
653
|
+
if (parts.length >= 2) {
|
|
654
|
+
const dateStr = parts[1].trim();
|
|
655
|
+
if (dateStr && dateStr.length === 8) {
|
|
656
|
+
// Convert YYYYMMDD to YYYY-MM-DD
|
|
657
|
+
detailQueryDate = `${dateStr.substring(0, 4)}-${dateStr.substring(4, 6)}-${dateStr.substring(6, 8)}`;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
642
661
|
// Include detail API call if requested (default: false for announcements)
|
|
643
|
-
if (includeDetail) {
|
|
662
|
+
if (includeDetail && detailQueryDate) {
|
|
644
663
|
try {
|
|
645
664
|
const detail = await this.fetchStocksSplitAnnouncementDetail({
|
|
646
665
|
symbol: data.symbol,
|
|
647
|
-
date:
|
|
666
|
+
date: detailQueryDate
|
|
648
667
|
});
|
|
649
668
|
return Object.assign(Object.assign({}, data), detail);
|
|
650
669
|
}
|