aiden-shared-calculations-unified 1.0.34 → 1.0.36

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 (58) hide show
  1. package/README.MD +77 -77
  2. package/calculations/activity/historical/activity_by_pnl_status.js +85 -85
  3. package/calculations/activity/historical/daily_asset_activity.js +85 -85
  4. package/calculations/activity/historical/daily_user_activity_tracker.js +144 -144
  5. package/calculations/activity/historical/speculator_adjustment_activity.js +76 -76
  6. package/calculations/asset_metrics/asset_position_size.js +57 -57
  7. package/calculations/backtests/strategy-performance.js +229 -245
  8. package/calculations/behavioural/historical/asset_crowd_flow.js +165 -170
  9. package/calculations/behavioural/historical/drawdown_response.js +58 -58
  10. package/calculations/behavioural/historical/dumb-cohort-flow.js +249 -249
  11. package/calculations/behavioural/historical/gain_response.js +57 -57
  12. package/calculations/behavioural/historical/in_loss_asset_crowd_flow.js +98 -98
  13. package/calculations/behavioural/historical/in_profit_asset_crowd_flow.js +99 -99
  14. package/calculations/behavioural/historical/paper_vs_diamond_hands.js +39 -39
  15. package/calculations/behavioural/historical/position_count_pnl.js +67 -67
  16. package/calculations/behavioural/historical/smart-cohort-flow.js +250 -250
  17. package/calculations/behavioural/historical/smart_money_flow.js +165 -165
  18. package/calculations/behavioural/historical/user-investment-profile.js +412 -412
  19. package/calculations/capital_flow/historical/crowd-cash-flow-proxy.js +121 -121
  20. package/calculations/capital_flow/historical/deposit_withdrawal_percentage.js +117 -117
  21. package/calculations/capital_flow/historical/new_allocation_percentage.js +49 -49
  22. package/calculations/insights/daily_bought_vs_sold_count.js +55 -55
  23. package/calculations/insights/daily_buy_sell_sentiment_count.js +49 -49
  24. package/calculations/insights/daily_ownership_delta.js +55 -55
  25. package/calculations/insights/daily_total_positions_held.js +39 -39
  26. package/calculations/meta/capital_deployment_strategy.js +129 -137
  27. package/calculations/meta/capital_liquidation_performance.js +121 -163
  28. package/calculations/meta/capital_vintage_performance.js +121 -158
  29. package/calculations/meta/cash-flow-deployment.js +110 -124
  30. package/calculations/meta/cash-flow-liquidation.js +126 -142
  31. package/calculations/meta/crowd_sharpe_ratio_proxy.js +83 -91
  32. package/calculations/meta/profit_cohort_divergence.js +77 -91
  33. package/calculations/meta/smart-dumb-divergence-index.js +116 -138
  34. package/calculations/meta/social_flow_correlation.js +99 -125
  35. package/calculations/pnl/asset_pnl_status.js +46 -46
  36. package/calculations/pnl/historical/profitability_migration.js +57 -57
  37. package/calculations/pnl/historical/user_profitability_tracker.js +117 -117
  38. package/calculations/pnl/profitable_and_unprofitable_status.js +64 -64
  39. package/calculations/sectors/historical/diversification_pnl.js +76 -76
  40. package/calculations/sectors/historical/sector_rotation.js +67 -67
  41. package/calculations/sentiment/historical/crowd_conviction_score.js +80 -80
  42. package/calculations/socialPosts/social-asset-posts-trend.js +52 -52
  43. package/calculations/socialPosts/social-top-mentioned-words.js +102 -102
  44. package/calculations/socialPosts/social-topic-interest-evolution.js +53 -53
  45. package/calculations/socialPosts/social-word-mentions-trend.js +62 -62
  46. package/calculations/socialPosts/social_activity_aggregation.js +103 -103
  47. package/calculations/socialPosts/social_event_correlation.js +121 -121
  48. package/calculations/socialPosts/social_sentiment_aggregation.js +114 -114
  49. package/calculations/speculators/historical/risk_appetite_change.js +54 -54
  50. package/calculations/speculators/historical/tsl_effectiveness.js +74 -74
  51. package/index.js +33 -33
  52. package/package.json +32 -32
  53. package/utils/firestore_utils.js +76 -76
  54. package/utils/price_data_provider.js +142 -142
  55. package/utils/sector_mapping_provider.js +74 -74
  56. package/calculations/capital_flow/historical/reallocation_increase_percentage.js +0 -63
  57. package/calculations/speculators/stop_loss_distance_by_sector_short_long_breakdown.js +0 -91
  58. package/calculations/speculators/stop_loss_distance_by_ticker_short_long_breakdown.js +0 -73
