import { writeFileSync } from 'fs'; // 全球交易所股票代码获取脚本 // 数据源: https://github.com/adanos-software/free-ticker-database (MIT License, 免费, 无需认证) const url = 'https://raw.githubusercontent.com/adanos-software/free-ticker-database/main/data/tickers.csv'; const targetExchanges = process.argv.slice(2); const exchangeNames = { NSE_IN: '印度国家证券交易所', HKEX: '香港交易所', TSE: '东京证券交易所', LSE: '伦敦证券交易所', XETRA: '法兰克福证券交易所', ASX: '澳大利亚证券交易所', TSX: '多伦多证券交易所', SGX: '新加坡交易所', KRX: '韩国交易所', BSE_IN: '印度孟买证券交易所', SSE: '上海证券交易所', SZSE: '深圳证券交易所', TWSE: '台湾证券交易所', B3: '巴西证券交易所', Euronext: '泛欧交易所', SIX: '瑞士证券交易所', BIST: '伊斯坦布尔证券交易所', SET: '泰国证券交易所', IDX: '印度尼西亚证券交易所', Bursa: '马来西亚证券交易所', TASE: '特拉维夫证券交易所', JSE: '约翰内斯堡证券交易所', WSE: '华沙证券交易所', AMS: '阿姆斯特丹交易所', STO: '斯德哥尔摩交易所', HEL: '赫尔辛基交易所', CPH: '哥本哈根交易所', OSL: '奥斯陆交易所', BME: '马德里交易所', PSX: '巴基斯坦交易所', PSE: '菲律宾交易所', HOSE: '胡志明交易所', ATHEX: '雅典交易所', ADX: '阿布扎比交易所', BMV: '墨西哥交易所', TADAWUL: '沙特交易所', NZX: '新西兰交易所', NEO: '加拿大NEO交易所', TSXV: '多伦多创业板', KOSDAQ: '韩国KOSDAQ', TPEX: '台湾兴柜', BATS: 'BATS交易所', }; if (targetExchanges.length === 0) { const list = Object.keys(exchangeNames).map(k => `${k} (${exchangeNames[k]})`).join('\n '); console.error(`用法: node fetch_global.mjs [EXCHANGE_CODE2 ...]\n\n支持交易所:\n ${list}`); process.exit(1); } console.error(`下载数据中...`); const res = await fetch(url); const csv = await res.text(); console.error(`完成 (${(csv.length / 1024 / 1024).toFixed(1)} MB), 解析中...`); const lines = csv.split('\n'); const groups = {}; for (const code of targetExchanges) groups[code] = []; // CSV 按列精确解析: ticker,name,exchange,asset_type,... for (let i = 1; i < lines.length; i++) { const line = lines[i]; if (!line.trim()) continue; // 找逗号位置 const c1 = line.indexOf(','); if (c1 === -1) continue; const c2 = line.indexOf(',', c1 + 1); if (c2 === -1) continue; const c3 = line.indexOf(',', c2 + 1); if (c3 === -1) continue; const c4 = line.indexOf(',', c3 + 1); if (c4 === -1) continue; const ticker = line.slice(0, c1); const name = line.slice(c1 + 1, c2); const exchange = line.slice(c2 + 1, c3); const assetType = line.slice(c3 + 1, c4); if (!groups[exchange]) continue; groups[exchange].push({ c: ticker, n: name, type: assetType }); } for (const code of targetExchanges) { const stocks = groups[code]; const name = exchangeNames[code] || code; const filename = `stocks_${code.toLowerCase()}.txt`; let filtered = stocks.filter(s => s.type === 'Stock'); if (filtered.length === 0) filtered = stocks; const out = [`var s = new Array();`]; for (let i = 0; i < filtered.length; i++) { const n = filtered[i].n.replace(/"/g, '\\"'); out.push(`s[${i}] = { c: "${filtered[i].c}", n: "${n}" };`); } writeFileSync(filename, out.join('\n') + '\n'); console.error(`${code} (${name}): ${filtered.length} 只 → ${filename}`); }