aiden-shared-calculations-unified 1.0.84 → 1.0.87

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 (70) hide show
  1. package/calculations/core/asset-pnl-status.js +36 -106
  2. package/calculations/core/asset-position-size.js +40 -91
  3. package/calculations/core/average-daily-pnl-all-users.js +18 -57
  4. package/calculations/core/average-daily-pnl-per-sector.js +41 -88
  5. package/calculations/core/average-daily-pnl-per-stock.js +38 -91
  6. package/calculations/core/average-daily-position-pnl.js +19 -49
  7. package/calculations/core/holding-duration-per-asset.js +25 -127
  8. package/calculations/core/instrument-price-change-1d.js +30 -49
  9. package/calculations/core/instrument-price-momentum-20d.js +50 -60
  10. package/calculations/core/long-position-per-stock.js +39 -68
  11. package/calculations/core/overall-holding-duration.js +16 -87
  12. package/calculations/core/overall-profitability-ratio.js +11 -40
  13. package/calculations/core/platform-buy-sell-sentiment.js +41 -124
  14. package/calculations/core/platform-daily-bought-vs-sold-count.js +41 -99
  15. package/calculations/core/platform-daily-ownership-delta.js +68 -126
  16. package/calculations/core/platform-ownership-per-sector.js +45 -96
  17. package/calculations/core/platform-total-positions-held.js +20 -80
  18. package/calculations/core/pnl-distribution-per-stock.js +29 -135
  19. package/calculations/core/price-metrics.js +95 -206
  20. package/calculations/core/profitability-ratio-per-sector.js +34 -79
  21. package/calculations/core/profitability-ratio-per-stock.js +32 -88
  22. package/calculations/core/profitability-skew-per-stock.js +41 -94
  23. package/calculations/core/profitable-and-unprofitable-status.js +44 -76
  24. package/calculations/core/sentiment-per-stock.js +24 -77
  25. package/calculations/core/short-position-per-stock.js +35 -43
  26. package/calculations/core/social-activity-aggregation.js +26 -49
  27. package/calculations/core/social-asset-posts-trend.js +38 -94
  28. package/calculations/core/social-event-correlation.js +26 -93
  29. package/calculations/core/social-sentiment-aggregation.js +20 -44
  30. package/calculations/core/social-top-mentioned-words.js +35 -87
  31. package/calculations/core/social-topic-interest-evolution.js +22 -111
  32. package/calculations/core/social-topic-sentiment-matrix.js +38 -104
  33. package/calculations/core/social-word-mentions-trend.js +27 -104
  34. package/calculations/core/speculator-asset-sentiment.js +31 -72
  35. package/calculations/core/speculator-danger-zone.js +48 -84
  36. package/calculations/core/speculator-distance-to-stop-loss-per-leverage.js +20 -52
  37. package/calculations/core/speculator-distance-to-tp-per-leverage.js +23 -53
  38. package/calculations/core/speculator-entry-distance-to-sl-per-leverage.js +20 -50
  39. package/calculations/core/speculator-entry-distance-to-tp-per-leverage.js +23 -50
  40. package/calculations/core/speculator-leverage-per-asset.js +25 -64
  41. package/calculations/core/speculator-leverage-per-sector.js +27 -63
  42. package/calculations/core/speculator-risk-reward-ratio-per-asset.js +24 -53
  43. package/calculations/core/speculator-stop-loss-distance-by-sector-short-long-breakdown.js +55 -68
  44. package/calculations/core/speculator-stop-loss-distance-by-ticker-short-long-breakdown.js +54 -71
  45. package/calculations/core/speculator-stop-loss-per-asset.js +19 -44
  46. package/calculations/core/speculator-take-profit-per-asset.js +20 -57
  47. package/calculations/core/speculator-tsl-per-asset.js +17 -56
  48. package/calculations/core/total-long-figures.js +16 -31
  49. package/calculations/core/total-long-per-sector.js +39 -61
  50. package/calculations/core/total-short-figures.js +13 -32
  51. package/calculations/core/total-short-per-sector.js +39 -61
  52. package/calculations/core/users-processed.js +11 -46
  53. package/calculations/gauss/cohort-capital-flow.js +54 -173
  54. package/calculations/gauss/cohort-definer.js +77 -163
  55. package/calculations/gauss/daily-dna-filter.js +29 -83
  56. package/calculations/gauss/gauss-divergence-signal.js +22 -109
  57. package/calculations/gem/cohort-momentum-state.js +27 -72
  58. package/calculations/gem/cohort-skill-definition.js +36 -52
  59. package/calculations/gem/platform-conviction-divergence.js +18 -60
  60. package/calculations/gem/quant-skill-alpha-signal.js +25 -98
  61. package/calculations/gem/skilled-cohort-flow.js +67 -175
  62. package/calculations/gem/skilled-unskilled-divergence.js +18 -73
  63. package/calculations/gem/unskilled-cohort-flow.js +64 -172
  64. package/calculations/helix/helix-contrarian-signal.js +20 -114
  65. package/calculations/helix/herd-consensus-score.js +42 -124
  66. package/calculations/helix/winner-loser-flow.js +36 -118
  67. package/calculations/pyro/risk-appetite-index.js +33 -74
  68. package/calculations/pyro/squeeze-potential.js +30 -87
  69. package/calculations/pyro/volatility-signal.js +33 -78
  70. package/package.json +1 -1