@@ -1,54 +1,54 @@
1
- /**
2
- * @fileoverview Aggregates counts of all topics extracted by the AI
3
- * from social posts for the day. Used to build a "Topic Interest Area" chart.
4
- * This calculation ONLY uses the social post insights context.
5
- */
6
-
7
- class SocialTopicInterestEvolution {
8
- constructor() {
9
- this.topicCounts = {};
10
- this.processed = false;
11
- }
12
-
13
- /**
14
- * @param {null} todayPortfolio - Not used.
15
- * ... (other params not used) ...
16
- * @param {object} todaySocialPostInsights - Map of { [postId]: postData } for today.
17
- * @param {object} yesterdaySocialPostInsights - Not used.
18
- */
19
- async process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, todaySocialPostInsights, yesterdaySocialPostInsights) {
20
-
21
- if (this.processed || !todaySocialPostInsights) {
22
- return;
23
- }
24
- this.processed = true;
25
-
26
- const posts = Object.values(todaySocialPostInsights);
27
-
28
- for (const post of posts) {
29
- // Topics are in post.sentiment.topics
30
- const topics = post.sentiment?.topics;
31
- if (!topics || !Array.isArray(topics)) continue;
32
-
33
- for (const topic of topics) {
34
- // Normalize topic for consistent aggregation
35
- const normalizedTopic = String(topic).toLowerCase().trim();
36
- if (normalizedTopic) {
37
- this.topicCounts[normalizedTopic] = (this.topicCounts[normalizedTopic] || 0) + 1;
38
- }
39
- }
40
- }
41
- }
42
-
43
- async getResult() {
44
- // Returns an object like: { "earnings": 45, "cpi": 12, "fed": 22 }
45
- return this.topicCounts;
46
- }
47
-
48
- reset() {
49
- this.topicCounts = {};
50
- this.processed = false;
51
- }
52
- }
53
-
1
+ /**
2
+ * @fileoverview Aggregates counts of all topics extracted by the AI
3
+ * from social posts for the day. Used to build a "Topic Interest Area" chart.
4
+ * This calculation ONLY uses the social post insights context.
5
+ */
6
+
7
+ class SocialTopicInterestEvolution {
8
+ constructor() {
9
+ this.topicCounts = {};
10
+ this.processed = false;
11
+ }
12
+
13
+ /**
14
+ * @param {null} todayPortfolio - Not used.
15
+ * ... (other params not used) ...
16
+ * @param {object} todaySocialPostInsights - Map of { [postId]: postData } for today.
17
+ * @param {object} yesterdaySocialPostInsights - Not used.
18
+ */
19
+ async process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, todaySocialPostInsights, yesterdaySocialPostInsights) {
20
+
21
+ if (this.processed || !todaySocialPostInsights) {
22
+ return;
23
+ }
24
+ this.processed = true;
25
+
26
+ const posts = Object.values(todaySocialPostInsights);
27
+
28
+ for (const post of posts) {
29
+ // Topics are in post.sentiment.topics
30
+ const topics = post.sentiment?.topics;
31
+ if (!topics || !Array.isArray(topics)) continue;
32
+
33
+ for (const topic of topics) {
34
+ // Normalize topic for consistent aggregation
35
+ const normalizedTopic = String(topic).toLowerCase().trim();
36
+ if (normalizedTopic) {
37
+ this.topicCounts[normalizedTopic] = (this.topicCounts[normalizedTopic] || 0) + 1;
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ async getResult() {
44
+ // Returns an object like: { "earnings": 45, "cpi": 12, "fed": 22 }
45
+ return this.topicCounts;
46
+ }
47
+
48
+ reset() {
49
+ this.topicCounts = {};
50
+ this.processed = false;
51
+ }
52
+ }
53
+
54
54
  module.exports = SocialTopicInterestEvolution;
@@ -1,63 +1,63 @@
1
- /**
2
- * @fileoverview Tracks daily mentions of a pre-defined list of keywords.
3
- * This calculation ONLY uses the social post insights context.
4
- */
5
-
6
- class SocialWordMentionsTrend {
7
- constructor() {
8
- // A pre-defined list of keywords to track
9
- this.KEYWORDS = [
10
- 'inflation', 'fed', 'fomc', 'cpi', 'earnings',
11
- 'recession', 'bullish', 'bearish', 'buy', 'sell',
12
- 'war', 'acquisition', 'ai'
13
- ];
14
- this.mentions = {};
15
- this.processed = false;
16
- }
17
-
18
- /**
19
- * @param {null} todayPortfolio - Not used.
20
- * ... (other params not used) ...
21
- * @param {object} todaySocialPostInsights - Map of { [postId]: postData } for today.
22
- * @param {object} yesterdaySocialPostInsights - Not used.
23
- */
24
- async process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, todaySocialPostInsights, yesterdaySocialPostInsights) {
25
-
26
- if (this.processed || !todaySocialPostInsights) {
27
- return;
28
- }
29
- this.processed = true;
30
-
31
- // Initialize all keywords with 0 counts
32
- this.mentions = this.KEYWORDS.reduce((acc, key) => {
33
- acc[key] = 0;
34
- return acc;
35
- }, {});
36
-
37
- const posts = Object.values(todaySocialPostInsights);
38
-
39
- for (const post of posts) {
40
- const text = post.fullText?.toLowerCase() || '';
41
- if (!text) continue;
42
-
43
- for (const keyword of this.KEYWORDS) {
44
- // Count once per post, even if mentioned multiple times
45
- if (text.includes(keyword)) {
46
- this.mentions[keyword]++;
47
- }
48
- }
49
- }
50
- }
51
-
52
- async getResult() {
53
- // Returns an object like: { "inflation": 5, "fed": 12, "ai": 30 }
54
- return this.mentions;
55
- }
56
-
57
- reset() {
58
- this.mentions = {};
59
- this.processed = false;
60
- }
61
- }
62
-
1
+ /**
2
+ * @fileoverview Tracks daily mentions of a pre-defined list of keywords.
3
+ * This calculation ONLY uses the social post insights context.
4
+ */
5
+
6
+ class SocialWordMentionsTrend {
7
+ constructor() {
8
+ // A pre-defined list of keywords to track
9
+ this.KEYWORDS = [
10
+ 'inflation', 'fed', 'fomc', 'cpi', 'earnings',
11
+ 'recession', 'bullish', 'bearish', 'buy', 'sell',
12
+ 'war', 'acquisition', 'ai'
13
+ ];
14
+ this.mentions = {};
15
+ this.processed = false;
16
+ }
17
+
18
+ /**
19
+ * @param {null} todayPortfolio - Not used.
20
+ * ... (other params not used) ...
21
+ * @param {object} todaySocialPostInsights - Map of { [postId]: postData } for today.
22
+ * @param {object} yesterdaySocialPostInsights - Not used.
23
+ */
24
+ async process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, todaySocialPostInsights, yesterdaySocialPostInsights) {
25
+
26
+ if (this.processed || !todaySocialPostInsights) {
27
+ return;
28
+ }
29
+ this.processed = true;
30
+
31
+ // Initialize all keywords with 0 counts
32
+ this.mentions = this.KEYWORDS.reduce((acc, key) => {
33
+ acc[key] = 0;
34
+ return acc;
35
+ }, {});
36
+
37
+ const posts = Object.values(todaySocialPostInsights);
38
+
39
+ for (const post of posts) {
40
+ const text = post.fullText?.toLowerCase() || '';
41
+ if (!text) continue;
42
+
43
+ for (const keyword of this.KEYWORDS) {
44
+ // Count once per post, even if mentioned multiple times
45
+ if (text.includes(keyword)) {
46
+ this.mentions[keyword]++;
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ async getResult() {
53
+ // Returns an object like: { "inflation": 5, "fed": 12, "ai": 30 }
54
+ return this.mentions;
55
+ }
56
+
57
+ reset() {
58
+ this.mentions = {};
59
+ this.processed = false;
60
+ }
61
+ }
62
+
63
63
  module.exports = SocialWordMentionsTrend;
@@ -1,103 +1,103 @@
1
- /**
2
- * @fileoverview Aggregates activity data (likes, comments) from social posts.
3
- * This calculation ONLY uses the social post insights context, not portfolio data.
4
- */
5
-
6
- class SocialActivityAggregation {
7
- constructor() {
8
- this.tickerActivity = {};
9
- this.totalLikes = 0;
10
- this.totalComments = 0;
11
- this.totalPosts = 0; // <-- ADD THIS LINE
12
- this.processed = false; // Flag to ensure this runs only once
13
- }
14
-
15
- /**
16
- * @param {null} todayPortfolio - Not used.
17
- * @param {null} yesterdayPortfolio - Not used.
18
- * @param {null} userId - Not used.
19
- * @param {object} context - Shared context (e.g., mappings).
20
- * @param {object} todayInsights - Daily instrument insights.
21
- * @param {object} yesterdayInsights - Yesterday's instrument insights.
22
- * @param {object} todaySocialPostInsights - Map of { [postId]: postData } for today.
23
- * @param {object} yesterdaySocialPostInsights - Map of { [postId]: postData } for yesterday.
24
- */
25
- async process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, todaySocialPostInsights, yesterdaySocialPostInsights) {
26
- // This process should only run once per day
27
- if (this.processed || !todaySocialPostInsights) {
28
- return;
29
- }
30
- this.processed = true;
31
- this.totalPosts = Object.keys(todaySocialPostInsights).length;
32
-
33
- const posts = Object.values(todaySocialPostInsights);
34
-
35
- for (const post of posts) {
36
- const likeCount = post.likeCount || 0;
37
- const commentCount = post.commentCount || 0;
38
-
39
- // 1. Aggregate global counts
40
- this.totalLikes += likeCount;
41
- this.totalComments += commentCount;
42
-
43
- // 2. Aggregate counts per ticker
44
- if (post.tickers && Array.isArray(post.tickers)) {
45
- for (const ticker of post.tickers) {
46
- if (!this.tickerActivity[ticker]) {
47
- this.tickerActivity[ticker] = {
48
- totalLikes: 0,
49
- totalComments: 0,
50
- totalPosts: 0
51
- };
52
- }
53
- this.tickerActivity[ticker].totalLikes += likeCount;
54
- this.tickerActivity[ticker].totalComments += commentCount;
55
- this.tickerActivity[ticker].totalPosts++;
56
- }
57
- }
58
- }
59
- }
60
-
61
- async getResult() {
62
- if (!this.processed) return {};
63
-
64
- // Calculate average activity per ticker
65
- const tickerAverageActivity = {};
66
- for (const ticker in this.tickerActivity) {
67
- const data = this.tickerActivity[ticker];
68
- if (data.totalPosts > 0) {
69
- tickerAverageActivity[ticker] = {
70
- avgLikesPerPost: data.totalLikes / data.totalPosts,
71
- avgCommentsPerPost: data.totalComments / data.totalPosts,
72
- ...data // Include total counts
73
- };
74
- } else {
75
- tickerAverageActivity[ticker] = {
76
- avgLikesPerPost: 0,
77
- avgCommentsPerPost: 0,
78
- ...data
79
- };
80
- }
81
- }
82
-
83
- return {
84
- globalActivity: {
85
- totalLikes: this.totalLikes,
86
- totalComments: this.totalComments,
87
- totalPosts: this.totalPosts
88
- // --- END FIX ---
89
- },
90
- tickerActivity: tickerAverageActivity
91
- };
92
- }
93
-
94
- reset() {
95
- this.tickerActivity = {};
96
- this.totalLikes = 0;
97
- this.totalComments = 0;
98
- this.totalPosts = 0;
99
- this.processed = false;
100
- }
101
- }
102
-
103
- module.exports = SocialActivityAggregation;
1
+ /**
2
+ * @fileoverview Aggregates activity data (likes, comments) from social posts.
3
+ * This calculation ONLY uses the social post insights context, not portfolio data.
4
+ */
5
+
6
+ class SocialActivityAggregation {
7
+ constructor() {
8
+ this.tickerActivity = {};
9
+ this.totalLikes = 0;
10
+ this.totalComments = 0;
11
+ this.totalPosts = 0; // <-- ADD THIS LINE
12
+ this.processed = false; // Flag to ensure this runs only once
13
+ }
14
+
15
+ /**
16
+ * @param {null} todayPortfolio - Not used.
17
+ * @param {null} yesterdayPortfolio - Not used.
18
+ * @param {null} userId - Not used.
19
+ * @param {object} context - Shared context (e.g., mappings).
20
+ * @param {object} todayInsights - Daily instrument insights.
21
+ * @param {object} yesterdayInsights - Yesterday's instrument insights.
22
+ * @param {object} todaySocialPostInsights - Map of { [postId]: postData } for today.
23
+ * @param {object} yesterdaySocialPostInsights - Map of { [postId]: postData } for yesterday.
24
+ */
25
+ async process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, todaySocialPostInsights, yesterdaySocialPostInsights) {
26
+ // This process should only run once per day
27
+ if (this.processed || !todaySocialPostInsights) {
28
+ return;
29
+ }
30
+ this.processed = true;
31
+ this.totalPosts = Object.keys(todaySocialPostInsights).length;
32
+
33
+ const posts = Object.values(todaySocialPostInsights);
34
+
35
+ for (const post of posts) {
36
+ const likeCount = post.likeCount || 0;
37
+ const commentCount = post.commentCount || 0;
38
+
39
+ // 1. Aggregate global counts
40
+ this.totalLikes += likeCount;
41
+ this.totalComments += commentCount;
42
+
43
+ // 2. Aggregate counts per ticker
44
+ if (post.tickers && Array.isArray(post.tickers)) {
45
+ for (const ticker of post.tickers) {
46
+ if (!this.tickerActivity[ticker]) {
47
+ this.tickerActivity[ticker] = {
48
+ totalLikes: 0,
49
+ totalComments: 0,
50
+ totalPosts: 0
51
+ };
52
+ }
53
+ this.tickerActivity[ticker].totalLikes += likeCount;
54
+ this.tickerActivity[ticker].totalComments += commentCount;
55
+ this.tickerActivity[ticker].totalPosts++;
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ async getResult() {
62
+ if (!this.processed) return {};
63
+
64
+ // Calculate average activity per ticker
65
+ const tickerAverageActivity = {};
66
+ for (const ticker in this.tickerActivity) {
67
+ const data = this.tickerActivity[ticker];
68
+ if (data.totalPosts > 0) {
69
+ tickerAverageActivity[ticker] = {
70
+ avgLikesPerPost: data.totalLikes / data.totalPosts,
71
+ avgCommentsPerPost: data.totalComments / data.totalPosts,
72
+ ...data // Include total counts
73
+ };
74
+ } else {
75
+ tickerAverageActivity[ticker] = {
76
+ avgLikesPerPost: 0,
77
+ avgCommentsPerPost: 0,
78
+ ...data
79
+ };
80
+ }
81
+ }
82
+
83
+ return {
84
+ globalActivity: {
85
+ totalLikes: this.totalLikes,
86
+ totalComments: this.totalComments,
87
+ totalPosts: this.totalPosts
88
+ // --- END FIX ---
89
+ },
90
+ tickerActivity: tickerAverageActivity
91
+ };
92
+ }
93
+
94
+ reset() {
95
+ this.tickerActivity = {};
96
+ this.totalLikes = 0;
97
+ this.totalComments = 0;
98
+ this.totalPosts = 0;
99
+ this.processed = false;
100
+ }
101
+ }
102
+
103
+ module.exports = SocialActivityAggregation;