aiden-shared-calculations-unified 1.0.76 → 1.0.77

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 (114) hide show
  1. package/calculations/{pnl/asset_pnl_status.js → core/asset-pnl-status.js} +20 -0
  2. package/calculations/{asset_metrics/asset_position_size.js → core/asset-position-size.js} +25 -1
  3. package/calculations/{pnl/average_daily_pnl_all_users.js → core/average-daily-pnl-all-users.js} +22 -0
  4. package/calculations/{pnl/average_daily_pnl_per_sector.js → core/average-daily-pnl-per-sector.js} +22 -0
  5. package/calculations/{pnl/average_daily_pnl_per_stock.js → core/average-daily-pnl-per-stock.js} +22 -0
  6. package/calculations/{pnl/average_daily_position_pnl.js → core/average-daily-position-pnl.js} +22 -0
  7. package/calculations/{behavioural/historical/holding_duration_per_asset.js → core/holding-duration-per-asset.js} +44 -4
  8. package/calculations/{meta/gem_instrument-price-momentum.js → core/instrument-price-momentum-20d.js} +17 -4
  9. package/calculations/{short_and_long_stats/long_position_per_stock.js → core/long-position-per-stock.js} +24 -0
  10. package/calculations/{behavioural/overall_holding_duration.js → core/overall-holding-duration.js} +27 -3
  11. package/calculations/{pnl/overall_profitability_ratio.js → core/overall-profitability-ratio.js} +24 -0
  12. package/calculations/{insights/daily_buy_sell_sentiment_count.js → core/platform-buy-sell-sentiment.js} +22 -0
  13. package/calculations/{insights/historical/daily_bought_vs_sold_count.js → core/platform-daily-bought-vs-sold-count.js} +22 -0
  14. package/calculations/{insights/historical/daily_ownership_delta.js → core/platform-daily-ownership-delta.js} +22 -0
  15. package/calculations/{insights/daily_ownership_per_sector.js → core/platform-ownership-per-sector.js} +22 -0
  16. package/calculations/{insights/daily_total_positions_held.js → core/platform-total-positions-held.js} +22 -0
  17. package/calculations/{pnl/pnl_distribution_per_stock.js → core/pnl-distribution-per-stock.js} +24 -0
  18. package/calculations/{pnl/profitability_ratio_per_sector,js → core/profitability-ratio-per-sector.js} +35 -5
  19. package/calculations/{pnl/profitability_ratio_per_stock.js → core/profitability-ratio-per-stock.js} +24 -0
  20. package/calculations/{pnl/profitability_skew_per_stock.js → core/profitability-skew-per-stock.js} +24 -0
  21. package/calculations/{pnl/profitable_and_unprofitable_status.js → core/profitable-and-unprofitable-status.js} +24 -0
  22. package/calculations/{short_and_long_stats/sentiment_per_stock.js → core/sentiment-per-stock.js} +20 -0
  23. package/calculations/{short_and_long_stats/short_position_per_stock.js → core/short-position-per-stock.js} +24 -0
  24. package/calculations/{socialPosts/social_activity_aggregation.js → core/social-activity-aggregation.js} +32 -8
  25. package/calculations/{socialPosts → core}/social-asset-posts-trend.js +30 -8
  26. package/calculations/{socialPosts/social_event_correlation.js → core/social-event-correlation.js} +24 -2
  27. package/calculations/{socialPosts/social_sentiment_aggregation.js → core/social-sentiment-aggregation.js} +23 -0
  28. package/calculations/{socialPosts → core}/social-top-mentioned-words.js +31 -8
  29. package/calculations/{socialPosts → core}/social-topic-interest-evolution.js +35 -11
  30. package/calculations/{socialPosts → core}/social-topic-sentiment-matrix.js +34 -10
  31. package/calculations/{socialPosts → core}/social-word-mentions-trend.js +36 -11
  32. package/calculations/{speculators/speculator_asset_sentiment.js → core/speculator-asset-sentiment.js} +20 -0
  33. package/calculations/{speculators/speculator_danger_zone.js → core/speculator-danger-zone.js} +22 -0
  34. package/calculations/{speculators/distance_to_stop_loss_per_leverage.js → core/speculator-distance-to-stop-loss-per-leverage.js} +24 -0
  35. package/calculations/{speculators/distance_to_tp_per_leverage.js → core/speculator-distance-to-tp-per-leverage.js} +24 -0
  36. package/calculations/{speculators/entry_distance_to_sl_per_leverage.js → core/speculator-entry-distance-to-sl-per-leverage.js} +24 -0
  37. package/calculations/{speculators/entry_distance_to_tp_per_leverage.js → core/speculator-entry-distance-to-tp-per-leverage.js} +24 -0
  38. package/calculations/{speculators/leverage_per_asset.js → core/speculator-leverage-per-asset.js} +20 -0
  39. package/calculations/{speculators/leverage_per_sector.js → core/speculator-leverage-per-sector.js} +22 -0
  40. package/calculations/{speculators/risk_reward_ratio_per_asset.js → core/speculator-risk-reward-ratio-per-asset.js} +20 -0
  41. package/calculations/{speculators/stop_loss_distance_by_sector_short_long_breakdown.js → core/speculator-stop-loss-distance-by-sector-short-long-breakdown.js} +22 -0
  42. package/calculations/{speculators/stop_loss_distance_by_ticker_short_long_breakdown.js → core/speculator-stop-loss-distance-by-ticker-short-long-breakdown.js} +24 -0
  43. package/calculations/{speculators/stop_loss_per_asset.js → core/speculator-stop-loss-per-asset.js} +24 -0
  44. package/calculations/{speculators/take_profit_per_asset.js → core/speculator-take-profit-per-asset.js} +24 -0
  45. package/calculations/{speculators/tsl_per_asset.js → core/speculator-tsl-per-asset.js} +24 -0
  46. package/calculations/{short_and_long_stats/total_long_figures.js → core/total-long-figures.js} +24 -0
  47. package/calculations/{sectors/total_long_per_sector.js → core/total-long-per-sector.js} +22 -0
  48. package/calculations/{short_and_long_stats/total_short_figures.js → core/total-short-figures.js} +24 -0
  49. package/calculations/{sectors/total_short_per_sector.js → core/total-short-per-sector.js} +22 -0
  50. package/calculations/{sanity/users_processed.js → core/users-processed.js} +22 -0
  51. package/calculations/gauss/cohort-capital-flow.js +216 -0
  52. package/calculations/gauss/cohort-definer.js +211 -0
  53. package/calculations/gauss/daily-dna-filter.js +130 -0
  54. package/calculations/gauss/gauss-divergence-signal.js +160 -0
  55. package/calculations/{meta/gem_cohort-momentum-state.js → gem/cohort-momentum-state.js} +22 -7
  56. package/calculations/{behavioural/historical/gem_cohort-skill-definition.js → gem/cohort-skill-definition.js} +18 -1
  57. package/calculations/{sentiment/gem_platform-conviction-divergence.js → gem/platform-conviction-divergence.js} +13 -0
  58. package/calculations/{meta/gem_quant-skill-alpha-signal.js → gem/quant-skill-alpha-signal.js} +25 -8
  59. package/calculations/{behavioural/historical/gem_skilled-cohort-flow.js → gem/skilled-cohort-flow.js} +16 -2
  60. package/calculations/{meta/gem_skilled-unskilled-divergence.js → gem/skilled-unskilled-divergence.js} +18 -4
  61. package/calculations/{behavioural/historical/gem_unskilled-cohort-flow.js → gem/unskilled-cohort-flow.js} +16 -2
  62. package/calculations/helix/helix-contrarian-signal.js +154 -0
  63. package/calculations/helix/herd-consensus-score.js +152 -0
  64. package/calculations/helix/winner-loser-flow.js +206 -0
  65. package/calculations/{behavioural/historical → legacy}/asset_crowd_flow.js +1 -1
  66. package/calculations/{sentiment/historical → legacy}/crowd_conviction_score.js +1 -1
  67. package/calculations/{activity/historical → legacy}/daily_asset_activity.js +1 -1
  68. package/calculations/{behavioural/historical → legacy}/dumb-cohort-flow.js +1 -1
  69. package/calculations/{behavioural/historical → legacy}/in_loss_asset_crowd_flow.js +1 -1
  70. package/calculations/{behavioural/historical → legacy}/in_profit_asset_crowd_flow.js +1 -1
  71. package/calculations/{speculators/historical → legacy}/risk_appetite_change.js +3 -1
  72. package/calculations/{sectors/historical → legacy}/sector_rotation.js +1 -1
  73. package/calculations/{behavioural/historical → legacy}/smart-cohort-flow.js +1 -1
  74. package/calculations/{behavioural/historical → legacy}/smart_money_flow.js +1 -1
  75. package/calculations/{behavioural/historical → legacy}/user-investment-profile.js +2 -2
  76. package/calculations/pyro/risk-appetite-index.js +153 -0
  77. package/calculations/pyro/squeeze-potential.js +158 -0
  78. package/calculations/pyro/volatility-signal.js +133 -0
  79. package/package.json +1 -1
  80. package/calculations/socialPosts/gem_social_sentiment_aggregation.js +0 -146
  81. /package/calculations/{activity/historical → legacy}/activity_by_pnl_status.js +0 -0
  82. /package/calculations/{meta → legacy}/capital_deployment_strategy.js +0 -0
  83. /package/calculations/{meta → legacy}/capital_liquidation_performance.js +0 -0
  84. /package/calculations/{meta → legacy}/capital_vintage_performance.js +0 -0
  85. /package/calculations/{meta → legacy}/cash-flow-deployment.js +0 -0
  86. /package/calculations/{meta → legacy}/cash-flow-liquidation.js +0 -0
  87. /package/calculations/{capital_flow/historical → legacy}/crowd-cash-flow-proxy.js +0 -0
  88. /package/calculations/{meta → legacy}/crowd_sharpe_ratio_proxy.js +0 -0
  89. /package/calculations/{activity/historical → legacy}/daily_user_activity_tracker.js +0 -0
  90. /package/calculations/{capital_flow/historical → legacy}/deposit_withdrawal_percentage.js +0 -0
  91. /package/calculations/{sectors/historical → legacy}/diversification_pnl.js +0 -0
  92. /package/calculations/{behavioural/historical → legacy}/drawdown_response.js +0 -0
  93. /package/calculations/{behavioural/historical → legacy}/gain_response.js +0 -0
  94. /package/calculations/{behavioural/historical → legacy}/historical_performance_aggregator.js +0 -0
  95. /package/calculations/{meta → legacy}/negative_expectancy_cohort_flow.js +0 -0
  96. /package/calculations/{capital_flow/historical → legacy}/new_allocation_percentage.js +0 -0
  97. /package/calculations/{behavioural/historical → legacy}/paper_vs_diamond_hands.js +0 -0
  98. /package/calculations/{behavioural/historical → legacy}/position_count_pnl.js +0 -0
  99. /package/calculations/{meta → legacy}/positive_expectancy_cohort_flow.js +0 -0
  100. /package/calculations/{meta → legacy}/profit_cohort_divergence.js +0 -0
  101. /package/calculations/{pnl/historical → legacy}/profitability_migration.js +0 -0
  102. /package/calculations/{capital_flow/historical → legacy}/reallocation_increase_percentage.js +0 -0
  103. /package/calculations/{meta → legacy}/shark_attack_signal.js +0 -0
  104. /package/calculations/{meta → legacy}/smart-dumb-divergence-index.js +0 -0
  105. /package/calculations/{meta → legacy}/smart_dumb_divergence_index_v2.js +0 -0
  106. /package/calculations/{meta → legacy}/social-predictive-regime-state.js +0 -0
  107. /package/calculations/{meta → legacy}/social-topic-driver-index.js +0 -0
  108. /package/calculations/{meta → legacy}/social-topic-predictive-potential.js +0 -0
  109. /package/calculations/{meta → legacy}/social_flow_correlation.js +0 -0
  110. /package/calculations/{activity/historical → legacy}/speculator_adjustment_activity.js +0 -0
  111. /package/calculations/{backtests → legacy}/strategy-performance.js +0 -0
  112. /package/calculations/{speculators/historical → legacy}/tsl_effectiveness.js +0 -0
  113. /package/calculations/{meta → legacy}/user_expectancy_score.js +0 -0
  114. /package/calculations/{pnl/historical → legacy}/user_profitability_tracker.js +0 -0
