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.
- package/functions/computation-system/index.js +2 -2
- package/functions/computation-system/utils/data_loader.js +0 -2
- package/functions/computation-system/utils/utils.js +1 -5
- package/functions/core/utils/firestore_utils.js +1 -1
- package/functions/dispatcher/helpers/dispatch_helpers.js +0 -2
- package/functions/dispatcher/index.js +1 -1
- package/functions/etoro-price-fetcher/helpers/handler_helpers.js +1 -1
- package/functions/fetch-insights/helpers/handler_helpers.js +1 -1
- package/functions/generic-api/helpers/api_helpers.js +1 -1
- package/functions/invalid-speculator-handler/helpers/handler_helpers.js +1 -1
- package/functions/orchestrator/helpers/discovery_helpers.js +6 -8
- package/functions/orchestrator/index.js +2 -2
- package/functions/orchestrator/utils/index.js +1 -1
- package/functions/speculator-cleanup-orchestrator/helpers/cleanup_helpers.js +0 -1
- package/functions/task-engine/handler_creator.js +0 -10
- package/functions/task-engine/index.js +2 -2
- package/index.js +16 -16
- package/package.json +1 -1
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const { runComputationOrchestrator } = require('./helpers/orchestration_helpers.js');
|
|
6
|
-
const { createComputationSystemHandler } = require('./handler_creator.js');
|
|
6
|
+
const { createComputationSystemHandler } = require('./handler_creator.js');
|
|
7
7
|
|
|
8
8
|
module.exports = {
|
|
9
9
|
runComputationOrchestrator,
|
|
10
|
-
createComputationSystemHandler,
|
|
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 =
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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;
|
|
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,
|
|
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);
|
|
204
|
+
await firestoreUtils.clearCollection(pendingSpecCollection);
|
|
207
205
|
await firestoreUtils.batchWriteShardedIds(
|
|
208
|
-
pendingSpecCollection,
|
|
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
|
|
58
|
+
// Reset locks happens once per entry point
|
|
59
59
|
|
|
60
|
-
// 1. Define Thresholds
|
|
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
|
|
@@ -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');
|
|
7
|
+
const { createTaskEngineHandler } = require('./handler_creator');
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
10
10
|
helpers,
|
|
11
11
|
utils,
|
|
12
|
-
createTaskEngineHandler,
|
|
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
|
|
8
|
-
const Orchestrator
|
|
9
|
-
const TaskEngine
|
|
10
|
-
const ComputationSystem
|
|
11
|
-
const GenericAPI
|
|
12
|
-
const Dispatcher
|
|
13
|
-
const InvalidSpeculatorHandler
|
|
14
|
-
const SpeculatorCleanupOrchestrator = require('./functions/speculator-cleanup-orchestrator');
|
|
15
|
-
const FetchInsights
|
|
16
|
-
const EtoroPriceFetcher
|
|
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,
|
|
24
|
-
Dispatcher,
|
|
25
|
-
InvalidSpeculatorHandler,
|
|
26
|
-
SpeculatorCleanupOrchestrator,
|
|
27
|
-
FetchInsights,
|
|
28
|
-
EtoroPriceFetcher
|
|
23
|
+
GenericAPI,
|
|
24
|
+
Dispatcher,
|
|
25
|
+
InvalidSpeculatorHandler,
|
|
26
|
+
SpeculatorCleanupOrchestrator,
|
|
27
|
+
FetchInsights,
|
|
28
|
+
EtoroPriceFetcher
|
|
29
29
|
};
|