aiden-shared-calculations-unified 1.0.83 → 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.
Files changed (71) hide show
  1. package/calculations/core/asset-pnl-status.js +122 -104
  2. package/calculations/core/asset-position-size.js +110 -73
  3. package/calculations/core/average-daily-pnl-all-users.js +17 -3
  4. package/calculations/core/average-daily-pnl-per-sector.js +83 -75
  5. package/calculations/core/average-daily-pnl-per-stock.js +84 -73
  6. package/calculations/core/average-daily-position-pnl.js +2 -2
  7. package/calculations/core/holding-duration-per-asset.js +24 -23
  8. package/calculations/core/instrument-price-change-1d.js +72 -82
  9. package/calculations/core/instrument-price-momentum-20d.js +66 -100
  10. package/calculations/core/long-position-per-stock.js +21 -13
  11. package/calculations/core/overall-holding-duration.js +8 -3
  12. package/calculations/core/overall-profitability-ratio.js +2 -2
  13. package/calculations/core/platform-buy-sell-sentiment.js +75 -22
  14. package/calculations/core/platform-daily-bought-vs-sold-count.js +19 -10
  15. package/calculations/core/platform-daily-ownership-delta.js +39 -15
  16. package/calculations/core/platform-ownership-per-sector.js +38 -18
  17. package/calculations/core/platform-total-positions-held.js +36 -14
  18. package/calculations/core/pnl-distribution-per-stock.js +39 -36
  19. package/calculations/core/price-metrics.js +70 -172
  20. package/calculations/core/profitability-ratio-per-sector.js +23 -29
  21. package/calculations/core/profitability-ratio-per-stock.js +20 -13
  22. package/calculations/core/profitability-skew-per-stock.js +20 -13
  23. package/calculations/core/profitable-and-unprofitable-status.js +34 -10
  24. package/calculations/core/sentiment-per-stock.js +20 -9
  25. package/calculations/core/short-position-per-stock.js +23 -37
  26. package/calculations/core/social-activity-aggregation.js +41 -115
  27. package/calculations/core/social-asset-posts-trend.js +77 -94
  28. package/calculations/core/social-event-correlation.js +87 -106
  29. package/calculations/core/social-sentiment-aggregation.js +56 -138
  30. package/calculations/core/social-top-mentioned-words.js +74 -106
  31. package/calculations/core/social-topic-interest-evolution.js +94 -94
  32. package/calculations/core/social-topic-sentiment-matrix.js +90 -74
  33. package/calculations/core/social-word-mentions-trend.js +92 -106
  34. package/calculations/core/speculator-asset-sentiment.js +63 -92
  35. package/calculations/core/speculator-danger-zone.js +77 -90
  36. package/calculations/core/speculator-distance-to-stop-loss-per-leverage.js +75 -90
  37. package/calculations/core/speculator-distance-to-tp-per-leverage.js +75 -88
  38. package/calculations/core/speculator-entry-distance-to-sl-per-leverage.js +75 -90
  39. package/calculations/core/speculator-entry-distance-to-tp-per-leverage.js +74 -89
  40. package/calculations/core/speculator-leverage-per-asset.js +62 -57
  41. package/calculations/core/speculator-leverage-per-sector.js +53 -65
  42. package/calculations/core/speculator-risk-reward-ratio-per-asset.js +71 -76
  43. package/calculations/core/speculator-stop-loss-distance-by-sector-short-long-breakdown.js +60 -81
  44. package/calculations/core/speculator-stop-loss-distance-by-ticker-short-long-breakdown.js +57 -77
  45. package/calculations/core/speculator-stop-loss-per-asset.js +43 -80
  46. package/calculations/core/speculator-take-profit-per-asset.js +45 -69
  47. package/calculations/core/speculator-tsl-per-asset.js +42 -49
  48. package/calculations/core/total-long-figures.js +19 -19
  49. package/calculations/core/total-long-per-sector.js +39 -36
  50. package/calculations/core/total-short-figures.js +19 -19
  51. package/calculations/core/total-short-per-sector.js +39 -36
  52. package/calculations/core/users-processed.js +52 -25
  53. package/calculations/gauss/cohort-capital-flow.js +38 -29
  54. package/calculations/gauss/cohort-definer.js +17 -25
  55. package/calculations/gauss/daily-dna-filter.js +10 -4
  56. package/calculations/gauss/gauss-divergence-signal.js +28 -6
  57. package/calculations/gem/cohort-momentum-state.js +113 -92
  58. package/calculations/gem/cohort-skill-definition.js +23 -53
  59. package/calculations/gem/platform-conviction-divergence.js +62 -116
  60. package/calculations/gem/quant-skill-alpha-signal.js +107 -123
  61. package/calculations/gem/skilled-cohort-flow.js +178 -167
  62. package/calculations/gem/skilled-unskilled-divergence.js +73 -113
  63. package/calculations/gem/unskilled-cohort-flow.js +176 -166
  64. package/calculations/helix/helix-contrarian-signal.js +91 -83
  65. package/calculations/helix/herd-consensus-score.js +135 -97
  66. package/calculations/helix/winner-loser-flow.js +14 -16
  67. package/calculations/pyro/risk-appetite-index.js +121 -123
  68. package/calculations/pyro/squeeze-potential.js +93 -125
  69. package/calculations/pyro/volatility-signal.js +109 -97
  70. package/package.json +5 -5
  71. package/README.MD +0 -155
@@ -1,19 +1,19 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for speculator metric.
2
+ * @fileoverview Calculation (Pass 1) for speculator leverage.
3
3
  *
4
- * This metric answers: "For each sector, what is the
5
- * distribution of leverage levels used by speculators?"
4
+ * This metric answers: "For each sector, what is the average
5
+ * leverage used by speculators?"
6
6
  */
7
- const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
7
+ // --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
8
8
 
9
- class LeveragePerSector {
9
+ class SpeculatorLeveragePerSector {
10
10
  constructor() {
11
- // { [sector]: { [leverage]: count } }
11
+ // { [sectorName]: { sum: 0, count: 0 } }
12
12
  this.sectors = new Map();
13
- this.mappings = null;
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
  */
@@ -22,12 +22,11 @@ class LeveragePerSector {
22
22
  type: 'standard',
23
23
  rootDataDependencies: ['portfolio'],
24
24
  isHistorical: false,
25
- userType: 'speculator',
25
+ userType: 'speculator', // <-- KEY: Only runs for speculators
26
26
  category: 'core_speculator'
27
27
  };
28
28
  }
29
29
 
30
- // --- NEW ---
31
30
  /**
32
31
  * Statically declare dependencies.
33
32
  */
@@ -37,92 +36,81 @@ class LeveragePerSector {
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
- const leverageSchema = {
41
+ const sectorSchema = {
44
42
  "type": "object",
45
- "description": "Distribution of leverage levels for this sector.",
46
- "patternProperties": {
47
- // Leverage level, e.g., "1x", "5x", "inf"
48
- "^[0-9inf]+x$": {
49
- "type": "number",
50
- "description": "Count of positions at this leverage."
51
- }
43
+ "properties": {
44
+ "avg_leverage": { "type": "number" },
45
+ "position_count": { "type": "number" }
52
46
  },
53
- "additionalProperties": { "type": "number" }
47
+ "required": ["avg_leverage", "position_count"]
54
48
  };
55
49
 
56
50
  return {
57
51
  "type": "object",
58
- "description": "Calculates the distribution of leverage levels used by speculators for each sector.",
59
- "patternProperties": {
60
- "^.*$": leverageSchema // Sector
61
- },
62
- "additionalProperties": leverageSchema
52
+ "description": "Calculates the average leverage used by speculators for each sector.",
53
+ "patternProperties": { "^.*$": sectorSchema },
54
+ "additionalProperties": sectorSchema
63
55
  };
64
56
  }
65
57
 
66
- _initSector(sector) {
67
- if (!this.sectors.has(sector)) {
68
- this.sectors.set(sector, {
69
- '1x': 0,
70
- '2x': 0,
71
- '5x': 0,
72
- '10x': 0,
73
- 'inf': 0 // For other leverages
74
- });
75
- }
76
- }
77
-
78
- _getLeverageBucket(leverage) {
79
- switch (leverage) {
80
- case 1: return '1x';
81
- case 2: return '2x';
82
- case 5: return '5x';
83
- case 10: return '10x';
84
- default: return 'inf';
58
+ _initSector(sectorName) {
59
+ if (!this.sectors.has(sectorName)) {
60
+ this.sectors.set(sectorName, { sum: 0, count: 0 });
85
61
  }
86
62
  }
87
63
 
88
- process(portfolioData, yesterdayPortfolio, userId, context) {
89
- if (portfolioData?.context?.userType !== 'speculator') {
90
- return;
64
+ // --- STANDARD 0: UPDATED SIGNATURE ---
65
+ async process(todayPortfolio, yesterdayPortfolio, userId, context) {
66
+ // --- STANDARD 0: FIXED ---
67
+ if (!this.sectorMap) {
68
+ this.sectorMap = context.sectorMapping;
91
69
  }
92
-
93
- if (!this.mappings) {
94
- this.mappings = context.mappings;
95
- }
96
-
97
- const positions = portfolioData.PublicPositions;
98
- if (!positions || !Array.isArray(positions) || !this.mappings) {
70
+
71
+ const positions = todayPortfolio.PublicPositions;
72
+ if (!positions || !Array.isArray(positions) || !this.sectorMap) {
99
73
  return;
100
74
  }
101
75
 
102
76
  for (const pos of positions) {
103
77
  const instrumentId = pos.InstrumentID;
104
- if (!instrumentId) continue;
78
+ const leverage = pos.Leverage;
105
79
 
106
- const sector = this.mappings.instrumentToSector[instrumentId] || 'Other';
107
- this._initSector(sector);
108
- const sectorData = this.sectors.get(sector);
80
+ if (!instrumentId || !leverage || leverage <= 1) {
81
+ continue; // Only care about leveraged positions
82
+ }
109
83
 
110
- const leverage = pos.Leverage || 1;
111
- const key = this._getLeverageBucket(leverage);
84
+ // --- STANDARD 0: FIXED ---
85
+ const sectorName = this.sectorMap[instrumentId] || 'N/A';
86
+ this._initSector(sectorName);
87
+ const sectorData = this.sectors.get(sectorName);
112
88
 
113
- sectorData[key]++;
89
+ sectorData.sum += leverage;
90
+ sectorData.count++;
114
91
  }
115
92
  }
116
93
 
117
94
  async getResult() {
118
- // Convert Map to plain object
119
- return Object.fromEntries(this.sectors);
95
+ // --- STANDARD 0: REMOVED forbidden data load ---
96
+
97
+ const result = {};
98
+ for (const [sectorName, data] of this.sectors.entries()) {
99
+ if (data.count > 0) {
100
+ result[sectorName] = {
101
+ avg_leverage: data.sum / data.count,
102
+ position_count: data.count
103
+ };
104
+ }
105
+ }
106
+ return result;
120
107
  }
121
108
 
122
109
  reset() {
123
110
  this.sectors.clear();
124
- this.mappings = null;
111
+ // --- STANDARD 0: RENAMED ---
112
+ this.sectorMap = null;
125
113
  }
126
114
  }
127
115
 
128
- module.exports = LeveragePerSector;
116
+ module.exports = SpeculatorLeveragePerSector;
@@ -1,124 +1,119 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for speculator metric.
3
- *
4
- * This metric answers: "What is the average Risk/Reward
5
- * ratio (based on SL/TP) for speculator positions on each asset?"
2
+ * @fileoverview Calculation (Pass 1) for speculator R/R.
3
+ * --- FIX ---
4
+ * - Rewritten logic to calculate R/R from raw schema fields
5
+ * (OpenRate, StopLossRate, TakeProfitRate) instead of non-existent
6
+ * 'PctTo...' fields.
7
+ * - Updated process signature to match worker.
6
8
  */
7
- const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
8
9
 
9
- class RiskRewardRatioPerAsset {
10
+ class SpeculatorRiskRewardRatioPerAsset {
10
11
  constructor() {
11
- // { [instrumentId]: { sum_rr: 0, count: 0 } }
12
12
  this.assets = new Map();
13
- this.mappings = null;
13
+ this.tickerMap = null;
14
14
  }
15
15
 
16
- /**
17
- * Defines the output schema for this calculation.
18
- * @returns {object} JSON Schema object
19
- */
20
- static getSchema() {
21
- const tickerSchema = {
22
- "type": "object",
23
- "properties": {
24
- "avg_rr_ratio": {
25
- "type": "number",
26
- "description": "Average Risk/Reward ratio (Reward / Risk)."
27
- },
28
- "count": {
29
- "type": "number",
30
- "description": "Count of positions with both SL and TP set."
31
- }
32
- },
33
- "required": ["avg_rr_ratio", "count"]
34
- };
35
-
36
- return {
37
- "type": "object",
38
- "description": "Calculates the average Risk/Reward ratio from SL/TP settings for each asset.",
39
- "patternProperties": {
40
- "^.*$": tickerSchema // Ticker
41
- },
42
- "additionalProperties": tickerSchema
43
- };
44
- }
45
-
46
- /**
47
- * Statically defines all metadata for the manifest builder.
48
- */
49
16
  static getMetadata() {
50
17
  return {
51
18
  type: 'standard',
52
19
  rootDataDependencies: ['portfolio'],
53
20
  isHistorical: false,
54
- userType: 'speculator',
21
+ userType: 'speculator', // <-- KEY: Only runs for speculators
55
22
  category: 'core_speculator'
56
23
  };
57
24
  }
58
25
 
59
- /**
60
- * Statically declare dependencies.
61
- */
62
26
  static getDependencies() {
63
27
  return [];
64
28
  }
65
29
 
30
+ static getSchema() {
31
+ const tickerSchema = {
32
+ "type": "object",
33
+ "properties": {
34
+ "avg_rr_ratio": { "type": ["number", "null"] },
35
+ "position_count": { "type": "number" }
36
+ },
37
+ "required": ["avg_rr_ratio", "position_count"]
38
+ };
39
+
40
+ return {
41
+ "type": "object",
42
+ "description": "Calculates the average Risk/Reward ratio at entry for speculators per asset.",
43
+ "patternProperties": { "^.*$": tickerSchema },
44
+ "additionalProperties": tickerSchema
45
+ };
46
+ }
47
+
66
48
  _initAsset(instrumentId) {
67
49
  if (!this.assets.has(instrumentId)) {
68
- this.assets.set(instrumentId, { sum_rr: 0, count: 0 });
50
+ this.assets.set(instrumentId, { sum: 0, count: 0 });
69
51
  }
70
52
  }
71
53
 
72
- process(portfolioData) {
73
- if (portfolioData?.context?.userType !== 'speculator') {
74
- return;
54
+ // --- THIS IS THE FIX ---
55
+ process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, fetchedDependencies) {
56
+ if (!this.tickerMap) {
57
+ this.tickerMap = context.instrumentToTicker;
75
58
  }
76
-
77
- const positions = portfolioData.PublicPositions;
59
+
60
+ const positions = todayPortfolio.PublicPositions;
78
61
  if (!positions || !Array.isArray(positions)) {
79
62
  return;
80
63
  }
81
64
 
82
65
  for (const pos of positions) {
83
66
  const instrumentId = pos.InstrumentID;
84
- const sl_rate = pos.StopLossRate || 0;
85
- const tp_rate = pos.TakeProfitRate || 0;
86
- const open_rate = pos.OpenRate || 0;
87
-
88
- // Need all three to calculate R/R
89
- if (!instrumentId || sl_rate === 0 || tp_rate === 0 || open_rate === 0) {
90
- continue;
67
+ const slRate = pos.StopLossRate;
68
+ const tpRate = pos.TakeProfitRate;
69
+ const openRate = pos.OpenRate;
70
+
71
+ if (!instrumentId || !slRate || slRate <= 0 || !tpRate || tpRate <= 0 || !openRate || openRate <= 0) {
72
+ continue; // Must have SL, TP, and OpenRate
91
73
  }
92
-
93
- const risk = Math.abs(open_rate - sl_rate);
94
- const reward = Math.abs(tp_rate - open_rate);
95
-
96
- if (risk === 0) {
97
- continue; // Cannot divide by zero
74
+
75
+ let risk = 0;
76
+ let reward = 0;
77
+
78
+ if (pos.IsBuy) {
79
+ // Long
80
+ risk = openRate - slRate;
81
+ reward = tpRate - openRate;
82
+ } else {
83
+ // Short
84
+ risk = slRate - openRate;
85
+ reward = openRate - tpRate;
86
+ }
87
+
88
+ // If risk or reward is negative/zero, it's an invalid R/R setup
89
+ if (risk <= 0 || reward <= 0) {
90
+ continue;
98
91
  }
99
-
100
- const rr_ratio = reward / risk;
101
-
92
+
102
93
  this._initAsset(instrumentId);
103
94
  const assetData = this.assets.get(instrumentId);
104
- assetData.sum_rr += rr_ratio;
95
+
96
+ const rrRatio = reward / risk;
97
+
98
+ assetData.sum += rrRatio;
105
99
  assetData.count++;
106
100
  }
107
101
  }
102
+ // --- END FIX ---
108
103
 
109
104
  async getResult() {
110
- if (!this.mappings) {
111
- this.mappings = await loadInstrumentMappings();
105
+ if (!this.tickerMap) {
106
+ return {};
112
107
  }
113
108
 
114
109
  const result = {};
115
110
  for (const [instrumentId, data] of this.assets.entries()) {
116
- const ticker = this.mappings.instrumentToTicker[instrumentId] || `id_${instrumentId}`;
117
-
111
+ const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
112
+
118
113
  if (data.count > 0) {
119
114
  result[ticker] = {
120
- avg_rr_ratio: data.sum_rr / data.count,
121
- count: data.count
115
+ avg_rr_ratio: data.sum / data.count,
116
+ position_count: data.count
122
117
  };
123
118
  }
124
119
  }
@@ -127,8 +122,8 @@ class RiskRewardRatioPerAsset {
127
122
 
128
123
  reset() {
129
124
  this.assets.clear();
130
- this.mappings = null;
125
+ this.tickerMap = null;
131
126
  }
132
127
  }
133
128
 
134
- module.exports = RiskRewardRatioPerAsset;
129
+ module.exports = SpeculatorRiskRewardRatioPerAsset;
@@ -1,140 +1,119 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for speculator metric.
3
- *
4
- * This metric answers: "For each sector, what is the
5
- * average stop loss distance (in % and value) for
6
- * long and short positions?"
2
+ * @fileoverview Calculation (Pass 1) for speculator SL distance.
3
+ * --- FIX ---
4
+ * - Rewritten logic to calculate SL distance from raw schema fields
5
+ * (StopLossRate, CurrentRate) instead of 'PctToStopLoss'.
6
+ * - Updated process signature to match worker.
7
7
  */
8
- const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
9
8
 
10
- class StopLossDistanceBySectorShortLongBreakdown {
9
+ class SpeculatorSLDistanceBySectorShortLong {
11
10
  constructor() {
12
- // { [sector]: { long_pct: [], long_val: [], short_pct: [], short_val: [] } }
13
11
  this.sectors = new Map();
14
- this.mappings = null;
12
+ this.sectorMap = null;
15
13
  }
16
14
 
17
- // --- NEW ---
18
- /**
19
- * Statically defines all metadata for the manifest builder.
20
- */
21
15
  static getMetadata() {
22
16
  return {
23
17
  type: 'standard',
24
18
  rootDataDependencies: ['portfolio'],
25
19
  isHistorical: false,
26
- userType: 'speculator',
20
+ userType: 'speculator', // <-- KEY: Only runs for speculators
27
21
  category: 'core_speculator'
28
22
  };
29
23
  }
30
24
 
31
- // --- NEW ---
32
- /**
33
- * Statically declare dependencies.
34
- */
35
25
  static getDependencies() {
36
26
  return [];
37
27
  }
38
28
 
39
- /**
40
- * Defines the output schema for this calculation.
41
- * @returns {object} JSON Schema object
42
- */
43
29
  static getSchema() {
44
30
  const sectorSchema = {
45
31
  "type": "object",
46
32
  "properties": {
47
- "long_avg_dist_pct": { "type": "number" },
48
- "long_avg_dist_val": { "type": "number" },
49
- "long_count": { "type": "number" },
50
- "short_avg_dist_pct": { "type": "number" },
51
- "short_avg_dist_val": { "type": "number" },
52
- "short_count": { "type": "number" }
53
- },
54
- "required": ["long_avg_dist_pct", "long_avg_dist_val", "long_count", "short_avg_dist_pct", "short_avg_dist_val", "short_count"]
33
+ "long_avg_distance_pct": { "type": "number" },
34
+ "long_position_count": { "type": "number" },
35
+ "short_avg_distance_pct": { "type": "number" },
36
+ "short_position_count": { "type": "number" }
37
+ }
55
38
  };
56
39
 
57
40
  return {
58
41
  "type": "object",
59
- "description": "Calculates avg SL distance (% and value) for long/short positions, grouped by sector.",
60
- "patternProperties": {
61
- "^.*$": sectorSchema // Sector
62
- },
42
+ "description": "Calculates the average distance to SL, broken down by long/short, per sector.",
43
+ "patternProperties": { "^.*$": sectorSchema },
63
44
  "additionalProperties": sectorSchema
64
45
  };
65
46
  }
66
47
 
67
- _initSector(sector) {
68
- if (!this.sectors.has(sector)) {
69
- this.sectors.set(sector, {
70
- long_pct: [], long_val: [], short_pct: [], short_val: []
71
- });
48
+ _initSector(sectorName) {
49
+ if (!this.sectors.has(sectorName)) {
50
+ this.sectors.set(sectorName, { long_sum: 0, long_count: 0, short_sum: 0, short_count: 0 });
72
51
  }
73
52
  }
74
-
75
- _avg(arr) {
76
- if (arr.length === 0) return 0;
77
- return arr.reduce((a, b) => a + b, 0) / arr.length;
78
- }
79
53
 
80
- process(portfolioData, yesterdayPortfolio, userId, context) {
81
- if (portfolioData?.context?.userType !== 'speculator') {
82
- return;
54
+ // --- THIS IS THE FIX ---
55
+ process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, fetchedDependencies) {
56
+ if (!this.sectorMap) {
57
+ this.sectorMap = context.sectorMapping;
83
58
  }
84
- if (!this.mappings) {
85
- this.mappings = context.mappings;
86
- }
87
-
88
- const positions = portfolioData.PublicPositions;
89
- if (!positions || !Array.isArray(positions) || !this.mappings) {
59
+
60
+ const positions = todayPortfolio.PublicPositions;
61
+ if (!positions || !Array.isArray(positions) || !this.sectorMap) {
90
62
  return;
91
63
  }
92
64
 
93
65
  for (const pos of positions) {
94
66
  const instrumentId = pos.InstrumentID;
95
- const sl_rate = pos.StopLossRate || 0;
96
- const open_rate = pos.OpenRate || 0;
97
-
98
- if (!instrumentId || sl_rate === 0 || open_rate === 0) {
99
- continue;
67
+ const slRate = pos.StopLossRate;
68
+ const currentRate = pos.CurrentRate;
69
+
70
+ if (!instrumentId || !slRate || slRate <= 0 || !currentRate || currentRate <= 0) {
71
+ continue; // No SL or invalid data
100
72
  }
101
-
102
- const sector = this.mappings.instrumentToSector[instrumentId] || 'Other';
103
- this._initSector(sector);
104
- const sectorData = this.sectors.get(sector);
105
-
106
- const distance_val = Math.abs(open_rate - sl_rate);
107
- const distance_pct = (distance_val / open_rate) * 100;
108
-
73
+
74
+ const sectorName = this.sectorMap[instrumentId] || 'N/A';
75
+ this._initSector(sectorName);
76
+ const sectorData = this.sectors.get(sectorName);
77
+
78
+ let pctToSL = 0;
109
79
  if (pos.IsBuy) {
110
- sectorData.long_pct.push(distance_pct);
111
- sectorData.long_val.push(distance_val);
80
+ // Long: (Current - SL) / Current
81
+ pctToSL = (currentRate - slRate) / currentRate;
82
+ if (pctToSL > 0) {
83
+ sectorData.long_sum += (pctToSL * 100);
84
+ sectorData.long_count++;
85
+ }
112
86
  } else {
113
- sectorData.short_pct.push(distance_pct);
114
- sectorData.short_val.push(distance_val);
87
+ // Short: (SL - Current) / Current
88
+ pctToSL = (slRate - currentRate) / currentRate;
89
+ if (pctToSL > 0) {
90
+ sectorData.short_sum += (pctToSL * 100);
91
+ sectorData.short_count++;
92
+ }
115
93
  }
116
94
  }
117
95
  }
96
+ // --- END FIX ---
118
97
 
119
98
  async getResult() {
120
99
  const result = {};
121
- for (const [sector, data] of this.sectors.entries()) {
122
- result[sector] = {
123
- long_avg_dist_pct: this._avg(data.long_pct),
124
- long_avg_dist_val: this._avg(data.long_val),
125
- long_count: data.long_pct.length,
126
- short_avg_dist_pct: this._avg(data.short_pct),
127
- short_avg_dist_val: this._avg(data.short_val),
128
- short_count: data.short_pct.length
129
- };
100
+ for (const [sectorName, data] of this.sectors.entries()) {
101
+ if (data.long_count > 0 || data.short_count > 0) {
102
+ result[sectorName] = {
103
+ long_avg_distance_pct: (data.long_count > 0) ? (data.long_sum / data.long_count) : 0,
104
+ long_position_count: data.long_count,
105
+ short_avg_distance_pct: (data.short_count > 0) ? (data.short_sum / data.short_count) : 0,
106
+ short_position_count: data.short_count
107
+ };
108
+ }
130
109
  }
131
110
  return result;
132
111
  }
133
112
 
134
113
  reset() {
135
114
  this.sectors.clear();
136
- this.mappings = null;
115
+ this.sectorMap = null;
137
116
  }
138
117
  }
139
118
 
140
- module.exports = StopLossDistanceBySectorShortLongBreakdown;
119
+ module.exports = SpeculatorSLDistanceBySectorShortLong;