@fin.cx/opendata 3.0.0 → 3.2.0
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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/stocks/classes.baseproviderservice.d.ts +129 -0
- package/dist_ts/stocks/classes.baseproviderservice.js +204 -0
- package/dist_ts/stocks/classes.fundamentalsservice.d.ts +104 -0
- package/dist_ts/stocks/classes.fundamentalsservice.js +298 -0
- package/dist_ts/stocks/classes.stockdataservice.d.ts +121 -0
- package/dist_ts/stocks/classes.stockdataservice.js +495 -0
- package/dist_ts/stocks/index.d.ts +6 -0
- package/dist_ts/stocks/index.js +9 -2
- package/dist_ts/stocks/interfaces/fundamentals.d.ts +82 -0
- package/dist_ts/stocks/interfaces/fundamentals.js +6 -0
- package/dist_ts/stocks/interfaces/stockdata.d.ts +57 -0
- package/dist_ts/stocks/interfaces/stockdata.js +2 -0
- package/dist_ts/stocks/providers/provider.secedgar.d.ts +102 -0
- package/dist_ts/stocks/providers/provider.secedgar.js +343 -0
- package/package.json +1 -1
- package/readme.md +453 -403
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/stocks/classes.baseproviderservice.ts +296 -0
- package/ts/stocks/classes.fundamentalsservice.ts +404 -0
- package/ts/stocks/classes.stockdataservice.ts +647 -0
- package/ts/stocks/index.ts +10 -2
- package/ts/stocks/interfaces/fundamentals.ts +102 -0
- package/ts/stocks/interfaces/stockdata.ts +65 -0
- package/ts/stocks/providers/provider.secedgar.ts +429 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@fin.cx/opendata',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.2.0',
|
|
7
7
|
description: 'A comprehensive TypeScript library for accessing business data and real-time financial information. Features include German company data management with MongoDB integration, JSONL bulk processing, automated Handelsregister interactions, and real-time stock market data from multiple providers.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxrQkFBa0I7SUFDeEIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHVTQUF1UztDQUNyVCxDQUFBIn0=
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base provider entry for tracking provider state
|
|
3
|
+
*/
|
|
4
|
+
export interface IBaseProviderEntry<TProvider> {
|
|
5
|
+
provider: TProvider;
|
|
6
|
+
config: IBaseProviderConfig;
|
|
7
|
+
lastError?: Error;
|
|
8
|
+
lastErrorTime?: Date;
|
|
9
|
+
successCount: number;
|
|
10
|
+
errorCount: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Base provider configuration
|
|
14
|
+
*/
|
|
15
|
+
export interface IBaseProviderConfig {
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
priority: number;
|
|
18
|
+
timeout?: number;
|
|
19
|
+
retryAttempts?: number;
|
|
20
|
+
retryDelay?: number;
|
|
21
|
+
cacheTTL?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Base provider interface
|
|
25
|
+
*/
|
|
26
|
+
export interface IBaseProvider {
|
|
27
|
+
name: string;
|
|
28
|
+
priority: number;
|
|
29
|
+
isAvailable(): Promise<boolean>;
|
|
30
|
+
readonly requiresAuth: boolean;
|
|
31
|
+
readonly rateLimit?: {
|
|
32
|
+
requestsPerMinute: number;
|
|
33
|
+
requestsPerDay?: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Cache entry for any data type
|
|
38
|
+
*/
|
|
39
|
+
export interface IBaseCacheEntry<TData> {
|
|
40
|
+
data: TData;
|
|
41
|
+
timestamp: Date;
|
|
42
|
+
ttl: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Base service for managing data providers with caching
|
|
46
|
+
* Shared logic extracted from StockPriceService and FundamentalsService
|
|
47
|
+
*/
|
|
48
|
+
export declare abstract class BaseProviderService<TProvider extends IBaseProvider, TData> {
|
|
49
|
+
protected providers: Map<string, IBaseProviderEntry<TProvider>>;
|
|
50
|
+
protected cache: Map<string, IBaseCacheEntry<TData>>;
|
|
51
|
+
protected logger: Console;
|
|
52
|
+
protected cacheConfig: {
|
|
53
|
+
ttl: number;
|
|
54
|
+
maxEntries: number;
|
|
55
|
+
};
|
|
56
|
+
constructor(cacheConfig?: {
|
|
57
|
+
ttl?: number;
|
|
58
|
+
maxEntries?: number;
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* Register a provider
|
|
62
|
+
*/
|
|
63
|
+
register(provider: TProvider, config?: Partial<IBaseProviderConfig>): void;
|
|
64
|
+
/**
|
|
65
|
+
* Unregister a provider
|
|
66
|
+
*/
|
|
67
|
+
unregister(providerName: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* Get a specific provider by name
|
|
70
|
+
*/
|
|
71
|
+
getProvider(name: string): TProvider | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Get all registered providers
|
|
74
|
+
*/
|
|
75
|
+
getAllProviders(): TProvider[];
|
|
76
|
+
/**
|
|
77
|
+
* Get enabled providers sorted by priority
|
|
78
|
+
*/
|
|
79
|
+
getEnabledProviders(): TProvider[];
|
|
80
|
+
/**
|
|
81
|
+
* Check health of all providers
|
|
82
|
+
*/
|
|
83
|
+
checkProvidersHealth(): Promise<Map<string, boolean>>;
|
|
84
|
+
/**
|
|
85
|
+
* Get provider statistics
|
|
86
|
+
*/
|
|
87
|
+
getProviderStats(): Map<string, {
|
|
88
|
+
successCount: number;
|
|
89
|
+
errorCount: number;
|
|
90
|
+
lastError?: string;
|
|
91
|
+
lastErrorTime?: Date;
|
|
92
|
+
}>;
|
|
93
|
+
/**
|
|
94
|
+
* Clear all cached data
|
|
95
|
+
*/
|
|
96
|
+
clearCache(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Set cache TTL
|
|
99
|
+
*/
|
|
100
|
+
setCacheTTL(ttl: number): void;
|
|
101
|
+
/**
|
|
102
|
+
* Get cache statistics
|
|
103
|
+
*/
|
|
104
|
+
getCacheStats(): {
|
|
105
|
+
size: number;
|
|
106
|
+
maxEntries: number;
|
|
107
|
+
ttl: number;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Fetch with retry logic
|
|
111
|
+
*/
|
|
112
|
+
protected fetchWithRetry<T>(fetchFn: () => Promise<T>, config: IBaseProviderConfig): Promise<T>;
|
|
113
|
+
/**
|
|
114
|
+
* Get from cache if not expired
|
|
115
|
+
*/
|
|
116
|
+
protected getFromCache(key: string): TData | null;
|
|
117
|
+
/**
|
|
118
|
+
* Add to cache with TTL
|
|
119
|
+
*/
|
|
120
|
+
protected addToCache(key: string, data: TData, ttl?: number): void;
|
|
121
|
+
/**
|
|
122
|
+
* Track successful fetch for provider
|
|
123
|
+
*/
|
|
124
|
+
protected trackSuccess(providerName: string): void;
|
|
125
|
+
/**
|
|
126
|
+
* Track failed fetch for provider
|
|
127
|
+
*/
|
|
128
|
+
protected trackError(providerName: string, error: Error): void;
|
|
129
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base service for managing data providers with caching
|
|
4
|
+
* Shared logic extracted from StockPriceService and FundamentalsService
|
|
5
|
+
*/
|
|
6
|
+
export class BaseProviderService {
|
|
7
|
+
constructor(cacheConfig) {
|
|
8
|
+
this.providers = new Map();
|
|
9
|
+
this.cache = new Map();
|
|
10
|
+
this.logger = console;
|
|
11
|
+
this.cacheConfig = {
|
|
12
|
+
ttl: 60000, // Default 60 seconds
|
|
13
|
+
maxEntries: 10000
|
|
14
|
+
};
|
|
15
|
+
if (cacheConfig) {
|
|
16
|
+
this.cacheConfig = { ...this.cacheConfig, ...cacheConfig };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register a provider
|
|
21
|
+
*/
|
|
22
|
+
register(provider, config) {
|
|
23
|
+
const defaultConfig = {
|
|
24
|
+
enabled: true,
|
|
25
|
+
priority: provider.priority,
|
|
26
|
+
timeout: 30000,
|
|
27
|
+
retryAttempts: 2,
|
|
28
|
+
retryDelay: 1000,
|
|
29
|
+
cacheTTL: this.cacheConfig.ttl
|
|
30
|
+
};
|
|
31
|
+
const mergedConfig = { ...defaultConfig, ...config };
|
|
32
|
+
this.providers.set(provider.name, {
|
|
33
|
+
provider,
|
|
34
|
+
config: mergedConfig,
|
|
35
|
+
successCount: 0,
|
|
36
|
+
errorCount: 0
|
|
37
|
+
});
|
|
38
|
+
console.log(`Registered provider: ${provider.name}`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Unregister a provider
|
|
42
|
+
*/
|
|
43
|
+
unregister(providerName) {
|
|
44
|
+
this.providers.delete(providerName);
|
|
45
|
+
console.log(`Unregistered provider: ${providerName}`);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get a specific provider by name
|
|
49
|
+
*/
|
|
50
|
+
getProvider(name) {
|
|
51
|
+
return this.providers.get(name)?.provider;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get all registered providers
|
|
55
|
+
*/
|
|
56
|
+
getAllProviders() {
|
|
57
|
+
return Array.from(this.providers.values()).map(entry => entry.provider);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get enabled providers sorted by priority
|
|
61
|
+
*/
|
|
62
|
+
getEnabledProviders() {
|
|
63
|
+
return Array.from(this.providers.values())
|
|
64
|
+
.filter(entry => entry.config.enabled)
|
|
65
|
+
.sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0))
|
|
66
|
+
.map(entry => entry.provider);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check health of all providers
|
|
70
|
+
*/
|
|
71
|
+
async checkProvidersHealth() {
|
|
72
|
+
const health = new Map();
|
|
73
|
+
for (const [name, entry] of this.providers) {
|
|
74
|
+
if (!entry.config.enabled) {
|
|
75
|
+
health.set(name, false);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const isAvailable = await entry.provider.isAvailable();
|
|
80
|
+
health.set(name, isAvailable);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
health.set(name, false);
|
|
84
|
+
console.error(`Health check failed for ${name}:`, error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return health;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get provider statistics
|
|
91
|
+
*/
|
|
92
|
+
getProviderStats() {
|
|
93
|
+
const stats = new Map();
|
|
94
|
+
for (const [name, entry] of this.providers) {
|
|
95
|
+
stats.set(name, {
|
|
96
|
+
successCount: entry.successCount,
|
|
97
|
+
errorCount: entry.errorCount,
|
|
98
|
+
lastError: entry.lastError?.message,
|
|
99
|
+
lastErrorTime: entry.lastErrorTime
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return stats;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clear all cached data
|
|
106
|
+
*/
|
|
107
|
+
clearCache() {
|
|
108
|
+
this.cache.clear();
|
|
109
|
+
console.log('Cache cleared');
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Set cache TTL
|
|
113
|
+
*/
|
|
114
|
+
setCacheTTL(ttl) {
|
|
115
|
+
this.cacheConfig.ttl = ttl;
|
|
116
|
+
console.log(`Cache TTL set to ${ttl}ms`);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get cache statistics
|
|
120
|
+
*/
|
|
121
|
+
getCacheStats() {
|
|
122
|
+
return {
|
|
123
|
+
size: this.cache.size,
|
|
124
|
+
maxEntries: this.cacheConfig.maxEntries,
|
|
125
|
+
ttl: this.cacheConfig.ttl
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Fetch with retry logic
|
|
130
|
+
*/
|
|
131
|
+
async fetchWithRetry(fetchFn, config) {
|
|
132
|
+
const maxAttempts = config.retryAttempts || 1;
|
|
133
|
+
let lastError;
|
|
134
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
135
|
+
try {
|
|
136
|
+
return await fetchFn();
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
lastError = error;
|
|
140
|
+
if (attempt < maxAttempts) {
|
|
141
|
+
const delay = (config.retryDelay || 1000) * attempt;
|
|
142
|
+
console.log(`Retry attempt ${attempt} after ${delay}ms`);
|
|
143
|
+
await plugins.smartdelay.delayFor(delay);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
throw lastError || new Error('Unknown error during fetch');
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get from cache if not expired
|
|
151
|
+
*/
|
|
152
|
+
getFromCache(key) {
|
|
153
|
+
const entry = this.cache.get(key);
|
|
154
|
+
if (!entry) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
// Check if cache entry has expired
|
|
158
|
+
const age = Date.now() - entry.timestamp.getTime();
|
|
159
|
+
if (entry.ttl !== Infinity && age > entry.ttl) {
|
|
160
|
+
this.cache.delete(key);
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return entry.data;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Add to cache with TTL
|
|
167
|
+
*/
|
|
168
|
+
addToCache(key, data, ttl) {
|
|
169
|
+
// Enforce max entries limit
|
|
170
|
+
if (this.cache.size >= this.cacheConfig.maxEntries) {
|
|
171
|
+
// Remove oldest entry
|
|
172
|
+
const oldestKey = this.cache.keys().next().value;
|
|
173
|
+
if (oldestKey) {
|
|
174
|
+
this.cache.delete(oldestKey);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
this.cache.set(key, {
|
|
178
|
+
data,
|
|
179
|
+
timestamp: new Date(),
|
|
180
|
+
ttl: ttl || this.cacheConfig.ttl
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Track successful fetch for provider
|
|
185
|
+
*/
|
|
186
|
+
trackSuccess(providerName) {
|
|
187
|
+
const entry = this.providers.get(providerName);
|
|
188
|
+
if (entry) {
|
|
189
|
+
entry.successCount++;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Track failed fetch for provider
|
|
194
|
+
*/
|
|
195
|
+
trackError(providerName, error) {
|
|
196
|
+
const entry = this.providers.get(providerName);
|
|
197
|
+
if (entry) {
|
|
198
|
+
entry.errorCount++;
|
|
199
|
+
entry.lastError = error;
|
|
200
|
+
entry.lastErrorTime = new Date();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5iYXNlcHJvdmlkZXJzZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvc3RvY2tzL2NsYXNzZXMuYmFzZXByb3ZpZGVyc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQWlEekM7OztHQUdHO0FBQ0gsTUFBTSxPQUFnQixtQkFBbUI7SUFVdkMsWUFBWSxXQUFtRDtRQVRyRCxjQUFTLEdBQUcsSUFBSSxHQUFHLEVBQXlDLENBQUM7UUFDN0QsVUFBSyxHQUFHLElBQUksR0FBRyxFQUFrQyxDQUFDO1FBQ2xELFdBQU0sR0FBRyxPQUFPLENBQUM7UUFFakIsZ0JBQVcsR0FBRztZQUN0QixHQUFHLEVBQUUsS0FBSyxFQUFFLHFCQUFxQjtZQUNqQyxVQUFVLEVBQUUsS0FBSztTQUNsQixDQUFDO1FBR0EsSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNoQixJQUFJLENBQUMsV0FBVyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsV0FBVyxFQUFFLENBQUM7UUFDN0QsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNJLFFBQVEsQ0FBQyxRQUFtQixFQUFFLE1BQXFDO1FBQ3hFLE1BQU0sYUFBYSxHQUF3QjtZQUN6QyxPQUFPLEVBQUUsSUFBSTtZQUNiLFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUTtZQUMzQixPQUFPLEVBQUUsS0FBSztZQUNkLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLFVBQVUsRUFBRSxJQUFJO1lBQ2hCLFFBQVEsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUc7U0FDL0IsQ0FBQztRQUVGLE1BQU0sWUFBWSxHQUFHLEVBQUUsR0FBRyxhQUFhLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztRQUVyRCxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFO1lBQ2hDLFFB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
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { IFundamentalsProvider, IFundamentalsProviderConfig, IFundamentalsProviderRegistry, IStockFundamentals, IFundamentalsRequest } from './interfaces/fundamentals.js';
|
|
2
|
+
/**
|
|
3
|
+
* Service for managing fundamental data providers and caching
|
|
4
|
+
* Parallel to StockPriceService but for fundamental data instead of prices
|
|
5
|
+
*/
|
|
6
|
+
export declare class FundamentalsService implements IFundamentalsProviderRegistry {
|
|
7
|
+
private providers;
|
|
8
|
+
private cache;
|
|
9
|
+
private logger;
|
|
10
|
+
private cacheConfig;
|
|
11
|
+
constructor(cacheConfig?: {
|
|
12
|
+
ttl?: number;
|
|
13
|
+
maxEntries?: number;
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* Register a fundamentals provider
|
|
17
|
+
*/
|
|
18
|
+
register(provider: IFundamentalsProvider, config?: IFundamentalsProviderConfig): void;
|
|
19
|
+
/**
|
|
20
|
+
* Unregister a provider
|
|
21
|
+
*/
|
|
22
|
+
unregister(providerName: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Get a specific provider by name
|
|
25
|
+
*/
|
|
26
|
+
getProvider(name: string): IFundamentalsProvider | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Get all registered providers
|
|
29
|
+
*/
|
|
30
|
+
getAllProviders(): IFundamentalsProvider[];
|
|
31
|
+
/**
|
|
32
|
+
* Get enabled providers sorted by priority
|
|
33
|
+
*/
|
|
34
|
+
getEnabledProviders(): IFundamentalsProvider[];
|
|
35
|
+
/**
|
|
36
|
+
* Get fundamental data for a single ticker
|
|
37
|
+
*/
|
|
38
|
+
getFundamentals(ticker: string): Promise<IStockFundamentals>;
|
|
39
|
+
/**
|
|
40
|
+
* Get fundamental data for multiple tickers
|
|
41
|
+
*/
|
|
42
|
+
getBatchFundamentals(tickers: string[]): Promise<IStockFundamentals[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Unified data fetching method
|
|
45
|
+
*/
|
|
46
|
+
getData(request: IFundamentalsRequest): Promise<IStockFundamentals | IStockFundamentals[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Enrich fundamentals with calculated metrics using current price
|
|
49
|
+
*/
|
|
50
|
+
enrichWithPrice(fundamentals: IStockFundamentals, price: number): Promise<IStockFundamentals>;
|
|
51
|
+
/**
|
|
52
|
+
* Enrich batch fundamentals with prices
|
|
53
|
+
*/
|
|
54
|
+
enrichBatchWithPrices(fundamentalsList: IStockFundamentals[], priceMap: Map<string, number>): Promise<IStockFundamentals[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Check health of all providers
|
|
57
|
+
*/
|
|
58
|
+
checkProvidersHealth(): Promise<Map<string, boolean>>;
|
|
59
|
+
/**
|
|
60
|
+
* Get provider statistics
|
|
61
|
+
*/
|
|
62
|
+
getProviderStats(): Map<string, {
|
|
63
|
+
successCount: number;
|
|
64
|
+
errorCount: number;
|
|
65
|
+
lastError?: string;
|
|
66
|
+
lastErrorTime?: Date;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Clear all cached data
|
|
70
|
+
*/
|
|
71
|
+
clearCache(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Set cache TTL
|
|
74
|
+
*/
|
|
75
|
+
setCacheTTL(ttl: number): void;
|
|
76
|
+
/**
|
|
77
|
+
* Get cache statistics
|
|
78
|
+
*/
|
|
79
|
+
getCacheStats(): {
|
|
80
|
+
size: number;
|
|
81
|
+
maxEntries: number;
|
|
82
|
+
ttl: number;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Fetch with retry logic
|
|
86
|
+
*/
|
|
87
|
+
private fetchWithRetry;
|
|
88
|
+
/**
|
|
89
|
+
* Generate cache key for request
|
|
90
|
+
*/
|
|
91
|
+
private getCacheKey;
|
|
92
|
+
/**
|
|
93
|
+
* Get from cache if not expired
|
|
94
|
+
*/
|
|
95
|
+
private getFromCache;
|
|
96
|
+
/**
|
|
97
|
+
* Add to cache with TTL
|
|
98
|
+
*/
|
|
99
|
+
private addToCache;
|
|
100
|
+
/**
|
|
101
|
+
* Get human-readable request description
|
|
102
|
+
*/
|
|
103
|
+
private getRequestDescription;
|
|
104
|
+
}
|