bulltrackers-module 1.0.733 → 1.0.734

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.
Files changed (56) hide show
  1. package/functions/computation-system-v2/README.md +152 -0
  2. package/functions/computation-system-v2/computations/PopularInvestorProfileMetrics.js +720 -0
  3. package/functions/computation-system-v2/computations/PopularInvestorRiskAssessment.js +176 -0
  4. package/functions/computation-system-v2/computations/PopularInvestorRiskMetrics.js +294 -0
  5. package/functions/computation-system-v2/computations/TestComputation.js +46 -0
  6. package/functions/computation-system-v2/computations/UserPortfolioSummary.js +172 -0
  7. package/functions/computation-system-v2/config/bulltrackers.config.js +317 -0
  8. package/functions/computation-system-v2/framework/core/Computation.js +73 -0
  9. package/functions/computation-system-v2/framework/core/Manifest.js +223 -0
  10. package/functions/computation-system-v2/framework/core/RuleInjector.js +53 -0
  11. package/functions/computation-system-v2/framework/core/Rules.js +231 -0
  12. package/functions/computation-system-v2/framework/core/RunAnalyzer.js +163 -0
  13. package/functions/computation-system-v2/framework/cost/CostTracker.js +154 -0
  14. package/functions/computation-system-v2/framework/data/DataFetcher.js +399 -0
  15. package/functions/computation-system-v2/framework/data/QueryBuilder.js +232 -0
  16. package/functions/computation-system-v2/framework/data/SchemaRegistry.js +287 -0
  17. package/functions/computation-system-v2/framework/execution/Orchestrator.js +498 -0
  18. package/functions/computation-system-v2/framework/execution/TaskRunner.js +35 -0
  19. package/functions/computation-system-v2/framework/execution/middleware/CostTrackerMiddleware.js +32 -0
  20. package/functions/computation-system-v2/framework/execution/middleware/LineageMiddleware.js +32 -0
  21. package/functions/computation-system-v2/framework/execution/middleware/Middleware.js +14 -0
  22. package/functions/computation-system-v2/framework/execution/middleware/ProfilerMiddleware.js +47 -0
  23. package/functions/computation-system-v2/framework/index.js +45 -0
  24. package/functions/computation-system-v2/framework/lineage/LineageTracker.js +147 -0
  25. package/functions/computation-system-v2/framework/monitoring/Profiler.js +80 -0
  26. package/functions/computation-system-v2/framework/resilience/Checkpointer.js +66 -0
  27. package/functions/computation-system-v2/framework/scheduling/ScheduleValidator.js +327 -0
  28. package/functions/computation-system-v2/framework/storage/StateRepository.js +286 -0
  29. package/functions/computation-system-v2/framework/storage/StorageManager.js +469 -0
  30. package/functions/computation-system-v2/framework/storage/index.js +9 -0
  31. package/functions/computation-system-v2/framework/testing/ComputationTester.js +86 -0
  32. package/functions/computation-system-v2/framework/utils/Graph.js +205 -0
  33. package/functions/computation-system-v2/handlers/dispatcher.js +109 -0
  34. package/functions/computation-system-v2/handlers/index.js +23 -0
  35. package/functions/computation-system-v2/handlers/onDemand.js +289 -0
  36. package/functions/computation-system-v2/handlers/scheduler.js +327 -0
  37. package/functions/computation-system-v2/index.js +163 -0
  38. package/functions/computation-system-v2/rules/index.js +49 -0
  39. package/functions/computation-system-v2/rules/instruments.js +465 -0
  40. package/functions/computation-system-v2/rules/metrics.js +304 -0
  41. package/functions/computation-system-v2/rules/portfolio.js +534 -0
  42. package/functions/computation-system-v2/rules/rankings.js +655 -0
  43. package/functions/computation-system-v2/rules/social.js +562 -0
  44. package/functions/computation-system-v2/rules/trades.js +545 -0
  45. package/functions/computation-system-v2/scripts/migrate-sectors.js +73 -0
  46. package/functions/computation-system-v2/test/test-dispatcher.js +317 -0
  47. package/functions/computation-system-v2/test/test-framework.js +500 -0
  48. package/functions/computation-system-v2/test/test-real-execution.js +166 -0
  49. package/functions/computation-system-v2/test/test-real-integration.js +194 -0
  50. package/functions/computation-system-v2/test/test-refactor-e2e.js +131 -0
  51. package/functions/computation-system-v2/test/test-results.json +31 -0
  52. package/functions/computation-system-v2/test/test-risk-metrics-computation.js +329 -0
  53. package/functions/computation-system-v2/test/test-scheduler.js +204 -0
  54. package/functions/computation-system-v2/test/test-storage.js +449 -0
  55. package/functions/orchestrator/index.js +18 -26
  56. package/package.json +3 -2
