bulltrackers-module 1.0.762 → 1.0.764
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 +22 -4
- package/functions/computation-system-v2/core-api.js +0 -9
- 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;
|
|
@@ -11,6 +11,27 @@
|
|
|
11
11
|
// Load business rules
|
|
12
12
|
const rules = require('../rules');
|
|
13
13
|
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
// Dynamic Computation Loader
|
|
18
|
+
function loadComputations() {
|
|
19
|
+
const computationsDir = path.join(__dirname, '../computations');
|
|
20
|
+
const files = fs.readdirSync(computationsDir);
|
|
21
|
+
|
|
22
|
+
return files
|
|
23
|
+
.filter(file => file.endsWith('.js') && !file.startsWith('_')) // Skip hidden/test files
|
|
24
|
+
.map(file => {
|
|
25
|
+
try {
|
|
26
|
+
return require(path.join(computationsDir, file));
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.error(`[Config] Failed to load computation ${file}:`, e.message);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.filter(Boolean); // Remove nulls
|
|
33
|
+
}
|
|
34
|
+
|
|
14
35
|
module.exports = {
|
|
15
36
|
// =========================================================================
|
|
16
37
|
// PROJECT CONFIGURATION
|
|
@@ -201,10 +222,7 @@ module.exports = {
|
|
|
201
222
|
// by one as they're migrated from v1.
|
|
202
223
|
// =========================================================================
|
|
203
224
|
|
|
204
|
-
computations:
|
|
205
|
-
// Add migrated computations here:
|
|
206
|
-
// require('../computations/UserRiskScore'),
|
|
207
|
-
],
|
|
225
|
+
computations: loadComputations(),
|
|
208
226
|
|
|
209
227
|
// =========================================================================
|
|
210
228
|
// PREDEFINED FILTER SETS
|
|
@@ -9,15 +9,6 @@ const config = require('./config/bulltrackers.config');
|
|
|
9
9
|
const { ManifestBuilder } = require('./framework/core/Manifest');
|
|
10
10
|
const { Computation } = require('./framework/core/Computation');
|
|
11
11
|
|
|
12
|
-
// Add computations to config
|
|
13
|
-
config.computations = [
|
|
14
|
-
require('./computations/UserPortfolioSummary'),
|
|
15
|
-
require('./computations/PopularInvestorProfileMetrics'),
|
|
16
|
-
require('./computations/PopularInvestorRiskAssessment'),
|
|
17
|
-
require('./computations/PopularInvestorRiskMetrics'),
|
|
18
|
-
// Add more computations here as they're migrated
|
|
19
|
-
];
|
|
20
|
-
|
|
21
12
|
// Singleton orchestrator instance
|
|
22
13
|
let orchestrator = null;
|
|
23
14
|
|