@@ -13,6 +13,28 @@ class ProfitabilityRatioPerStock {
13
13
  this.mappings = null;
14
14
  }
15
15
 
16
+ // --- NEW ---
17
+ /**
18
+ * Statically defines all metadata for the manifest builder.
19
+ */
20
+ static getMetadata() {
21
+ return {
22
+ type: 'standard',
23
+ rootDataDependencies: ['portfolio'],
24
+ isHistorical: false,
25
+ userType: 'all',
26
+ category: 'core_pnl'
27
+ };
28
+ }
29
+
30
+ // --- NEW ---
31
+ /**
32
+ * Statically declare dependencies.
33
+ */
34
+ static getDependencies() {
35
+ return [];
36
+ }
37
+
16
38
  /**
17
39
  * Defines the output schema for this calculation.
18
40
  * @returns {object} JSON Schema object
@@ -57,6 +79,8 @@ class ProfitabilityRatioPerStock {
57
79
  }
58
80
  }
59
81
 
82
+ // --- REFACTORED ---
83
+ // Simplified signature
60
84
  process(portfolioData) {
61
85
  const positions = portfolioData.PublicPositions || portfolioData.AggregatedPositions;
62
86
  if (!positions || !Array.isArray(positions)) {
@@ -16,6 +16,28 @@ class ProfitabilitySkewPerStock {
16
16
  this.mappings = null;
17
17
  }
18
18
 
19
+ // --- NEW ---
20
+ /**
21
+ * Statically defines all metadata for the manifest builder.
22
+ */
23
+ static getMetadata() {
24
+ return {
25
+ type: 'standard',
26
+ rootDataDependencies: ['portfolio'],
27
+ isHistorical: false,
28
+ userType: 'all',
29
+ category: 'core_pnl'
30
+ };
31
+ }
32
+
33
+ // --- NEW ---
34
+ /**
35
+ * Statically declare dependencies.
36
+ */
37
+ static getDependencies() {
38
+ return [];
39
+ }
40
+
19
41
  /**
20
42
  * Defines the output schema for this calculation.
21
43
  * @returns {object} JSON Schema object
@@ -58,6 +80,8 @@ class ProfitabilitySkewPerStock {
58
80
  }
59
81
  }
60
82
 
83
+ // --- REFACTORED ---
84
+ // Simplified signature
61
85
  process(portfolioData) {
62
86
  const positions = portfolioData.PublicPositions || portfolioData.AggregatedPositions;
63
87
  if (!positions || !Array.isArray(positions)) {
@@ -10,6 +10,28 @@ class ProfitableAndUnprofitableStatus {
10
10
  this.total_in_loss = 0;
11
11
  }
12
12
 
13
+ // --- NEW ---
14
+ /**
15
+ * Statically defines all metadata for the manifest builder.
16
+ */
17
+ static getMetadata() {
18
+ return {
19
+ type: 'standard',
20
+ rootDataDependencies: ['portfolio'], // Needs portfolio.Summary
21
+ isHistorical: false,
22
+ userType: 'all',
23
+ category: 'core_pnl'
24
+ };
25
+ }
26
+
27
+ // --- NEW ---
28
+ /**
29
+ * Statically declare dependencies.
30
+ */
31
+ static getDependencies() {
32
+ return [];
33
+ }
34
+
13
35
  /**
14
36
  * Defines the output schema for this calculation.
15
37
  * @returns {object} JSON Schema object
@@ -36,6 +58,8 @@ class ProfitableAndUnprofitableStatus {
36
58
  };
37
59
  }
38
60
 
61
+ // --- REFACTORED ---
62
+ // Simplified signature
39
63
  process(portfolioData) {
40
64
  // Use the P&L from the summary, which is for the *day*
41
65
  const dailyPnl = portfolioData.Summary?.NetProfit || 0;
@@ -48,6 +48,26 @@ class SentimentPerStock {
48
48
  };
49
49
  }
50
50
 
51
+ /**
52
+ * Statically defines all metadata for the manifest builder.
53
+ */
54
+ static getMetadata() {
55
+ return {
56
+ type: 'standard',
57
+ rootDataDependencies: ['portfolio'],
58
+ isHistorical: false,
59
+ userType: 'all',
60
+ category: 'core_sentiment'
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Statically declare dependencies.
66
+ */
67
+ static getDependencies() {
68
+ return [];
69
+ }
70
+
51
71
  _initAsset(instrumentId) {
52
72
  if (!this.assets.has(instrumentId)) {
53
73
  this.assets.set(instrumentId, {
@@ -13,6 +13,28 @@ class ShortPositionPerStock {
13
13
  this.mappings = null;
14
14
  }
15
15
 
16
+ // --- NEW ---
17
+ /**
18
+ * Statically defines all metadata for the manifest builder.
19
+ */
20
+ static getMetadata() {
21
+ return {
22
+ type: 'standard',
23
+ rootDataDependencies: ['portfolio'],
24
+ isHistorical: false,
25
+ userType: 'all',
26
+ category: 'core_sentiment'
27
+ };
28
+ }
29
+
30
+ // --- NEW ---
31
+ /**
32
+ * Statically declare dependencies.
33
+ */
34
+ static getDependencies() {
35
+ return [];
36
+ }
37
+
16
38
  /**
17
39
  * Defines the output schema for this calculation.
18
40
  * @returns {object} JSON Schema object
@@ -40,6 +62,8 @@ class ShortPositionPerStock {
40
62
  }
41
63
  }
42
64
 
65
+ // --- REFACTORED ---
66
+ // Simplified signature
43
67
  process(portfolioData) {
44
68
  const positions = portfolioData.PublicPositions || portfolioData.AggregatedPositions;
45
69
  if (!positions || !Array.isArray(positions)) {
@@ -16,6 +16,28 @@ class SocialActivityAggregation {
16
16
  this.perTicker = new Map();
17
17
  }
18
18
 
19
+ // --- NEW ---
20
+ /**
21
+ * Statically defines all metadata for the manifest builder.
22
+ */
23
+ static getMetadata() {
24
+ return {
25
+ type: 'meta', // Runs once, not per-user
26
+ rootDataDependencies: ['social'], // Needs the social posts doc
27
+ isHistorical: false,
28
+ userType: 'n/a',
29
+ category: 'core_social'
30
+ };
31
+ }
32
+
33
+ // --- NEW ---
34
+ /**
35
+ * Statically declare dependencies.
36
+ */
37
+ static getDependencies() {
38
+ return [];
39
+ }
40
+
19
41
  /**
20
42
  * Defines the output schema for this calculation.
21
43
  * @returns {object} JSON Schema object
@@ -67,19 +89,21 @@ class SocialActivityAggregation {
67
89
  }
68
90
  }
69
91
 
92
+ // --- REFACTORED ---
70
93
  /**
94
+ * This is a 'meta' calculation.
71
95
  * @param {string} dateStr - Today's date.
72
- * @param {object} dependencies - db, logger.
73
- * @param {object} config - Computation config.
74
- * @param {object} fetchedDependencies - (UNUSED) In-memory results.
96
+ * @param {object} rootData - The root data object.
97
+ * @param {object} dependencies - db, logger, calculationUtils.
75
98
  */
76
- async process(dateStr, dependencies, config, fetchedDependencies) {
99
+ async process(dateStr, rootData, dependencies) {
77
100
  const { calculationUtils } = dependencies;
78
- const todaySocialPosts = await calculationUtils.loadSocialData(dateStr);
101
+ // The runner provides social data inside rootData
102
+ const todaySocialPosts = rootData.todaySocialPostInsights || {};
79
103
 
80
- for (const post of todaySocialPosts) {
81
- const likes = post.likes || 0;
82
- const comments = post.comments || 0;
104
+ for (const post of Object.values(todaySocialPosts)) {
105
+ const likes = post.likeCount || 0;
106
+ const comments = post.commentCount || 0;
83
107
 
84
108
  // 1. Aggregate global stats
85
109
  this.global.total_posts++;
@@ -13,6 +13,28 @@ class SocialAssetPostsTrend {
13
13
  this.assetData = new Map();
14
14
  }
15
15
 
16
+ // --- NEW ---
17
+ /**
18
+ * Statically defines all metadata for the manifest builder.
19
+ */
20
+ static getMetadata() {
21
+ return {
22
+ type: 'meta',
23
+ rootDataDependencies: ['social'], // Needs social posts
24
+ isHistorical: false, // It's stateful, but reads its *own* history
25
+ userType: 'n/a',
26
+ category: 'core_social'
27
+ };
28
+ }
29
+
30
+ // --- NEW ---
31
+ /**
32
+ * Statically declare dependencies.
33
+ */
34
+ static getDependencies() {
35
+ return [];
36
+ }
37
+
16
38
  /**
17
39
  * Defines the output schema for this calculation.
18
40
  * @returns {object} JSON Schema object
@@ -49,16 +71,17 @@ class SocialAssetPostsTrend {
49
71
  };
50
72
  }
51
73
 
74
+ // --- REFACTORED ---
52
75
  /**
53
76
  * @param {string} dateStr - Today's date.
54
- * @param {object} dependencies - db, logger.
55
- * @param {object} config - Computation config.
56
- * @param {object} fetchedDependencies - (UNUSED) In-memory results.
77
+ * @param {object} rootData - The root data object.
78
+ * @param {object} dependencies - db, logger, calculationUtils
57
79
  */
58
- async process(dateStr, dependencies, config, fetchedDependencies) {
59
- const { db, logger, calculationUtils } = dependencies;
80
+ async process(dateStr, rootData, dependencies) {
81
+ const { calculationUtils } = dependencies;
60
82
 
61
83
  // 1. Load this metric's history from yesterday
84
+ // The runner must provide `loadYesterdayData` on calculationUtils
62
85
  const yHistoryData = await calculationUtils.loadYesterdayData('social-asset-posts-trend');
63
86
 
64
87
  // 2. Initialize state with history
@@ -72,10 +95,9 @@ class SocialAssetPostsTrend {
72
95
  }
73
96
 
74
97
  // 3. Process today's raw social data
75
- // This relies on the social data loader (not shown here)
76
- const todaySocialPosts = await calculationUtils.loadSocialData(dateStr);
98
+ const todaySocialPosts = rootData.todaySocialPostInsights || {};
77
99
 
78
- for (const post of todaySocialPosts) {
100
+ for (const post of Object.values(todaySocialPosts)) {
79
101
  const tickers = post.tickers || [];
80
102
  for (const ticker of tickers) {
81
103
  if (!this.assetData.has(ticker)) {
@@ -11,6 +11,28 @@ class SocialEventCorrelation {
11
11
  this.processed = false;
12
12
  }
13
13
 
14
+ // --- NEW ---
15
+ /**
16
+ * Statically defines all metadata for the manifest builder.
17
+ */
18
+ static getMetadata() {
19
+ return {
20
+ type: 'standard', // Runs per-user, but only executes logic once
21
+ rootDataDependencies: ['social'],
22
+ isHistorical: true, // Needs yesterday's social posts
23
+ userType: 'all', // Runs on the first user and then stops
24
+ category: 'core_social'
25
+ };
26
+ }
27
+
28
+ // --- NEW ---
29
+ /**
30
+ * Statically declare dependencies.
31
+ */
32
+ static getDependencies() {
33
+ return [];
34
+ }
35
+
14
36
  /**
15
37
  * Helper to process a set of posts and populate volume/topic counts.
16
38
  * @param {object} socialPostInsights - Map of { [postId]: postData }
@@ -52,8 +74,8 @@ class SocialEventCorrelation {
52
74
  * @param {null} yesterdayPortfolio - Not used.
53
75
  * @param {null} userId - Not used.
54
76
  * @param {object} context - Shared context (e.g., mappings).
55
- * @param {object} todayInsights - Daily instrument insights.
56
- * @param {object} yesterdayInsights - Yesterday's instrument insights.
77
+ * @param {object} todayInsights - (Not used)
78
+ * @param {object} yesterdayInsights - (Not used)
57
79
  * @param {object} todaySocialPostInsights - Map of { [postId]: postData } for today.
58
80
  * @param {object} yesterdaySocialPostInsights - Map of { [postId]: postData } for yesterday.
59
81
  */
@@ -58,6 +58,26 @@ class SocialSentimentAggregation {
58
58
  };
59
59
  }
60
60
 
61
+ /**
62
+ * Statically defines all metadata for the manifest builder.
63
+ */
64
+ static getMetadata() {
65
+ return {
66
+ type: 'meta',
67
+ rootDataDependencies: ['social'],
68
+ isHistorical: false,
69
+ userType: 'n/a',
70
+ category: 'core_metrics'
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Statically declare dependencies.
76
+ */
77
+ static getDependencies() {
78
+ return [];
79
+ }
80
+
61
81
  _initTicker(ticker) {
62
82
  if (!this.perTicker.has(ticker)) {
63
83
  this.perTicker.set(ticker, {
@@ -76,9 +96,12 @@ class SocialSentimentAggregation {
76
96
  */
77
97
  async process(dateStr, dependencies, config, fetchedDependencies) {
78
98
  const { calculationUtils } = dependencies;
99
+ // This helper should exist on calculationUtils, loaded by the runner
79
100
  const todaySocialPosts = await calculationUtils.loadSocialData(dateStr);
80
101
 
81
102
  for (const post of todaySocialPosts) {
103
+ // This logic assumes 'sentiment' is a simple string,
104
+ // not the object from gemini. This is correct for this calc.
82
105
  const sentiment = post.sentiment || 'neutral'; // 'bullish', 'bearish', 'neutral'
83
106
 
84
107
  // 1. Aggregate global sentiment
@@ -15,6 +15,28 @@ class SocialTopMentionedWords {
15
15
  this.stopWords = new Set(['the', 'a', 'is', 'in', 'to', 'for', 'of', 'and', 'it', 'on', 'with', 'that', 'this', 'buy', 'sell']);
16
16
  }
17
17
 
18
+ // --- NEW ---
19
+ /**
20
+ * Statically defines all metadata for the manifest builder.
21
+ */
22
+ static getMetadata() {
23
+ return {
24
+ type: 'meta',
25
+ rootDataDependencies: ['social'],
26
+ isHistorical: false, // Stateful
27
+ userType: 'n/a',
28
+ category: 'core_social'
29
+ };
30
+ }
31
+
32
+ // --- NEW ---
33
+ /**
34
+ * Statically declare dependencies.
35
+ */
36
+ static getDependencies() {
37
+ return [];
38
+ }
39
+
18
40
  /**
19
41
  * Defines the output schema for this calculation.
20
42
  * @returns {object} JSON Schema object
@@ -38,14 +60,14 @@ class SocialTopMentionedWords {
38
60
  };
39
61
  }
40
62
 
63
+ // --- REFACTORED ---
41
64
  /**
42
65
  * @param {string} dateStr - Today's date.
43
- * @param {object} dependencies - db, logger.
44
- * @param {object} config - Computation config.
45
- * @param {object} fetchedDependencies - (UNUSED) In-memory results.
66
+ * @param {object} rootData - The root data object.
67
+ * @param {object} dependencies - db, logger, calculationUtils
46
68
  */
47
- async process(dateStr, dependencies, config, fetchedDependencies) {
48
- const { db, logger, calculationUtils } = dependencies;
69
+ async process(dateStr, rootData, dependencies) {
70
+ const { calculationUtils } = dependencies;
49
71
 
50
72
  // 1. Load this metric's history from yesterday
51
73
  // Note: History is stored by word
@@ -61,10 +83,11 @@ class SocialTopMentionedWords {
61
83
  }
62
84
 
63
85
  // 2. Process today's raw social data
64
- const todaySocialPosts = await calculationUtils.loadSocialData(dateStr);
86
+ const todaySocialPosts = rootData.todaySocialPostInsights || {};
65
87
 
66
- for (const post of todaySocialPosts) {
67
- const text = (post.content || '').toLowerCase().replace(/[^a-z\s]/g, '');
88
+ for (const post of Object.values(todaySocialPosts)) {
89
+ // Use `fullText` for complete analysis
90
+ const text = (post.fullText || '').toLowerCase().replace(/[^a-z\s]/g, '');
68
91
  const words = text.split(/\s+/);
69
92
 
70
93
  for (const word of words) {
@@ -12,6 +12,28 @@ class SocialTopicInterestEvolution {
12
12
  this.topicData = new Map();
13
13
  }
14
14
 
15
+ // --- NEW ---
16
+ /**
17
+ * Statically defines all metadata for the manifest builder.
18
+ */
19
+ static getMetadata() {
20
+ return {
21
+ type: 'meta',
22
+ rootDataDependencies: ['social'],
23
+ isHistorical: false, // Stateful, not historical
24
+ userType: 'n/a',
25
+ category: 'core_social'
26
+ };
27
+ }
28
+
29
+ // --- NEW ---
30
+ /**
31
+ * Statically declare dependencies.
32
+ */
33
+ static getDependencies() {
34
+ return [];
35
+ }
36
+
15
37
  /**
16
38
  * Defines the output schema for this calculation.
17
39
  * @returns {object} JSON Schema object
@@ -48,14 +70,14 @@ class SocialTopicInterestEvolution {
48
70
  };
49
71
  }
50
72
 
73
+ // --- REFACTORED ---
51
74
  /**
52
75
  * @param {string} dateStr - Today's date.
53
- * @param {object} dependencies - db, logger.
54
- * @param {object} config - Computation config.
55
- * @param {object} fetchedDependencies - (UNUSED) In-memory results.
76
+ * @param {object} rootData - The root data object.
77
+ * @param {object} dependencies - db, logger, calculationUtils
56
78
  */
57
- async process(dateStr, dependencies, config, fetchedDependencies) {
58
- const { db, logger, calculationUtils } = dependencies;
79
+ async process(dateStr, rootData, dependencies) {
80
+ const { calculationUtils } = dependencies;
59
81
 
60
82
  // 1. Load this metric's history from yesterday
61
83
  const yHistoryData = await calculationUtils.loadYesterdayData('social-topic-interest-evolution');
@@ -70,16 +92,18 @@ class SocialTopicInterestEvolution {
70
92
  }
71
93
 
72
94
  // 2. Process today's raw social data
73
- const todaySocialPosts = await calculationUtils.loadSocialData(dateStr);
95
+ const todaySocialPosts = rootData.todaySocialPostInsights || {};
74
96
 
75
- for (const post of todaySocialPosts) {
97
+ for (const post of Object.values(todaySocialPosts)) {
76
98
  // Assume topics are extracted by the social loader
77
- const topics = post.topics || [];
99
+ // This now correctly reads the topics from the sentiment object
100
+ const topics = post.sentiment?.topics || [];
78
101
  for (const topic of topics) {
79
- if (!this.topicData.has(topic)) {
80
- this.topicData.set(topic, { count: 0, history: [] });
102
+ const normalizedTopic = topic.toLowerCase(); // Normalize
103
+ if (!this.topicData.has(normalizedTopic)) {
104
+ this.topicData.set(normalizedTopic, { count: 0, history: [] });
81
105
  }
82
- this.topicData.get(topic).count++;
106
+ this.topicData.get(normalizedTopic).count++;
83
107
  }
84
108
  }
85
109
  }
@@ -12,6 +12,28 @@ class SocialTopicSentimentMatrix {
12
12
  this.matrix = new Map();
13
13
  }
14
14
 
15
+ // --- NEW ---
16
+ /**
17
+ * Statically defines all metadata for the manifest builder.
18
+ */
19
+ static getMetadata() {
20
+ return {
21
+ type: 'meta',
22
+ rootDataDependencies: ['social'],
23
+ isHistorical: false,
24
+ userType: 'n/a',
25
+ category: 'core_social'
26
+ };
27
+ }
28
+
29
+ // --- NEW ---
30
+ /**
31
+ * Statically declare dependencies.
32
+ */
33
+ static getDependencies() {
34
+ return [];
35
+ }
36
+
15
37
  /**
16
38
  * Defines the output schema for this calculation.
17
39
  * @returns {object} JSON Schema object
@@ -48,23 +70,25 @@ class SocialTopicSentimentMatrix {
48
70
  }
49
71
  }
50
72
 
73
+ // --- REFACTORED ---
51
74
  /**
52
75
  * @param {string} dateStr - Today's date.
53
- * @param {object} dependencies - db, logger.
54
- * @param {object} config - Computation config.
55
- * @param {object} fetchedDependencies - (UNUSED) In-memory results.
76
+ * @param {object} rootData - The root data object.
77
+ * @param {object} dependencies - db, logger, calculationUtils
56
78
  */
57
- async process(dateStr, dependencies, config, fetchedDependencies) {
79
+ async process(dateStr, rootData, dependencies) {
58
80
  const { calculationUtils } = dependencies;
59
- const todaySocialPosts = await calculationUtils.loadSocialData(dateStr);
81
+ const todaySocialPosts = rootData.todaySocialPostInsights || {};
60
82
 
61
- for (const post of todaySocialPosts) {
62
- const topics = post.topics || [];
63
- const sentiment = post.sentiment || 'neutral'; // 'bullish', 'bearish', 'neutral'
83
+ for (const post of Object.values(todaySocialPosts)) {
84
+ const topics = post.sentiment?.topics || [];
85
+ // Use the structured sentiment object
86
+ const sentiment = post.sentiment?.overallSentiment?.toLowerCase() || 'neutral';
64
87
 
65
88
  for (const topic of topics) {
66
- this._initTopic(topic);
67
- const data = this.matrix.get(topic);
89
+ const normalizedTopic = topic.toLowerCase(); // Normalize
90
+ this._initTopic(normalizedTopic);
91
+ const data = this.matrix.get(normalizedTopic);
68
92
 
69
93
  if (sentiment === 'bullish') {
70
94
  data.bullish++;
@@ -14,6 +14,28 @@ class SocialWordMentionsTrend {
14
14
  this.keywords = [];
15
15
  }
16
16
 
17
+ // --- NEW ---
18
+ /**
19
+ * Statically defines all metadata for the manifest builder.
20
+ */
21
+ static getMetadata() {
22
+ return {
23
+ type: 'meta',
24
+ rootDataDependencies: ['social'],
25
+ isHistorical: false, // Stateful
26
+ userType: 'n/a',
27
+ category: 'core_social'
28
+ };
29
+ }
30
+
31
+ // --- NEW ---
32
+ /**
33
+ * Statically declare dependencies.
34
+ */
35
+ static getDependencies() {
36
+ return [];
37
+ }
38
+
17
39
  /**
18
40
  * Defines the output schema for this calculation.
19
41
  * @returns {object} JSON Schema object
@@ -50,14 +72,15 @@ class SocialWordMentionsTrend {
50
72
  };
51
73
  }
52
74
 
75
+ // --- REFACTORED ---
53
76
  /**
54
77
  * @param {string} dateStr - Today's date.
55
- * @param {object} dependencies - db, logger.
78
+ * @param {object} rootData - The root data object.
79
+ * @param {object} dependencies - db, logger, calculationUtils
56
80
  * @param {object} config - Computation config.
57
- * @param {object} fetchedDependencies - (UNUSED) In-memory results.
58
81
  */
59
- async process(dateStr, dependencies, config, fetchedDependencies) {
60
- const { db, logger, calculationUtils } = dependencies;
82
+ async process(dateStr, rootData, dependencies, config) {
83
+ const { calculationUtils } = dependencies;
61
84
 
62
85
  // 1. Load keywords from config (or another source)
63
86
  this.keywords = config.trackedKeywords || ['inflation', 'fed', 'AI', 'crypto', 'recession'];
@@ -67,21 +90,23 @@ class SocialWordMentionsTrend {
67
90
 
68
91
  // 3. Initialize state for all keywords
69
92
  for (const keyword of this.keywords) {
70
- this.keywordData.set(keyword, {
93
+ const normalizedKey = keyword.toLowerCase();
94
+ this.keywordData.set(normalizedKey, {
71
95
  count: 0,
72
- history: yHistoryData?.[keyword]?.history_30d || []
96
+ history: yHistoryData?.[normalizedKey]?.history_30d || []
73
97
  });
74
98
  }
75
99
 
76
100
  // 4. Process today's raw social data
77
- const todaySocialPosts = await calculationUtils.loadSocialData(dateStr);
101
+ const todaySocialPosts = rootData.todaySocialPostInsights || {};
78
102
 
79
- for (const post of todaySocialPosts) {
80
- const text = (post.content || '').toLowerCase();
103
+ for (const post of Object.values(todaySocialPosts)) {
104
+ const text = (post.fullText || '').toLowerCase();
81
105
 
82
106
  for (const keyword of this.keywords) {
83
- if (text.includes(keyword.toLowerCase())) {
84
- this.keywordData.get(keyword).count++;
107
+ const normalizedKey = keyword.toLowerCase();
108
+ if (text.includes(normalizedKey)) {
109
+ this.keywordData.get(normalizedKey).count++;
85
110
  }
86
111
  }
87
112
  }