@@ -1,42 +1,26 @@
1
1
  /**
2
2
  * @fileoverview Calculation (Pass 1) for total users processed.
3
- *
4
- * This metric is a simple counter that tracks the total number
5
- * of users processed and the breakdown by user type (Normal/Speculator).
6
- *
7
- * It is a fundamental metric for sanity-checking the data stream.
3
+ * REFACTORED: Uses context.user.type.
8
4
  */
9
5
  class UsersProcessed {
10
6
  constructor() {
11
7
  this.totalUsers = 0;
12
8
  this.normalUsers = 0;
13
9
  this.speculatorUsers = 0;
14
- this.totalValue = 0;
15
10
  }
16
11
 
17
- /**
18
- * Statically defines all metadata for the manifest builder.
19
- */
20
12
  static getMetadata() {
21
13
  return {
22
14
  type: 'standard',
23
- rootDataDependencies: ['portfolio'], // Needs summary
15
+ rootDataDependencies: ['portfolio'],
24
16
  isHistorical: false,
25
17
  userType: 'all',
26
- category: 'core_metrics' // A fundamental metric
18
+ category: 'core_metrics'
27
19
  };
28
20
  }
29
21
 
30
- /**
31
- * Statically declare dependencies.
32
- */
33
- static getDependencies() {
34
- return [];
35
- }
22
+ static getDependencies() { return []; }
36
23
 
37
- /**
38
- * Defines the output schema for this calculation.
39
- */
40
24
  static getSchema() {
41
25
  return {
42
26
  "type": "object",
@@ -44,47 +28,29 @@ class UsersProcessed {
44
28
  "properties": {
45
29
  "total_users": { "type": "number" },
46
30
  "normal_users": { "type": "number" },
47
- "speculator_users": { "type": "number" },
48
- "total_portfolio_value": { "type": "number" }
31
+ "speculator_users": { "type": "number" }
49
32
  },
50
- "required": ["total_users", "normal_users", "speculator_users", "total_portfolio_value"]
33
+ "required": ["total_users", "normal_users", "speculator_users"]
51
34
  };
52
35
  }
53
36
 
54
- // --- UPDATED SIGNATURE ---
55
- process(
56
- todayPortfolio,
57
- yesterdayPortfolio,
58
- userId,
59
- context,
60
- todayInsights,
61
- yesterdayInsights,
62
- todaySocialPostInsights,
63
- yesterdaySocialPostInsights,
64
- todayHistory
65
- ) {
37
+ process(context) {
38
+ const { user } = context;
39
+
66
40
  this.totalUsers++;
67
41
 
68
- // Use the userType from the context, which is set by the orchestrator
69
- if (context.userType === 'speculator') {
42
+ if (user.type === 'speculator') {
70
43
  this.speculatorUsers++;
71
44
  } else {
72
45
  this.normalUsers++;
73
46
  }
74
-
75
- // --- UPDATED ---
76
- const portfolioValue = todayPortfolio?.Summary?.PortfolioValue;
77
- if (typeof portfolioValue === 'number') {
78
- this.totalValue += portfolioValue;
79
- }
80
47
  }
81
48
 
82
49
  getResult() {
83
50
  return {
84
51
  total_users: this.totalUsers,
85
52
  normal_users: this.normalUsers,
86
- speculator_users: this.speculatorUsers,
87
- total_portfolio_value: this.totalValue
53
+ speculator_users: this.speculatorUsers
88
54
  };
89
55
  }
90
56
 
@@ -92,7 +58,6 @@ class UsersProcessed {
92
58
  this.totalUsers = 0;
93
59
  this.normalUsers = 0;
94
60
  this.speculatorUsers = 0;
95
- this.totalValue = 0;
96
61
  }
97
62
  }
98
63
 
@@ -1,42 +1,15 @@
1
1
  /**
2
2
  * @fileoverview GAUSS Product Line (Pass 3)
3
- *
4
- * This 'standard' calculation streams all user portfolios, tags
5
- * each user with their "Gauss" cohort (from Pass 2), and calculates
6
- * the price-adjusted capital flow for each cohort, per asset.
7
- *
8
- * This is the primary input for the final Pass 4 signal.
9
- *
10
- * --- REVISED 11/12/2025 ---
11
- * - Removed dependency on 'insights' data.
12
- * - Added dependency on 'instrument-price-change-1d' (Pass 1 meta calc).
13
- * - Price adjustment logic now uses the reliable 1-day price change
14
- * from the new dependency.
15
- * - **FIXED:** getResult() was wrapping the ticker map in an "assets" object,
16
- * causing a schema validation failure in the test harness.
17
- * --------------------------
3
+ * REFACTORED: Implemented getResult logic and mapping caching.
18
4
  */
19
- // --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
20
-
21
-
22
5
  class CohortCapitalFlow {
23
6
  constructor() {
24
- // { [cohortName]: Map<instrumentId, { flow_data... }> }
25
7
  this.cohortFlows = new Map();
26
- // { [userId]: "cohortName" }
27
8
  this.cohortMap = new Map();
28
- // --- STANDARD 0: RENAMED ---
29
- this.tickerMap = null;
9
+ this.tickerMap = null; // Cache mappings
30
10
  this.dependenciesLoaded = false;
31
-
32
- // --- NEW ---
33
- // This will store the { [ticker]: { price_change_1d_pct: 5.5 } } map
34
- this.priceChangeMap = null;
35
11
  }
36
12
 
37
- /**
38
- * Defines the output schema for this calculation.
39
- */
40
13
  static getSchema() {
41
14
  const flowSchema = {
42
15
  "type": "object",
@@ -46,156 +19,84 @@ class CohortCapitalFlow {
46
19
  },
47
20
  "required": ["net_flow_percentage", "net_flow_contribution"]
48
21
  };
49
-
50
- const cohortSchema = {
51
- "type": "object",
52
- "description": "Price-adjusted capital flow for all assets for a specific cohort.",
53
- "patternProperties": { "^.*$": flowSchema }, // Ticker
54
- "additionalProperties": flowSchema
55
- };
56
-
57
22
  return {
58
23
  "type": "object",
59
- "description": "Contains a map of cohort names to their asset flow data.",
60
- "patternProperties": {
61
- "^.*$": cohortSchema // Cohort Name
62
- },
63
- "additionalProperties": cohortSchema
24
+ "patternProperties": { "^.*$": { "type": "object", "patternProperties": { "^.*$": flowSchema } } }
64
25
  };
65
26
  }
66
27
 
67
- /**
68
- * Statically defines all metadata for the manifest builder.
69
- */
70
28
  static getMetadata() {
71
29
  return {
72
30
  type: 'standard',
73
31
  rootDataDependencies: ['portfolio', 'history'],
74
- isHistorical: true, // Needs T-1 portfolio for flow
32
+ isHistorical: true,
75
33
  userType: 'all',
76
34
  category: 'gauss'
77
35
  };
78
36
  }
79
37
 
80
- /**
81
- * Statically declare dependencies.
82
- */
83
38
  static getDependencies() {
84
- return [
85
- 'cohort-definer', // from gauss (Pass 2)
86
- 'instrument-price-change-1d' // from core (Pass 1)
87
- ];
88
- }
89
-
90
- _getPortfolioPositions(portfolio) {
91
- // FIX: Check for Normal User (AggregatedPositions) OR Speculator (PublicPositions)
92
- if (portfolio?.AggregatedPositions) {
93
- return portfolio.AggregatedPositions; // Normal User
94
- }
95
- if (portfolio?.PublicPositions) {
96
- return portfolio.PublicPositions; // Speculator User
97
- }
98
- return [];
39
+ return ['cohort-definer', 'instrument-price-change-1d'];
99
40
  }
100
41
 
101
42
  _initFlowData(cohortName, instrumentId) {
102
- if (!this.cohortFlows.has(cohortName)) {
103
- this.cohortFlows.set(cohortName, new Map());
104
- }
43
+ if (!this.cohortFlows.has(cohortName)) this.cohortFlows.set(cohortName, new Map());
105
44
  if (!this.cohortFlows.get(cohortName).has(instrumentId)) {
106
45
  this.cohortFlows.get(cohortName).set(instrumentId, {
107
- total_invested_yesterday: 0,
108
- total_invested_today: 0,
109
- price_change_yesterday: 0, // Weighted sum
46
+ total_invested_yesterday: 0, total_invested_today: 0, price_change_yesterday: 0
110
47
  });
111
48
  }
112
49
  }
113
50
 
114
- /**
115
- * Loads dependencies into memory on the first process() call.
116
- */
117
- _loadDependencies(fetchedDependencies) {
51
+ _loadDependencies(computed) {
118
52
  if (this.dependenciesLoaded) return;
119
-
120
- // 1. Load Cohort Definitions
121
- const cohortData = fetchedDependencies['cohort-definer'];
53
+ const cohortData = computed['cohort-definer'];
122
54
  if (cohortData) {
123
55
  for (const [cohortName, userIds] of Object.entries(cohortData)) {
124
- if (Array.isArray(userIds)) {
125
- for (const userId of userIds) {
126
- this.cohortMap.set(userId, cohortName);
127
- }
128
- }
56
+ if (Array.isArray(userIds)) userIds.forEach(uid => this.cohortMap.set(uid, cohortName));
129
57
  }
130
58
  }
131
-
132
- // 2. Load Price Change Data
133
- this.priceChangeMap = fetchedDependencies['instrument-price-change-1d'] || {};
134
-
135
59
  this.dependenciesLoaded = true;
136
60
  }
137
61
 
138
- process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, fetchedDependencies) {
139
- this._loadDependencies(fetchedDependencies);
140
-
141
- // --- STANDARD 0: FIXED ---
142
- if (!this.tickerMap) {
143
- this.tickerMap = context.instrumentToTicker;
144
- }
62
+ process(context) {
63
+ const { user, computed, mappings, math } = context;
64
+ const { extract } = math;
145
65
 
146
- const cohortName = this.cohortMap.get(userId);
147
- if (!cohortName) {
148
- return; // Not in a defined cohort, skip.
149
- }
150
-
151
- if (!todayPortfolio || !yesterdayPortfolio) {
152
- return;
153
- }
66
+ // Cache mapping for getResult phase
67
+ if (!this.tickerMap) this.tickerMap = mappings.instrumentToTicker;
154
68
 
155
- const yPos = this._getPortfolioPositions(yesterdayPortfolio);
156
- const tPos = this._getPortfolioPositions(todayPortfolio);
157
-
158
- if (!yPos || !tPos) {
159
- return; // Must have AggregatedPositions for both days
160
- }
69
+ this._loadDependencies(computed);
161
70
 
162
- if (!this.priceChangeMap) {
163
- return; // Cannot calculate price-adjusted flow
164
- }
71
+ const cohortName = this.cohortMap.get(user.id);
72
+ if (!cohortName) return;
165
73
 
166
- // --- STANDARD 0: Check must be done before use ---
167
- if (!this.tickerMap) {
168
- return; // Cannot map instruments to tickers
169
- }
74
+ const priceChangeMap = computed['instrument-price-change-1d'];
75
+ if (!priceChangeMap) return;
170
76
 
171
- const yPosMap = new Map(yPos.map(p => [p.InstrumentID, p]));
172
- const tPosMap = new Map(tPos.map(p => [p.InstrumentID, p]));
77
+ const yPos = extract.getPositions(user.portfolio.yesterday, user.type);
78
+ const tPos = extract.getPositions(user.portfolio.today, user.type);
79
+
80
+ const yPosMap = new Map(yPos.map(p => [extract.getInstrumentId(p), p]));
81
+ const tPosMap = new Map(tPos.map(p => [extract.getInstrumentId(p), p]));
173
82
  const allInstrumentIds = new Set([...yPosMap.keys(), ...tPosMap.keys()]);
174
83
 
175
- for (const instrumentId of allInstrumentIds) {
176
- if (!instrumentId) continue;
177
-
178
- this._initFlowData(cohortName, instrumentId);
179
- const asset = this.cohortFlows.get(cohortName).get(instrumentId);
84
+ for (const instId of allInstrumentIds) {
85
+ if (!instId) continue;
180
86
 
181
- const yP = yPosMap.get(instrumentId);
182
- const tP = tPosMap.get(instrumentId);
87
+ this._initFlowData(cohortName, instId);
88
+ const asset = this.cohortFlows.get(cohortName).get(instId);
183
89
 
184
- const yInvested = yP?.Invested || 0;
185
- const tInvested = tP?.Invested || 0;
90
+ const yInvested = extract.getPositionWeight(yPosMap.get(instId), user.type);
91
+ const tInvested = extract.getPositionWeight(tPosMap.get(instId), user.type);
186
92
 
187
93
  if (yInvested > 0) {
188
94
  asset.total_invested_yesterday += yInvested;
189
95
 
190
- // --- STANDARD 0: SIMPLIFIED ---
191
- const ticker = this.tickerMap[instrumentId];
192
- const yPriceChange_pct = (ticker && this.priceChangeMap[ticker])
193
- ? this.priceChangeMap[ticker].price_change_1d_pct
194
- : 0;
96
+ const ticker = this.tickerMap[instId];
97
+ const yPriceChange_pct = (ticker && priceChangeMap[ticker]) ? priceChangeMap[ticker].change_1d_pct : 0;
195
98
 
196
- const yPriceChange_decimal = (yPriceChange_pct || 0) / 100.0;
197
-
198
- asset.price_change_yesterday += yPriceChange_decimal * yInvested; // Weighted sum
99
+ asset.price_change_yesterday += (yPriceChange_pct / 100.0) * yInvested;
199
100
  }
200
101
  if (tInvested > 0) {
201
102
  asset.total_invested_today += tInvested;
@@ -203,62 +104,42 @@ class CohortCapitalFlow {
203
104
  }
204
105
  }
205
106
 
206
- // --- THIS IS THE FIX ---
207
107
  async getResult() {
208
- // --- STANDARD 0: REMOVED forbidden data load ---
209
-
210
- // Failsafe check
211
- if (!this.tickerMap) {
212
- return {}; // process() must run first to set mappings
213
- }
214
-
215
108
  const finalResult = {};
109
+
110
+ if (!this.tickerMap) return {}; // Should be populated by process()
216
111
 
217
- for (const [cohortName, assetMap] of this.cohortFlows.entries()) {
218
- const cohortAssets = {};
219
- for (const [instrumentId, data] of assetMap.entries()) {
220
- // --- STANDARD 0: SIMPLIFIED ---
221
- const ticker = this.tickerMap[instrumentId];
222
- if (!ticker) continue;
112
+ for (const [cohortName, assetsMap] of this.cohortFlows.entries()) {
113
+ finalResult[cohortName] = {};
114
+
115
+ for (const [instId, data] of assetsMap.entries()) {
116
+ const ticker = this.tickerMap[instId] || `id_${instId}`;
223
117
 
224
- const { total_invested_yesterday, total_invested_today, price_change_yesterday } = data;
118
+ // Logic: Flow = Today - (Yesterday * (1 + PriceChange))
119
+ // This isolates the capital movement from the price action.
120
+ const expectedToday = data.total_invested_yesterday + data.price_change_yesterday;
121
+ const netFlow = data.total_invested_today - expectedToday;
225
122
 
226
- if (total_invested_yesterday > 0) {
227
- const avg_price_change_decimal = price_change_yesterday / total_invested_yesterday;
228
- const price_adjusted_yesterday_value = total_invested_yesterday * (1 + avg_price_change_decimal);
229
- const flow_contribution = total_invested_today - price_adjusted_yesterday_value;
230
- const net_flow_percentage = (flow_contribution / total_invested_yesterday) * 100;
231
-
232
- if (isFinite(net_flow_percentage) && isFinite(flow_contribution)) {
233
- cohortAssets[ticker] = {
234
- net_flow_percentage: net_flow_percentage,
235
- net_flow_contribution: flow_contribution
236
- };
237
- }
238
- } else if (total_invested_today > 0) {
239
- cohortAssets[ticker] = {
240
- net_flow_percentage: Infinity, // Represents pure inflow
241
- net_flow_contribution: total_invested_today
242
- };
243
- }
123
+ // Avoid divide by zero or noise for very small numbers
124
+ const denominator = Math.max(1, (data.total_invested_yesterday + data.total_invested_today) / 2);
125
+ const netFlowPct = (netFlow / denominator) * 100;
126
+
127
+ finalResult[cohortName][ticker] = {
128
+ net_flow_percentage: netFlowPct,
129
+ net_flow_contribution: netFlow
130
+ };
244
131
  }
245
- // Was: finalResult[cohortName] = { assets: cohortAssets };
246
- // Is:
247
- finalResult[cohortName] = cohortAssets;
248
132
  }
249
133
 
250
134
  return finalResult;
251
135
  }
252
- // --- END FIX ---
253
136
 
254
137
  reset() {
255
138
  this.cohortFlows.clear();
256
139
  this.cohortMap.clear();
257
- // --- STANDARD 0: RENAMED ---
258
140
  this.tickerMap = null;
259
141
  this.dependenciesLoaded = false;
260
- this.priceChangeMap = null;
261
142
  }
262
143
  }
263
144
 
264
- module.exports = CohortCapitalFlow;
145
+ module.exports = CohortCapitalFlow;