aiden-shared-calculations-unified 1.0.86 → 1.0.88

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 (80) hide show
  1. package/calculations/capitulation/asset-volatility-estimator.js +96 -0
  2. package/calculations/capitulation/retail-capitulation-risk-forecast.js +173 -0
  3. package/calculations/core/asset-cost-basis-profile.js +127 -0
  4. package/calculations/core/asset-pnl-status.js +36 -106
  5. package/calculations/core/asset-position-size.js +40 -91
  6. package/calculations/core/average-daily-pnl-all-users.js +18 -57
  7. package/calculations/core/average-daily-pnl-per-sector.js +41 -88
  8. package/calculations/core/average-daily-pnl-per-stock.js +38 -91
  9. package/calculations/core/average-daily-position-pnl.js +19 -49
  10. package/calculations/core/holding-duration-per-asset.js +25 -127
  11. package/calculations/core/instrument-price-change-1d.js +30 -49
  12. package/calculations/core/instrument-price-momentum-20d.js +50 -60
  13. package/calculations/core/long-position-per-stock.js +39 -68
  14. package/calculations/core/overall-holding-duration.js +16 -87
  15. package/calculations/core/overall-profitability-ratio.js +11 -40
  16. package/calculations/core/platform-buy-sell-sentiment.js +41 -124
  17. package/calculations/core/platform-daily-bought-vs-sold-count.js +41 -99
  18. package/calculations/core/platform-daily-ownership-delta.js +68 -126
  19. package/calculations/core/platform-ownership-per-sector.js +45 -96
  20. package/calculations/core/platform-total-positions-held.js +20 -80
  21. package/calculations/core/pnl-distribution-per-stock.js +29 -135
  22. package/calculations/core/price-metrics.js +95 -206
  23. package/calculations/core/profitability-ratio-per-sector.js +34 -79
  24. package/calculations/core/profitability-ratio-per-stock.js +32 -88
  25. package/calculations/core/profitability-skew-per-stock.js +41 -94
  26. package/calculations/core/profitable-and-unprofitable-status.js +44 -76
  27. package/calculations/core/sentiment-per-stock.js +24 -77
  28. package/calculations/core/short-position-per-stock.js +35 -43
  29. package/calculations/core/social-activity-aggregation.js +26 -49
  30. package/calculations/core/social-asset-posts-trend.js +38 -94
  31. package/calculations/core/social-event-correlation.js +26 -93
  32. package/calculations/core/social-sentiment-aggregation.js +20 -44
  33. package/calculations/core/social-top-mentioned-words.js +35 -87
  34. package/calculations/core/social-topic-interest-evolution.js +22 -111
  35. package/calculations/core/social-topic-sentiment-matrix.js +38 -104
  36. package/calculations/core/social-word-mentions-trend.js +27 -104
  37. package/calculations/core/speculator-asset-sentiment.js +31 -72
  38. package/calculations/core/speculator-danger-zone.js +48 -84
  39. package/calculations/core/speculator-distance-to-stop-loss-per-leverage.js +20 -52
  40. package/calculations/core/speculator-distance-to-tp-per-leverage.js +23 -53
  41. package/calculations/core/speculator-entry-distance-to-sl-per-leverage.js +20 -50
  42. package/calculations/core/speculator-entry-distance-to-tp-per-leverage.js +23 -50
  43. package/calculations/core/speculator-leverage-per-asset.js +25 -64
  44. package/calculations/core/speculator-leverage-per-sector.js +27 -63
  45. package/calculations/core/speculator-risk-reward-ratio-per-asset.js +24 -53
  46. package/calculations/core/speculator-stop-loss-distance-by-sector-short-long-breakdown.js +55 -68
  47. package/calculations/core/speculator-stop-loss-distance-by-ticker-short-long-breakdown.js +54 -71
  48. package/calculations/core/speculator-stop-loss-per-asset.js +19 -44
  49. package/calculations/core/speculator-take-profit-per-asset.js +20 -57
  50. package/calculations/core/speculator-tsl-per-asset.js +17 -56
  51. package/calculations/core/test..js +0 -0
  52. package/calculations/core/total-long-figures.js +16 -31
  53. package/calculations/core/total-long-per-sector.js +39 -61
  54. package/calculations/core/total-short-figures.js +13 -32
  55. package/calculations/core/total-short-per-sector.js +39 -61
  56. package/calculations/core/users-processed.js +11 -46
  57. package/calculations/gauss/cohort-capital-flow.js +54 -173
  58. package/calculations/gauss/cohort-definer.js +77 -163
  59. package/calculations/gauss/daily-dna-filter.js +29 -83
  60. package/calculations/gauss/gauss-divergence-signal.js +22 -109
  61. package/calculations/gem/cohort-momentum-state.js +27 -72
  62. package/calculations/gem/cohort-skill-definition.js +36 -52
  63. package/calculations/gem/platform-conviction-divergence.js +18 -60
  64. package/calculations/gem/quant-skill-alpha-signal.js +25 -98
  65. package/calculations/gem/skilled-cohort-flow.js +67 -175
  66. package/calculations/gem/skilled-unskilled-divergence.js +18 -73
  67. package/calculations/gem/unskilled-cohort-flow.js +64 -172
  68. package/calculations/ghost-book/cost-basis-density.js +79 -0
  69. package/calculations/ghost-book/liquidity-vacuum.js +52 -0
  70. package/calculations/ghost-book/retail-gamma-exposure.js +86 -0
  71. package/calculations/helix/helix-contrarian-signal.js +20 -114
  72. package/calculations/helix/herd-consensus-score.js +42 -124
  73. package/calculations/helix/winner-loser-flow.js +36 -118
  74. package/calculations/predicative-alpha/cognitive-dissonance.js +113 -0
  75. package/calculations/predicative-alpha/diamond-hand-fracture.js +90 -0
  76. package/calculations/predicative-alpha/mimetic-latency.js +124 -0
  77. package/calculations/pyro/risk-appetite-index.js +33 -74
  78. package/calculations/pyro/squeeze-potential.js +30 -87
  79. package/calculations/pyro/volatility-signal.js +33 -78
  80. package/package.json +1 -1
