Files
market_screener/server/clients/YahooFinanceClient.ts
T
2026-06-05 23:34:25 -04:00

53 lines
1.6 KiB
TypeScript

import YahooFinance from 'yahoo-finance2';
import type { YahooNewsItem, YahooSearchOptions, YahooFinanceLib } from '../types';
import { YAHOO_MODULES } from '../config/constants';
export class YahooFinanceClient {
private lib: YahooFinanceLib;
constructor() {
this.lib = new (YahooFinance as unknown as new (_opts: object) => YahooFinanceLib)({
suppressNotices: ['yahooSurvey'],
});
}
/** Normalise ticker before hitting Yahoo: BRK.B → BRK-B */
private static normalise(ticker: string): string {
return ticker.toUpperCase().replace(/\./g, '-');
}
async fetchSummary(ticker: string, retries = 3, backoff = 1000): Promise<any> {
const normalised = YahooFinanceClient.normalise(ticker);
for (let attempt = 0; attempt < retries; attempt++) {
try {
return await this.lib.quoteSummary(
normalised,
{ modules: YAHOO_MODULES },
{ validateResult: false },
);
} catch (error) {
if (attempt === retries - 1) throw error;
await new Promise<void>((resolve) => setTimeout(resolve, backoff * (attempt + 1)));
}
}
}
async fetchCalendarEvents(ticker: string): Promise<any | null> {
try {
const result = await this.lib.quoteSummary(
YahooFinanceClient.normalise(ticker),
{ modules: ['calendarEvents'] },
{ validateResult: false },
);
return result.calendarEvents ?? null;
} catch {
return null;
}
}
async search(query: string, opts: YahooSearchOptions = {}): Promise<YahooNewsItem[]> {
const { news = [] } = await this.lib.search(query, opts);
return news;
}
}