54 lines
1.5 KiB
JavaScript
54 lines
1.5 KiB
JavaScript
import { YahooClient } from '../market/YahooClient.js';
|
|
|
|
const NEWS_QUERIES = ['stock market today', 'earnings report', 'market news'];
|
|
const MAX_STORIES = 15;
|
|
const TICKER_REGEX = /^[A-Z]{1,6}$/;
|
|
|
|
export class CatalystAnalyst {
|
|
constructor({ logger } = {}) {
|
|
this.client = new YahooClient();
|
|
this.logger = logger ?? { write: (msg) => process.stdout.write(msg) };
|
|
}
|
|
|
|
async run() {
|
|
this.logger.write('🔍 Fetching market news...');
|
|
const stories = await this._fetchNews();
|
|
const tickers = this._extractTickers(stories);
|
|
this.logger.write(` ${stories.length} stories, ${tickers.length} tickers\n`);
|
|
return { tickers, stories };
|
|
}
|
|
|
|
async _fetchNews() {
|
|
const seen = new Map();
|
|
for (const query of NEWS_QUERIES) {
|
|
try {
|
|
const { news = [] } = await this.client.yf.search(query, { newsCount: 8, quotesCount: 0 });
|
|
for (const s of news) {
|
|
if (!seen.has(s.title)) {
|
|
seen.set(s.title, {
|
|
title: s.title,
|
|
publisher: s.publisher,
|
|
link: s.link,
|
|
relatedTickers: s.relatedTickers ?? [],
|
|
});
|
|
}
|
|
}
|
|
} catch {
|
|
/* skip failed query */
|
|
}
|
|
}
|
|
return [...seen.values()].slice(0, MAX_STORIES);
|
|
}
|
|
|
|
_extractTickers(stories) {
|
|
const tickers = new Set();
|
|
for (const { relatedTickers } of stories) {
|
|
for (const t of relatedTickers) {
|
|
const clean = t.split(':')[0].toUpperCase();
|
|
if (TICKER_REGEX.test(clean)) tickers.add(clean);
|
|
}
|
|
}
|
|
return [...tickers];
|
|
}
|
|
}
|