feat(stocks): Add provider fetch limits, intraday incremental fetch, cache deduplication, and provider safety/warning improvements
This commit is contained in:
@@ -378,8 +378,18 @@ export class CoinGeckoProvider implements IStockProvider {
|
||||
const marketCapData = responseData.market_caps || [];
|
||||
const volumeData = responseData.total_volumes || [];
|
||||
|
||||
// Process each data point
|
||||
for (let i = 0; i < priceData.length; i++) {
|
||||
// Warn if processing large amount of historical data
|
||||
const maxRecords = this.config?.maxRecords || 10000;
|
||||
if (priceData.length > maxRecords) {
|
||||
this.logger.warn(
|
||||
`Historical request for ${request.ticker} returned ${priceData.length} records, ` +
|
||||
`which exceeds maxRecords limit of ${maxRecords}. Processing first ${maxRecords} only.`
|
||||
);
|
||||
}
|
||||
|
||||
// Process each data point (up to maxRecords)
|
||||
const recordsToProcess = Math.min(priceData.length, maxRecords);
|
||||
for (let i = 0; i < recordsToProcess; i++) {
|
||||
const [timestamp, price] = priceData[i];
|
||||
const date = new Date(timestamp);
|
||||
|
||||
@@ -480,8 +490,19 @@ export class CoinGeckoProvider implements IStockProvider {
|
||||
const marketCapData = responseData.market_caps || [];
|
||||
const volumeData = responseData.total_volumes || [];
|
||||
|
||||
// Apply limit if specified
|
||||
const limit = request.limit || priceData.length;
|
||||
// Apply default limit if user didn't specify one (performance optimization)
|
||||
const effectiveLimit = request.limit || this.config?.defaultIntradayLimit || 1000;
|
||||
|
||||
// Warn if fetching large amount of data without explicit limit
|
||||
if (!request.limit && priceData.length > effectiveLimit) {
|
||||
this.logger.warn(
|
||||
`Intraday request for ${request.ticker} returned ${priceData.length} records but no limit specified. ` +
|
||||
`Applying default limit of ${effectiveLimit}. Consider adding a limit to the request for better performance.`
|
||||
);
|
||||
}
|
||||
|
||||
// Apply limit (take most recent data)
|
||||
const limit = Math.min(effectiveLimit, priceData.length);
|
||||
const dataToProcess = priceData.slice(-limit);
|
||||
|
||||
for (let i = 0; i < dataToProcess.length; i++) {
|
||||
@@ -624,21 +645,34 @@ export class CoinGeckoProvider implements IStockProvider {
|
||||
|
||||
const coinList = await response.json() as ICoinListItem[];
|
||||
|
||||
// Clear cache before rebuilding to prevent memory leak
|
||||
// Keep only entries that are in priorityTickerMap
|
||||
const priorityEntries = new Map<string, string>();
|
||||
for (const [key, value] of this.priorityTickerMap) {
|
||||
priorityEntries.set(key, value);
|
||||
}
|
||||
this.coinMapCache.clear();
|
||||
|
||||
// Restore priority mappings
|
||||
for (const [key, value] of priorityEntries) {
|
||||
this.coinMapCache.set(key, value);
|
||||
}
|
||||
|
||||
// Build mapping: symbol -> id
|
||||
for (const coin of coinList) {
|
||||
const symbol = coin.symbol.toLowerCase();
|
||||
const id = coin.id.toLowerCase();
|
||||
|
||||
// Don't overwrite priority mappings or existing cache entries
|
||||
if (!this.priorityTickerMap.has(symbol) && !this.coinMapCache.has(symbol)) {
|
||||
// Don't overwrite priority mappings
|
||||
if (!this.priorityTickerMap.has(symbol)) {
|
||||
this.coinMapCache.set(symbol, id);
|
||||
}
|
||||
// Always cache the ID mapping
|
||||
// Always cache the ID mapping (id -> id for when users pass CoinGecko IDs directly)
|
||||
this.coinMapCache.set(id, id);
|
||||
}
|
||||
|
||||
this.coinListLoadedAt = new Date();
|
||||
this.logger.info(`Loaded ${coinList.length} coins from CoinGecko`);
|
||||
this.logger.info(`Loaded ${coinList.length} coins from CoinGecko (cache: ${this.coinMapCache.size} entries)`);
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to load coin list from CoinGecko:', error);
|
||||
// Don't throw - we can still work with direct IDs
|
||||
|
||||
Reference in New Issue
Block a user