aiden-shared-calculations-unified 1.0.82 → 1.0.84
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.
- package/calculations/core/asset-pnl-status.js +122 -104
- package/calculations/core/asset-position-size.js +110 -73
- package/calculations/core/average-daily-pnl-all-users.js +17 -3
- package/calculations/core/average-daily-pnl-per-sector.js +83 -75
- package/calculations/core/average-daily-pnl-per-stock.js +84 -73
- package/calculations/core/average-daily-position-pnl.js +2 -2
- package/calculations/core/holding-duration-per-asset.js +24 -23
- package/calculations/core/instrument-price-change-1d.js +72 -82
- package/calculations/core/instrument-price-momentum-20d.js +66 -100
- package/calculations/core/long-position-per-stock.js +21 -13
- package/calculations/core/overall-holding-duration.js +8 -3
- package/calculations/core/overall-profitability-ratio.js +2 -2
- package/calculations/core/platform-buy-sell-sentiment.js +75 -22
- package/calculations/core/platform-daily-bought-vs-sold-count.js +19 -10
- package/calculations/core/platform-daily-ownership-delta.js +39 -15
- package/calculations/core/platform-ownership-per-sector.js +38 -18
- package/calculations/core/platform-total-positions-held.js +36 -14
- package/calculations/core/pnl-distribution-per-stock.js +39 -36
- package/calculations/core/price-metrics.js +70 -172
- package/calculations/core/profitability-ratio-per-sector.js +23 -29
- package/calculations/core/profitability-ratio-per-stock.js +20 -13
- package/calculations/core/profitability-skew-per-stock.js +20 -13
- package/calculations/core/profitable-and-unprofitable-status.js +34 -10
- package/calculations/core/sentiment-per-stock.js +20 -9
- package/calculations/core/short-position-per-stock.js +23 -37
- package/calculations/core/social-activity-aggregation.js +41 -115
- package/calculations/core/social-asset-posts-trend.js +77 -94
- package/calculations/core/social-event-correlation.js +87 -106
- package/calculations/core/social-sentiment-aggregation.js +56 -138
- package/calculations/core/social-top-mentioned-words.js +74 -106
- package/calculations/core/social-topic-interest-evolution.js +94 -94
- package/calculations/core/social-topic-sentiment-matrix.js +90 -74
- package/calculations/core/social-word-mentions-trend.js +92 -106
- package/calculations/core/speculator-asset-sentiment.js +63 -92
- package/calculations/core/speculator-danger-zone.js +77 -90
- package/calculations/core/speculator-distance-to-stop-loss-per-leverage.js +75 -90
- package/calculations/core/speculator-distance-to-tp-per-leverage.js +75 -88
- package/calculations/core/speculator-entry-distance-to-sl-per-leverage.js +75 -90
- package/calculations/core/speculator-entry-distance-to-tp-per-leverage.js +74 -89
- package/calculations/core/speculator-leverage-per-asset.js +62 -57
- package/calculations/core/speculator-leverage-per-sector.js +53 -65
- package/calculations/core/speculator-risk-reward-ratio-per-asset.js +71 -76
- package/calculations/core/speculator-stop-loss-distance-by-sector-short-long-breakdown.js +60 -81
- package/calculations/core/speculator-stop-loss-distance-by-ticker-short-long-breakdown.js +57 -77
- package/calculations/core/speculator-stop-loss-per-asset.js +43 -80
- package/calculations/core/speculator-take-profit-per-asset.js +45 -69
- package/calculations/core/speculator-tsl-per-asset.js +42 -49
- package/calculations/core/total-long-figures.js +19 -19
- package/calculations/core/total-long-per-sector.js +39 -36
- package/calculations/core/total-short-figures.js +19 -19
- package/calculations/core/total-short-per-sector.js +39 -36
- package/calculations/core/users-processed.js +52 -25
- package/calculations/gauss/cohort-capital-flow.js +38 -29
- package/calculations/gauss/cohort-definer.js +17 -25
- package/calculations/gauss/daily-dna-filter.js +10 -4
- package/calculations/gauss/gauss-divergence-signal.js +28 -6
- package/calculations/gem/cohort-momentum-state.js +113 -92
- package/calculations/gem/cohort-skill-definition.js +23 -53
- package/calculations/gem/platform-conviction-divergence.js +62 -116
- package/calculations/gem/quant-skill-alpha-signal.js +107 -123
- package/calculations/gem/skilled-cohort-flow.js +178 -167
- package/calculations/gem/skilled-unskilled-divergence.js +73 -113
- package/calculations/gem/unskilled-cohort-flow.js +176 -166
- package/calculations/helix/helix-contrarian-signal.js +91 -83
- package/calculations/helix/herd-consensus-score.js +135 -97
- package/calculations/helix/winner-loser-flow.js +14 -14
- package/calculations/pyro/risk-appetite-index.js +121 -123
- package/calculations/pyro/squeeze-potential.js +93 -125
- package/calculations/pyro/volatility-signal.js +109 -97
- package/package.json +9 -9
- package/README.MD +0 -78
|
@@ -7,16 +7,16 @@ _ This metric answers: "For each stock, what is the sum and
|
|
|
7
7
|
* This helps determine if returns are skewed (e.g., many small
|
|
8
8
|
* wins and a few huge losses).
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
// --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
|
|
11
11
|
|
|
12
12
|
class ProfitabilitySkewPerStock {
|
|
13
13
|
constructor() {
|
|
14
14
|
// { [instrumentId]: { profit_sum: 0, profit_count: 0, loss_sum: 0, loss_count: 0 } }
|
|
15
15
|
this.assets = new Map();
|
|
16
|
-
|
|
16
|
+
// --- STANDARD 0: RENAMED ---
|
|
17
|
+
this.tickerMap = null;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
// --- NEW ---
|
|
20
20
|
/**
|
|
21
21
|
* Statically defines all metadata for the manifest builder.
|
|
22
22
|
*/
|
|
@@ -30,7 +30,6 @@ class ProfitabilitySkewPerStock {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
// --- NEW ---
|
|
34
33
|
/**
|
|
35
34
|
* Statically declare dependencies.
|
|
36
35
|
*/
|
|
@@ -40,7 +39,6 @@ class ProfitabilitySkewPerStock {
|
|
|
40
39
|
|
|
41
40
|
/**
|
|
42
41
|
* Defines the output schema for this calculation.
|
|
43
|
-
* @returns {object} JSON Schema object
|
|
44
42
|
*/
|
|
45
43
|
static getSchema() {
|
|
46
44
|
const tickerSchema = {
|
|
@@ -80,10 +78,14 @@ class ProfitabilitySkewPerStock {
|
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
|
|
83
|
-
// ---
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
// --- STANDARD 0: UPDATED SIGNATURE ---
|
|
82
|
+
process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
83
|
+
// --- STANDARD 0: ADDED ---
|
|
84
|
+
if (!this.tickerMap) {
|
|
85
|
+
this.tickerMap = context.instrumentToTicker;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
|
|
87
89
|
if (!positions || !Array.isArray(positions)) {
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
@@ -107,13 +109,17 @@ class ProfitabilitySkewPerStock {
|
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
async getResult() {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
// --- STANDARD 0: REMOVED forbidden data load ---
|
|
113
|
+
|
|
114
|
+
// Failsafe check
|
|
115
|
+
if (!this.tickerMap) {
|
|
116
|
+
return {}; // process() must run first
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
const result = {};
|
|
115
120
|
for (const [instrumentId, data] of this.assets.entries()) {
|
|
116
|
-
|
|
121
|
+
// --- STANDARD 0: SIMPLIFIED ---
|
|
122
|
+
const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
|
|
117
123
|
|
|
118
124
|
const avgProfit = (data.profit_count > 0) ? (data.profit_sum / data.profit_count) : 0;
|
|
119
125
|
const avgLoss = (data.loss_count > 0) ? (Math.abs(data.loss_sum) / data.loss_count) : 0;
|
|
@@ -131,7 +137,8 @@ class ProfitabilitySkewPerStock {
|
|
|
131
137
|
|
|
132
138
|
reset() {
|
|
133
139
|
this.assets.clear();
|
|
134
|
-
|
|
140
|
+
// --- STANDARD 0: RENAMED ---
|
|
141
|
+
this.tickerMap = null;
|
|
135
142
|
}
|
|
136
143
|
}
|
|
137
144
|
|
|
@@ -10,7 +10,6 @@ class ProfitableAndUnprofitableStatus {
|
|
|
10
10
|
this.total_in_loss = 0;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
// --- NEW ---
|
|
14
13
|
/**
|
|
15
14
|
* Statically defines all metadata for the manifest builder.
|
|
16
15
|
*/
|
|
@@ -24,7 +23,6 @@ class ProfitableAndUnprofitableStatus {
|
|
|
24
23
|
};
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
// --- NEW ---
|
|
28
26
|
/**
|
|
29
27
|
* Statically declare dependencies.
|
|
30
28
|
*/
|
|
@@ -34,7 +32,6 @@ class ProfitableAndUnprofitableStatus {
|
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
34
|
* Defines the output schema for this calculation.
|
|
37
|
-
* @returns {object} JSON Schema object
|
|
38
35
|
*/
|
|
39
36
|
static getSchema() {
|
|
40
37
|
return {
|
|
@@ -58,15 +55,42 @@ class ProfitableAndUnprofitableStatus {
|
|
|
58
55
|
};
|
|
59
56
|
}
|
|
60
57
|
|
|
61
|
-
// ---
|
|
62
|
-
|
|
63
|
-
process(portfolioData) {
|
|
64
|
-
// Use the P&L from the summary, which is for the *day*
|
|
65
|
-
const dailyPnl = portfolioData.Summary?.NetProfit || 0;
|
|
58
|
+
// --- UPDATED SIGNATURE ---
|
|
59
|
+
process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
// ---
|
|
62
|
+
// FIX: The 'data-generator.js' does not provide a 'Summary' object
|
|
63
|
+
// or a root-level 'NetProfit' field.
|
|
64
|
+
// We must derive the overall P&L from the individual positions,
|
|
65
|
+
// which *are* generated.
|
|
66
|
+
// ---
|
|
67
|
+
const positions = todayPortfolio.AggregatedPositions;
|
|
68
|
+
if (!positions || !Array.isArray(positions) || positions.length === 0) {
|
|
69
|
+
return; // No positions, no P&L status
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let totalInvested = 0;
|
|
73
|
+
let weightedPnlSum = 0;
|
|
74
|
+
|
|
75
|
+
for (const pos of positions) {
|
|
76
|
+
const invested = pos.Invested;
|
|
77
|
+
const pnl = pos.NetProfit;
|
|
78
|
+
|
|
79
|
+
if (typeof invested === 'number' && typeof pnl === 'number') {
|
|
80
|
+
totalInvested += invested;
|
|
81
|
+
weightedPnlSum += (pnl * invested); // Weight the P&L by its size
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (totalInvested === 0) {
|
|
86
|
+
return; // No invested capital, no P&L status
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const overallPnl = weightedPnlSum / totalInvested;
|
|
90
|
+
|
|
91
|
+
if (overallPnl > 0) {
|
|
68
92
|
this.total_in_profit++;
|
|
69
|
-
} else if (
|
|
93
|
+
} else if (overallPnl < 0) {
|
|
70
94
|
this.total_in_loss++;
|
|
71
95
|
}
|
|
72
96
|
}
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
* This metric answers: "For each stock, what is the count
|
|
5
5
|
* of long versus short positions?"
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
// --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
|
|
8
8
|
|
|
9
9
|
class SentimentPerStock {
|
|
10
10
|
constructor() {
|
|
11
11
|
// { [instrumentId]: { long: 0, short: 0 } }
|
|
12
12
|
this.assets = new Map();
|
|
13
|
-
|
|
13
|
+
// --- STANDARD 0: RENAMED ---
|
|
14
|
+
this.tickerMap = null;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Defines the output schema for this calculation.
|
|
18
|
-
* @returns {object} JSON Schema object
|
|
19
19
|
*/
|
|
20
20
|
static getSchema() {
|
|
21
21
|
const tickerSchema = {
|
|
@@ -77,8 +77,14 @@ class SentimentPerStock {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
// --- STANDARD 0: UPDATED SIGNATURE ---
|
|
81
|
+
process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
82
|
+
// --- STANDARD 0: ADDED ---
|
|
83
|
+
if (!this.tickerMap) {
|
|
84
|
+
this.tickerMap = context.instrumentToTicker;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
|
|
82
88
|
if (!positions || !Array.isArray(positions)) {
|
|
83
89
|
return;
|
|
84
90
|
}
|
|
@@ -99,13 +105,17 @@ class SentimentPerStock {
|
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
async getResult() {
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
// --- STANDARD 0: REMOVED forbidden data load ---
|
|
109
|
+
|
|
110
|
+
// Failsafe check
|
|
111
|
+
if (!this.tickerMap) {
|
|
112
|
+
return {}; // process() must run first
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
const result = {};
|
|
107
116
|
for (const [instrumentId, data] of this.assets.entries()) {
|
|
108
|
-
|
|
117
|
+
// --- STANDARD 0: SIMPLIFIED ---
|
|
118
|
+
const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
|
|
109
119
|
|
|
110
120
|
if (data.long > 0 || data.short > 0) {
|
|
111
121
|
result[ticker] = {
|
|
@@ -120,7 +130,8 @@ class SentimentPerStock {
|
|
|
120
130
|
|
|
121
131
|
reset() {
|
|
122
132
|
this.assets.clear();
|
|
123
|
-
|
|
133
|
+
// --- STANDARD 0: RENAMED ---
|
|
134
|
+
this.tickerMap = null;
|
|
124
135
|
}
|
|
125
136
|
}
|
|
126
137
|
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Calculation (Pass 1) for short positions per stock.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* --- FIX ---
|
|
4
|
+
* - Logic updated to check for *both* Speculator schema (pos.IsBuy === false)
|
|
5
|
+
* and Normal schema (pos.Direction === 'Sell') to match schema.md.
|
|
6
6
|
*/
|
|
7
|
-
const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
|
|
8
7
|
|
|
9
8
|
class ShortPositionPerStock {
|
|
10
9
|
constructor() {
|
|
11
|
-
// We will store { [instrumentId]: count }
|
|
12
10
|
this.assets = new Map();
|
|
13
|
-
this.
|
|
11
|
+
this.tickerMap = null;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
|
-
// --- NEW ---
|
|
17
|
-
/**
|
|
18
|
-
* Statically defines all metadata for the manifest builder.
|
|
19
|
-
*/
|
|
20
14
|
static getMetadata() {
|
|
21
15
|
return {
|
|
22
16
|
type: 'standard',
|
|
@@ -27,32 +21,18 @@ class ShortPositionPerStock {
|
|
|
27
21
|
};
|
|
28
22
|
}
|
|
29
23
|
|
|
30
|
-
// --- NEW ---
|
|
31
|
-
/**
|
|
32
|
-
* Statically declare dependencies.
|
|
33
|
-
*/
|
|
34
24
|
static getDependencies() {
|
|
35
25
|
return [];
|
|
36
26
|
}
|
|
37
27
|
|
|
38
|
-
/**
|
|
39
|
-
* Defines the output schema for this calculation.
|
|
40
|
-
* @returns {object} JSON Schema object
|
|
41
|
-
*/
|
|
42
28
|
static getSchema() {
|
|
43
29
|
return {
|
|
44
30
|
"type": "object",
|
|
45
31
|
"description": "Calculates the total count of short ('sell') positions for each asset.",
|
|
46
32
|
"patternProperties": {
|
|
47
|
-
|
|
48
|
-
"^.*$": {
|
|
49
|
-
"type": "number",
|
|
50
|
-
"description": "The total count of short positions for this asset."
|
|
51
|
-
}
|
|
33
|
+
"^.*$": { "type": "number" }
|
|
52
34
|
},
|
|
53
|
-
"additionalProperties": {
|
|
54
|
-
"type": "number"
|
|
55
|
-
}
|
|
35
|
+
"additionalProperties": { "type": "number" }
|
|
56
36
|
};
|
|
57
37
|
}
|
|
58
38
|
|
|
@@ -62,20 +42,26 @@ class ShortPositionPerStock {
|
|
|
62
42
|
}
|
|
63
43
|
}
|
|
64
44
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
45
|
+
process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, fetchedDependencies) {
|
|
46
|
+
if (!this.tickerMap) {
|
|
47
|
+
this.tickerMap = context.instrumentToTicker;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
|
|
69
51
|
if (!positions || !Array.isArray(positions)) {
|
|
70
52
|
return;
|
|
71
53
|
}
|
|
72
54
|
|
|
73
55
|
for (const pos of positions) {
|
|
74
|
-
//
|
|
75
|
-
|
|
56
|
+
// --- THIS IS THE FIX ---
|
|
57
|
+
// Check for Speculator (IsBuy) OR Normal (Direction)
|
|
58
|
+
const isShort = (pos.IsBuy === false) || (pos.Direction === 'Sell');
|
|
59
|
+
|
|
60
|
+
if (isShort) {
|
|
61
|
+
// --- END FIX ---
|
|
76
62
|
const instrumentId = pos.InstrumentID;
|
|
77
63
|
if (!instrumentId) continue;
|
|
78
|
-
|
|
64
|
+
|
|
79
65
|
this._initAsset(instrumentId);
|
|
80
66
|
this.assets.set(instrumentId, this.assets.get(instrumentId) + 1);
|
|
81
67
|
}
|
|
@@ -83,13 +69,13 @@ class ShortPositionPerStock {
|
|
|
83
69
|
}
|
|
84
70
|
|
|
85
71
|
async getResult() {
|
|
86
|
-
if (!this.
|
|
87
|
-
|
|
72
|
+
if (!this.tickerMap) {
|
|
73
|
+
return {};
|
|
88
74
|
}
|
|
89
75
|
|
|
90
76
|
const result = {};
|
|
91
77
|
for (const [instrumentId, count] of this.assets.entries()) {
|
|
92
|
-
const ticker = this.
|
|
78
|
+
const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
|
|
93
79
|
result[ticker] = count;
|
|
94
80
|
}
|
|
95
81
|
return result;
|
|
@@ -97,7 +83,7 @@ class ShortPositionPerStock {
|
|
|
97
83
|
|
|
98
84
|
reset() {
|
|
99
85
|
this.assets.clear();
|
|
100
|
-
this.
|
|
86
|
+
this.tickerMap = null;
|
|
101
87
|
}
|
|
102
88
|
}
|
|
103
89
|
|
|
@@ -1,155 +1,81 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* @fileoverview Calculation (Pass 2 - Meta) for social activity.
|
|
3
|
+
* --- FIX ---
|
|
4
|
+
* 1. Changed 'process' signature to 5-arg 'meta' standard.
|
|
5
|
+
* 2. Changed data access to read 'dateStr.social' (Arg 1, the metaPayload).
|
|
6
|
+
* 3. Changed 'socialDoc.posts' to 'socialDoc' (which IS the map of posts).
|
|
7
|
+
* 4. Changed 'post.comments' to 'post.commentCount'.
|
|
8
|
+
* 5. Changed 'post.likes' to 'post.likeCount'.
|
|
7
9
|
*/
|
|
8
10
|
class SocialActivityAggregation {
|
|
11
|
+
|
|
9
12
|
constructor() {
|
|
10
|
-
this.
|
|
11
|
-
total_posts: 0,
|
|
12
|
-
total_likes: 0,
|
|
13
|
-
total_comments: 0
|
|
14
|
-
};
|
|
15
|
-
// { [ticker]: { total_posts: 0, total_likes: 0, total_comments: 0 } }
|
|
16
|
-
this.perTicker = new Map();
|
|
13
|
+
this.result = {};
|
|
17
14
|
}
|
|
18
15
|
|
|
19
|
-
// --- NEW ---
|
|
20
|
-
/**
|
|
21
|
-
* Statically defines all metadata for the manifest builder.
|
|
22
|
-
*/
|
|
23
16
|
static getMetadata() {
|
|
24
17
|
return {
|
|
25
|
-
type: 'meta',
|
|
26
|
-
rootDataDependencies: ['social'],
|
|
18
|
+
type: 'meta',
|
|
19
|
+
rootDataDependencies: ['social'],
|
|
27
20
|
isHistorical: false,
|
|
28
21
|
userType: 'n/a',
|
|
29
22
|
category: 'core_social'
|
|
30
23
|
};
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
// --- NEW ---
|
|
34
|
-
/**
|
|
35
|
-
* Statically declare dependencies.
|
|
36
|
-
*/
|
|
37
26
|
static getDependencies() {
|
|
38
27
|
return [];
|
|
39
28
|
}
|
|
40
29
|
|
|
41
|
-
/**
|
|
42
|
-
* Defines the output schema for this calculation.
|
|
43
|
-
* @returns {object} JSON Schema object
|
|
44
|
-
*/
|
|
45
30
|
static getSchema() {
|
|
46
|
-
|
|
31
|
+
return {
|
|
47
32
|
"type": "object",
|
|
33
|
+
"description": "Aggregates the total social activity for the day.",
|
|
48
34
|
"properties": {
|
|
49
35
|
"total_posts": { "type": "number" },
|
|
50
|
-
"total_likes": { "type": "number" },
|
|
51
36
|
"total_comments": { "type": "number" },
|
|
52
|
-
"
|
|
53
|
-
"avg_comments_per_post": { "type": "number" }
|
|
54
|
-
},
|
|
55
|
-
"required": ["total_posts", "total_likes", "total_comments", "avg_likes_per_post", "avg_comments_per_post"]
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
"type": "object",
|
|
60
|
-
"description": "Aggregates social activity (posts, likes, comments) globally and per ticker.",
|
|
61
|
-
"properties": {
|
|
62
|
-
"global_activity": {
|
|
63
|
-
...statsSchema,
|
|
64
|
-
"description": "Aggregated activity across all posts."
|
|
65
|
-
},
|
|
66
|
-
"per_ticker": {
|
|
67
|
-
"type": "object",
|
|
68
|
-
"description": "Aggregated activity broken down by asset ticker.",
|
|
69
|
-
"patternProperties": {
|
|
70
|
-
"^.*$": {
|
|
71
|
-
...statsSchema,
|
|
72
|
-
"description": "Aggregated activity for a specific ticker."
|
|
73
|
-
} // Ticker
|
|
74
|
-
},
|
|
75
|
-
"additionalProperties": statsSchema
|
|
76
|
-
}
|
|
37
|
+
"total_likes": { "type": "number" }
|
|
77
38
|
},
|
|
78
|
-
"required": ["
|
|
39
|
+
"required": ["total_posts", "total_comments", "total_likes"]
|
|
79
40
|
};
|
|
80
41
|
}
|
|
81
42
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
43
|
+
// --- THIS IS THE FIX ---
|
|
44
|
+
async process(dateStr, rootData, dependencies, config, fetchedDependencies) {
|
|
45
|
+
|
|
46
|
+
// Get social data from Arg 1 (metaPayload)
|
|
47
|
+
const socialDoc = dateStr.social; // This IS the map of posts
|
|
48
|
+
|
|
49
|
+
if (!socialDoc || typeof socialDoc !== 'object') {
|
|
50
|
+
this.result = { total_posts: 0, total_comments: 0, total_likes: 0 };
|
|
51
|
+
return;
|
|
89
52
|
}
|
|
90
|
-
}
|
|
91
53
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
* @param {object} rootData - The root data object.
|
|
97
|
-
* @param {object} dependencies - db, logger, calculationUtils.
|
|
98
|
-
*/
|
|
99
|
-
async process(dateStr, rootData, dependencies) {
|
|
100
|
-
const { calculationUtils } = dependencies;
|
|
101
|
-
// The runner provides social data inside rootData
|
|
102
|
-
const todaySocialPosts = rootData.todaySocialPostInsights || {};
|
|
54
|
+
const postsArray = Object.values(socialDoc);
|
|
55
|
+
let totalPosts = postsArray.length;
|
|
56
|
+
let totalComments = 0;
|
|
57
|
+
let totalLikes = 0;
|
|
103
58
|
|
|
104
|
-
for (const post of
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// 1. Aggregate global stats
|
|
109
|
-
this.global.total_posts++;
|
|
110
|
-
this.global.total_likes += likes;
|
|
111
|
-
this.global.total_comments += comments;
|
|
112
|
-
|
|
113
|
-
// 2. Aggregate per-ticker stats
|
|
114
|
-
const tickers = post.tickers || [];
|
|
115
|
-
for (const ticker of tickers) {
|
|
116
|
-
this._initTicker(ticker);
|
|
117
|
-
const data = this.perTicker.get(ticker);
|
|
118
|
-
data.total_posts++;
|
|
119
|
-
data.total_likes += likes;
|
|
120
|
-
data.total_comments += comments;
|
|
121
|
-
}
|
|
59
|
+
for (const post of postsArray) {
|
|
60
|
+
// Use schema.md fields
|
|
61
|
+
totalComments += post.commentCount || 0;
|
|
62
|
+
totalLikes += post.likeCount || 0;
|
|
122
63
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
...data,
|
|
129
|
-
avg_likes_per_post: (posts > 0) ? (data.total_likes / posts) : 0,
|
|
130
|
-
avg_comments_per_post: (posts > 0) ? (data.total_comments / posts) : 0
|
|
64
|
+
|
|
65
|
+
this.result = {
|
|
66
|
+
total_posts: totalPosts,
|
|
67
|
+
total_comments: totalComments,
|
|
68
|
+
total_likes: totalLikes
|
|
131
69
|
};
|
|
132
70
|
}
|
|
71
|
+
// --- END FIX ---
|
|
133
72
|
|
|
134
|
-
async getResult() {
|
|
135
|
-
|
|
136
|
-
const global_activity = this._calculateAverages(this.global);
|
|
137
|
-
|
|
138
|
-
// Calculate averages for per-ticker
|
|
139
|
-
const per_ticker = {};
|
|
140
|
-
for (const [ticker, data] of this.perTicker.entries()) {
|
|
141
|
-
per_ticker[ticker] = this._calculateAverages(data);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
global_activity,
|
|
146
|
-
per_ticker
|
|
147
|
-
};
|
|
73
|
+
async getResult(fetchedDependencies) {
|
|
74
|
+
return this.result;
|
|
148
75
|
}
|
|
149
76
|
|
|
150
77
|
reset() {
|
|
151
|
-
this.
|
|
152
|
-
this.perTicker.clear();
|
|
78
|
+
this.result = {};
|
|
153
79
|
}
|
|
154
80
|
}
|
|
155
81
|
|