bulltrackers-module 1.0.763 → 1.0.765
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-v2/computations/BehavioralAnomaly.js +281 -0
- package/functions/computation-system-v2/computations/NewSectorExposure.js +135 -0
- package/functions/computation-system-v2/computations/NewSocialPost.js +99 -0
- package/functions/computation-system-v2/computations/PositionInvestedIncrease.js +148 -0
- package/functions/computation-system-v2/computations/RiskScoreIncrease.js +140 -0
- package/functions/computation-system-v2/config/bulltrackers.config.js +1 -1
- package/functions/computation-system-v2/docs/Agents.MD +964 -0
- package/functions/computation-system-v2/framework/execution/RemoteTaskRunner.js +115 -135
- package/functions/computation-system-v2/handlers/scheduler.js +8 -2
- package/functions/computation-system-v2/handlers/worker.js +110 -181
- package/package.json +1 -1
- package/functions/computation-system-v2/docs/admin.md +0 -117
- package/functions/computation-system-v2/docs/api_reference.md +0 -118
- package/functions/computation-system-v2/docs/architecture.md +0 -103
- package/functions/computation-system-v2/docs/developer_guide.md +0 -125
- package/functions/computation-system-v2/docs/operations.md +0 -99
- package/functions/computation-system-v2/docs/plans.md +0 -588
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
const { Computation } = require('../framework');
|
|
2
|
+
|
|
3
|
+
class RiskScoreIncrease extends Computation {
|
|
4
|
+
|
|
5
|
+
static getConfig() {
|
|
6
|
+
return {
|
|
7
|
+
name: 'RiskScoreIncrease',
|
|
8
|
+
// V2 Migration: Switch to per-entity for parallel processing
|
|
9
|
+
type: 'per-entity',
|
|
10
|
+
category: 'alerts',
|
|
11
|
+
isHistorical: true,
|
|
12
|
+
|
|
13
|
+
// V2 Migration: Define strict data requirements
|
|
14
|
+
requires: {
|
|
15
|
+
'rankings': {
|
|
16
|
+
lookback: 1, // Fetches Today + Yesterday
|
|
17
|
+
mandatory: true,
|
|
18
|
+
// Optimization: Only fetch needed fields
|
|
19
|
+
fields: ['user_id', 'rankings_data', 'date'],
|
|
20
|
+
// Filter applied at data fetch level (replacing V1 userType logic)
|
|
21
|
+
filter: { user_type: 'POPULAR_INVESTOR' }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// V2 Migration: Explicit storage configuration for backward compatibility
|
|
26
|
+
storage: {
|
|
27
|
+
bigquery: true,
|
|
28
|
+
firestore: {
|
|
29
|
+
enabled: true,
|
|
30
|
+
// Ensures V1 alert system can find the document
|
|
31
|
+
path: 'alerts/{date}/RiskScoreIncrease/{entityId}',
|
|
32
|
+
merge: true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// ============================================================
|
|
37
|
+
// LEGACY METADATA PRESERVED EXACTLY
|
|
38
|
+
// This section is read by the external Alert System
|
|
39
|
+
// ============================================================
|
|
40
|
+
userType: 'POPULAR_INVESTOR',
|
|
41
|
+
alert: {
|
|
42
|
+
id: 'increasedRisk',
|
|
43
|
+
frontendName: 'Increased Risk',
|
|
44
|
+
description: 'Alert when a Popular Investor\'s risk score increases',
|
|
45
|
+
messageTemplate: '{piUsername}\'s risk score increased by {change} points (from {previous} to {current})',
|
|
46
|
+
severity: 'high',
|
|
47
|
+
configKey: 'increasedRisk',
|
|
48
|
+
isDynamic: true,
|
|
49
|
+
dynamicConfig: {
|
|
50
|
+
thresholds: [
|
|
51
|
+
{
|
|
52
|
+
key: 'minChange',
|
|
53
|
+
type: 'number',
|
|
54
|
+
label: 'Minimum risk increase',
|
|
55
|
+
description: 'Only alert if risk increases by at least this many points',
|
|
56
|
+
default: 0,
|
|
57
|
+
min: 0,
|
|
58
|
+
max: 10,
|
|
59
|
+
step: 0.5,
|
|
60
|
+
unit: 'points'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: 'minRiskLevel',
|
|
64
|
+
type: 'number',
|
|
65
|
+
label: 'Minimum risk level',
|
|
66
|
+
description: 'Only alert if new risk score is above this level',
|
|
67
|
+
default: 0,
|
|
68
|
+
min: 0,
|
|
69
|
+
max: 10,
|
|
70
|
+
step: 0.5,
|
|
71
|
+
unit: 'risk score'
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
resultFields: {
|
|
75
|
+
change: 'change',
|
|
76
|
+
newValue: 'currentRisk',
|
|
77
|
+
oldValue: 'previousRisk'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async process(context) {
|
|
85
|
+
const { data, entityId, date, rules } = context;
|
|
86
|
+
|
|
87
|
+
// 1. Data Access
|
|
88
|
+
// In V2 with lookback: 1, this is an array of entries sorted by date
|
|
89
|
+
const rankingHistory = data['rankings'] || [];
|
|
90
|
+
|
|
91
|
+
// Find today's and yesterday's entries specifically by date string
|
|
92
|
+
const todayEntry = rankingHistory.find(d => d.date === date);
|
|
93
|
+
|
|
94
|
+
// Calculate yesterday's date string for lookup
|
|
95
|
+
const yesterdayDate = new Date(date);
|
|
96
|
+
yesterdayDate.setDate(yesterdayDate.getDate() - 1);
|
|
97
|
+
const yesterdayStr = yesterdayDate.toISOString().split('T')[0];
|
|
98
|
+
|
|
99
|
+
const yesterdayEntry = rankingHistory.find(d => d.date === yesterdayStr);
|
|
100
|
+
|
|
101
|
+
// 2. Business Logic (Using Rules)
|
|
102
|
+
// Extract raw JSON data using rules
|
|
103
|
+
const todayData = rules.rankings.extractRankingsData(todayEntry);
|
|
104
|
+
const yesterdayData = rules.rankings.extractRankingsData(yesterdayEntry);
|
|
105
|
+
|
|
106
|
+
// Using rules.rankings to safely extract the score
|
|
107
|
+
// getRiskScore(data)
|
|
108
|
+
const currentRisk = todayData ? rules.rankings.getRiskScore(todayData) : null;
|
|
109
|
+
const previousRisk = yesterdayData ? rules.rankings.getRiskScore(yesterdayData) : null;
|
|
110
|
+
|
|
111
|
+
// 3. Validation
|
|
112
|
+
// If today's risk data is missing, we cannot evaluate
|
|
113
|
+
if (currentRisk === null || currentRisk === undefined) {
|
|
114
|
+
this.log('WARN', `No current risk data for ${entityId}`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 4. Comparison Logic
|
|
119
|
+
const isBaselineReset = (previousRisk === null || previousRisk === undefined);
|
|
120
|
+
const change = isBaselineReset ? 0 : (currentRisk - previousRisk);
|
|
121
|
+
const hasIncreased = !isBaselineReset && (currentRisk > previousRisk);
|
|
122
|
+
|
|
123
|
+
// 5. Construct Result
|
|
124
|
+
// Matches the structure required by the "alert.dynamicConfig.resultFields"
|
|
125
|
+
const result = {
|
|
126
|
+
currentRisk,
|
|
127
|
+
previousRisk: isBaselineReset ? 'N/A' : previousRisk,
|
|
128
|
+
change: change,
|
|
129
|
+
isBaselineReset,
|
|
130
|
+
triggered: hasIncreased, // Helpful flag for query filtering
|
|
131
|
+
updatedAt: new Date().toISOString()
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// 6. Save Result
|
|
135
|
+
// This writes to BigQuery AND the Firestore path defined in getConfig
|
|
136
|
+
this.setResult(entityId, result);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = RiskScoreIncrease;
|
|
@@ -316,7 +316,7 @@ module.exports = {
|
|
|
316
316
|
location: 'europe-west1',
|
|
317
317
|
queueName: 'computation-triggers',
|
|
318
318
|
dispatcherUrl: process.env.DISPATCHER_URL ||
|
|
319
|
-
'https://europe-west1-stocks-12345.cloudfunctions.net/
|
|
319
|
+
'https://europe-west1-stocks-12345.cloudfunctions.net/compute-dispatcher',
|
|
320
320
|
// Service account for OIDC authentication when invoking Dispatcher
|
|
321
321
|
// This SA needs roles/cloudfunctions.invoker on the Dispatcher function
|
|
322
322
|
serviceAccountEmail: process.env.CLOUD_TASKS_SA_EMAIL ||
|