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,12 +1,8 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for speculator SL entry distance.
3
- * --- FIX ---
4
- * - Rewritten logic to calculate *entry* SL distance from raw schema fields
5
- * (StopLossRate, OpenRate) instead of the non-existent
6
- * 'PctToStopLossAtEntry' field.
7
- * - Updated process signature to match worker.
2
+ * @fileoverview Calculation (Pass 1) for speculator Entry distance to SL.
3
+ * REFACTORED: Uses extract.getOpenRate vs extract.getStopLossRate.
8
4
  */
9
- const BUCKETS = [1, 2, 5, 10, 20, 30]; // Leverage buckets
5
+ const BUCKETS = [1, 2, 5, 10, 20, 30];
10
6
 
11
7
  class SpeculatorEntryDistanceToSLPerLeverage {
12
8
  constructor() {
@@ -16,9 +12,7 @@ class SpeculatorEntryDistanceToSLPerLeverage {
16
12
 
17
13
  _initBuckets() {
18
14
  this.buckets.clear();
19
- for (const b of BUCKETS) {
20
- this.buckets.set(b, { sum: 0, count: 0 });
21
- }
15
+ for (const b of BUCKETS) this.buckets.set(b, { sum: 0, count: 0 });
22
16
  this.buckets.set('other', { sum: 0, count: 0 });
23
17
  }
24
18
 
@@ -32,9 +26,7 @@ class SpeculatorEntryDistanceToSLPerLeverage {
32
26
  };
33
27
  }
34
28
 
35
- static getDependencies() {
36
- return [];
37
- }
29
+ static getDependencies() { return []; }
38
30
 
39
31
  static getSchema() {
40
32
  const bucketSchema = {
@@ -44,47 +36,29 @@ class SpeculatorEntryDistanceToSLPerLeverage {
44
36
  "position_count": { "type": "number" }
45
37
  }
46
38
  };
47
-
48
- return {
49
- "type": "object",
50
- "description": "Calculates the average *entry* distance to stop-loss, bucketed by leverage.",
51
- "properties": {
52
- "x1": bucketSchema,
53
- "x2": bucketSchema,
54
- "x5": bucketSchema,
55
- "x10": bucketSchema,
56
- "x20": bucketSchema,
57
- "x30": bucketSchema,
58
- "other": bucketSchema
59
- }
60
- };
39
+ return { "type": "object", "patternProperties": { "^.*$": bucketSchema } };
61
40
  }
62
41
 
63
42
  _getBucket(leverage) {
64
- if (this.buckets.has(leverage)) {
65
- return this.buckets.get(leverage);
66
- }
67
- return this.buckets.get('other');
43
+ return this.buckets.has(leverage) ? this.buckets.get(leverage) : this.buckets.get('other');
68
44
  }
69
45
 
70
- // --- THIS IS THE FIX ---
71
- process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, fetchedDependencies) {
72
- const positions = todayPortfolio.PublicPositions;
73
- if (!positions || !Array.isArray(positions)) {
74
- return;
75
- }
46
+ process(context) {
47
+ const { extract } = context.math;
48
+ const { user } = context;
49
+ const positions = extract.getPositions(user.portfolio.today, user.type);
76
50
 
77
51
  for (const pos of positions) {
78
- const leverage = pos.Leverage;
79
- const slRate = pos.StopLossRate;
80
- const openRate = pos.OpenRate;
52
+ const leverage = extract.getLeverage(pos);
53
+ const slRate = extract.getStopLossRate(pos);
54
+ const openRate = extract.getOpenRate(pos);
81
55
 
82
- if (!leverage || !slRate || slRate <= 0 || !openRate || openRate <= 0) {
83
- continue;
84
- }
56
+ if (!leverage || !slRate || slRate <= 0 || !openRate || openRate <= 0) continue;
85
57
 
58
+ const direction = extract.getDirection(pos);
86
59
  let pctToSL = 0;
87
- if (pos.IsBuy) {
60
+
61
+ if (direction === 'Buy') {
88
62
  // Long: (Open - SL) / Open
89
63
  pctToSL = (openRate - slRate) / openRate;
90
64
  } else {
@@ -92,16 +66,13 @@ class SpeculatorEntryDistanceToSLPerLeverage {
92
66
  pctToSL = (slRate - openRate) / openRate;
93
67
  }
94
68
 
95
- if (pctToSL <= 0) {
96
- continue; // SL is at or beyond open price, invalid
97
- }
69
+ if (pctToSL <= 0) continue; // Invalid distance
98
70
 
99
71
  const bucket = this._getBucket(leverage);
100
- bucket.sum += (pctToSL * 100); // Convert to percentage
72
+ bucket.sum += (pctToSL * 100);
101
73
  bucket.count++;
102
74
  }
103
75
  }
104
- // --- END FIX ---
105
76
 
106
77
  getResult() {
107
78
  const result = {};
@@ -119,5 +90,4 @@ class SpeculatorEntryDistanceToSLPerLeverage {
119
90
  this._initBuckets();
120
91
  }
121
92
  }
122
-
123
93
  module.exports = SpeculatorEntryDistanceToSLPerLeverage;
@@ -1,14 +1,10 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for speculator TP entry distance.
3
- * --- FIX ---
4
- * - Rewritten logic to calculate *entry* TP distance from raw schema fields
5
- * (TakeProfitRate, OpenRate) instead of the non-existent
6
- * 'PctToTakeProfitAtEntry' field.
7
- * - Updated process signature to match worker.
2
+ * @fileoverview Calculation (Pass 1) for speculator TP Entry distance (Open Price vs TP).
3
+ * REFACTORED: Uses context.math.extract.
8
4
  */
9
- const BUCKETS = [1, 2, 5, 10, 20, 30]; // Leverage buckets
5
+ const BUCKETS = [1, 2, 5, 10, 20, 30];
10
6
 
11
- class SpeculatorEntryDistanceToTPPerLeverage {
7
+ class SpeculatorEntryDistanceToTpPerLeverage {
12
8
  constructor() {
13
9
  this.buckets = new Map();
14
10
  this._initBuckets();
@@ -16,9 +12,7 @@ class SpeculatorEntryDistanceToTPPerLeverage {
16
12
 
17
13
  _initBuckets() {
18
14
  this.buckets.clear();
19
- for (const b of BUCKETS) {
20
- this.buckets.set(b, { sum: 0, count: 0 });
21
- }
15
+ for (const b of BUCKETS) this.buckets.set(b, { sum: 0, count: 0 });
22
16
  this.buckets.set('other', { sum: 0, count: 0 });
23
17
  }
24
18
 
@@ -27,14 +21,12 @@ class SpeculatorEntryDistanceToTPPerLeverage {
27
21
  type: 'standard',
28
22
  rootDataDependencies: ['portfolio'],
29
23
  isHistorical: false,
30
- userType: 'speculator',
24
+ userType: 'speculator',
31
25
  category: 'core_speculator'
32
26
  };
33
27
  }
34
28
 
35
- static getDependencies() {
36
- return [];
37
- }
29
+ static getDependencies() { return []; }
38
30
 
39
31
  static getSchema() {
40
32
  const bucketSchema = {
@@ -44,47 +36,32 @@ class SpeculatorEntryDistanceToTPPerLeverage {
44
36
  "position_count": { "type": "number" }
45
37
  }
46
38
  };
47
-
48
- return {
49
- "type": "object",
50
- "description": "Calculates the average *entry* distance to take-profit, bucketed by leverage.",
51
- "properties": {
52
- "x1": bucketSchema,
53
- "x2": bucketSchema,
54
- "x5": bucketSchema,
55
- "x10": bucketSchema,
56
- "x20": bucketSchema,
57
- "x30": bucketSchema,
58
- "other": bucketSchema
59
- }
60
- };
39
+ return { "type": "object", "patternProperties": { "^.*$": bucketSchema } };
61
40
  }
62
41
 
63
42
  _getBucket(leverage) {
64
- if (this.buckets.has(leverage)) {
65
- return this.buckets.get(leverage);
66
- }
67
- return this.buckets.get('other');
43
+ return this.buckets.has(leverage) ? this.buckets.get(leverage) : this.buckets.get('other');
68
44
  }
69
45
 
70
- // --- THIS IS THE FIX ---
71
- process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, fetchedDependencies) {
72
- const positions = todayPortfolio.PublicPositions;
73
- if (!positions || !Array.isArray(positions)) {
74
- return;
75
- }
46
+ process(context) {
47
+ const { extract } = context.math;
48
+ const { user } = context;
49
+
50
+ const positions = extract.getPositions(user.portfolio.today, user.type);
76
51
 
77
52
  for (const pos of positions) {
78
- const leverage = pos.Leverage;
79
- const tpRate = pos.TakeProfitRate;
80
- const openRate = pos.OpenRate;
53
+ const leverage = extract.getLeverage(pos);
54
+ const tpRate = extract.getTakeProfitRate(pos);
55
+ const openRate = extract.getOpenRate(pos);
81
56
 
82
57
  if (!leverage || !tpRate || tpRate <= 0 || !openRate || openRate <= 0) {
83
58
  continue;
84
59
  }
85
60
 
61
+ const direction = extract.getDirection(pos);
86
62
  let pctToTP = 0;
87
- if (pos.IsBuy) {
63
+
64
+ if (direction === 'Buy') {
88
65
  // Long: (TP - Open) / Open
89
66
  pctToTP = (tpRate - openRate) / openRate;
90
67
  } else {
@@ -92,16 +69,13 @@ class SpeculatorEntryDistanceToTPPerLeverage {
92
69
  pctToTP = (openRate - tpRate) / openRate;
93
70
  }
94
71
 
95
- if (pctToTP <= 0) {
96
- continue; // TP is at or below open price, invalid
97
- }
72
+ if (pctToTP <= 0) continue;
98
73
 
99
74
  const bucket = this._getBucket(leverage);
100
- bucket.sum += (pctToTP * 100); // Convert to percentage
75
+ bucket.sum += (pctToTP * 100);
101
76
  bucket.count++;
102
77
  }
103
78
  }
104
- // --- END FIX ---
105
79
 
106
80
  getResult() {
107
81
  const result = {};
@@ -119,5 +93,4 @@ class SpeculatorEntryDistanceToTPPerLeverage {
119
93
  this._initBuckets();
120
94
  }
121
95
  }
122
-
123
- module.exports = SpeculatorEntryDistanceToTPPerLeverage;
96
+ module.exports = SpeculatorEntryDistanceToTpPerLeverage;
@@ -1,42 +1,25 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for speculator leverage.
3
- *
4
- * This metric answers: "For each asset, what is the average
5
- * leverage used by speculators?"
2
+ * @fileoverview Calculation (Pass 1) for speculator leverage per asset.
3
+ * REFACTORED: Uses context.math.extract.getLeverage.
6
4
  */
7
- // --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
8
-
9
5
  class SpeculatorLeveragePerAsset {
10
6
  constructor() {
11
- // { [instrumentId]: { sum: 0, count: 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",
@@ -46,64 +29,44 @@ class SpeculatorLeveragePerAsset {
46
29
  },
47
30
  "required": ["avg_leverage", "position_count"]
48
31
  };
49
-
50
- return {
51
- "type": "object",
52
- "description": "Calculates the average leverage used by speculators for each asset.",
53
- "patternProperties": { "^.*$": tickerSchema },
54
- "additionalProperties": tickerSchema
55
- };
32
+ return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
56
33
  }
57
34
 
58
35
  _initAsset(instrumentId) {
59
36
  if (!this.assets.has(instrumentId)) {
60
- this.assets.set(instrumentId, { sum: 0, count: 0 });
37
+ this.assets.set(instrumentId, { leverageSum: 0, count: 0 });
61
38
  }
62
39
  }
63
40
 
64
- // --- STANDARD 0: UPDATED SIGNATURE ---
65
- process(todayPortfolio, yesterdayPortfolio, userId, context) {
66
- // --- STANDARD 0: ADDED ---
67
- if (!this.tickerMap) {
68
- this.tickerMap = context.instrumentToTicker;
69
- }
41
+ process(context) {
42
+ const { extract } = context.math;
43
+ const { mappings, user } = context;
44
+ if (!this.tickerMap) this.tickerMap = mappings.instrumentToTicker;
70
45
 
71
- const positions = todayPortfolio.PublicPositions;
72
- if (!positions || !Array.isArray(positions)) {
73
- return;
74
- }
46
+ const positions = extract.getPositions(user.portfolio.today, user.type);
75
47
 
76
48
  for (const pos of positions) {
77
- const instrumentId = pos.InstrumentID;
78
- const leverage = pos.Leverage;
79
-
80
- if (!instrumentId || !leverage || leverage <= 1) {
81
- continue; // Only care about leveraged positions
82
- }
83
-
84
- this._initAsset(instrumentId);
85
- const assetData = this.assets.get(instrumentId);
86
- assetData.sum += leverage;
87
- assetData.count++;
88
- }
89
- }
49
+ const instId = extract.getInstrumentId(pos);
50
+ if (!instId) continue;
90
51
 
91
- async getResult() {
92
- // --- STANDARD 0: REMOVED forbidden data load ---
52
+ const leverage = extract.getLeverage(pos);
53
+ if (leverage <= 0) continue;
93
54
 
94
- // Failsafe check
95
- if (!this.tickerMap) {
96
- return {}; // process() must run first
55
+ this._initAsset(instId);
56
+ const data = this.assets.get(instId);
57
+ data.leverageSum += leverage;
58
+ data.count++;
97
59
  }
60
+ }
98
61
 
62
+ async getResult() {
63
+ if (!this.tickerMap) return {};
99
64
  const result = {};
100
- for (const [instrumentId, data] of this.assets.entries()) {
101
- // --- STANDARD 0: SIMPLIFIED ---
102
- const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
103
-
65
+ for (const [instId, data] of this.assets.entries()) {
66
+ const ticker = this.tickerMap[instId] || `id_${instId}`;
104
67
  if (data.count > 0) {
105
68
  result[ticker] = {
106
- avg_leverage: data.sum / data.count,
69
+ avg_leverage: data.leverageSum / data.count,
107
70
  position_count: data.count
108
71
  };
109
72
  }
@@ -113,9 +76,7 @@ class SpeculatorLeveragePerAsset {
113
76
 
114
77
  reset() {
115
78
  this.assets.clear();
116
- // --- STANDARD 0: RENAMED ---
117
79
  this.tickerMap = null;
118
80
  }
119
81
  }
120
-
121
82
  module.exports = SpeculatorLeveragePerAsset;
@@ -1,42 +1,25 @@
1
1
  /**
2
- * @fileoverview Calculation (Pass 1) for speculator leverage.
3
- *
4
- * This metric answers: "For each sector, what is the average
5
- * leverage used by speculators?"
2
+ * @fileoverview Calculation (Pass 1) for speculator leverage per sector.
3
+ * REFACTORED: Uses context.math.extract.
6
4
  */
7
- // --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
8
-
9
5
  class SpeculatorLeveragePerSector {
10
6
  constructor() {
11
- // { [sectorName]: { sum: 0, 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',
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 sectorSchema = {
42
25
  "type": "object",
@@ -46,59 +29,42 @@ class SpeculatorLeveragePerSector {
46
29
  },
47
30
  "required": ["avg_leverage", "position_count"]
48
31
  };
49
-
50
- return {
51
- "type": "object",
52
- "description": "Calculates the average leverage used by speculators for each sector.",
53
- "patternProperties": { "^.*$": sectorSchema },
54
- "additionalProperties": sectorSchema
55
- };
32
+ return { "type": "object", "patternProperties": { "^.*$": sectorSchema } };
56
33
  }
57
34
 
58
- _initSector(sectorName) {
59
- if (!this.sectors.has(sectorName)) {
60
- this.sectors.set(sectorName, { sum: 0, count: 0 });
35
+ _initSector(sector) {
36
+ if (!this.sectorData.has(sector)) {
37
+ this.sectorData.set(sector, { leverageSum: 0, count: 0 });
61
38
  }
62
39
  }
63
40
 
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;
69
- }
41
+ process(context) {
42
+ const { extract } = context.math;
43
+ const { mappings, user } = context;
44
+ if (!this.sectorMap) this.sectorMap = mappings.sectorMapping;
70
45
 
71
- const positions = todayPortfolio.PublicPositions;
72
- if (!positions || !Array.isArray(positions) || !this.sectorMap) {
73
- return;
74
- }
46
+ const positions = extract.getPositions(user.portfolio.today, user.type);
75
47
 
76
48
  for (const pos of positions) {
77
- const instrumentId = pos.InstrumentID;
78
- const leverage = pos.Leverage;
79
-
80
- if (!instrumentId || !leverage || leverage <= 1) {
81
- continue; // Only care about leveraged positions
82
- }
83
-
84
- // --- STANDARD 0: FIXED ---
85
- const sectorName = this.sectorMap[instrumentId] || 'N/A';
86
- this._initSector(sectorName);
87
- const sectorData = this.sectors.get(sectorName);
49
+ const instId = extract.getInstrumentId(pos);
50
+ if (!instId) continue;
51
+
52
+ const sector = this.sectorMap[instId] || 'Unknown';
53
+ const leverage = extract.getLeverage(pos);
88
54
 
89
- sectorData.sum += leverage;
90
- sectorData.count++;
55
+ this._initSector(sector);
56
+ const data = this.sectorData.get(sector);
57
+ data.leverageSum += leverage;
58
+ data.count++;
91
59
  }
92
60
  }
93
61
 
94
62
  async getResult() {
95
- // --- STANDARD 0: REMOVED forbidden data load ---
96
-
97
63
  const result = {};
98
- for (const [sectorName, data] of this.sectors.entries()) {
64
+ for (const [sector, data] of this.sectorData.entries()) {
99
65
  if (data.count > 0) {
100
- result[sectorName] = {
101
- avg_leverage: data.sum / data.count,
66
+ result[sector] = {
67
+ avg_leverage: data.leverageSum / data.count,
102
68
  position_count: data.count
103
69
  };
104
70
  }
@@ -107,10 +73,8 @@ class SpeculatorLeveragePerSector {
107
73
  }
108
74
 
109
75
  reset() {
110
- this.sectors.clear();
111
- // --- STANDARD 0: RENAMED ---
76
+ this.sectorData.clear();
112
77
  this.sectorMap = null;
113
78
  }
114
79
  }
115
-
116
80
  module.exports = SpeculatorLeveragePerSector;
@@ -1,12 +1,7 @@
1
1
  /**
2
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.
3
+ * REFACTORED: Uses rate extraction.
8
4
  */
9
-
10
5
  class SpeculatorRiskRewardRatioPerAsset {
11
6
  constructor() {
12
7
  this.assets = new Map();
@@ -18,14 +13,12 @@ class SpeculatorRiskRewardRatioPerAsset {
18
13
  type: 'standard',
19
14
  rootDataDependencies: ['portfolio'],
20
15
  isHistorical: false,
21
- userType: 'speculator', // <-- KEY: Only runs for speculators
16
+ userType: 'speculator',
22
17
  category: 'core_speculator'
23
18
  };
24
19
  }
25
20
 
26
- static getDependencies() {
27
- return [];
28
- }
21
+ static getDependencies() { return []; }
29
22
 
30
23
  static getSchema() {
31
24
  const tickerSchema = {
@@ -36,13 +29,7 @@ class SpeculatorRiskRewardRatioPerAsset {
36
29
  },
37
30
  "required": ["avg_rr_ratio", "position_count"]
38
31
  };
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
- };
32
+ return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
46
33
  }
47
34
 
48
35
  _initAsset(instrumentId) {
@@ -51,65 +38,50 @@ class SpeculatorRiskRewardRatioPerAsset {
51
38
  }
52
39
  }
53
40
 
54
- // --- THIS IS THE FIX ---
55
- process(todayPortfolio, yesterdayPortfolio, userId, context, todayInsights, yesterdayInsights, fetchedDependencies) {
56
- if (!this.tickerMap) {
57
- this.tickerMap = context.instrumentToTicker;
58
- }
41
+ process(context) {
42
+ const { extract } = context.math;
43
+ const { mappings, user } = context;
44
+ if (!this.tickerMap) this.tickerMap = mappings.instrumentToTicker;
59
45
 
60
- const positions = todayPortfolio.PublicPositions;
61
- if (!positions || !Array.isArray(positions)) {
62
- return;
63
- }
46
+ const positions = extract.getPositions(user.portfolio.today, user.type);
64
47
 
65
48
  for (const pos of positions) {
66
- const instrumentId = pos.InstrumentID;
67
- const slRate = pos.StopLossRate;
68
- const tpRate = pos.TakeProfitRate;
69
- const openRate = pos.OpenRate;
49
+ const instId = extract.getInstrumentId(pos);
50
+ const slRate = extract.getStopLossRate(pos);
51
+ const tpRate = extract.getTakeProfitRate(pos);
52
+ const openRate = extract.getOpenRate(pos);
70
53
 
71
- if (!instrumentId || !slRate || slRate <= 0 || !tpRate || tpRate <= 0 || !openRate || openRate <= 0) {
72
- continue; // Must have SL, TP, and OpenRate
54
+ if (!instId || !slRate || slRate <= 0 || !tpRate || tpRate <= 0 || !openRate || openRate <= 0) {
55
+ continue;
73
56
  }
74
57
 
58
+ const direction = extract.getDirection(pos);
75
59
  let risk = 0;
76
60
  let reward = 0;
77
61
 
78
- if (pos.IsBuy) {
79
- // Long
62
+ if (direction === 'Buy') {
80
63
  risk = openRate - slRate;
81
64
  reward = tpRate - openRate;
82
65
  } else {
83
- // Short
84
66
  risk = slRate - openRate;
85
67
  reward = openRate - tpRate;
86
68
  }
87
69
 
88
- // If risk or reward is negative/zero, it's an invalid R/R setup
89
- if (risk <= 0 || reward <= 0) {
90
- continue;
91
- }
92
-
93
- this._initAsset(instrumentId);
94
- const assetData = this.assets.get(instrumentId);
70
+ if (risk <= 0 || reward <= 0) continue;
95
71
 
96
- const rrRatio = reward / risk;
72
+ this._initAsset(instId);
73
+ const assetData = this.assets.get(instId);
97
74
 
98
- assetData.sum += rrRatio;
75
+ assetData.sum += (reward / risk);
99
76
  assetData.count++;
100
77
  }
101
78
  }
102
- // --- END FIX ---
103
79
 
104
80
  async getResult() {
105
- if (!this.tickerMap) {
106
- return {};
107
- }
108
-
81
+ if (!this.tickerMap) return {};
109
82
  const result = {};
110
- for (const [instrumentId, data] of this.assets.entries()) {
111
- const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
112
-
83
+ for (const [instId, data] of this.assets.entries()) {
84
+ const ticker = this.tickerMap[instId] || `id_${instId}`;
113
85
  if (data.count > 0) {
114
86
  result[ticker] = {
115
87
  avg_rr_ratio: data.sum / data.count,
@@ -125,5 +97,4 @@ class SpeculatorRiskRewardRatioPerAsset {
125
97
  this.tickerMap = null;
126
98
  }
127
99
  }
128
-
129
100
  module.exports = SpeculatorRiskRewardRatioPerAsset;