bulltrackers-module 1.0.498 → 1.0.500
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.
|
@@ -95,12 +95,23 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
95
95
|
logger.log('INFO', `[RootDataIndexer] Starting Root Data Availability Scan... Mode: ${scanMode}`, { targetDate });
|
|
96
96
|
|
|
97
97
|
// 1. Price Availability - Read from date tracking documents
|
|
98
|
-
// Find the latest
|
|
98
|
+
// Find the latest price tracking document and extract available dates
|
|
99
99
|
const priceAvailabilitySet = new Set();
|
|
100
100
|
|
|
101
|
+
// Get price tracking collection name from registry if available
|
|
102
|
+
let priceTrackingCollectionName = 'pricedatastoreddates';
|
|
103
|
+
if (dependencies.collectionRegistry && dependencies.collectionRegistry.getCollectionPath) {
|
|
104
|
+
try {
|
|
105
|
+
const trackingPath = dependencies.collectionRegistry.getCollectionPath('rootData', 'priceTracking', { fetchDate: '2025-01-01' });
|
|
106
|
+
priceTrackingCollectionName = trackingPath.split('/')[0];
|
|
107
|
+
} catch (e) {
|
|
108
|
+
logger.log('WARN', `[RootDataIndexer] Failed to get price tracking collection from registry, using default: ${e.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
101
112
|
try {
|
|
102
113
|
// Get the latest price date tracking document
|
|
103
|
-
const dateTrackingRef = db.collection(
|
|
114
|
+
const dateTrackingRef = db.collection(priceTrackingCollectionName)
|
|
104
115
|
.orderBy('fetchDate', 'desc')
|
|
105
116
|
.limit(1);
|
|
106
117
|
|
|
@@ -109,6 +120,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
109
120
|
if (!dateTrackingSnapshot.empty) {
|
|
110
121
|
const latestTrackingDoc = dateTrackingSnapshot.docs[0].data();
|
|
111
122
|
const datesAvailable = latestTrackingDoc.datesAvailable || [];
|
|
123
|
+
const fetchDate = latestTrackingDoc.fetchDate;
|
|
112
124
|
|
|
113
125
|
// Add all dates from the tracking document
|
|
114
126
|
datesAvailable.forEach(dateKey => {
|
|
@@ -117,7 +129,22 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
117
129
|
}
|
|
118
130
|
});
|
|
119
131
|
|
|
120
|
-
|
|
132
|
+
// IMPORTANT: If the tracking document was written for today (fetchDate matches targetDate),
|
|
133
|
+
// we should consider prices available for that date even if the API didn't return that exact date.
|
|
134
|
+
// This is because the price fetcher ran for that date and stored prices (even if they're historical).
|
|
135
|
+
if (targetDate && fetchDate === targetDate) {
|
|
136
|
+
priceAvailabilitySet.add(targetDate);
|
|
137
|
+
logger.log('INFO', `[RootDataIndexer] Added fetchDate (${fetchDate}) to price availability set for target date check`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
logger.log('INFO', `[RootDataIndexer] Loaded ${priceAvailabilitySet.size} price dates from tracking document (fetchDate: ${fetchDate})`);
|
|
141
|
+
|
|
142
|
+
// Debug: Log a sample of dates and check if target date is present
|
|
143
|
+
if (targetDate) {
|
|
144
|
+
const sampleDates = Array.from(priceAvailabilitySet).slice(0, 5);
|
|
145
|
+
const hasTargetDate = priceAvailabilitySet.has(targetDate);
|
|
146
|
+
logger.log('INFO', `[RootDataIndexer] Price availability check for ${targetDate}: ${hasTargetDate ? 'FOUND' : 'NOT FOUND'}. Sample dates: ${sampleDates.join(', ')}`);
|
|
147
|
+
}
|
|
121
148
|
} else {
|
|
122
149
|
logger.log('WARN', '[RootDataIndexer] No price date tracking documents found. Falling back to empty set.');
|
|
123
150
|
}
|
|
@@ -266,11 +293,11 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
266
293
|
// Single tracking documents at root level:
|
|
267
294
|
// - PopularInvestorSocialPostData/_dates -> fetchedDates.{date}
|
|
268
295
|
// - SignedInUserSocialPostData/_dates -> fetchedDates.{date}
|
|
269
|
-
// For generic social (InstrumentFeedSocialPostData), check the
|
|
296
|
+
// For generic social (InstrumentFeedSocialPostData), check the posts subcollection
|
|
270
297
|
const [piSocialTrackingDoc, signedInSocialTrackingDoc, genericSocialSnap] = await Promise.all([
|
|
271
298
|
db.collection('PopularInvestorSocialPostData').doc('_dates').get(),
|
|
272
299
|
db.collection('SignedInUserSocialPostData').doc('_dates').get(),
|
|
273
|
-
db.collection('InstrumentFeedSocialPostData').doc(dateStr).limit(1).get()
|
|
300
|
+
db.collection('InstrumentFeedSocialPostData').doc(dateStr).collection('posts').limit(1).get()
|
|
274
301
|
]);
|
|
275
302
|
|
|
276
303
|
// Check if date exists in tracking documents
|
|
@@ -326,7 +353,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
326
353
|
const [
|
|
327
354
|
normPortExists, specPortExists,
|
|
328
355
|
normHistExists, specHistExists,
|
|
329
|
-
insightsSnap,
|
|
356
|
+
insightsSnap, genericSocialExists,
|
|
330
357
|
piRankingsSnap,
|
|
331
358
|
piPortExists,
|
|
332
359
|
piDeepExists,
|
|
@@ -339,7 +366,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
339
366
|
checkAnyPartExists(normHistPartsRef),
|
|
340
367
|
checkAnyPartExists(specHistPartsRef),
|
|
341
368
|
insightsRef.get(),
|
|
342
|
-
|
|
369
|
+
Promise.resolve(!genericSocialSnap.empty),
|
|
343
370
|
piRankingsRef.get(),
|
|
344
371
|
// Check new structure first, fallback to legacy
|
|
345
372
|
checkDateCollectionHasDocs(piPortfoliosCollectionRef).then(exists => exists || checkAnyPartExists(piPortfoliosPartsRef)),
|
|
@@ -392,20 +419,16 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
392
419
|
availability.hasPortfolio = normPortExists || specPortExists || piPortExists || signedInPortExists;
|
|
393
420
|
availability.hasHistory = normHistExists || specHistExists || piHistExists || signedInHistExists;
|
|
394
421
|
availability.hasInsights = insightsSnap.exists;
|
|
395
|
-
availability.hasSocial =
|
|
422
|
+
availability.hasSocial = foundPISocial || foundSignedInSocial || genericSocialExists;
|
|
396
423
|
|
|
397
424
|
// Price Check
|
|
398
|
-
if
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
// NOTE: The Global Scan at 01:00 UTC will strictly verify prices.
|
|
406
|
-
availability.hasPrices = priceAvailabilitySet.has(dateStr);
|
|
407
|
-
} else {
|
|
408
|
-
availability.hasPrices = priceAvailabilitySet.has(dateStr);
|
|
425
|
+
// Check if the target date exists in the price availability set
|
|
426
|
+
// The set is populated from the price tracking document's datesAvailable array
|
|
427
|
+
const hasPriceForDate = priceAvailabilitySet.has(dateStr);
|
|
428
|
+
availability.hasPrices = hasPriceForDate;
|
|
429
|
+
|
|
430
|
+
if (targetDate && !hasPriceForDate) {
|
|
431
|
+
logger.log('WARN', `[RootDataIndexer/${dateStr}] Price data not found in tracking document. Set size: ${priceAvailabilitySet.size}, Date checked: ${dateStr}`);
|
|
409
432
|
}
|
|
410
433
|
|
|
411
434
|
await db.collection(availabilityCollection).doc(dateStr).set(availability);
|