aiden-shared-calculations-unified 1.0.83 → 1.0.86
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 -16
- 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 +5 -5
- package/README.MD +0 -155
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for speculator
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for speculator TSL usage.
|
|
3
3
|
*
|
|
4
|
-
* This metric answers: "For each asset,
|
|
5
|
-
* speculators
|
|
6
|
-
* versus disabled?"
|
|
4
|
+
* This metric answers: "For each asset, what percentage
|
|
5
|
+
* of speculators are using a *trailing* stop-loss?"
|
|
7
6
|
*/
|
|
8
|
-
|
|
7
|
+
// --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
|
|
9
8
|
|
|
10
|
-
class
|
|
9
|
+
class SpeculatorTSLPerAsset {
|
|
11
10
|
constructor() {
|
|
12
|
-
// { [instrumentId]: {
|
|
11
|
+
// { [instrumentId]: { with_tsl: 0, total: 0 } }
|
|
13
12
|
this.assets = new Map();
|
|
14
|
-
|
|
13
|
+
// --- STANDARD 0: RENAMED ---
|
|
14
|
+
this.tickerMap = null;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
// --- NEW ---
|
|
18
17
|
/**
|
|
19
18
|
* Statically defines all metadata for the manifest builder.
|
|
20
19
|
*/
|
|
@@ -23,12 +22,11 @@ class TslPerAsset {
|
|
|
23
22
|
type: 'standard',
|
|
24
23
|
rootDataDependencies: ['portfolio'],
|
|
25
24
|
isHistorical: false,
|
|
26
|
-
userType: 'speculator',
|
|
25
|
+
userType: 'speculator', // <-- KEY: Only runs for speculators
|
|
27
26
|
category: 'core_speculator'
|
|
28
27
|
};
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
// --- NEW ---
|
|
32
30
|
/**
|
|
33
31
|
* Statically declare dependencies.
|
|
34
32
|
*/
|
|
@@ -38,49 +36,40 @@ class TslPerAsset {
|
|
|
38
36
|
|
|
39
37
|
/**
|
|
40
38
|
* Defines the output schema for this calculation.
|
|
41
|
-
* @returns {object} JSON Schema object
|
|
42
39
|
*/
|
|
43
40
|
static getSchema() {
|
|
44
41
|
const tickerSchema = {
|
|
45
42
|
"type": "object",
|
|
46
43
|
"properties": {
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"type": "number",
|
|
51
|
-
"description": "Percentage of positions with TSL enabled."
|
|
52
|
-
}
|
|
44
|
+
"tsl_usage_pct": { "type": "number" },
|
|
45
|
+
"tsl_count": { "type": "number" },
|
|
46
|
+
"total_count": { "type": "number" }
|
|
53
47
|
},
|
|
54
|
-
"required": ["
|
|
48
|
+
"required": ["tsl_usage_pct", "tsl_count", "total_count"]
|
|
55
49
|
};
|
|
56
50
|
|
|
57
51
|
return {
|
|
58
52
|
"type": "object",
|
|
59
|
-
"description": "Calculates the
|
|
60
|
-
"patternProperties": {
|
|
61
|
-
"^.*$": tickerSchema // Ticker
|
|
62
|
-
},
|
|
53
|
+
"description": "Calculates the percentage of speculators using a *trailing* stop-loss per asset.",
|
|
54
|
+
"patternProperties": { "^.*$": tickerSchema },
|
|
63
55
|
"additionalProperties": tickerSchema
|
|
64
56
|
};
|
|
65
57
|
}
|
|
66
58
|
|
|
67
59
|
_initAsset(instrumentId) {
|
|
68
60
|
if (!this.assets.has(instrumentId)) {
|
|
69
|
-
this.assets.set(instrumentId, {
|
|
70
|
-
enabled: 0,
|
|
71
|
-
disabled: 0
|
|
72
|
-
});
|
|
61
|
+
this.assets.set(instrumentId, { with_tsl: 0, total: 0 });
|
|
73
62
|
}
|
|
74
63
|
}
|
|
75
64
|
|
|
76
|
-
// ---
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
|
|
65
|
+
// --- STANDARD 0: UPDATED SIGNATURE ---
|
|
66
|
+
process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
67
|
+
// --- STANDARD 0: ADDED ---
|
|
68
|
+
if (!this.tickerMap) {
|
|
69
|
+
this.tickerMap = context.instrumentToTicker;
|
|
81
70
|
}
|
|
82
|
-
|
|
83
|
-
const positions =
|
|
71
|
+
|
|
72
|
+
const positions = todayPortfolio.PublicPositions;
|
|
84
73
|
if (!positions || !Array.isArray(positions)) {
|
|
85
74
|
return;
|
|
86
75
|
}
|
|
@@ -91,30 +80,33 @@ class TslPerAsset {
|
|
|
91
80
|
|
|
92
81
|
this._initAsset(instrumentId);
|
|
93
82
|
const assetData = this.assets.get(instrumentId);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
assetData.
|
|
83
|
+
assetData.total++;
|
|
84
|
+
|
|
85
|
+
// HasTrailingStopLoss is a boolean
|
|
86
|
+
if (pos.HasTrailingStopLoss === true) {
|
|
87
|
+
assetData.with_tsl++;
|
|
99
88
|
}
|
|
100
89
|
}
|
|
101
90
|
}
|
|
102
91
|
|
|
103
92
|
async getResult() {
|
|
104
|
-
|
|
105
|
-
|
|
93
|
+
// --- STANDARD 0: REMOVED forbidden data load ---
|
|
94
|
+
|
|
95
|
+
// Failsafe check
|
|
96
|
+
if (!this.tickerMap) {
|
|
97
|
+
return {}; // process() must run first
|
|
106
98
|
}
|
|
107
99
|
|
|
108
100
|
const result = {};
|
|
109
101
|
for (const [instrumentId, data] of this.assets.entries()) {
|
|
110
|
-
|
|
111
|
-
const
|
|
102
|
+
// --- STANDARD 0: SIMPLIFIED ---
|
|
103
|
+
const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
|
|
112
104
|
|
|
113
|
-
if (total > 0) {
|
|
105
|
+
if (data.total > 0) {
|
|
114
106
|
result[ticker] = {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
107
|
+
tsl_usage_pct: (data.with_tsl / data.total) * 100,
|
|
108
|
+
tsl_count: data.with_tsl,
|
|
109
|
+
total_count: data.total
|
|
118
110
|
};
|
|
119
111
|
}
|
|
120
112
|
}
|
|
@@ -123,8 +115,9 @@ class TslPerAsset {
|
|
|
123
115
|
|
|
124
116
|
reset() {
|
|
125
117
|
this.assets.clear();
|
|
126
|
-
|
|
118
|
+
// --- STANDARD 0: RENAMED ---
|
|
119
|
+
this.tickerMap = null;
|
|
127
120
|
}
|
|
128
121
|
}
|
|
129
122
|
|
|
130
|
-
module.exports =
|
|
123
|
+
module.exports = SpeculatorTSLPerAsset;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Calculation (Pass 1) for total long figures.
|
|
3
3
|
*
|
|
4
|
-
* This metric answers: "What is the total
|
|
5
|
-
* ('buy') positions
|
|
4
|
+
* This metric answers: "What is the total $USD value
|
|
5
|
+
* and total count of all long ('buy') positions?"
|
|
6
6
|
*/
|
|
7
7
|
class TotalLongFigures {
|
|
8
8
|
constructor() {
|
|
9
|
-
this.
|
|
9
|
+
this.totalInvestedUsd = 0;
|
|
10
|
+
this.totalPositions = 0;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
// --- NEW ---
|
|
13
13
|
/**
|
|
14
14
|
* Statically defines all metadata for the manifest builder.
|
|
15
15
|
*/
|
|
@@ -23,7 +23,6 @@ class TotalLongFigures {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
// --- NEW ---
|
|
27
26
|
/**
|
|
28
27
|
* Statically declare dependencies.
|
|
29
28
|
*/
|
|
@@ -33,45 +32,46 @@ class TotalLongFigures {
|
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
34
|
* Defines the output schema for this calculation.
|
|
36
|
-
* @returns {object} JSON Schema object
|
|
37
35
|
*/
|
|
38
36
|
static getSchema() {
|
|
39
37
|
return {
|
|
40
38
|
"type": "object",
|
|
41
|
-
"description": "
|
|
39
|
+
"description": "Aggregates the total $USD value and count of all long positions.",
|
|
42
40
|
"properties": {
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
"description": "The aggregated count of all long positions."
|
|
46
|
-
}
|
|
41
|
+
"total_invested_usd": { "type": "number" },
|
|
42
|
+
"total_positions_count": { "type": "number" }
|
|
47
43
|
},
|
|
48
|
-
"required": ["
|
|
44
|
+
"required": ["total_invested_usd", "total_positions_count"]
|
|
49
45
|
};
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
// ---
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const positions =
|
|
48
|
+
// --- UPDATED SIGNATURE ---
|
|
49
|
+
process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
50
|
+
// --- UPDATED ---
|
|
51
|
+
const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
|
|
56
52
|
if (!positions || !Array.isArray(positions)) {
|
|
57
53
|
return;
|
|
58
54
|
}
|
|
59
55
|
|
|
60
56
|
for (const pos of positions) {
|
|
57
|
+
// Only count 'buy' (long) positions
|
|
61
58
|
if (pos.IsBuy) {
|
|
62
|
-
this.
|
|
59
|
+
this.totalInvestedUsd += pos.Invested || 0;
|
|
60
|
+
this.totalPositions++;
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
getResult() {
|
|
68
66
|
return {
|
|
69
|
-
|
|
67
|
+
total_invested_usd: this.totalInvestedUsd,
|
|
68
|
+
total_positions_count: this.totalPositions
|
|
70
69
|
};
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
reset() {
|
|
74
|
-
this.
|
|
73
|
+
this.totalInvestedUsd = 0;
|
|
74
|
+
this.totalPositions = 0;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for total long
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for total long value per sector.
|
|
3
3
|
*
|
|
4
|
-
* This metric answers: "What is the total
|
|
5
|
-
* positions
|
|
4
|
+
* This metric answers: "What is the total $USD value
|
|
5
|
+
* of all long ('buy') positions, grouped by sector?"
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
// --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
|
|
8
8
|
|
|
9
9
|
class TotalLongPerSector {
|
|
10
10
|
constructor() {
|
|
11
|
-
//
|
|
11
|
+
// { [sectorName]: { total_invested_usd: 0, total_positions_count: 0 } }
|
|
12
12
|
this.sectors = new Map();
|
|
13
|
-
|
|
13
|
+
// --- STANDARD 0: RENAMED ---
|
|
14
|
+
this.sectorMap = null;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
// --- NEW ---
|
|
17
17
|
/**
|
|
18
18
|
* Statically defines all metadata for the manifest builder.
|
|
19
19
|
*/
|
|
@@ -27,7 +27,6 @@ class TotalLongPerSector {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
// --- NEW ---
|
|
31
30
|
/**
|
|
32
31
|
* Statically declare dependencies.
|
|
33
32
|
*/
|
|
@@ -37,39 +36,39 @@ class TotalLongPerSector {
|
|
|
37
36
|
|
|
38
37
|
/**
|
|
39
38
|
* Defines the output schema for this calculation.
|
|
40
|
-
* @returns {object} JSON Schema object
|
|
41
39
|
*/
|
|
42
40
|
static getSchema() {
|
|
43
|
-
|
|
41
|
+
const sectorSchema = {
|
|
44
42
|
"type": "object",
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"^.*$": {
|
|
49
|
-
"type": "number",
|
|
50
|
-
"description": "The total count of long positions for this sector."
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"additionalProperties": {
|
|
54
|
-
"type": "number"
|
|
43
|
+
"properties": {
|
|
44
|
+
"total_invested_usd": { "type": "number" },
|
|
45
|
+
"total_positions_count": { "type": "number" }
|
|
55
46
|
}
|
|
56
47
|
};
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"description": "Calculates the total $USD value and count of long positions per sector.",
|
|
52
|
+
"patternProperties": { "^.*$": sectorSchema },
|
|
53
|
+
"additionalProperties": sectorSchema
|
|
54
|
+
};
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
_initSector(
|
|
60
|
-
if (!this.sectors.has(
|
|
61
|
-
this.sectors.set(
|
|
57
|
+
_initSector(sectorName) {
|
|
58
|
+
if (!this.sectors.has(sectorName)) {
|
|
59
|
+
this.sectors.set(sectorName, { total_invested_usd: 0, total_positions_count: 0 });
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
// --- STANDARD 0: UPDATED SIGNATURE ---
|
|
64
|
+
async process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
65
|
+
// --- STANDARD 0: FIXED ---
|
|
66
|
+
if (!this.sectorMap) {
|
|
67
|
+
this.sectorMap = context.sectorMapping;
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
const positions =
|
|
72
|
-
if (!positions || !Array.isArray(positions) || !this.
|
|
70
|
+
const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
|
|
71
|
+
if (!positions || !Array.isArray(positions) || !this.sectorMap) {
|
|
73
72
|
return;
|
|
74
73
|
}
|
|
75
74
|
|
|
@@ -79,22 +78,26 @@ class TotalLongPerSector {
|
|
|
79
78
|
const instrumentId = pos.InstrumentID;
|
|
80
79
|
if (!instrumentId) continue;
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
this.
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
// --- STANDARD 0: FIXED ---
|
|
82
|
+
const sectorName = this.sectorMap[instrumentId] || 'N/A';
|
|
83
|
+
this._initSector(sectorName);
|
|
84
|
+
const sectorData = this.sectors.get(sectorName);
|
|
85
|
+
|
|
86
|
+
sectorData.total_invested_usd += pos.Invested || 0;
|
|
87
|
+
sectorData.total_positions_count++;
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
getResult() {
|
|
91
|
-
//
|
|
92
|
+
async getResult() {
|
|
93
|
+
// --- STANDARD 0: REMOVED forbidden data load ---
|
|
92
94
|
return Object.fromEntries(this.sectors);
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
reset() {
|
|
96
98
|
this.sectors.clear();
|
|
97
|
-
|
|
99
|
+
// --- STANDARD 0: RENAMED ---
|
|
100
|
+
this.sectorMap = null;
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
103
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Calculation (Pass 1) for total short figures.
|
|
3
3
|
*
|
|
4
|
-
* This metric answers: "What is the total
|
|
5
|
-
* ('sell') positions
|
|
4
|
+
* This metric answers: "What is the total $USD value
|
|
5
|
+
* and total count of all short ('sell') positions?"
|
|
6
6
|
*/
|
|
7
7
|
class TotalShortFigures {
|
|
8
8
|
constructor() {
|
|
9
|
-
this.
|
|
9
|
+
this.totalInvestedUsd = 0;
|
|
10
|
+
this.totalPositions = 0;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
// --- NEW ---
|
|
13
13
|
/**
|
|
14
14
|
* Statically defines all metadata for the manifest builder.
|
|
15
15
|
*/
|
|
@@ -23,7 +23,6 @@ class TotalShortFigures {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
// --- NEW ---
|
|
27
26
|
/**
|
|
28
27
|
* Statically declare dependencies.
|
|
29
28
|
*/
|
|
@@ -33,45 +32,46 @@ class TotalShortFigures {
|
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
34
|
* Defines the output schema for this calculation.
|
|
36
|
-
* @returns {object} JSON Schema object
|
|
37
35
|
*/
|
|
38
36
|
static getSchema() {
|
|
39
37
|
return {
|
|
40
38
|
"type": "object",
|
|
41
|
-
"description": "
|
|
39
|
+
"description": "Aggregates the total $USD value and count of all short positions.",
|
|
42
40
|
"properties": {
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
"description": "The aggregated count of all short positions."
|
|
46
|
-
}
|
|
41
|
+
"total_invested_usd": { "type": "number" },
|
|
42
|
+
"total_positions_count": { "type": "number" }
|
|
47
43
|
},
|
|
48
|
-
"required": ["
|
|
44
|
+
"required": ["total_invested_usd", "total_positions_count"]
|
|
49
45
|
};
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
// ---
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const positions =
|
|
48
|
+
// --- UPDATED SIGNATURE ---
|
|
49
|
+
process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
50
|
+
// --- UPDATED ---
|
|
51
|
+
const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
|
|
56
52
|
if (!positions || !Array.isArray(positions)) {
|
|
57
53
|
return;
|
|
58
54
|
}
|
|
59
55
|
|
|
60
56
|
for (const pos of positions) {
|
|
57
|
+
// Only count 'sell' (short) positions
|
|
61
58
|
if (!pos.IsBuy) {
|
|
62
|
-
this.
|
|
59
|
+
this.totalInvestedUsd += pos.Invested || 0;
|
|
60
|
+
this.totalPositions++;
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
getResult() {
|
|
68
66
|
return {
|
|
69
|
-
|
|
67
|
+
total_invested_usd: this.totalInvestedUsd,
|
|
68
|
+
total_positions_count: this.totalPositions
|
|
70
69
|
};
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
reset() {
|
|
74
|
-
this.
|
|
73
|
+
this.totalInvestedUsd = 0;
|
|
74
|
+
this.totalPositions = 0;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for total short
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for total short value per sector.
|
|
3
3
|
*
|
|
4
|
-
* This metric answers: "What is the total
|
|
5
|
-
* positions
|
|
4
|
+
* This metric answers: "What is the total $USD value
|
|
5
|
+
* of all short ('sell') positions, grouped by sector?"
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
// --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
|
|
8
8
|
|
|
9
9
|
class TotalShortPerSector {
|
|
10
10
|
constructor() {
|
|
11
|
-
//
|
|
11
|
+
// { [sectorName]: { total_invested_usd: 0, total_positions_count: 0 } }
|
|
12
12
|
this.sectors = new Map();
|
|
13
|
-
|
|
13
|
+
// --- STANDARD 0: RENAMED ---
|
|
14
|
+
this.sectorMap = null;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
// --- NEW ---
|
|
17
17
|
/**
|
|
18
18
|
* Statically defines all metadata for the manifest builder.
|
|
19
19
|
*/
|
|
@@ -27,7 +27,6 @@ class TotalShortPerSector {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
// --- NEW ---
|
|
31
30
|
/**
|
|
32
31
|
* Statically declare dependencies.
|
|
33
32
|
*/
|
|
@@ -37,39 +36,39 @@ class TotalShortPerSector {
|
|
|
37
36
|
|
|
38
37
|
/**
|
|
39
38
|
* Defines the output schema for this calculation.
|
|
40
|
-
* @returns {object} JSON Schema object
|
|
41
39
|
*/
|
|
42
40
|
static getSchema() {
|
|
43
|
-
|
|
41
|
+
const sectorSchema = {
|
|
44
42
|
"type": "object",
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"^.*$": {
|
|
49
|
-
"type": "number",
|
|
50
|
-
"description": "The total count of short positions for this sector."
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"additionalProperties": {
|
|
54
|
-
"type": "number"
|
|
43
|
+
"properties": {
|
|
44
|
+
"total_invested_usd": { "type": "number" },
|
|
45
|
+
"total_positions_count": { "type": "number" }
|
|
55
46
|
}
|
|
56
47
|
};
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"description": "Calculates the total $USD value and count of short positions per sector.",
|
|
52
|
+
"patternProperties": { "^.*$": sectorSchema },
|
|
53
|
+
"additionalProperties": sectorSchema
|
|
54
|
+
};
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
_initSector(
|
|
60
|
-
if (!this.sectors.has(
|
|
61
|
-
this.sectors.set(
|
|
57
|
+
_initSector(sectorName) {
|
|
58
|
+
if (!this.sectors.has(sectorName)) {
|
|
59
|
+
this.sectors.set(sectorName, { total_invested_usd: 0, total_positions_count: 0 });
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
// --- STANDARD 0: UPDATED SIGNATURE ---
|
|
64
|
+
async process(todayPortfolio, yesterdayPortfolio, userId, context) {
|
|
65
|
+
// --- STANDARD 0: FIXED ---
|
|
66
|
+
if (!this.sectorMap) {
|
|
67
|
+
this.sectorMap = context.sectorMapping;
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
const positions =
|
|
72
|
-
if (!positions || !Array.isArray(positions) || !this.
|
|
70
|
+
const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
|
|
71
|
+
if (!positions || !Array.isArray(positions) || !this.sectorMap) {
|
|
73
72
|
return;
|
|
74
73
|
}
|
|
75
74
|
|
|
@@ -79,22 +78,26 @@ class TotalShortPerSector {
|
|
|
79
78
|
const instrumentId = pos.InstrumentID;
|
|
80
79
|
if (!instrumentId) continue;
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
this.
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
// --- STANDARD 0: FIXED ---
|
|
82
|
+
const sectorName = this.sectorMap[instrumentId] || 'N/A';
|
|
83
|
+
this._initSector(sectorName);
|
|
84
|
+
const sectorData = this.sectors.get(sectorName);
|
|
85
|
+
|
|
86
|
+
sectorData.total_invested_usd += pos.Invested || 0;
|
|
87
|
+
sectorData.total_positions_count++;
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
getResult() {
|
|
91
|
-
//
|
|
92
|
+
async getResult() {
|
|
93
|
+
// --- STANDARD 0: REMOVED forbidden data load ---
|
|
92
94
|
return Object.fromEntries(this.sectors);
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
reset() {
|
|
96
98
|
this.sectors.clear();
|
|
97
|
-
|
|
99
|
+
// --- STANDARD 0: RENAMED ---
|
|
100
|
+
this.sectorMap = null;
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
103
|
|