bulltrackers-module 1.0.800 → 1.0.802

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.
@@ -16,6 +16,8 @@ async function handleComputationResultWrite(change, context, config, dependencie
16
16
 
17
17
  if (!isAlertComputation(cachedAlertTypes, computationName)) return;
18
18
 
19
+ console.log("The computations assigned to on document write are," + computationName)
20
+
19
21
  const payload = {
20
22
  date,
21
23
  computationName,
@@ -32,4 +34,4 @@ async function handleComputationResultWrite(change, context, config, dependencie
32
34
  }
33
35
  }
34
36
 
35
- module.exports = { handleComputationResultWrite };
37
+ module.exports = { handleComputationResultWrite };
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  const config = {
7
- name: 'GlobalAumPerAsset30D', // Normalized name
7
+ name: 'GlobalAumPerAsset30D',
8
8
  type: 'global',
9
9
  category: 'market_insights',
10
10
 
@@ -19,7 +19,7 @@ const config = {
19
19
  }
20
20
  },
21
21
 
22
- dependencies: ['pidailyassetaum'], // Lowercase normalized
22
+ dependencies: ['pidailyassetaum'],
23
23
 
24
24
  storage: {
25
25
  bigquery: true
@@ -32,11 +32,11 @@ async function process(context) {
32
32
  let rows = data['results'];
33
33
  if (!rows || (Array.isArray(rows) && rows.length === 0)) {
34
34
  if (log) log('[GlobalAumPerAsset] No input data found.');
35
- return { result: null }; // V3 returns object with result
35
+ return { result: null };
36
36
  }
37
37
 
38
38
  if (!Array.isArray(rows) && typeof rows === 'object') {
39
- rows = Object.values(rows); // Handle possible object map from BQ adapter
39
+ rows = Object.values(rows);
40
40
  }
41
41
 
42
42
  if (log) log(`[GlobalAumPerAsset] Aggregating ${rows.length} PI portfolios...`);
@@ -77,7 +77,6 @@ async function process(context) {
77
77
 
78
78
  if (log) log(`[GlobalAumPerAsset] Generated stats for ${materializedViewData.length} unique assets from ${piCount} PIs.`);
79
79
 
80
- // V3 expects return value, not this.setResult
81
80
  return {
82
81
  status: 'completed',
83
82
  result: materializedViewData
@@ -24,7 +24,6 @@ const config = {
24
24
  'ticker_mappings': {
25
25
  mandatory: false,
26
26
  fields: ['instrument_id', 'ticker'],
27
- // [CRITICAL] Disable batch filtering to get global map
28
27
  entityField: null
29
28
  },
30
29
  'pi_master_list': {
@@ -53,7 +52,6 @@ async function process(context) {
53
52
  };
54
53
 
55
54
  // --- HELPER: V3 Data Normalizer ---
56
- // Handles difference between Batch (keyed map) and Global (array) returns
57
55
  const getEntityRows = (dataset) => {
58
56
  if (!dataset) return [];
59
57
  if (dataset[entityId]) {
@@ -107,7 +105,6 @@ async function process(context) {
107
105
  }
108
106
 
109
107
  // 5. Calculation using V3 Libs
110
- // Uses lib.portfolio.* and lib.rankings.* instead of V2 rules
111
108
  const pData = portfolio.extractPortfolioData(validPortfolio);
112
109
  const rData = rankings.extractRankingsData(validRanking);
113
110
 
@@ -123,7 +120,7 @@ async function process(context) {
123
120
  positions.forEach(pos => {
124
121
  const id = portfolio.getInstrumentId(pos);
125
122
  const ticker = resolveTicker(id);
126
- const weight = portfolio.getInvested(pos); // V3 lib handles % normalization
123
+ const weight = portfolio.getInvested(pos);
127
124
 
128
125
  if (weight > 0) {
129
126
  const dollarValue = (weight / 100) * totalAum;
@@ -2,6 +2,7 @@
2
2
  * @fileoverview Popular Investor Profile Metrics
3
3
  * Migrated to V3 System.
4
4
  * FIXED: Corrected function call 'getTradesCount' and 'getTotalTrades' typo.
5
+ * OPTIMIZED: Uses 1-day lookback for trade history (rolling window) to prevent cost violations.
5
6
  */
6
7
 
7
8
  /** @typedef {import('../framework/core/ContextBuilder').ComputationContext} ComputationContext */
@@ -20,7 +21,7 @@ exports.config = {
20
21
  fields: ['user_id', 'portfolio_data', 'date']
21
22
  },
22
23
  'trade_history_snapshots': {
23
- lookback: 30,
24
+ lookback: 1, // OPTIMIZED: Rolling history contained in single snapshot
24
25
  mandatory: false,
25
26
  fields: ['user_id', 'history_data', 'date']
26
27
  },
@@ -221,38 +222,38 @@ exports.process = (ctx) => {
221
222
  gain: lib.rankings.getTotalGain(rData),
222
223
  copiers: lib.rankings.getCopiers(rData),
223
224
  winRatio: lib.rankings.getWinRatio(rData),
224
- // [FIX] Changed from getTotalTrades to getTradesCount
225
225
  trades: lib.rankings.getTradesCount(rData)
226
226
  };
227
227
  }
228
228
  }
229
229
 
230
230
  // ==========================================================================================
231
- // 4. TRADES
231
+ // 4. TRADES (OPTIMIZED)
232
232
  // ==========================================================================================
233
233
  const profitableMap = new Map();
234
234
  const allClosedTrades = [];
235
235
 
236
- historyData.forEach(dayDoc => {
237
- const trades = lib.trades.extractTrades(dayDoc);
238
- trades.forEach(trade => {
239
- const closeDate = lib.trades.getCloseDate(trade);
240
- if (!closeDate) return;
241
-
242
- const dKey = closeDate.toISOString().split('T')[0];
243
- const profit = lib.trades.getNetProfit(trade);
244
-
245
- const entry = profitableMap.get(dKey) || { date: dKey, profitableCount: 0, totalCount: 0 };
246
- entry.totalCount++;
247
- if (profit > 0) entry.profitableCount++;
248
- profitableMap.set(dKey, entry);
249
-
250
- allClosedTrades.push({
251
- ticker: resolveTicker(lib.trades.getInstrumentId(trade)),
252
- closeDate: closeDate,
253
- netProfit: profit,
254
- direction: lib.trades.isBuy(trade) ? 'Buy' : 'Sell'
255
- });
236
+ // Only process the latest history snapshot as it contains the rolling history
237
+ const latestHistory = historyData.length > 0 ? historyData[historyData.length - 1] : null;
238
+ const trades = latestHistory ? lib.trades.extractTrades(latestHistory) : [];
239
+
240
+ trades.forEach(trade => {
241
+ const closeDate = lib.trades.getCloseDate(trade);
242
+ if (!closeDate) return;
243
+
244
+ const dKey = closeDate.toISOString().split('T')[0];
245
+ const profit = lib.trades.getNetProfit(trade);
246
+
247
+ const entry = profitableMap.get(dKey) || { date: dKey, profitableCount: 0, totalCount: 0 };
248
+ entry.totalCount++;
249
+ if (profit > 0) entry.profitableCount++;
250
+ profitableMap.set(dKey, entry);
251
+
252
+ allClosedTrades.push({
253
+ ticker: resolveTicker(lib.trades.getInstrumentId(trade)),
254
+ closeDate: closeDate,
255
+ netProfit: profit,
256
+ direction: lib.trades.isBuy(trade) ? 'Buy' : 'Sell'
256
257
  });
257
258
  });
258
259
 
@@ -2,6 +2,7 @@
2
2
  * @fileoverview Signed-In User Profile Metrics (V3 Recipe)
3
3
  * Migrated from V2 computation.
4
4
  * FIXED: Explicit fields, global lookups, and PI exclusion logic.
5
+ * OPTIMIZED: Uses 1-day lookback for trade history (rolling window) to prevent cost violations.
5
6
  */
6
7
 
7
8
  /** @typedef {import('../framework/core/ContextBuilder').ComputationContext} ComputationContext */
@@ -22,7 +23,7 @@ exports.config = {
22
23
  filter: { user_type: 'SIGNED_IN_USER' }
23
24
  },
24
25
  'trade_history_snapshots': {
25
- lookback: 30,
26
+ lookback: 1, // OPTIMIZED: Rolling history contained in single snapshot
26
27
  fields: ['user_id', 'history_data', 'date'],
27
28
  filter: { user_type: 'SIGNED_IN_USER' }
28
29
  },
@@ -95,7 +96,6 @@ exports.process = (ctx) => {
95
96
  const piMasterList = toArray(data['pi_master_list']);
96
97
 
97
98
  // Check if the current entity is actually a PI (Source of Truth: Master List)
98
- // This handles cases where user_type might be incorrect in snapshots
99
99
  const isPopularInvestor = piMasterList.some(pi => String(pi.cid) === String(entityId));
100
100
 
101
101
  if (isPopularInvestor) {
@@ -185,30 +185,31 @@ exports.process = (ctx) => {
185
185
  });
186
186
  result.myPosts.data = socialFeed.sort((a, b) => new Date(b.date) - new Date(a.date)).slice(0, 20);
187
187
 
188
- // --- 7. Trades Processing ---
188
+ // --- 7. Trades Processing (OPTIMIZED) ---
189
189
  const dailyPnL = new Map();
190
190
  const winLoss = { wins: 0, losses: 0, profit: 0, loss: 0 };
191
191
  const tradeStats = new Map();
192
192
 
193
- historyData.forEach(dayDoc => {
194
- const trades = lib.trades.extractTrades(dayDoc);
195
- trades.forEach(t => {
196
- const closeDate = lib.trades.getCloseDate(t);
197
- if (!closeDate) return;
193
+ // Only process the latest history snapshot as it contains the rolling history
194
+ const latestHistory = historyData.length > 0 ? historyData[historyData.length - 1] : null;
195
+ const trades = latestHistory ? lib.trades.extractTrades(latestHistory) : [];
198
196
 
199
- const dKey = closeDate.toISOString().split('T')[0];
200
- const profit = lib.trades.getNetProfit(t);
197
+ trades.forEach(t => {
198
+ const closeDate = lib.trades.getCloseDate(t);
199
+ if (!closeDate) return;
201
200
 
202
- const entry = tradeStats.get(dKey) || { date: dKey, profitableCount: 0, totalCount: 0 };
203
- entry.totalCount++;
204
- if (profit > 0) entry.profitableCount++;
205
- tradeStats.set(dKey, entry);
201
+ const dKey = closeDate.toISOString().split('T')[0];
202
+ const profit = lib.trades.getNetProfit(t);
206
203
 
207
- if (profit > 0) { winLoss.wins++; winLoss.profit += profit; }
208
- else if (profit < 0) { winLoss.losses++; winLoss.loss += profit; }
204
+ const entry = tradeStats.get(dKey) || { date: dKey, profitableCount: 0, totalCount: 0 };
205
+ entry.totalCount++;
206
+ if (profit > 0) entry.profitableCount++;
207
+ tradeStats.set(dKey, entry);
209
208
 
210
- dailyPnL.set(dKey, (dailyPnL.get(dKey) || 0) + profit);
211
- });
209
+ if (profit > 0) { winLoss.wins++; winLoss.profit += profit; }
210
+ else if (profit < 0) { winLoss.losses++; winLoss.loss += profit; }
211
+
212
+ dailyPnL.set(dKey, (dailyPnL.get(dKey) || 0) + profit);
212
213
  });
213
214
 
214
215
  result.profitablePositions.data = Array.from(tradeStats.values())
@@ -161,7 +161,9 @@ class StateRepository {
161
161
 
162
162
  return { completedBatches: snapshot.data().count };
163
163
  } catch (e) {
164
- return { completedBatches: 0 };
164
+ // [FIX] Log the error!
165
+ this.logger.error(`[StateRepo] getCheckpointProgress failed for ${checkpointId}: ${e.message}`);
166
+ return { completedBatches: 0 };
165
167
  }
166
168
  }
167
169
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.800",
3
+ "version": "1.0.802",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [