aiden-shared-calculations-unified 1.0.98 → 1.0.99

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @fileoverview CORE Product Line (Pass 1 - Meta)
3
3
  * Calculates annualized volatility.
4
- * Safe for sharded execution (accumulates results).
4
+ * Clean: System automatically handles sharding for large result sets.
5
5
  */
6
6
  class AssetVolatilityEstimator {
7
7
  constructor() {
@@ -37,16 +37,10 @@ class AssetVolatilityEstimator {
37
37
  const { compute, priceExtractor } = math;
38
38
 
39
39
  if (!prices || !prices.history) return;
40
-
41
- // Efficiently extract only histories present in this shard/context
42
40
  const allHistories = priceExtractor.getAllHistories(prices);
43
41
 
44
- const batchResult = {};
45
-
46
42
  for (const [key, candles] of allHistories.entries()) {
47
43
  let ticker = key;
48
-
49
- // Resolve ticker logic
50
44
  if (prices.history[key] && prices.history[key].instrumentId) {
51
45
  const instId = prices.history[key].instrumentId;
52
46
  if (mappings && mappings.instrumentToTicker && mappings.instrumentToTicker[instId]) {
@@ -54,7 +48,6 @@ class AssetVolatilityEstimator {
54
48
  }
55
49
  }
56
50
 
57
- // Guard: Need enough data for a trend
58
51
  if (!candles || candles.length < 10) continue;
59
52
 
60
53
  const logReturns = [];
@@ -63,36 +56,32 @@ class AssetVolatilityEstimator {
63
56
  for (let i = 1; i < candles.length; i++) {
64
57
  const prev = candles[i-1].price;
65
58
  const curr = candles[i].price;
66
-
67
- // Guard: Prevent log(0) or log(negative) errors
68
59
  if (prev > 0 && curr > 0) {
69
60
  logReturns.push(Math.log(curr / prev));
70
61
  lastPrice = curr;
71
62
  }
72
63
  }
73
64
 
74
- const LOOKBACK = 30;
75
- const relevantReturns = logReturns.slice(-LOOKBACK);
76
-
77
- // Guard: Need enough returns for Standard Deviation
65
+ const relevantReturns = logReturns.slice(-30);
78
66
  if (relevantReturns.length < 5) continue;
79
67
 
80
68
  const stdDev = compute.standardDeviation(relevantReturns);
81
69
  const annualizedVol = stdDev * Math.sqrt(365);
82
70
 
83
- batchResult[ticker] = {
71
+ this.result[ticker] = {
84
72
  volatility_30d: Number(annualizedVol.toFixed(4)),
85
73
  last_price: lastPrice,
86
74
  data_points: relevantReturns.length
87
75
  };
88
76
  }
89
-
90
- // Accumulate results (handling batched execution)
91
- Object.assign(this.result, batchResult);
92
77
  }
93
78
 
94
- async getResult() { return this.result; }
79
+ async getResult() {
80
+ // No manual sharding needed.
81
+ // If this object > 1MB, the system auto-shards it.
82
+ return this.result;
83
+ }
84
+
95
85
  reset() { this.result = {}; }
96
86
  }
97
-
98
87
  module.exports = AssetVolatilityEstimator;
@@ -13,6 +13,7 @@ class InsightsTotalLongFigures {
13
13
  type: 'meta',
14
14
  rootDataDependencies: ['insights'],
15
15
  isHistorical: false,
16
+ userType: 'n/a',
16
17
  category: 'core_sentiment'
17
18
  };
18
19
  }
@@ -32,9 +33,14 @@ class InsightsTotalLongFigures {
32
33
 
33
34
  process(context) {
34
35
  const { insights: insightsHelper } = context.math;
35
- const insights = insightsHelper.getInsights(context);
36
+ const rawInsights = insightsHelper.getInsights(context);
36
37
 
37
- if (!insights) return;
38
+ // FIX: Extract the 'today' array from the wrapper object
39
+ const insights = (rawInsights && Array.isArray(rawInsights.today))
40
+ ? rawInsights.today
41
+ : (Array.isArray(rawInsights) ? rawInsights : []);
42
+
43
+ if (insights.length === 0) return;
38
44
 
39
45
  for (const insight of insights) {
40
46
  this.totalPositions += insightsHelper.getLongCount(insight);
@@ -43,7 +49,6 @@ class InsightsTotalLongFigures {
43
49
 
44
50
  getResult() {
45
51
  return {
46
- total_long_exposure_weight: 0, // Not available in Insights
47
52
  total_positions_count: this.totalPositions
48
53
  };
49
54
  }
@@ -1,12 +1,9 @@
1
1
  /**
2
2
  * @fileoverview Core Metric (Pass 2)
3
- * REFACTORED: Buckets P&L status by User Profile.
4
- * - Pivots data to be User-Centric (User -> Winners/Losers).
5
- * - Removes sharding complexity (fits within 1MB via structure optimization).
3
+ * Clean: System automatically handles sharding (e.g. 20k users).
6
4
  */
7
5
  class AssetPnlStatus {
8
6
  constructor() {
9
- // Map<UserId, { winners: Set<String>, losers: Set<String> }>
10
7
  this.userStats = new Map();
11
8
  }
12
9
 
@@ -28,9 +25,8 @@ class AssetPnlStatus {
28
25
  "properties": {
29
26
  "by_user": {
30
27
  "type": "object",
31
- "description": "Map of User IDs to their winning/losing assets and sectors.",
32
28
  "patternProperties": {
33
- "^[0-9]+$": { // Matches User IDs (CIDs)
29
+ "^[0-9]+$": {
34
30
  "type": "object",
35
31
  "properties": {
36
32
  "winners": { "type": "array", "items": { "type": "string" } },
@@ -56,11 +52,9 @@ class AssetPnlStatus {
56
52
  const { mappings, user } = context;
57
53
  const userId = user.id;
58
54
 
59
- // 1. Get Positions using the standard extractor
60
55
  const positions = extract.getPositions(user.portfolio.today, user.type);
61
56
  if (!positions || positions.length === 0) return;
62
57
 
63
- // 2. Lazy init stats only if needed
64
58
  let stats = null;
65
59
 
66
60
  for (const pos of positions) {
@@ -68,7 +62,7 @@ class AssetPnlStatus {
68
62
  if (!instId) continue;
69
63
 
70
64
  const pnl = extract.getNetProfit(pos);
71
- if (pnl === 0) continue; // Ignore flat positions
65
+ if (pnl === 0) continue;
72
66
 
73
67
  const ticker = mappings.instrumentToTicker[instId];
74
68
  const sector = mappings.instrumentToSector[instId];
@@ -76,15 +70,11 @@ class AssetPnlStatus {
76
70
 
77
71
  if (ticker || sector) {
78
72
  if (!stats) stats = this._initUser(userId);
79
-
80
73
  if (ticker) {
81
- if (isWinner) stats.winners.add(ticker);
82
- else stats.losers.add(ticker);
74
+ if (isWinner) stats.winners.add(ticker); else stats.losers.add(ticker);
83
75
  }
84
-
85
76
  if (sector) {
86
- if (isWinner) stats.winners.add(sector);
87
- else stats.losers.add(sector);
77
+ if (isWinner) stats.winners.add(sector); else stats.losers.add(sector);
88
78
  }
89
79
  }
90
80
  }
@@ -94,7 +84,6 @@ class AssetPnlStatus {
94
84
  const byUser = {};
95
85
 
96
86
  for (const [userId, stats] of this.userStats) {
97
- // Only include users who actually have relevant P&L data
98
87
  if (stats.winners.size > 0 || stats.losers.size > 0) {
99
88
  byUser[userId] = {
100
89
  winners: Array.from(stats.winners),
@@ -103,12 +92,11 @@ class AssetPnlStatus {
103
92
  }
104
93
  }
105
94
 
95
+ // Return flat object. Orchestrator handles 1MB limit.
106
96
  return { by_user: byUser };
107
97
  }
108
98
 
109
- reset() {
110
- this.userStats.clear();
111
- }
99
+ reset() { this.userStats.clear(); }
112
100
  }
113
101
 
114
102
  module.exports = AssetPnlStatus;
@@ -1,18 +1,43 @@
1
1
  class InsightsDailyBoughtVsSoldCount {
2
2
  constructor() { this.results = {}; }
3
- static getMetadata() { return { type: 'meta', rootDataDependencies: ['insights'], isHistorical: true, category: 'core_metrics' }; }
3
+
4
+ static getMetadata() {
5
+ return {
6
+ type: 'meta',
7
+ rootDataDependencies: ['insights'],
8
+ isHistorical: true,
9
+ userType: 'n/a',
10
+ category: 'core_metrics'
11
+ };
12
+ }
13
+
4
14
  static getDependencies() { return []; }
15
+
5
16
  static getSchema() {
6
- const tickerSchema = { "type": "object", "properties": { "positions_bought": { "type": "number" }, "positions_sold": { "type": "number" }, "net_change": { "type": "number" } }, "required": ["positions_bought", "positions_sold", "net_change"] };
17
+ const tickerSchema = {
18
+ "type": "object",
19
+ "properties": {
20
+ "positions_bought": { "type": "number" },
21
+ "positions_sold": { "type": "number" },
22
+ "net_change": { "type": "number" }
23
+ },
24
+ "required": ["positions_bought", "positions_sold", "net_change"]
25
+ };
7
26
  return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
8
27
  }
28
+
9
29
  process(context) {
10
30
  const { insights: insightsHelper } = context.math;
11
- const insights = insightsHelper.getInsights(context);
31
+ const rawInsights = insightsHelper.getInsights(context);
12
32
  const { mappings } = context;
13
33
  const tickerMap = mappings.instrumentToTicker || {};
14
34
 
15
- if (!insights || !Array.isArray(insights)) return; // FIX: Strict array check
35
+ // FIX: Extract the 'today' array from the wrapper object
36
+ const insights = (rawInsights && Array.isArray(rawInsights.today))
37
+ ? rawInsights.today
38
+ : (Array.isArray(rawInsights) ? rawInsights : []);
39
+
40
+ if (insights.length === 0) return;
16
41
 
17
42
  for (const insight of insights) {
18
43
  const instId = insight.instrumentId;
@@ -22,10 +47,15 @@ class InsightsDailyBoughtVsSoldCount {
22
47
  const sold = netChange < 0 ? Math.abs(netChange) : 0;
23
48
 
24
49
  if (bought > 0 || sold > 0) {
25
- this.results[ticker] = { positions_bought: bought, positions_sold: sold, net_change: netChange };
50
+ this.results[ticker] = {
51
+ positions_bought: bought,
52
+ positions_sold: sold,
53
+ net_change: netChange
54
+ };
26
55
  }
27
56
  }
28
57
  }
58
+
29
59
  async getResult() { return this.results; }
30
60
  reset() { this.results = {}; }
31
61
  }
@@ -1,30 +1,61 @@
1
1
  class InsightsDailyOwnershipDelta {
2
2
  constructor() { this.results = {}; }
3
- static getMetadata() { return { type: 'meta', rootDataDependencies: ['insights'], isHistorical: true, category: 'core_metrics' }; }
3
+
4
+ static getMetadata() {
5
+ return {
6
+ type: 'meta',
7
+ rootDataDependencies: ['insights'],
8
+ isHistorical: true,
9
+ userType: 'n/a',
10
+ category: 'core_metrics'
11
+ };
12
+ }
13
+
4
14
  static getDependencies() { return []; }
15
+
5
16
  static getSchema() {
6
- const tickerSchema = { "type": "object", "properties": { "owners_added": { "type": "number" }, "owners_removed": { "type": "number" }, "net_ownership_change": { "type": "number" } }, "required": ["owners_added", "owners_removed", "net_ownership_change"] };
17
+ const tickerSchema = {
18
+ "type": "object",
19
+ "properties": {
20
+ "owners_added": { "type": "number" },
21
+ "owners_removed": { "type": "number" },
22
+ "net_ownership_change": { "type": "number" }
23
+ },
24
+ "required": ["owners_added", "owners_removed", "net_ownership_change"]
25
+ };
7
26
  return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
8
27
  }
28
+
9
29
  process(context) {
10
30
  const { insights: insightsHelper } = context.math;
11
- const insights = insightsHelper.getInsights(context);
31
+ const rawInsights = insightsHelper.getInsights(context);
12
32
  const { mappings } = context;
13
33
  const tickerMap = mappings.instrumentToTicker || {};
14
34
 
15
- if (!insights || !Array.isArray(insights)) return; // FIX: Strict array check
35
+ // FIX: Extract the 'today' array from the wrapper object
36
+ const insights = (rawInsights && Array.isArray(rawInsights.today))
37
+ ? rawInsights.today
38
+ : (Array.isArray(rawInsights) ? rawInsights : []);
39
+
40
+ if (insights.length === 0) return;
16
41
 
17
42
  for (const insight of insights) {
18
43
  const netChange = insightsHelper.getNetOwnershipChange(insight);
19
44
  if (netChange === 0) continue;
45
+
20
46
  const instId = insight.instrumentId;
21
47
  const ticker = tickerMap[instId] || `id_${instId}`;
22
48
  const added = netChange > 0 ? netChange : 0;
23
49
  const removed = netChange < 0 ? Math.abs(netChange) : 0;
24
50
 
25
- this.results[ticker] = { owners_added: added, owners_removed: removed, net_ownership_change: netChange };
51
+ this.results[ticker] = {
52
+ owners_added: added,
53
+ owners_removed: removed,
54
+ net_ownership_change: netChange
55
+ };
26
56
  }
27
57
  }
58
+
28
59
  async getResult() { return this.results; }
29
60
  reset() { this.results = {}; }
30
61
  }
@@ -1,29 +1,61 @@
1
1
  class InsightsSentimentPerStock {
2
2
  constructor() { this.results = {}; }
3
+
3
4
  static getSchema() {
4
- const tickerSchema = { "type": "object", "properties": { "long_count": { "type": "number" }, "short_count": { "type": "number" }, "sentiment_ratio": { "type": ["number", "null"] } }, "required": ["long_count", "short_count", "sentiment_ratio"] };
5
+ const tickerSchema = {
6
+ "type": "object",
7
+ "properties": {
8
+ "long_count": { "type": "number" },
9
+ "short_count": { "type": "number" },
10
+ "sentiment_ratio": { "type": ["number", "null"] }
11
+ },
12
+ "required": ["long_count", "short_count", "sentiment_ratio"]
13
+ };
5
14
  return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
6
15
  }
7
- static getMetadata() { return { type: 'meta', rootDataDependencies: ['insights'], isHistorical: false, category: 'core_sentiment' }; }
16
+
17
+ static getMetadata() {
18
+ return {
19
+ type: 'meta',
20
+ rootDataDependencies: ['insights'],
21
+ isHistorical: false,
22
+ userType: 'n/a',
23
+ category: 'core_sentiment'
24
+ };
25
+ }
26
+
8
27
  static getDependencies() { return []; }
28
+
9
29
  process(context) {
10
30
  const { insights: insightsHelper } = context.math;
11
- const insights = insightsHelper.getInsights(context);
31
+ const rawInsights = insightsHelper.getInsights(context);
12
32
  const { mappings } = context;
13
33
  const tickerMap = mappings.instrumentToTicker || {};
14
34
 
15
- if (!insights || !Array.isArray(insights)) return; // FIX: Strict array check
35
+ // FIX: Extract the 'today' array from the wrapper object
36
+ const insights = (rawInsights && Array.isArray(rawInsights.today))
37
+ ? rawInsights.today
38
+ : (Array.isArray(rawInsights) ? rawInsights : []);
39
+
40
+ if (insights.length === 0) return;
16
41
 
17
42
  for (const insight of insights) {
18
43
  const longCount = insightsHelper.getLongCount(insight);
19
44
  const shortCount = insightsHelper.getShortCount(insight);
45
+
20
46
  if (longCount === 0 && shortCount === 0) continue;
47
+
21
48
  const instId = insight.instrumentId;
22
49
  const ticker = tickerMap[instId] || `id_${instId}`;
23
50
 
24
- this.results[ticker] = { long_count: longCount, short_count: shortCount, sentiment_ratio: (shortCount > 0) ? (longCount / shortCount) : null };
51
+ this.results[ticker] = {
52
+ long_count: longCount,
53
+ short_count: shortCount,
54
+ sentiment_ratio: (shortCount > 0) ? (longCount / shortCount) : null
55
+ };
25
56
  }
26
57
  }
58
+
27
59
  async getResult() { return this.results; }
28
60
  reset() { this.results = {}; }
29
61
  }
@@ -13,6 +13,7 @@ class InsightsTotalLongPerSector {
13
13
  type: 'meta',
14
14
  rootDataDependencies: ['insights'],
15
15
  isHistorical: false,
16
+ userType: 'n/a',
16
17
  category: 'core_sentiment'
17
18
  };
18
19
  }
@@ -33,11 +34,16 @@ class InsightsTotalLongPerSector {
33
34
 
34
35
  process(context) {
35
36
  const { insights: insightsHelper } = context.math;
36
- const insights = insightsHelper.getInsights(context);
37
+ const rawInsights = insightsHelper.getInsights(context);
37
38
  const { mappings } = context;
38
39
  const sectorMap = mappings.instrumentToSector || {};
39
40
 
40
- if (!insights) return;
41
+ // FIX: Extract the 'today' array from the wrapper object
42
+ const insights = (rawInsights && Array.isArray(rawInsights.today))
43
+ ? rawInsights.today
44
+ : (Array.isArray(rawInsights) ? rawInsights : []);
45
+
46
+ if (insights.length === 0) return;
41
47
 
42
48
  for (const insight of insights) {
43
49
  const longCount = insightsHelper.getLongCount(insight);
@@ -58,7 +64,6 @@ class InsightsTotalLongPerSector {
58
64
  for (const [sector, data] of this.sectorData.entries()) {
59
65
  if (data.count > 0) {
60
66
  result[sector] = {
61
- total_long_exposure_weight: 0, // Not available
62
67
  total_positions_count: data.count
63
68
  };
64
69
  }
@@ -1,18 +1,42 @@
1
1
  class InsightsTotalPositionsHeld {
2
2
  constructor() { this.totalPositions = 0; }
3
- static getMetadata() { return { type: 'meta', rootDataDependencies: ['insights'], isHistorical: false, category: 'Global-Platform-Metrics' }; }
3
+
4
+ static getMetadata() {
5
+ return {
6
+ type: 'meta',
7
+ rootDataDependencies: ['insights'],
8
+ isHistorical: false,
9
+ userType: 'n/a',
10
+ category: 'Global-Platform-Metrics'
11
+ };
12
+ }
13
+
4
14
  static getDependencies() { return []; }
5
- static getSchema() { return { "type": "object", "properties": { "total_positions_count": { "type": "number" } }, "required": ["total_positions_count"] }; }
15
+
16
+ static getSchema() {
17
+ return {
18
+ "type": "object",
19
+ "properties": { "total_positions_count": { "type": "number" } },
20
+ "required": ["total_positions_count"]
21
+ };
22
+ }
23
+
6
24
  process(context) {
7
25
  const { insights: insightsHelper } = context.math;
8
- const insights = insightsHelper.getInsights(context);
26
+ const rawInsights = insightsHelper.getInsights(context);
27
+
28
+ // FIX: Extract the 'today' array from the wrapper object
29
+ const insights = (rawInsights && Array.isArray(rawInsights.today))
30
+ ? rawInsights.today
31
+ : (Array.isArray(rawInsights) ? rawInsights : []);
9
32
 
10
- if (!insights || !Array.isArray(insights)) return; // FIX: Strict array check
33
+ if (insights.length === 0) return;
11
34
 
12
35
  for (const insight of insights) {
13
36
  this.totalPositions += insightsHelper.getTotalOwners(insight);
14
37
  }
15
38
  }
39
+
16
40
  getResult() { return { total_positions_count: this.totalPositions }; }
17
41
  reset() { this.totalPositions = 0; }
18
42
  }
@@ -8,7 +8,10 @@ class CostBasisDensity {
8
8
  static getMetadata() {
9
9
  return {
10
10
  type: 'meta', // Runs ONCE per day
11
- dependencies: ['asset-cost-basis-profile']
11
+ dependencies: ['asset-cost-basis-profile'],
12
+ userType: 'n/a', // FIXED: Added missing field
13
+ isHistorical: false, // FIXED: Explicitly defined
14
+ category: 'ghost_book'
12
15
  };
13
16
  }
14
17
 
@@ -34,37 +37,30 @@ class CostBasisDensity {
34
37
  const { computed, math } = context;
35
38
  const { signals: SignalPrimitives } = math;
36
39
 
37
- // 1. Get Union of Tickers (Safe Iteration)
38
40
  const tickers = SignalPrimitives.getUnionKeys(computed, ['asset-cost-basis-profile']);
39
41
 
40
42
  for (const ticker of tickers) {
41
- // 2. Safe Data Access
42
43
  const data = computed['asset-cost-basis-profile'][ticker];
43
44
 
44
- // Check for 'profile' specifically as it contains the density curve
45
45
  if (!data || !Array.isArray(data.profile) || data.profile.length < 3) {
46
46
  continue;
47
47
  }
48
48
 
49
- const profile = data.profile; // Array of {price, density}
49
+ const profile = data.profile;
50
50
  const currentPrice = data.current_price;
51
51
 
52
52
  const resistance = [];
53
53
  const support = [];
54
54
  let maxDensity = 0;
55
55
 
56
- // 3. Peak Detection Algorithm
57
- // Iterate through the KDE curve to find local maxima
58
56
  for (let i = 1; i < profile.length - 1; i++) {
59
57
  const prev = profile[i-1].density;
60
58
  const curr = profile[i].density;
61
59
  const next = profile[i+1].density;
62
60
 
63
- // Simple Peak Check
64
61
  if (curr > prev && curr > next) {
65
62
  const priceVal = Number(profile[i].price.toFixed(2));
66
63
 
67
- // Classify as Resistance (Overhead Supply) or Support (Underlying Demand)
68
64
  if (profile[i].price > currentPrice) {
69
65
  resistance.push(priceVal);
70
66
  } else {
@@ -75,20 +71,12 @@ class CostBasisDensity {
75
71
  }
76
72
  }
77
73
 
78
- // 4. Sort Walls by proximity to current price?
79
- // Currently slice(0,3) takes the first found, which are lower prices in a sorted KDE.
80
- // Support: We want HIGHEST prices below current (closest to current).
81
- // Resistance: We want LOWEST prices above current (closest to current).
82
-
83
- // Sort Descending (Highest Price First)
84
74
  support.sort((a, b) => b - a);
85
-
86
- // Sort Ascending (Lowest Price First)
87
75
  resistance.sort((a, b) => a - b);
88
76
 
89
77
  this.walls[ticker] = {
90
- resistance_zones: resistance.slice(0, 3), // Closest 3 resistance levels
91
- support_zones: support.slice(0, 3), // Closest 3 support levels
78
+ resistance_zones: resistance.slice(0, 3),
79
+ support_zones: support.slice(0, 3),
92
80
  nearest_wall_strength: Number(maxDensity.toFixed(4))
93
81
  };
94
82
  }
@@ -4,7 +4,10 @@ class LiquidityVacuum {
4
4
  static getMetadata() {
5
5
  return {
6
6
  type: 'meta',
7
- dependencies: ['asset-cost-basis-profile']
7
+ dependencies: ['asset-cost-basis-profile'],
8
+ userType: 'n/a', // FIXED: Added missing field
9
+ isHistorical: false, // FIXED: Explicitly defined
10
+ category: 'ghost_book'
8
11
  };
9
12
  }
10
13
 
@@ -22,16 +25,12 @@ class LiquidityVacuum {
22
25
 
23
26
  for (const ticker of tickers) {
24
27
  const data = computed['asset-cost-basis-profile'][ticker];
25
- // BUG FIX: Ensure data and profile exist before accessing length/integration
26
28
  if (!data || !data.profile || !Array.isArray(data.profile)) continue;
27
29
 
28
30
  const current = data.current_price;
29
31
  const totalInv = data.total_inventory_weight;
30
32
 
31
- // Integrate Danger Zone (0% to -5% drop)
32
33
  const riskVol = distribution.integrateProfile(data.profile, current * 0.95, current);
33
-
34
- // Ratio: At-Risk Inventory / Total Inventory
35
34
  const ratio = (totalInv > 0) ? (riskVol / totalInv) * 10 : 0;
36
35
 
37
36
  let status = "STABLE";
@@ -10,6 +10,8 @@ class RetailGammaExposure {
10
10
  type: 'meta',
11
11
  dependencies: ['skilled-cohort-flow', 'instrument-price-change-1d'],
12
12
  isHistorical: true, // Requires t-1, t-2... for rolling regression
13
+ userType: 'n/a', // FIXED: Added missing field
14
+ category: 'ghost_book'
13
15
  };
14
16
  }
15
17
 
@@ -33,20 +35,16 @@ class RetailGammaExposure {
33
35
 
34
36
  process(context) {
35
37
  const { computed, previousComputed, math } = context;
36
- // FIX: Destructure correct keys from context.math
37
- // 'signals' maps to SignalPrimitives, 'distribution' maps to DistributionAnalytics
38
38
  const { signals, distribution } = math;
39
39
 
40
40
  const tickers = signals.getUnionKeys(computed, ['skilled-cohort-flow']);
41
41
 
42
42
  for (const ticker of tickers) {
43
- // 1. Inputs
44
43
  const flow = signals.getMetric(computed, 'skilled-cohort-flow', ticker, 'net_flow_pct', 0);
45
44
  const priceChange = signals.getMetric(computed, 'instrument-price-change-1d', ticker, 'change_1d_pct', 0);
46
45
 
47
- // 2. State Management (Rolling Window)
48
46
  const prevResult = signals.getPreviousState(previousComputed, 'retail-gamma-exposure', ticker);
49
- const bufferSize = 14; // 2-week regression window
47
+ const bufferSize = 14;
50
48
 
51
49
  let flowBuffer = prevResult?._state?.flow_buffer || [];
52
50
  let priceBuffer = prevResult?._state?.price_buffer || [];
@@ -59,14 +57,12 @@ class RetailGammaExposure {
59
57
  priceBuffer.shift();
60
58
  }
61
59
 
62
- // 3. Regression: Flow ~ Alpha + Beta * PriceChange
63
60
  const regression = distribution.linearRegression(priceBuffer, flowBuffer);
64
61
  const beta = regression.slope;
65
62
 
66
- // 4. Regime Logic
67
63
  let regime = "NEUTRAL";
68
- if (beta > 0.5) regime = "ACCELERANT"; // Volatility Explosion Watch
69
- else if (beta < -0.5) regime = "STABILIZER"; // Chop Zone
64
+ if (beta > 0.5) regime = "ACCELERANT";
65
+ else if (beta < -0.5) regime = "STABILIZER";
70
66
 
71
67
  this.gammaResults[ticker] = {
72
68
  gamma_beta: Number(beta.toFixed(4)),
@@ -1,18 +1,18 @@
1
1
  /**
2
2
  * @fileoverview Cognitive Dissonance Arbitrage (CDA) v2.2
3
- * REFACTORED: Adheres to System Architecture and Schema v1.
3
+ * Clean: System automatically handles sharding.
4
4
  */
5
5
  class CognitiveDissonance {
6
6
  constructor() {
7
7
  this.cdaResults = {};
8
- this.alpha = 2 / (20 + 1); // EMA Alpha
8
+ this.alpha = 2 / (20 + 1);
9
9
  }
10
10
 
11
11
  static getMetadata() {
12
12
  return {
13
- type: 'meta', // Runs after standard calculations
13
+ type: 'meta',
14
14
  rootDataDependencies: [],
15
- isHistorical: true, // Requires t-1 state
15
+ isHistorical: true,
16
16
  userType: 'aggregate'
17
17
  };
18
18
  }
@@ -22,7 +22,6 @@ class CognitiveDissonance {
22
22
  }
23
23
 
24
24
  static getSchema() {
25
- // Schema remains strictly compliant with user definition
26
25
  const metricSchema = {
27
26
  "type": "object",
28
27
  "properties": {
@@ -31,7 +30,7 @@ class CognitiveDissonance {
31
30
  "z_sentiment": { "type": "number" },
32
31
  "z_flow": { "type": "number" },
33
32
  "price_confirmation": { "type": "boolean" },
34
- "_state": { "type": "object" } // Opaque state object
33
+ "_state": { "type": "object" }
35
34
  }
36
35
  };
37
36
  return { "type": "object", "patternProperties": { "^.*$": metricSchema } };
@@ -44,28 +43,24 @@ class CognitiveDissonance {
44
43
  const tickers = SignalPrimitives.getUnionKeys(computed, CognitiveDissonance.getDependencies());
45
44
 
46
45
  for (const ticker of tickers) {
47
- // 1. Get Metrics (Safe Access)
48
- // MAP: 'social-topic-sentiment-matrix' uses 'net_sentiment' NOT 'sentiment_score'
49
46
  const rawSentiment = SignalPrimitives.getMetric(computed, 'social-topic-sentiment-matrix', ticker, 'net_sentiment', 0);
50
47
  const rawFlow = SignalPrimitives.getMetric(computed, 'skilled-cohort-flow', ticker, 'net_flow_pct', 0);
51
- const priceChange = SignalPrimitives.getMetric(computed, 'instrument-price-change-1d', ticker, 'change_1d_pct', 0); // Map to correct field
48
+ const priceChange = SignalPrimitives.getMetric(computed, 'instrument-price-change-1d', ticker, 'change_1d_pct', 0);
52
49
 
53
- // 2. Get Previous State
50
+ // Transparent State Access
51
+ // The system has already re-assembled previousComputed from shards if necessary.
54
52
  const prevResult = SignalPrimitives.getPreviousState(previousComputed, 'cognitive-dissonance', ticker);
55
53
  const prevState = prevResult ? prevResult._state : { sent_mean: 0, sent_var: 1, flow_mean: 0, flow_var: 1 };
56
54
 
57
- // 3. Update Statistics (Math Layer)
58
55
  const sentStats = TimeSeries.updateEMAState(rawSentiment, { mean: prevState.sent_mean, variance: prevState.sent_var }, this.alpha);
59
56
  const flowStats = TimeSeries.updateEMAState(rawFlow, { mean: prevState.flow_mean, variance: prevState.flow_var }, this.alpha);
60
57
 
61
58
  const sentStdDev = Math.sqrt(sentStats.variance);
62
59
  const flowStdDev = Math.sqrt(flowStats.variance);
63
60
 
64
- // 4. Compute Z-Scores
65
61
  const zSentiment = (sentStdDev > 0.001) ? (rawSentiment - sentStats.mean) / sentStdDev : 0;
66
62
  const zFlow = (flowStdDev > 0.001) ? (rawFlow - flowStats.mean) / flowStdDev : 0;
67
63
 
68
- // 5. Logic (Voice vs Hands)
69
64
  const interaction = zSentiment * zFlow;
70
65
  let cdaScore = 0;
71
66
  let regime = "NEUTRAL";
@@ -76,8 +71,7 @@ class CognitiveDissonance {
76
71
  const activeHands = Math.abs(zFlow) > 0.5;
77
72
 
78
73
  if (disagree && loudVoice && activeHands) {
79
- cdaScore = -interaction; // Positive score = Bearish Dissonance (Euphoria + Selling)
80
-
74
+ cdaScore = -interaction;
81
75
  const priceAgreesWithSentiment = (Math.sign(priceChange) === Math.sign(zSentiment));
82
76
  const priceIsFlat = Math.abs(priceChange) < 0.5;
83
77
 
@@ -106,7 +100,7 @@ class CognitiveDissonance {
106
100
  }
107
101
  }
108
102
 
109
- getResult() { return this.cdaResults; }
103
+ async getResult() { return this.cdaResults; }
110
104
  reset() { this.cdaResults = {}; }
111
105
  }
112
106
  module.exports = CognitiveDissonance;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiden-shared-calculations-unified",
3
- "version": "1.0.98",
3
+ "version": "1.0.99",
4
4
  "description": "Shared calculation modules for the BullTrackers Computation System.",
5
5
  "main": "index.js",
6
6
  "files": [