@@ -1,42 +1,25 @@
1
1
  /**
2
2
  * @fileoverview Calculation (Pass 1) for speculator TSL usage.
3
- *
4
- * This metric answers: "For each asset, what percentage
5
- * of speculators are using a *trailing* stop-loss?"
3
+ * REFACTORED: Uses extraction for TSL boolean.
6
4
  */
7
- // --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
8
-
9
5
  class SpeculatorTSLPerAsset {
10
6
  constructor() {
11
- // { [instrumentId]: { with_tsl: 0, total: 0 } }
12
7
  this.assets = new Map();
13
- // --- STANDARD 0: RENAMED ---
14
8
  this.tickerMap = null;
15
9
  }
16
10
 
17
- /**
18
- * Statically defines all metadata for the manifest builder.
19
- */
20
11
  static getMetadata() {
21
12
  return {
22
13
  type: 'standard',
23
14
  rootDataDependencies: ['portfolio'],
24
15
  isHistorical: false,
25
- userType: 'speculator', // <-- KEY: Only runs for speculators
16
+ userType: 'speculator',
26
17
  category: 'core_speculator'
27
18
  };
28
19
  }
29
20
 
30
- /**
31
- * Statically declare dependencies.
32
- */
33
- static getDependencies() {
34
- return [];
35
- }
21
+ static getDependencies() { return []; }
36
22
 
37
- /**
38
- * Defines the output schema for this calculation.
39
- */
40
23
  static getSchema() {
41
24
  const tickerSchema = {
42
25
  "type": "object",
@@ -47,13 +30,7 @@ class SpeculatorTSLPerAsset {
47
30
  },
48
31
  "required": ["tsl_usage_pct", "tsl_count", "total_count"]
49
32
  };
50
-
51
- return {
52
- "type": "object",
53
- "description": "Calculates the percentage of speculators using a *trailing* stop-loss per asset.",
54
- "patternProperties": { "^.*$": tickerSchema },
55
- "additionalProperties": tickerSchema
56
- };
33
+ return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
57
34
  }
58
35
 
59
36
  _initAsset(instrumentId) {
@@ -62,46 +39,32 @@ class SpeculatorTSLPerAsset {
62
39
  }
63
40
  }
64
41
 
65
- // --- STANDARD 0: UPDATED SIGNATURE ---
66
- process(todayPortfolio, yesterdayPortfolio, userId, context) {
67
- // --- STANDARD 0: ADDED ---
68
- if (!this.tickerMap) {
69
- this.tickerMap = context.instrumentToTicker;
70
- }
42
+ process(context) {
43
+ const { extract } = context.math;
44
+ const { mappings, user } = context;
45
+ if (!this.tickerMap) this.tickerMap = mappings.instrumentToTicker;
71
46
 
72
- const positions = todayPortfolio.PublicPositions;
73
- if (!positions || !Array.isArray(positions)) {
74
- return;
75
- }
47
+ const positions = extract.getPositions(user.portfolio.today, user.type);
76
48
 
77
49
  for (const pos of positions) {
78
- const instrumentId = pos.InstrumentID;
79
- if (!instrumentId) continue;
50
+ const instId = extract.getInstrumentId(pos);
51
+ if (!instId) continue;
80
52
 
81
- this._initAsset(instrumentId);
82
- const assetData = this.assets.get(instrumentId);
53
+ this._initAsset(instId);
54
+ const assetData = this.assets.get(instId);
83
55
  assetData.total++;
84
56
 
85
- // HasTrailingStopLoss is a boolean
86
- if (pos.HasTrailingStopLoss === true) {
57
+ if (extract.getHasTSL(pos)) {
87
58
  assetData.with_tsl++;
88
59
  }
89
60
  }
90
61
  }
91
62
 
92
63
  async getResult() {
93
- // --- STANDARD 0: REMOVED forbidden data load ---
94
-
95
- // Failsafe check
96
- if (!this.tickerMap) {
97
- return {}; // process() must run first
98
- }
99
-
64
+ if (!this.tickerMap) return {};
100
65
  const result = {};
101
- for (const [instrumentId, data] of this.assets.entries()) {
102
- // --- STANDARD 0: SIMPLIFIED ---
103
- const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
104
-
66
+ for (const [instId, data] of this.assets.entries()) {
67
+ const ticker = this.tickerMap[instId] || `id_${instId}`;
105
68
  if (data.total > 0) {
106
69
  result[ticker] = {
107
70
  tsl_usage_pct: (data.with_tsl / data.total) * 100,
@@ -115,9 +78,7 @@ class SpeculatorTSLPerAsset {
115
78
 
116
79
  reset() {
117
80
  this.assets.clear();
118
- // --- STANDARD 0: RENAMED ---
119
81
  this.tickerMap = null;
120
82
  }
121
83
  }
122
-
123
84
  module.exports = SpeculatorTSLPerAsset;
File without changes
@@ -1,18 +1,13 @@
1
1
  /**
2
2
  * @fileoverview Calculation (Pass 1) for total long figures.
3
- *
4
- * This metric answers: "What is the total $USD value
5
- * and total count of all long ('buy') positions?"
3
+ * REFACTORED: Tracks exposure weight (percentage of equity), not USD.
6
4
  */
7
5
  class TotalLongFigures {
8
6
  constructor() {
9
- this.totalInvestedUsd = 0;
7
+ this.totalExposureWeight = 0;
10
8
  this.totalPositions = 0;
11
9
  }
12
10
 
13
- /**
14
- * Statically defines all metadata for the manifest builder.
15
- */
16
11
  static getMetadata() {
17
12
  return {
18
13
  type: 'standard',
@@ -23,40 +18,30 @@ class TotalLongFigures {
23
18
  };
24
19
  }
25
20
 
26
- /**
27
- * Statically declare dependencies.
28
- */
29
- static getDependencies() {
30
- return [];
31
- }
21
+ static getDependencies() { return []; }
32
22
 
33
- /**
34
- * Defines the output schema for this calculation.
35
- */
36
23
  static getSchema() {
37
24
  return {
38
25
  "type": "object",
39
- "description": "Aggregates the total $USD value and count of all long positions.",
40
26
  "properties": {
41
- "total_invested_usd": { "type": "number" },
27
+ "total_long_exposure_weight": { "type": "number", "description": "Sum of portfolio allocation percentages for all long positions." },
42
28
  "total_positions_count": { "type": "number" }
43
29
  },
44
- "required": ["total_invested_usd", "total_positions_count"]
30
+ "required": ["total_long_exposure_weight", "total_positions_count"]
45
31
  };
46
32
  }
47
33
 
48
- // --- UPDATED SIGNATURE ---
49
- process(todayPortfolio, yesterdayPortfolio, userId, context) {
50
- // --- UPDATED ---
51
- const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
52
- if (!positions || !Array.isArray(positions)) {
53
- return;
54
- }
34
+ process(context) {
35
+ const { extract } = context.math;
36
+ const { user } = context;
37
+
38
+ const positions = extract.getPositions(user.portfolio.today, user.type);
55
39
 
56
40
  for (const pos of positions) {
57
- // Only count 'buy' (long) positions
58
- if (pos.IsBuy) {
59
- this.totalInvestedUsd += pos.Invested || 0;
41
+ const direction = extract.getDirection(pos);
42
+
43
+ if (direction === 'Buy') {
44
+ this.totalExposureWeight += extract.getPositionWeight(pos, user.type);
60
45
  this.totalPositions++;
61
46
  }
62
47
  }
@@ -64,13 +49,13 @@ class TotalLongFigures {
64
49
 
65
50
  getResult() {
66
51
  return {
67
- total_invested_usd: this.totalInvestedUsd,
52
+ total_long_exposure_weight: this.totalExposureWeight,
68
53
  total_positions_count: this.totalPositions
69
54
  };
70
55
  }
71
56
 
72
57
  reset() {
73
- this.totalInvestedUsd = 0;
58
+ this.totalExposureWeight = 0;
74
59
  this.totalPositions = 0;
75
60
  }
76
61
  }
@@ -1,22 +1,13 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for total long value per sector.
3
- *
4
- * This metric answers: "What is the total $USD value
5
- * of all long ('buy') positions, grouped by sector?"
2
+ * @fileoverview Calculation (Pass 1) for long figures per sector.
3
+ * REFACTORED: Tracks exposure weight (percentage).
6
4
  */
7
- // --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
8
-
9
5
  class TotalLongPerSector {
10
6
  constructor() {
11
- // { [sectorName]: { total_invested_usd: 0, total_positions_count: 0 } }
12
- this.sectors = new Map();
13
- // --- STANDARD 0: RENAMED ---
7
+ this.sectorData = new Map();
14
8
  this.sectorMap = null;
15
9
  }
16
10
 
17
- /**
18
- * Statically defines all metadata for the manifest builder.
19
- */
20
11
  static getMetadata() {
21
12
  return {
22
13
  type: 'standard',
@@ -27,78 +18,65 @@ class TotalLongPerSector {
27
18
  };
28
19
  }
29
20
 
30
- /**
31
- * Statically declare dependencies.
32
- */
33
- static getDependencies() {
34
- return [];
35
- }
21
+ static getDependencies() { return []; }
36
22
 
37
- /**
38
- * Defines the output schema for this calculation.
39
- */
40
23
  static getSchema() {
41
- const sectorSchema = {
24
+ const schema = {
42
25
  "type": "object",
43
26
  "properties": {
44
- "total_invested_usd": { "type": "number" },
27
+ "total_long_exposure_weight": { "type": "number" },
45
28
  "total_positions_count": { "type": "number" }
46
- }
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
29
+ },
30
+ "required": ["total_long_exposure_weight", "total_positions_count"]
54
31
  };
32
+ return { "type": "object", "patternProperties": { "^.*$": schema } };
55
33
  }
56
34
 
57
- _initSector(sectorName) {
58
- if (!this.sectors.has(sectorName)) {
59
- this.sectors.set(sectorName, { total_invested_usd: 0, total_positions_count: 0 });
35
+ _initSector(sector) {
36
+ if (!this.sectorData.has(sector)) {
37
+ this.sectorData.set(sector, { weight: 0, count: 0 });
60
38
  }
61
39
  }
62
40
 
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;
68
- }
41
+ process(context) {
42
+ const { extract } = context.math;
43
+ const { mappings, user } = context;
44
+ if (!this.sectorMap) this.sectorMap = mappings.sectorMapping;
69
45
 
70
- const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
71
- if (!positions || !Array.isArray(positions) || !this.sectorMap) {
72
- return;
73
- }
46
+ const positions = extract.getPositions(user.portfolio.today, user.type);
74
47
 
75
48
  for (const pos of positions) {
76
- // Only count 'buy' (long) positions
77
- if (pos.IsBuy) {
78
- const instrumentId = pos.InstrumentID;
79
- if (!instrumentId) continue;
80
-
81
- // --- STANDARD 0: FIXED ---
82
- const sectorName = this.sectorMap[instrumentId] || 'N/A';
83
- this._initSector(sectorName);
84
- const sectorData = this.sectors.get(sectorName);
49
+ if (extract.getDirection(pos) !== 'Buy') continue;
85
50
 
86
- sectorData.total_invested_usd += pos.Invested || 0;
87
- sectorData.total_positions_count++;
88
- }
51
+ const instId = extract.getInstrumentId(pos);
52
+ if (!instId) continue;
53
+
54
+ const sector = this.sectorMap[instId] || 'Unknown';
55
+ const weight = extract.getPositionWeight(pos, user.type);
56
+
57
+ this._initSector(sector);
58
+ const data = this.sectorData.get(sector);
59
+ data.weight += weight;
60
+ data.count++;
89
61
  }
90
62
  }
91
63
 
92
64
  async getResult() {
93
- // --- STANDARD 0: REMOVED forbidden data load ---
94
- return Object.fromEntries(this.sectors);
65
+ const result = {};
66
+ for (const [sector, data] of this.sectorData.entries()) {
67
+ if (data.count > 0) {
68
+ result[sector] = {
69
+ total_long_exposure_weight: data.weight,
70
+ total_positions_count: data.count
71
+ };
72
+ }
73
+ }
74
+ return result;
95
75
  }
96
76
 
97
77
  reset() {
98
- this.sectors.clear();
99
- // --- STANDARD 0: RENAMED ---
78
+ this.sectorData.clear();
100
79
  this.sectorMap = null;
101
80
  }
102
81
  }
103
-
104
82
  module.exports = TotalLongPerSector;
@@ -1,18 +1,13 @@
1
1
  /**
2
2
  * @fileoverview Calculation (Pass 1) for total short figures.
3
- *
4
- * This metric answers: "What is the total $USD value
5
- * and total count of all short ('sell') positions?"
3
+ * REFACTORED: Tracks exposure weight (percentage).
6
4
  */
7
5
  class TotalShortFigures {
8
6
  constructor() {
9
- this.totalInvestedUsd = 0;
7
+ this.totalExposureWeight = 0;
10
8
  this.totalPositions = 0;
11
9
  }
12
10
 
13
- /**
14
- * Statically defines all metadata for the manifest builder.
15
- */
16
11
  static getMetadata() {
17
12
  return {
18
13
  type: 'standard',
@@ -23,40 +18,27 @@ class TotalShortFigures {
23
18
  };
24
19
  }
25
20
 
26
- /**
27
- * Statically declare dependencies.
28
- */
29
- static getDependencies() {
30
- return [];
31
- }
21
+ static getDependencies() { return []; }
32
22
 
33
- /**
34
- * Defines the output schema for this calculation.
35
- */
36
23
  static getSchema() {
37
24
  return {
38
25
  "type": "object",
39
- "description": "Aggregates the total $USD value and count of all short positions.",
40
26
  "properties": {
41
- "total_invested_usd": { "type": "number" },
27
+ "total_short_exposure_weight": { "type": "number" },
42
28
  "total_positions_count": { "type": "number" }
43
29
  },
44
- "required": ["total_invested_usd", "total_positions_count"]
30
+ "required": ["total_short_exposure_weight", "total_positions_count"]
45
31
  };
46
32
  }
47
33
 
48
- // --- UPDATED SIGNATURE ---
49
- process(todayPortfolio, yesterdayPortfolio, userId, context) {
50
- // --- UPDATED ---
51
- const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
52
- if (!positions || !Array.isArray(positions)) {
53
- return;
54
- }
34
+ process(context) {
35
+ const { extract } = context.math;
36
+ const { user } = context;
37
+ const positions = extract.getPositions(user.portfolio.today, user.type);
55
38
 
56
39
  for (const pos of positions) {
57
- // Only count 'sell' (short) positions
58
- if (!pos.IsBuy) {
59
- this.totalInvestedUsd += pos.Invested || 0;
40
+ if (extract.getDirection(pos) === 'Sell') {
41
+ this.totalExposureWeight += extract.getPositionWeight(pos, user.type);
60
42
  this.totalPositions++;
61
43
  }
62
44
  }
@@ -64,15 +46,14 @@ class TotalShortFigures {
64
46
 
65
47
  getResult() {
66
48
  return {
67
- total_invested_usd: this.totalInvestedUsd,
49
+ total_short_exposure_weight: this.totalExposureWeight,
68
50
  total_positions_count: this.totalPositions
69
51
  };
70
52
  }
71
53
 
72
54
  reset() {
73
- this.totalInvestedUsd = 0;
55
+ this.totalExposureWeight = 0;
74
56
  this.totalPositions = 0;
75
57
  }
76
58
  }
77
-
78
59
  module.exports = TotalShortFigures;
@@ -1,22 +1,13 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for total short value per sector.
3
- *
4
- * This metric answers: "What is the total $USD value
5
- * of all short ('sell') positions, grouped by sector?"
2
+ * @fileoverview Calculation (Pass 1) for short figures per sector.
3
+ * REFACTORED: Tracks exposure weight (percentage).
6
4
  */
7
- // --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
8
-
9
5
  class TotalShortPerSector {
10
6
  constructor() {
11
- // { [sectorName]: { total_invested_usd: 0, total_positions_count: 0 } }
12
- this.sectors = new Map();
13
- // --- STANDARD 0: RENAMED ---
7
+ this.sectorData = new Map();
14
8
  this.sectorMap = null;
15
9
  }
16
10
 
17
- /**
18
- * Statically defines all metadata for the manifest builder.
19
- */
20
11
  static getMetadata() {
21
12
  return {
22
13
  type: 'standard',
@@ -27,78 +18,65 @@ class TotalShortPerSector {
27
18
  };
28
19
  }
29
20
 
30
- /**
31
- * Statically declare dependencies.
32
- */
33
- static getDependencies() {
34
- return [];
35
- }
21
+ static getDependencies() { return []; }
36
22
 
37
- /**
38
- * Defines the output schema for this calculation.
39
- */
40
23
  static getSchema() {
41
- const sectorSchema = {
24
+ const schema = {
42
25
  "type": "object",
43
26
  "properties": {
44
- "total_invested_usd": { "type": "number" },
27
+ "total_short_exposure_weight": { "type": "number" },
45
28
  "total_positions_count": { "type": "number" }
46
- }
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
29
+ },
30
+ "required": ["total_short_exposure_weight", "total_positions_count"]
54
31
  };
32
+ return { "type": "object", "patternProperties": { "^.*$": schema } };
55
33
  }
56
34
 
57
- _initSector(sectorName) {
58
- if (!this.sectors.has(sectorName)) {
59
- this.sectors.set(sectorName, { total_invested_usd: 0, total_positions_count: 0 });
35
+ _initSector(sector) {
36
+ if (!this.sectorData.has(sector)) {
37
+ this.sectorData.set(sector, { weight: 0, count: 0 });
60
38
  }
61
39
  }
62
40
 
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;
68
- }
41
+ process(context) {
42
+ const { extract } = context.math;
43
+ const { mappings, user } = context;
44
+ if (!this.sectorMap) this.sectorMap = mappings.sectorMapping;
69
45
 
70
- const positions = todayPortfolio.PublicPositions || todayPortfolio.AggregatedPositions;
71
- if (!positions || !Array.isArray(positions) || !this.sectorMap) {
72
- return;
73
- }
46
+ const positions = extract.getPositions(user.portfolio.today, user.type);
74
47
 
75
48
  for (const pos of positions) {
76
- // Only count 'sell' (short) positions
77
- if (!pos.IsBuy) {
78
- const instrumentId = pos.InstrumentID;
79
- if (!instrumentId) continue;
80
-
81
- // --- STANDARD 0: FIXED ---
82
- const sectorName = this.sectorMap[instrumentId] || 'N/A';
83
- this._initSector(sectorName);
84
- const sectorData = this.sectors.get(sectorName);
49
+ if (extract.getDirection(pos) !== 'Sell') continue;
85
50
 
86
- sectorData.total_invested_usd += pos.Invested || 0;
87
- sectorData.total_positions_count++;
88
- }
51
+ const instId = extract.getInstrumentId(pos);
52
+ if (!instId) continue;
53
+
54
+ const sector = this.sectorMap[instId] || 'Unknown';
55
+ const weight = extract.getPositionWeight(pos, user.type);
56
+
57
+ this._initSector(sector);
58
+ const data = this.sectorData.get(sector);
59
+ data.weight += weight;
60
+ data.count++;
89
61
  }
90
62
  }
91
63
 
92
64
  async getResult() {
93
- // --- STANDARD 0: REMOVED forbidden data load ---
94
- return Object.fromEntries(this.sectors);
65
+ const result = {};
66
+ for (const [sector, data] of this.sectorData.entries()) {
67
+ if (data.count > 0) {
68
+ result[sector] = {
69
+ total_short_exposure_weight: data.weight,
70
+ total_positions_count: data.count
71
+ };
72
+ }
73
+ }
74
+ return result;
95
75
  }
96
76
 
97
77
  reset() {
98
- this.sectors.clear();
99
- // --- STANDARD 0: RENAMED ---
78
+ this.sectorData.clear();
100
79
  this.sectorMap = null;
101
80
  }
102
81
  }
103
-
104
82
  module.exports = TotalShortPerSector;