aiden-shared-calculations-unified 1.0.152 → 1.0.153

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 PI Asset AUM over the last 30 days.
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 injected by getDependencies()
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 globalAverages = {};
27
- let userCount = 0;
23
+ const globalTotals = {};
24
+ let piCount = 0;
28
25
 
29
26
  if (allUserResults) {
30
- Object.values(allUserResults).forEach(userOutput => {
31
- // userOutput is: { dailyMap, averageMap }
32
- const avgMap = userOutput.averageMap;
33
- if (!avgMap) return;
34
-
35
- userCount++;
36
- Object.entries(avgMap).forEach(([ticker, avgVal]) => {
37
- if (!globalAverages[ticker]) globalAverages[ticker] = 0;
38
- globalAverages[ticker] += avgVal;
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: The Sum of everyone's 30-Day Average Allocations
44
- this.results = globalAverages;
40
+ // Result: { AAPL: 5000000, TSLA: ... }
41
+ this.results = globalTotals;
45
42
 
46
- // CRITICAL FIX: MetaExecutor requires the data to be returned
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 using a Rolling 30-Day Window.
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 30 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', 'rankings'],
14
+ mandatoryRoots: ['portfolio'], // Rankings are mandatory but handled via lookback if missing today
14
15
 
15
- // 2. History: Load MY OWN results from the last 29 days
16
- // CRITICAL: Name must match the File Name (PIDailyAssetAUM)
17
- dependencySeries: {
18
- 'PIDailyAssetAUM': 29
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 30 days of rankings to be available in context.seriesData.root.rankings
18
+ rootDataSeries: {
19
+ rankings: 30
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: Calculate TODAY (T-0) ---
33
- const piAum = RankingsExtractor.getAUMValue(context.user.rankEntry);
34
- const todayAllocation = {};
35
-
36
- if (piAum > 0) {
37
- const positions = extract.getPositions(context.user.portfolio.today, context.user.type);
38
- positions.forEach(pos => {
39
- const instId = extract.getInstrumentId(pos);
40
- const ticker = context.mappings.instrumentToTicker[instId] || `ID:${instId}`;
41
- const pct = extract.getPositionValue(pos) || 0;
42
-
43
- // Convert % to $
44
- const usdValue = piAum * (pct / 100);
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 (usdValue > 0) {
47
- if (!todayAllocation[ticker]) todayAllocation[ticker] = 0;
48
- todayAllocation[ticker] += usdValue;
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
- // --- STEP B: Load History (T-1 to T-29) ---
54
- // Access using the FILE NAME key
55
- const historyMap = context.globalData.series?.results?.['PIDailyAssetAUM'] || {};
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
- // Always add Today
69
- rollingWindow.push(todayAllocation);
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
- // --- STEP C: Compute Rolling Average ---
72
- const summedStats = {};
73
-
74
- rollingWindow.forEach(dayAllocations => {
75
- Object.entries(dayAllocations).forEach(([ticker, val]) => {
76
- if (!summedStats[ticker]) summedStats[ticker] = { total: 0, count: 0 };
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
- if (validDays > 0) {
86
- Object.entries(summedStats).forEach(([ticker, stat]) => {
87
- rollingAverage[ticker] = stat.total / validDays;
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 D: Output Results ---
92
- // StandardExecutor reads 'this.results', it does NOT use the return value.
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiden-shared-calculations-unified",
3
- "version": "1.0.152",
3
+ "version": "1.0.153",
4
4
  "description": "Shared calculation modules for the BullTrackers Computation System.",
5
5
  "main": "index.js",
6
6
  "files": [