@@ -0,0 +1,465 @@
1
+ /**
2
+ * @fileoverview Instrument & Price Business Rules
3
+ *
4
+ * For working with:
5
+ * - instrument_insights (sentiment data)
6
+ * - asset_prices (price data)
7
+ * - ticker_mappings (instrument ID <-> ticker)
8
+ *
9
+ * Usage in computation:
10
+ * ```javascript
11
+ * const sentiment = rules.instruments.extractInsightsData(row);
12
+ * const buyPercent = rules.instruments.getBuyPercent(sentiment);
13
+ * const price = rules.instruments.getPrice(priceRow);
14
+ * ```
15
+ */
16
+
17
+ // =============================================================================
18
+ // INSTRUMENT INSIGHTS - sentiment data
19
+ // =============================================================================
20
+
21
+ /**
22
+ * Extract insights_data from an instrument_insights row.
23
+ * @param {Object} row - instrument_insights row
24
+ * @returns {Object|null}
25
+ */
26
+ function extractInsightsData(row) {
27
+ if (!row) return null;
28
+
29
+ let data = row.insights_data;
30
+
31
+ if (typeof data === 'string') {
32
+ try {
33
+ data = JSON.parse(data);
34
+ } catch (e) {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ return data || null;
40
+ }
41
+
42
+ /**
43
+ * Get instrument ID from insights row.
44
+ * @param {Object} row - instrument_insights row
45
+ * @returns {number|null}
46
+ */
47
+ function getInsightsInstrumentId(row) {
48
+ return row?.instrument_id || extractInsightsData(row)?.instrumentId || null;
49
+ }
50
+
51
+ /**
52
+ * Get buy percentage (% of owners in buy positions).
53
+ * @param {Object} data - insights_data object
54
+ * @returns {number}
55
+ */
56
+ function getBuyPercent(data) {
57
+ return data?.buy ?? 0;
58
+ }
59
+
60
+ /**
61
+ * Get sell percentage (% of owners in short positions).
62
+ * @param {Object} data - insights_data object
63
+ * @returns {number}
64
+ */
65
+ function getSellPercent(data) {
66
+ return data?.sell ?? 0;
67
+ }
68
+
69
+ /**
70
+ * Get growth percentage (% change in owners vs yesterday).
71
+ * @param {Object} data - insights_data object
72
+ * @returns {number}
73
+ */
74
+ function getGrowth(data) {
75
+ return data?.growth ?? 0;
76
+ }
77
+
78
+ /**
79
+ * Get platform percentage (% of platform that owns this asset).
80
+ * @param {Object} data - insights_data object
81
+ * @returns {number}
82
+ */
83
+ function getPlatformPercentage(data) {
84
+ return data?.percentage ?? 0;
85
+ }
86
+
87
+ /**
88
+ * Get total owners count.
89
+ * @param {Object} data - insights_data object
90
+ * @returns {number}
91
+ */
92
+ function getTotalOwners(data) {
93
+ return data?.total ?? 0;
94
+ }
95
+
96
+ /**
97
+ * Get previous buy percentage.
98
+ * @param {Object} data - insights_data object
99
+ * @returns {number}
100
+ */
101
+ function getPrevBuy(data) {
102
+ return data?.prevBuy ?? 0;
103
+ }
104
+
105
+ /**
106
+ * Get previous sell percentage.
107
+ * @param {Object} data - insights_data object
108
+ * @returns {number}
109
+ */
110
+ function getPrevSell(data) {
111
+ return data?.prevSell ?? 0;
112
+ }
113
+
114
+ /**
115
+ * Calculate sentiment score (-100 to +100).
116
+ * Positive = bullish, Negative = bearish.
117
+ * @param {Object} data - insights_data object
118
+ * @returns {number}
119
+ */
120
+ function calculateSentimentScore(data) {
121
+ const buy = getBuyPercent(data);
122
+ const sell = getSellPercent(data);
123
+
124
+ // Range: -100 (all sell) to +100 (all buy)
125
+ return buy - sell;
126
+ }
127
+
128
+ /**
129
+ * Determine sentiment category.
130
+ * @param {Object} data - insights_data object
131
+ * @returns {string} 'very_bullish' | 'bullish' | 'neutral' | 'bearish' | 'very_bearish'
132
+ */
133
+ function getSentimentCategory(data) {
134
+ const score = calculateSentimentScore(data);
135
+
136
+ if (score >= 40) return 'very_bullish';
137
+ if (score >= 10) return 'bullish';
138
+ if (score > -10) return 'neutral';
139
+ if (score > -40) return 'bearish';
140
+ return 'very_bearish';
141
+ }
142
+
143
+ /**
144
+ * Calculate sentiment change from previous day.
145
+ * @param {Object} data - insights_data object
146
+ * @returns {number}
147
+ */
148
+ function getSentimentChange(data) {
149
+ const currentScore = getBuyPercent(data) - getSellPercent(data);
150
+ const prevScore = getPrevBuy(data) - getPrevSell(data);
151
+
152
+ return currentScore - prevScore;
153
+ }
154
+
155
+ /**
156
+ * Check if sentiment is trending up.
157
+ * @param {Object} data - insights_data object
158
+ * @returns {boolean}
159
+ */
160
+ function isSentimentTrendingUp(data) {
161
+ return getSentimentChange(data) > 0;
162
+ }
163
+
164
+ // =============================================================================
165
+ // ASSET PRICES
166
+ // =============================================================================
167
+
168
+ /**
169
+ * Get price from asset_prices row.
170
+ * @param {Object} row - asset_prices row
171
+ * @returns {number}
172
+ */
173
+ function getPrice(row) {
174
+ return row?.price ?? row?.close ?? 0;
175
+ }
176
+
177
+ /**
178
+ * Get close price.
179
+ * @param {Object} row - asset_prices row
180
+ * @returns {number}
181
+ */
182
+ function getClosePrice(row) {
183
+ return row?.close ?? row?.price ?? 0;
184
+ }
185
+
186
+ /**
187
+ * Get open price.
188
+ * @param {Object} row - asset_prices row
189
+ * @returns {number|null}
190
+ */
191
+ function getOpenPrice(row) {
192
+ return row?.open || null;
193
+ }
194
+
195
+ /**
196
+ * Get high price.
197
+ * @param {Object} row - asset_prices row
198
+ * @returns {number|null}
199
+ */
200
+ function getHighPrice(row) {
201
+ return row?.high || null;
202
+ }
203
+
204
+ /**
205
+ * Get low price.
206
+ * @param {Object} row - asset_prices row
207
+ * @returns {number|null}
208
+ */
209
+ function getLowPrice(row) {
210
+ return row?.low || null;
211
+ }
212
+
213
+ /**
214
+ * Get volume.
215
+ * @param {Object} row - asset_prices row
216
+ * @returns {number|null}
217
+ */
218
+ function getVolume(row) {
219
+ return row?.volume || null;
220
+ }
221
+
222
+ /**
223
+ * Get instrument ID from price row.
224
+ * @param {Object} row - asset_prices row
225
+ * @returns {number|null}
226
+ */
227
+ function getPriceInstrumentId(row) {
228
+ return row?.instrument_id || null;
229
+ }
230
+
231
+ /**
232
+ * Get ticker from price row.
233
+ * @param {Object} row - asset_prices row
234
+ * @returns {string|null}
235
+ */
236
+ function getPriceTicker(row) {
237
+ const ticker = row?.ticker;
238
+ if (!ticker || ticker.startsWith('unknown_')) return null;
239
+ return ticker;
240
+ }
241
+
242
+ /**
243
+ * Calculate price change from open (if available).
244
+ * @param {Object} row - asset_prices row
245
+ * @returns {number|null}
246
+ */
247
+ function getDailyChange(row) {
248
+ const open = getOpenPrice(row);
249
+ const close = getClosePrice(row);
250
+
251
+ if (!open || !close || open === 0) return null;
252
+
253
+ return ((close - open) / open) * 100;
254
+ }
255
+
256
+ /**
257
+ * Calculate intraday range percentage (if available).
258
+ * @param {Object} row - asset_prices row
259
+ * @returns {number|null}
260
+ */
261
+ function getIntradayRange(row) {
262
+ const high = getHighPrice(row);
263
+ const low = getLowPrice(row);
264
+
265
+ if (!high || !low || low === 0) return null;
266
+
267
+ return ((high - low) / low) * 100;
268
+ }
269
+
270
+ // =============================================================================
271
+ // TICKER MAPPINGS
272
+ // =============================================================================
273
+
274
+ /**
275
+ * Build a ticker lookup map from ticker_mappings rows.
276
+ * @param {Array} rows - Array of ticker_mappings rows
277
+ * @returns {Object} { byId: Map<id, ticker>, byTicker: Map<ticker, id> }
278
+ */
279
+ function buildTickerMaps(rows) {
280
+ const byId = new Map();
281
+ const byTicker = new Map();
282
+
283
+ for (const row of (rows || [])) {
284
+ const id = row.instrument_id;
285
+ const ticker = row.ticker;
286
+
287
+ if (id && ticker) {
288
+ byId.set(id, ticker);
289
+ byTicker.set(ticker.toUpperCase(), id);
290
+ }
291
+ }
292
+
293
+ return { byId, byTicker };
294
+ }
295
+
296
+ /**
297
+ * Get ticker by instrument ID.
298
+ * @param {Map|Object} tickerMap - Map of id -> ticker (or byId map)
299
+ * @param {number|string} instrumentId - Instrument ID
300
+ * @returns {string|null}
301
+ */
302
+ function getTickerById(tickerMap, instrumentId) {
303
+ if (tickerMap instanceof Map) {
304
+ return tickerMap.get(Number(instrumentId)) || null;
305
+ }
306
+ return tickerMap?.[instrumentId] || null;
307
+ }
308
+
309
+ /**
310
+ * Get instrument ID by ticker.
311
+ * @param {Map|Object} tickerMap - Map of ticker -> id (or byTicker map)
312
+ * @param {string} ticker - Ticker symbol
313
+ * @returns {number|null}
314
+ */
315
+ function getIdByTicker(tickerMap, ticker) {
316
+ if (!ticker) return null;
317
+
318
+ if (tickerMap instanceof Map) {
319
+ return tickerMap.get(ticker.toUpperCase()) || null;
320
+ }
321
+ return tickerMap?.[ticker.toUpperCase()] || null;
322
+ }
323
+
324
+ // =============================================================================
325
+ // PRICE UTILITIES
326
+ // =============================================================================
327
+
328
+ /**
329
+ * Build a price lookup map from asset_prices rows.
330
+ * @param {Array} rows - Array of asset_prices rows
331
+ * @returns {Map} Map of instrumentId -> price
332
+ */
333
+ function buildPriceMap(rows) {
334
+ const priceMap = new Map();
335
+
336
+ for (const row of (rows || [])) {
337
+ const id = getPriceInstrumentId(row);
338
+ const price = getPrice(row);
339
+
340
+ if (id && price > 0) {
341
+ priceMap.set(id, price);
342
+ }
343
+ }
344
+
345
+ return priceMap;
346
+ }
347
+
348
+ /**
349
+ * Get price for an instrument from price map.
350
+ * @param {Map|Object} priceMap - Price lookup map
351
+ * @param {number|string} instrumentId - Instrument ID
352
+ * @returns {number}
353
+ */
354
+ function getPriceForInstrument(priceMap, instrumentId) {
355
+ if (priceMap instanceof Map) {
356
+ return priceMap.get(Number(instrumentId)) || 0;
357
+ }
358
+ return priceMap?.[instrumentId] || 0;
359
+ }
360
+
361
+ /**
362
+ * Calculate price change between two price rows.
363
+ * @param {Object} currentRow - Current price row
364
+ * @param {Object} previousRow - Previous price row
365
+ * @returns {Object} { absolute, percentage }
366
+ */
367
+ function calculatePriceChange(currentRow, previousRow) {
368
+ const current = getPrice(currentRow);
369
+ const previous = getPrice(previousRow);
370
+
371
+ if (!previous || previous === 0) {
372
+ return { absolute: 0, percentage: 0 };
373
+ }
374
+
375
+ return {
376
+ absolute: current - previous,
377
+ percentage: ((current - previous) / previous) * 100
378
+ };
379
+ }
380
+
381
+ // =============================================================================
382
+ // COMBINED INSTRUMENT INFO
383
+ // =============================================================================
384
+
385
+ /**
386
+ * Build comprehensive instrument info.
387
+ * @param {Object} options
388
+ * @param {Object} [options.insightsRow] - instrument_insights row
389
+ * @param {Object} [options.priceRow] - asset_prices row
390
+ * @param {Object} [options.tickerMaps] - Ticker maps
391
+ * @returns {Object}
392
+ */
393
+ function buildInstrumentInfo(options = {}) {
394
+ const { insightsRow, priceRow, tickerMaps } = options;
395
+
396
+ const insightsData = insightsRow ? extractInsightsData(insightsRow) : null;
397
+ const instrumentId = insightsRow
398
+ ? getInsightsInstrumentId(insightsRow)
399
+ : (priceRow ? getPriceInstrumentId(priceRow) : null);
400
+
401
+ const ticker = priceRow
402
+ ? getPriceTicker(priceRow)
403
+ : (tickerMaps?.byId ? getTickerById(tickerMaps.byId, instrumentId) : null);
404
+
405
+ return {
406
+ instrumentId,
407
+ ticker,
408
+
409
+ // Price data
410
+ price: priceRow ? getPrice(priceRow) : null,
411
+
412
+ // Sentiment data
413
+ sentiment: insightsData ? {
414
+ buyPercent: getBuyPercent(insightsData),
415
+ sellPercent: getSellPercent(insightsData),
416
+ score: calculateSentimentScore(insightsData),
417
+ category: getSentimentCategory(insightsData),
418
+ growth: getGrowth(insightsData),
419
+ platformPct: getPlatformPercentage(insightsData),
420
+ totalOwners: getTotalOwners(insightsData)
421
+ } : null
422
+ };
423
+ }
424
+
425
+ module.exports = {
426
+ // Insights
427
+ extractInsightsData,
428
+ getInsightsInstrumentId,
429
+ getBuyPercent,
430
+ getSellPercent,
431
+ getGrowth,
432
+ getPlatformPercentage,
433
+ getTotalOwners,
434
+ getPrevBuy,
435
+ getPrevSell,
436
+ calculateSentimentScore,
437
+ getSentimentCategory,
438
+ getSentimentChange,
439
+ isSentimentTrendingUp,
440
+
441
+ // Prices
442
+ getPrice,
443
+ getClosePrice,
444
+ getOpenPrice,
445
+ getHighPrice,
446
+ getLowPrice,
447
+ getVolume,
448
+ getPriceInstrumentId,
449
+ getPriceTicker,
450
+ getDailyChange,
451
+ getIntradayRange,
452
+
453
+ // Ticker mappings
454
+ buildTickerMaps,
455
+ getTickerById,
456
+ getIdByTicker,
457
+
458
+ // Price utilities
459
+ buildPriceMap,
460
+ getPriceForInstrument,
461
+ calculatePriceChange,
462
+
463
+ // Combined
464
+ buildInstrumentInfo
465
+ };