bulltrackers-module 1.0.25 → 1.0.26

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.
@@ -3,9 +3,9 @@
3
3
  */
4
4
 
5
5
  const { runComputationOrchestrator } = require('./helpers/orchestration_helpers.js');
6
- const { createComputationSystemHandler } = require('./handler_creator.js'); // <-- Import the new factory
6
+ const { createComputationSystemHandler } = require('./handler_creator.js');
7
7
 
8
8
  module.exports = {
9
9
  runComputationOrchestrator,
10
- createComputationSystemHandler, // <-- Export the factory
10
+ createComputationSystemHandler,
11
11
  };
@@ -6,9 +6,7 @@
6
6
  const { logger } = require("sharedsetup")(__filename);
7
7
  const { withRetry } = require('aiden-shared-calculations-unified').utils;
8
8
 
9
- // REMOVE Constants like COLLECTIONS_TO_QUERY, PART_REF_BATCH_SIZE
10
9
 
11
- // Modify getPortfolioPartRefs to accept config
12
10
  /**
13
11
  * Gets a list of all portfolio "part" document references for a given date.
14
12
  *
@@ -6,17 +6,14 @@
6
6
 
7
7
  const { FieldValue, FieldPath } = require('@google-cloud/firestore');
8
8
  const { logger } = require("sharedsetup")(__filename);
9
- // Import calculations and utils from the unified package
10
9
  const { calculations, utils } = require('aiden-shared-calculations-unified');
11
10
  const { withRetry } = utils; // Get withRetry from the package utils
12
11
 
13
- // REMOVE Constants like BATCH_SIZE_LIMIT, MAX_CONCURRENT_DATES
14
12
 
15
13
  // --- Calculation Categorization ---
16
- // This relies on the structure exported by 'aiden-shared-calculations-unified'
17
14
  const HISTORICAL_CALC_NAMES = new Set([
18
15
  'paper-vs-diamond-hands', 'smart-money-flow', 'profitability-migration',
19
- 'user-profitability-tracker', 'sector-rotation', 'crowd-conviction-score',
16
+ 'user-profitability-tracker', 'sector-rotation', 'crowd-conviction-score', // TODO Abstract these
20
17
  'risk-appetite-change', 'drawdown-response', 'gain-response',
21
18
  'tsl-effectiveness', 'position-count-pnl', 'diversification-pnl'
22
19
  ]);
@@ -24,7 +21,6 @@ const HISTORICAL_CALC_NAMES = new Set([
24
21
  const historicalCalculations = {};
25
22
  const dailyCalculations = {};
26
23
 
27
- // Assuming 'calculations' from the package has the same category structure
28
24
  for (const category in calculations) {
29
25
  for (const calcName in calculations[category]) {
30
26
  if (HISTORICAL_CALC_NAMES.has(calcName)) {
@@ -6,7 +6,7 @@ const { logger } = require("sharedsetup")(__filename);
6
6
 
7
7
  const db = new Firestore();
8
8
 
9
- const MAX_FIRESTORE_BATCH_SIZE = 500; // Firestore batch limit
9
+ const MAX_FIRESTORE_BATCH_SIZE = 400; // Firestore batch limit TODO Abstract this
10
10
 
11
11
  /**
12
12
  * Fetches and merges the most recent portfolio data for all normal users.
@@ -36,8 +36,6 @@ async function dispatchTasksInBatches(tasks, pubsubClient, config) {
36
36
  }
37
37
  } catch (publishError) {
38
38
  logger.log('ERROR', `[Module Dispatcher] Failed to publish batch ${Math.ceil((i + 1) / batchSize)}. Error: ${publishError.message}`, { errorStack: publishError.stack });
39
- // Decide on error handling: continue to next batch or throw?
40
- // For now, log and continue, but this might need adjustment based on requirements.
41
39
  }
42
40
  }
43
41
 
@@ -40,7 +40,7 @@ function createDispatcherHandler(config, pubsubClient) {
40
40
  } catch (error) {
41
41
  // Catch errors during decoding or major setup issues
42
42
  logger.log('ERROR', '[Module Dispatcher] FATAL error processing message', { errorMessage: error.message, errorStack: error.stack });
43
- // Re-throw to signal Pub/Sub to potentially retry (depending on subscription settings)
43
+ // Re-throw to signal Pub/Sub to potentially retry (depending on subscription settings) TODO - Do not retry?
44
44
  throw error;
45
45
  }
46
46
  };
@@ -109,7 +109,7 @@ exports.fetchAndStorePrices = async (firestore, logger, headerManager, proxyMana
109
109
  batch = firestore.batch(); // Start new batch
110
110
  batchCount = 0;
111
111
 
112
- // Optional: Add a small delay between large batch commits if needed
112
+ // Add a small delay between large batch commits if needed
113
113
  await new Promise(resolve => setTimeout(resolve, 50));
114
114
  }
115
115
  }
@@ -40,7 +40,7 @@ exports.fetchAndStoreInsights = async (firestore, logger, headerManager, proxyMa
40
40
  // Pass only the necessary parts of the selected header object
41
41
  const fetchOptions = {
42
42
  headers: selectedHeader.header, // Pass the actual header object
43
- timeout: 30000 // 30 second timeout - Note: Proxy manager might have its own timeout logic
43
+ timeout: 30000 // 30 second timeout - Note: Proxy manager might have its own timeout logic TODO - Check if this is needed?
44
44
  };
45
45
  const { response } = await proxyManager.fetch(config.etoroInsightsUrl, fetchOptions);
46
46
 
@@ -78,7 +78,7 @@ const getDateStringsInRange = (startDate, endDate) => {
78
78
  const fetchUnifiedData = async (config, firestore, logger, calcKeys, dateStrings, calcMap) => {
79
79
  const response = {};
80
80
  // Use collection/subcollection names from config
81
- const insightsCollection = config.unifiedInsightsCollection || 'unified_insights';
81
+ const insightsCollection = config.unifiedInsightsCollection || 'unified_insights'; //TODO - Decide if we remove the hardcoded backups
82
82
  const resultsSub = config.resultsSubcollection || 'results';
83
83
  const compsSub = config.computationsSubcollection || 'computations';
84
84
 
@@ -37,7 +37,7 @@ exports.handleInvalidSpeculator = async (message, firestore, FieldValue, logger,
37
37
  let targetDocRef;
38
38
 
39
39
  if (!querySnapshot.empty) {
40
- // Randomly select one of the available documents to reduce contention
40
+ // Randomly select one of the available documents to reduce contention TODO - This feels very shortcutty and inefficient
41
41
  const randomIndex = Math.floor(Math.random() * querySnapshot.docs.length);
42
42
  targetDocRef = querySnapshot.docs[randomIndex].ref;
43
43
  } else {
@@ -5,8 +5,6 @@ const { logger } = require("sharedsetup")(__filename);
5
5
  const coreUtils = require('../../core/utils');
6
6
  const { firestore: firestoreUtils, pubsub: pubsubUtils } = coreUtils;
7
7
 
8
- // --- All Constants Removed ---
9
-
10
8
  /**
11
9
  * Checks if discovery is needed for a given user type based on block capacities.
12
10
  * @async
@@ -111,7 +109,7 @@ async function getDiscoveryCandidates(userType, blocksToFill, config) {
111
109
  pendingSpecCollection,
112
110
  normalUserCollection, // Pass name for consistency, though fetch is skipped
113
111
  invalidSpecCollection,
114
- existingNormalUserIds: existingNormalUserIds // <-- Pass pre-fetched IDs
112
+ existingNormalUserIds: existingNormalUserIds
115
113
  });
116
114
 
117
115
  // --- Prioritization for Speculators ---
@@ -120,7 +118,7 @@ async function getDiscoveryCandidates(userType, blocksToFill, config) {
120
118
  const prioritizedCandidates = await firestoreUtils.getPrioritizedSpeculators(
121
119
  exclusionIds,
122
120
  speculatorInstrumentSet,
123
- latestNormalPortfolios // <-- Pass pre-fetched data
121
+ latestNormalPortfolios
124
122
  );
125
123
  logger.log('INFO', `Found ${prioritizedCandidates.length} potential new speculators from existing user pool.`);
126
124
 
@@ -148,7 +146,7 @@ async function getDiscoveryCandidates(userType, blocksToFill, config) {
148
146
 
149
147
  let randomId;
150
148
  let retryCount = 0;
151
- const MAX_RETRIES = 50; // This can remain as it's algorithm-specific
149
+ const MAX_RETRIES = 50;
152
150
  do {
153
151
  if (++retryCount > MAX_RETRIES) break;
154
152
  randomId = String(Math.floor(Math.random() * 1000000) + block.startId);
@@ -188,7 +186,7 @@ async function dispatchDiscovery(userType, candidates, config) {
188
186
  topicName,
189
187
  dispatchBatchSize,
190
188
  pubsubBatchSize,
191
- pendingSpecCollection, // <-- Change to singular
189
+ pendingSpecCollection,
192
190
  pendingMaxFieldsPerDoc,
193
191
  pendingMaxWritesPerBatch
194
192
  } = config;
@@ -203,9 +201,9 @@ async function dispatchDiscovery(userType, candidates, config) {
203
201
  const cidsArray = Array.from(candidates);
204
202
 
205
203
  if (isSpeculator) {
206
- await firestoreUtils.clearCollection(pendingSpecCollection); // <-- Change to singular
204
+ await firestoreUtils.clearCollection(pendingSpecCollection);
207
205
  await firestoreUtils.batchWriteShardedIds(
208
- pendingSpecCollection, // <-- And this line
206
+ pendingSpecCollection,
209
207
  cidsArray,
210
208
  new Date(),
211
209
  pendingMaxFieldsPerDoc,
@@ -55,9 +55,9 @@ async function runDiscovery(userType, config, globalConfig) {
55
55
  async function runUpdates(userType, config, globalConfig) {
56
56
  logger.log('INFO', `[Module Orchestrator] Collecting users for daily update (${userType})...`);
57
57
 
58
- // Reset locks happens once per entry point, keep it there.
58
+ // Reset locks happens once per entry point
59
59
 
60
- // 1. Define Thresholds (Remains the same logic as before)
60
+ // 1. Define Thresholds
61
61
  const now = new Date();
62
62
  const startOfTodayUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
63
63
  const sevenDaysAgoUTC = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); // Speculator grace period
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @fileoverview Exports Orchestrator-specific utility functions.
3
- * (Currently empty as per design, but structure is ready).
3
+ * (Is unused currently).
4
4
  */
5
5
 
6
6
  // Add Orchestrator-specific utils here if needed.
@@ -85,7 +85,6 @@ async function cleanupStaleSpeculators(firestore, logger, config, batch) {
85
85
  for (const doc of blocksSnapshot.docs) {
86
86
  const blockId = doc.id; // e.g., "19000000"
87
87
  const blockData = doc.data();
88
- // Firestore map keys cannot contain '.', so the keys are likely 'users.123456'
89
88
  const users = blockData.users || {};
90
89
  let usersRemovedFromBlock = 0;
91
90
  const updates = {}; // Updates specific to this block document
@@ -4,7 +4,6 @@
4
4
  const { Firestore } = require('@google-cloud/firestore'); // Needed if db is not passed in
5
5
  const { PubSub } = require('@google-cloud/pubsub'); // Needed if pubsub is not passed in
6
6
  const { logger: defaultLogger } = require("sharedsetup")(__filename); // Use default logger if none provided
7
- // const { core } = require('../../'); // <-- REMOVE this top-level import
8
7
 
9
8
  // Import the managers directly from their source
10
9
  const { IntelligentHeaderManager, IntelligentProxyManager } = require('../../functions/core/utils');
@@ -84,18 +83,9 @@ function createTaskEngineHandler(config, dependencies = {}) {
84
83
  // Acknowledge Pub/Sub by not throwing
85
84
  }
86
85
  } catch (error) {
87
- // Log the error but crucially *do not re-throw* if you want Pub/Sub to ack the message
88
- // Only re-throw if you want Pub/Sub to attempt redelivery based on its settings.
89
- // Your existing logic logs but then re-throws - decide if that's the desired behavior.
90
86
  logger.log('ERROR', `[TaskEngine/${taskId}] Failed.`, { errorMessage: error.message, errorStack: error.stack });
91
- // throw error; // Optional: Uncomment if you want Pub/Sub to retry
92
87
  } finally {
93
- // Ensure batches are flushed eventually, though the batch manager handles timed flushes.
94
- // A final flush here might be redundant if the instance stays alive, but could be useful
95
- // if the instance might terminate immediately after processing.
96
88
  try {
97
- // Consider if flushing on every single message is desired vs relying on timed flush
98
- // await batchManager.flushBatches();
99
89
  } catch (flushError) {
100
90
  logger.log('ERROR', `[TaskEngine/${taskId}] Error during final flush attempt.`, { error: flushError.message });
101
91
  }
@@ -4,10 +4,10 @@
4
4
 
5
5
  const helpers = require('./helpers');
6
6
  const utils = require('./utils');
7
- const { createTaskEngineHandler } = require('./handler_creator'); // <-- Import the new factory
7
+ const { createTaskEngineHandler } = require('./handler_creator');
8
8
 
9
9
  module.exports = {
10
10
  helpers,
11
11
  utils,
12
- createTaskEngineHandler, // <-- Export the factory
12
+ createTaskEngineHandler,
13
13
  };
package/index.js CHANGED
@@ -4,26 +4,26 @@
4
4
  * to be shared across multiple Cloud Functions.
5
5
  */
6
6
 
7
- const core = require('./functions/core');
8
- const Orchestrator = require('./functions/orchestrator');
9
- const TaskEngine = require('./functions/task-engine');
10
- const ComputationSystem = require('./functions/computation-system');
11
- const GenericAPI = require('./functions/generic-api'); // <-- ADD THIS
12
- const Dispatcher = require('./functions/dispatcher'); // <-- ADD THIS
13
- const InvalidSpeculatorHandler = require('./functions/invalid-speculator-handler'); // <-- ADD THIS
14
- const SpeculatorCleanupOrchestrator = require('./functions/speculator-cleanup-orchestrator'); // <-- ADD THIS
15
- const FetchInsights = require('./functions/fetch-insights'); // <-- ADD THIS
16
- const EtoroPriceFetcher = require('./functions/etoro-price-fetcher'); // <-- ADD THIS
7
+ const core = require('./functions/core');
8
+ const Orchestrator = require('./functions/orchestrator');
9
+ const TaskEngine = require('./functions/task-engine');
10
+ const ComputationSystem = require('./functions/computation-system');
11
+ const GenericAPI = require('./functions/generic-api');
12
+ const Dispatcher = require('./functions/dispatcher');
13
+ const InvalidSpeculatorHandler = require('./functions/invalid-speculator-handler');
14
+ const SpeculatorCleanupOrchestrator = require('./functions/speculator-cleanup-orchestrator');
15
+ const FetchInsights = require('./functions/fetch-insights');
16
+ const EtoroPriceFetcher = require('./functions/etoro-price-fetcher');
17
17
 
18
18
  module.exports = {
19
19
  core,
20
20
  Orchestrator,
21
21
  TaskEngine,
22
22
  ComputationSystem,
23
- GenericAPI, // <-- AND ADD THIS
24
- Dispatcher, // <-- AND ADD THIS
25
- InvalidSpeculatorHandler, // <-- AND ADD THIS
26
- SpeculatorCleanupOrchestrator, // <-- AND ADD THIS
27
- FetchInsights, // <-- AND ADD THIS
28
- EtoroPriceFetcher // <-- AND ADD THIS
23
+ GenericAPI,
24
+ Dispatcher,
25
+ InvalidSpeculatorHandler,
26
+ SpeculatorCleanupOrchestrator,
27
+ FetchInsights,
28
+ EtoroPriceFetcher
29
29
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.25",
3
+ "version": "1.0.26",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [