aiden-shared-calculations-unified 1.0.152 → 1.0.154
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.
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Aggregates
|
|
2
|
+
* @fileoverview Aggregates the $ AUM invested in every asset across all Popular Investors.
|
|
3
|
+
* Reads the results from PIDailyAssetAUM.
|
|
3
4
|
*/
|
|
4
5
|
class GlobalAumPerAsset30D {
|
|
5
6
|
static getMetadata() {
|
|
@@ -7,45 +8,42 @@ class GlobalAumPerAsset30D {
|
|
|
7
8
|
type: 'meta',
|
|
8
9
|
category: 'analytics',
|
|
9
10
|
rootDataDependencies: [],
|
|
10
|
-
// No dependencySeries needed! We just need Today's results via getDependencies.
|
|
11
11
|
schedule: { type: 'DAILY' }
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
static getDependencies() {
|
|
16
|
-
// Force running AFTER the Standard comp
|
|
17
|
-
// CRITICAL: Must match the File Name of the standard computation
|
|
18
16
|
return ['PIDailyAssetAUM'];
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
async process(context) {
|
|
22
|
-
// Access the results
|
|
23
|
-
// CRITICAL: Must match the File Name
|
|
20
|
+
// Access the map of results: { UserID: { Ticker: $Amount } }
|
|
24
21
|
const allUserResults = context.computed['PIDailyAssetAUM'];
|
|
25
22
|
|
|
26
|
-
const
|
|
27
|
-
let
|
|
23
|
+
const globalTotals = {};
|
|
24
|
+
let piCount = 0;
|
|
28
25
|
|
|
29
26
|
if (allUserResults) {
|
|
30
|
-
Object.values(allUserResults).forEach(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Object.entries(
|
|
37
|
-
if (!
|
|
38
|
-
|
|
27
|
+
Object.values(allUserResults).forEach(userAllocationMap => {
|
|
28
|
+
if (!userAllocationMap) return;
|
|
29
|
+
|
|
30
|
+
piCount++;
|
|
31
|
+
|
|
32
|
+
// userAllocationMap is { AAPL: 5000, TSLA: 2000, ... }
|
|
33
|
+
Object.entries(userAllocationMap).forEach(([ticker, usdValue]) => {
|
|
34
|
+
if (!globalTotals[ticker]) globalTotals[ticker] = 0;
|
|
35
|
+
globalTotals[ticker] += usdValue;
|
|
39
36
|
});
|
|
40
37
|
});
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
// Result:
|
|
44
|
-
this.results =
|
|
40
|
+
// Result: { AAPL: 5000000, TSLA: ... }
|
|
41
|
+
this.results = globalTotals;
|
|
45
42
|
|
|
46
|
-
//
|
|
43
|
+
// Return for potential debugging or further chaining
|
|
47
44
|
return this.results;
|
|
48
45
|
}
|
|
46
|
+
|
|
49
47
|
async getResult() { return this.results; }
|
|
50
48
|
}
|
|
51
49
|
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculates the $ AUM allocated to each asset for a single PI
|
|
2
|
+
* @fileoverview Calculates the $ AUM allocated to each asset for a single PI.
|
|
3
|
+
* Includes a lookback mechanism: If AUM is missing today, it checks the last 7 days of rankings.
|
|
3
4
|
*/
|
|
4
5
|
class PIDailyAssetAUM {
|
|
5
6
|
static getMetadata() {
|
|
6
7
|
return {
|
|
7
8
|
type: 'standard',
|
|
8
9
|
category: 'analytics',
|
|
9
|
-
userType: 'POPULAR_INVESTOR',
|
|
10
|
+
userType: 'POPULAR_INVESTOR', // Ensures we only run for PIs
|
|
10
11
|
|
|
11
12
|
// 1. Core Data
|
|
12
13
|
rootDataDependencies: ['portfolio', 'rankings'],
|
|
13
|
-
mandatoryRoots: ['portfolio',
|
|
14
|
+
mandatoryRoots: ['portfolio'], // Rankings are mandatory but handled via lookback if missing today
|
|
14
15
|
|
|
15
|
-
// 2.
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// 3. Bootstrap Flag: Allows running even if history is empty (First Run)
|
|
22
|
-
canHaveMissingSeries: true
|
|
16
|
+
// 2. Rankings Lookback Series
|
|
17
|
+
// This requests the last 7 days of rankings to be available in context.seriesData.root.rankings
|
|
18
|
+
rootDataSeries: {
|
|
19
|
+
rankings: 7
|
|
20
|
+
}
|
|
23
21
|
};
|
|
24
22
|
}
|
|
25
23
|
|
|
@@ -29,73 +27,63 @@ class PIDailyAssetAUM {
|
|
|
29
27
|
const { extract, RankingsExtractor } = context.math;
|
|
30
28
|
const userId = context.user.id;
|
|
31
29
|
|
|
32
|
-
// --- STEP A:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
30
|
+
// --- STEP A: Determine AUM (With Lookback) ---
|
|
31
|
+
// 1. Try Today
|
|
32
|
+
let piAum = RankingsExtractor.getAUMValue(context.user.rankEntry);
|
|
33
|
+
|
|
34
|
+
// 2. If missing, look back up to 30 days
|
|
35
|
+
if (!piAum || piAum === 0) {
|
|
36
|
+
const rankingsSeries = context.seriesData?.root?.rankings || {};
|
|
37
|
+
|
|
38
|
+
// Get dates sorted newest to oldest
|
|
39
|
+
const availableDates = Object.keys(rankingsSeries).sort((a, b) => b.localeCompare(a));
|
|
40
|
+
|
|
41
|
+
for (const dateKey of availableDates) {
|
|
42
|
+
const dailyRankings = rankingsSeries[dateKey];
|
|
43
|
+
const historicalEntry = RankingsExtractor.getEntry(dailyRankings, userId);
|
|
44
|
+
const historicalAum = RankingsExtractor.getAUMValue(historicalEntry);
|
|
45
45
|
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
if (historicalAum > 0) {
|
|
47
|
+
piAum = historicalAum;
|
|
48
|
+
// Optional: Log that we used historical data
|
|
49
|
+
// context.logger.log('INFO', `Using historical AUM for ${userId} from ${dateKey}: $${piAum}`);
|
|
50
|
+
break;
|
|
49
51
|
}
|
|
50
|
-
}
|
|
52
|
+
}
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const rollingWindow = [];
|
|
58
|
-
|
|
59
|
-
if (historyMap) {
|
|
60
|
-
Object.values(historyMap).forEach(dayResult => {
|
|
61
|
-
const userResult = dayResult[userId];
|
|
62
|
-
if (userResult && userResult.dailyMap) {
|
|
63
|
-
rollingWindow.push(userResult.dailyMap);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
55
|
+
// If still no AUM found, we cannot compute $ allocation
|
|
56
|
+
if (!piAum || piAum <= 0) {
|
|
57
|
+
return;
|
|
66
58
|
}
|
|
67
59
|
|
|
68
|
-
//
|
|
69
|
-
|
|
60
|
+
// --- STEP B: Calculate $ Allocation Per Asset ---
|
|
61
|
+
const allocationMap = {};
|
|
62
|
+
const positions = extract.getPositions(context.user.portfolio.today, context.user.type);
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
summedStats[ticker].total += val;
|
|
78
|
-
summedStats[ticker].count += 1;
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const rollingAverage = {};
|
|
83
|
-
const validDays = rollingWindow.length;
|
|
64
|
+
positions.forEach(pos => {
|
|
65
|
+
const instId = extract.getInstrumentId(pos);
|
|
66
|
+
const ticker = context.mappings.instrumentToTicker[instId] || `ID:${instId}`;
|
|
67
|
+
|
|
68
|
+
// Get Weight (%)
|
|
69
|
+
const pct = extract.getPositionWeight(pos); // Uses Invested or Amount based on schema
|
|
84
70
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
71
|
+
// Calculate $ Value: AUM * (Weight / 100)
|
|
72
|
+
// Note: Ensure pct is treated as percentage (e.g. 5.5 = 5.5%)
|
|
73
|
+
if (pct > 0) {
|
|
74
|
+
const usdValue = piAum * (pct / 100);
|
|
75
|
+
|
|
76
|
+
if (!allocationMap[ticker]) allocationMap[ticker] = 0;
|
|
77
|
+
allocationMap[ticker] += usdValue;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
90
80
|
|
|
91
|
-
// --- STEP
|
|
92
|
-
//
|
|
81
|
+
// --- STEP C: Output Results ---
|
|
82
|
+
// Format: { [UserId]: { Ticker: $Amount } }
|
|
93
83
|
this.results = {
|
|
94
|
-
[userId]:
|
|
95
|
-
dailyMap: todayAllocation,
|
|
96
|
-
averageMap: rollingAverage
|
|
97
|
-
}
|
|
84
|
+
[userId]: allocationMap
|
|
98
85
|
};
|
|
86
|
+
|
|
99
87
|
return this.results;
|
|
100
88
|
}
|
|
101
89
|
|