aiden-shared-calculations-unified 1.0.84 → 1.0.87
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 +36 -106
- package/calculations/core/asset-position-size.js +40 -91
- package/calculations/core/average-daily-pnl-all-users.js +18 -57
- package/calculations/core/average-daily-pnl-per-sector.js +41 -88
- package/calculations/core/average-daily-pnl-per-stock.js +38 -91
- package/calculations/core/average-daily-position-pnl.js +19 -49
- package/calculations/core/holding-duration-per-asset.js +25 -127
- package/calculations/core/instrument-price-change-1d.js +30 -49
- package/calculations/core/instrument-price-momentum-20d.js +50 -60
- package/calculations/core/long-position-per-stock.js +39 -68
- package/calculations/core/overall-holding-duration.js +16 -87
- package/calculations/core/overall-profitability-ratio.js +11 -40
- package/calculations/core/platform-buy-sell-sentiment.js +41 -124
- package/calculations/core/platform-daily-bought-vs-sold-count.js +41 -99
- package/calculations/core/platform-daily-ownership-delta.js +68 -126
- package/calculations/core/platform-ownership-per-sector.js +45 -96
- package/calculations/core/platform-total-positions-held.js +20 -80
- package/calculations/core/pnl-distribution-per-stock.js +29 -135
- package/calculations/core/price-metrics.js +95 -206
- package/calculations/core/profitability-ratio-per-sector.js +34 -79
- package/calculations/core/profitability-ratio-per-stock.js +32 -88
- package/calculations/core/profitability-skew-per-stock.js +41 -94
- package/calculations/core/profitable-and-unprofitable-status.js +44 -76
- package/calculations/core/sentiment-per-stock.js +24 -77
- package/calculations/core/short-position-per-stock.js +35 -43
- package/calculations/core/social-activity-aggregation.js +26 -49
- package/calculations/core/social-asset-posts-trend.js +38 -94
- package/calculations/core/social-event-correlation.js +26 -93
- package/calculations/core/social-sentiment-aggregation.js +20 -44
- package/calculations/core/social-top-mentioned-words.js +35 -87
- package/calculations/core/social-topic-interest-evolution.js +22 -111
- package/calculations/core/social-topic-sentiment-matrix.js +38 -104
- package/calculations/core/social-word-mentions-trend.js +27 -104
- package/calculations/core/speculator-asset-sentiment.js +31 -72
- package/calculations/core/speculator-danger-zone.js +48 -84
- package/calculations/core/speculator-distance-to-stop-loss-per-leverage.js +20 -52
- package/calculations/core/speculator-distance-to-tp-per-leverage.js +23 -53
- package/calculations/core/speculator-entry-distance-to-sl-per-leverage.js +20 -50
- package/calculations/core/speculator-entry-distance-to-tp-per-leverage.js +23 -50
- package/calculations/core/speculator-leverage-per-asset.js +25 -64
- package/calculations/core/speculator-leverage-per-sector.js +27 -63
- package/calculations/core/speculator-risk-reward-ratio-per-asset.js +24 -53
- package/calculations/core/speculator-stop-loss-distance-by-sector-short-long-breakdown.js +55 -68
- package/calculations/core/speculator-stop-loss-distance-by-ticker-short-long-breakdown.js +54 -71
- package/calculations/core/speculator-stop-loss-per-asset.js +19 -44
- package/calculations/core/speculator-take-profit-per-asset.js +20 -57
- package/calculations/core/speculator-tsl-per-asset.js +17 -56
- package/calculations/core/total-long-figures.js +16 -31
- package/calculations/core/total-long-per-sector.js +39 -61
- package/calculations/core/total-short-figures.js +13 -32
- package/calculations/core/total-short-per-sector.js +39 -61
- package/calculations/core/users-processed.js +11 -46
- package/calculations/gauss/cohort-capital-flow.js +54 -173
- package/calculations/gauss/cohort-definer.js +77 -163
- package/calculations/gauss/daily-dna-filter.js +29 -83
- package/calculations/gauss/gauss-divergence-signal.js +22 -109
- package/calculations/gem/cohort-momentum-state.js +27 -72
- package/calculations/gem/cohort-skill-definition.js +36 -52
- package/calculations/gem/platform-conviction-divergence.js +18 -60
- package/calculations/gem/quant-skill-alpha-signal.js +25 -98
- package/calculations/gem/skilled-cohort-flow.js +67 -175
- package/calculations/gem/skilled-unskilled-divergence.js +18 -73
- package/calculations/gem/unskilled-cohort-flow.js +64 -172
- package/calculations/helix/helix-contrarian-signal.js +20 -114
- package/calculations/helix/herd-consensus-score.js +42 -124
- package/calculations/helix/winner-loser-flow.js +36 -118
- package/calculations/pyro/risk-appetite-index.js +33 -74
- package/calculations/pyro/squeeze-potential.js +30 -87
- package/calculations/pyro/volatility-signal.js +33 -78
- package/package.json +1 -1
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for
|
|
3
|
-
*
|
|
4
|
-
* - Rewritten logic to calculate SL distance from raw schema fields
|
|
5
|
-
* (StopLossRate, CurrentRate) instead of 'PctToStopLoss'.
|
|
6
|
-
* - Updated process signature to match worker.
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for SL distance by sector.
|
|
3
|
+
* REFACTORED: Uses context.math.extract.
|
|
7
4
|
*/
|
|
8
|
-
|
|
9
|
-
class SpeculatorSLDistanceBySectorShortLong {
|
|
5
|
+
class SpeculatorSLDistanceSectorBreakdown {
|
|
10
6
|
constructor() {
|
|
11
|
-
this.
|
|
7
|
+
this.sectorData = new Map();
|
|
12
8
|
this.sectorMap = null;
|
|
13
9
|
}
|
|
14
10
|
|
|
@@ -17,93 +13,85 @@ class SpeculatorSLDistanceBySectorShortLong {
|
|
|
17
13
|
type: 'standard',
|
|
18
14
|
rootDataDependencies: ['portfolio'],
|
|
19
15
|
isHistorical: false,
|
|
20
|
-
userType: 'speculator',
|
|
16
|
+
userType: 'speculator',
|
|
21
17
|
category: 'core_speculator'
|
|
22
18
|
};
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
static getDependencies() {
|
|
26
|
-
return [];
|
|
27
|
-
}
|
|
21
|
+
static getDependencies() { return []; }
|
|
28
22
|
|
|
29
23
|
static getSchema() {
|
|
30
24
|
const sectorSchema = {
|
|
31
25
|
"type": "object",
|
|
32
26
|
"properties": {
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
"type": "object",
|
|
42
|
-
"description": "Calculates the average distance to SL, broken down by long/short, per sector.",
|
|
43
|
-
"patternProperties": { "^.*$": sectorSchema },
|
|
44
|
-
"additionalProperties": sectorSchema
|
|
27
|
+
"avg_long_sl_distance_pct": { "type": ["number", "null"] },
|
|
28
|
+
"avg_short_sl_distance_pct": { "type": ["number", "null"] },
|
|
29
|
+
"long_count": { "type": "number" },
|
|
30
|
+
"short_count": { "type": "number" }
|
|
31
|
+
},
|
|
32
|
+
"required": ["avg_long_sl_distance_pct", "avg_short_sl_distance_pct", "long_count", "short_count"]
|
|
45
33
|
};
|
|
34
|
+
return { "type": "object", "patternProperties": { "^.*$": sectorSchema } };
|
|
46
35
|
}
|
|
47
36
|
|
|
48
|
-
_initSector(
|
|
49
|
-
if (!this.
|
|
50
|
-
this.
|
|
37
|
+
_initSector(sector) {
|
|
38
|
+
if (!this.sectorData.has(sector)) {
|
|
39
|
+
this.sectorData.set(sector, {
|
|
40
|
+
longSum: 0, longCount: 0,
|
|
41
|
+
shortSum: 0, shortCount: 0
|
|
42
|
+
});
|
|
51
43
|
}
|
|
52
44
|
}
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
46
|
+
process(context) {
|
|
47
|
+
const { extract } = context.math;
|
|
48
|
+
const { mappings, user } = context;
|
|
49
|
+
if (!this.sectorMap) this.sectorMap = mappings.sectorMapping;
|
|
59
50
|
|
|
60
|
-
const positions =
|
|
61
|
-
if (!positions || !Array.isArray(positions) || !this.sectorMap) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
51
|
+
const positions = extract.getPositions(user.portfolio.today, user.type);
|
|
64
52
|
|
|
65
53
|
for (const pos of positions) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const currentRate = pos.CurrentRate;
|
|
54
|
+
const instId = extract.getInstrumentId(pos);
|
|
55
|
+
if (!instId) continue;
|
|
69
56
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const sectorName = this.sectorMap[instrumentId] || 'N/A';
|
|
75
|
-
this._initSector(sectorName);
|
|
76
|
-
const sectorData = this.sectors.get(sectorName);
|
|
57
|
+
const slRate = extract.getStopLossRate(pos);
|
|
58
|
+
const currentRate = extract.getCurrentRate(pos);
|
|
59
|
+
if (slRate <= 0 || currentRate <= 0) continue;
|
|
77
60
|
|
|
61
|
+
const sector = this.sectorMap[instId] || 'Unknown';
|
|
62
|
+
const direction = extract.getDirection(pos);
|
|
78
63
|
let pctToSL = 0;
|
|
79
|
-
|
|
80
|
-
|
|
64
|
+
|
|
65
|
+
if (direction === 'Buy') {
|
|
81
66
|
pctToSL = (currentRate - slRate) / currentRate;
|
|
82
|
-
if (pctToSL > 0) {
|
|
83
|
-
sectorData.long_sum += (pctToSL * 100);
|
|
84
|
-
sectorData.long_count++;
|
|
85
|
-
}
|
|
86
67
|
} else {
|
|
87
|
-
// Short: (SL - Current) / Current
|
|
88
68
|
pctToSL = (slRate - currentRate) / currentRate;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (pctToSL <= 0) continue;
|
|
72
|
+
|
|
73
|
+
this._initSector(sector);
|
|
74
|
+
const data = this.sectorData.get(sector);
|
|
75
|
+
|
|
76
|
+
if (direction === 'Buy') {
|
|
77
|
+
data.longSum += (pctToSL * 100);
|
|
78
|
+
data.longCount++;
|
|
79
|
+
} else {
|
|
80
|
+
data.shortSum += (pctToSL * 100);
|
|
81
|
+
data.shortCount++;
|
|
93
82
|
}
|
|
94
83
|
}
|
|
95
84
|
}
|
|
96
|
-
// --- END FIX ---
|
|
97
85
|
|
|
98
86
|
async getResult() {
|
|
99
87
|
const result = {};
|
|
100
|
-
for (const [
|
|
101
|
-
if (data.
|
|
102
|
-
result[
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
88
|
+
for (const [sector, data] of this.sectorData.entries()) {
|
|
89
|
+
if (data.longCount > 0 || data.shortCount > 0) {
|
|
90
|
+
result[sector] = {
|
|
91
|
+
avg_long_sl_distance_pct: data.longCount > 0 ? data.longSum / data.longCount : null,
|
|
92
|
+
avg_short_sl_distance_pct: data.shortCount > 0 ? data.shortSum / data.shortCount : null,
|
|
93
|
+
long_count: data.longCount,
|
|
94
|
+
short_count: data.shortCount
|
|
107
95
|
};
|
|
108
96
|
}
|
|
109
97
|
}
|
|
@@ -111,9 +99,8 @@ class SpeculatorSLDistanceBySectorShortLong {
|
|
|
111
99
|
}
|
|
112
100
|
|
|
113
101
|
reset() {
|
|
114
|
-
this.
|
|
102
|
+
this.sectorData.clear();
|
|
115
103
|
this.sectorMap = null;
|
|
116
104
|
}
|
|
117
105
|
}
|
|
118
|
-
|
|
119
|
-
module.exports = SpeculatorSLDistanceBySectorShortLong;
|
|
106
|
+
module.exports = SpeculatorSLDistanceSectorBreakdown;
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for
|
|
3
|
-
*
|
|
4
|
-
* - Rewritten logic to calculate SL distance from raw schema fields
|
|
5
|
-
* (StopLossRate, CurrentRate) instead of 'PctToStopLoss'.
|
|
6
|
-
* - Updated process signature to match worker.
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for SL distance broken down by direction.
|
|
3
|
+
* REFACTORED: Uses context.math.extract.
|
|
7
4
|
*/
|
|
8
|
-
|
|
9
|
-
class SpeculatorSLDistanceByTickerShortLong {
|
|
5
|
+
class SpeculatorSLDistanceTickerBreakdown {
|
|
10
6
|
constructor() {
|
|
11
7
|
this.assets = new Map();
|
|
12
8
|
this.tickerMap = null;
|
|
@@ -17,98 +13,86 @@ class SpeculatorSLDistanceByTickerShortLong {
|
|
|
17
13
|
type: 'standard',
|
|
18
14
|
rootDataDependencies: ['portfolio'],
|
|
19
15
|
isHistorical: false,
|
|
20
|
-
userType: 'speculator',
|
|
16
|
+
userType: 'speculator',
|
|
21
17
|
category: 'core_speculator'
|
|
22
18
|
};
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
static getDependencies() {
|
|
26
|
-
return [];
|
|
27
|
-
}
|
|
21
|
+
static getDependencies() { return []; }
|
|
28
22
|
|
|
29
23
|
static getSchema() {
|
|
30
24
|
const tickerSchema = {
|
|
31
25
|
"type": "object",
|
|
32
26
|
"properties": {
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
"type": "object",
|
|
42
|
-
"description": "Calculates the average distance to SL, broken down by long/short, per asset.",
|
|
43
|
-
"patternProperties": { "^.*$": tickerSchema },
|
|
44
|
-
"additionalProperties": tickerSchema
|
|
27
|
+
"avg_long_sl_distance_pct": { "type": ["number", "null"] },
|
|
28
|
+
"avg_short_sl_distance_pct": { "type": ["number", "null"] },
|
|
29
|
+
"long_count": { "type": "number" },
|
|
30
|
+
"short_count": { "type": "number" }
|
|
31
|
+
},
|
|
32
|
+
"required": ["avg_long_sl_distance_pct", "avg_short_sl_distance_pct", "long_count", "short_count"]
|
|
45
33
|
};
|
|
34
|
+
return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
|
|
46
35
|
}
|
|
47
36
|
|
|
48
|
-
_initAsset(
|
|
49
|
-
if (!this.assets.has(
|
|
50
|
-
this.assets.set(
|
|
37
|
+
_initAsset(instId) {
|
|
38
|
+
if (!this.assets.has(instId)) {
|
|
39
|
+
this.assets.set(instId, {
|
|
40
|
+
longSum: 0, longCount: 0,
|
|
41
|
+
shortSum: 0, shortCount: 0
|
|
42
|
+
});
|
|
51
43
|
}
|
|
52
44
|
}
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
46
|
+
process(context) {
|
|
47
|
+
const { extract } = context.math;
|
|
48
|
+
const { mappings, user } = context;
|
|
49
|
+
if (!this.tickerMap) this.tickerMap = mappings.instrumentToTicker;
|
|
59
50
|
|
|
60
|
-
const positions =
|
|
61
|
-
if (!positions || !Array.isArray(positions)) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
51
|
+
const positions = extract.getPositions(user.portfolio.today, user.type);
|
|
64
52
|
|
|
65
53
|
for (const pos of positions) {
|
|
66
|
-
const
|
|
67
|
-
const slRate = pos
|
|
68
|
-
const currentRate = pos
|
|
69
|
-
|
|
70
|
-
if (!
|
|
71
|
-
continue; // No SL or invalid data
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
this._initAsset(instrumentId);
|
|
75
|
-
const assetData = this.assets.get(instrumentId);
|
|
54
|
+
const instId = extract.getInstrumentId(pos);
|
|
55
|
+
const slRate = extract.getStopLossRate(pos);
|
|
56
|
+
const currentRate = extract.getCurrentRate(pos);
|
|
57
|
+
|
|
58
|
+
if (!instId || slRate <= 0 || currentRate <= 0) continue;
|
|
76
59
|
|
|
60
|
+
const direction = extract.getDirection(pos);
|
|
77
61
|
let pctToSL = 0;
|
|
78
|
-
|
|
79
|
-
|
|
62
|
+
|
|
63
|
+
if (direction === 'Buy') {
|
|
80
64
|
pctToSL = (currentRate - slRate) / currentRate;
|
|
81
|
-
if (pctToSL > 0) {
|
|
82
|
-
assetData.long_sum += (pctToSL * 100);
|
|
83
|
-
assetData.long_count++;
|
|
84
|
-
}
|
|
85
65
|
} else {
|
|
86
|
-
// Short: (SL - Current) / Current
|
|
87
66
|
pctToSL = (slRate - currentRate) / currentRate;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (pctToSL <= 0) continue;
|
|
70
|
+
|
|
71
|
+
this._initAsset(instId);
|
|
72
|
+
const data = this.assets.get(instId);
|
|
73
|
+
|
|
74
|
+
if (direction === 'Buy') {
|
|
75
|
+
data.longSum += (pctToSL * 100);
|
|
76
|
+
data.longCount++;
|
|
77
|
+
} else {
|
|
78
|
+
data.shortSum += (pctToSL * 100);
|
|
79
|
+
data.shortCount++;
|
|
92
80
|
}
|
|
93
81
|
}
|
|
94
82
|
}
|
|
95
|
-
// --- END FIX ---
|
|
96
83
|
|
|
97
84
|
async getResult() {
|
|
98
|
-
if (!this.tickerMap) {
|
|
99
|
-
return {};
|
|
100
|
-
}
|
|
101
|
-
|
|
85
|
+
if (!this.tickerMap) return {};
|
|
102
86
|
const result = {};
|
|
103
|
-
for (const [
|
|
104
|
-
const ticker = this.tickerMap[
|
|
105
|
-
|
|
106
|
-
if (data.
|
|
87
|
+
for (const [instId, data] of this.assets.entries()) {
|
|
88
|
+
const ticker = this.tickerMap[instId] || `id_${instId}`;
|
|
89
|
+
|
|
90
|
+
if (data.longCount > 0 || data.shortCount > 0) {
|
|
107
91
|
result[ticker] = {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
92
|
+
avg_long_sl_distance_pct: data.longCount > 0 ? data.longSum / data.longCount : null,
|
|
93
|
+
avg_short_sl_distance_pct: data.shortCount > 0 ? data.shortSum / data.shortCount : null,
|
|
94
|
+
long_count: data.longCount,
|
|
95
|
+
short_count: data.shortCount
|
|
112
96
|
};
|
|
113
97
|
}
|
|
114
98
|
}
|
|
@@ -120,5 +104,4 @@ class SpeculatorSLDistanceByTickerShortLong {
|
|
|
120
104
|
this.tickerMap = null;
|
|
121
105
|
}
|
|
122
106
|
}
|
|
123
|
-
|
|
124
|
-
module.exports = SpeculatorSLDistanceByTickerShortLong;
|
|
107
|
+
module.exports = SpeculatorSLDistanceTickerBreakdown;
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for speculator
|
|
3
|
-
*
|
|
4
|
-
* This metric answers: "For each asset, what percentage
|
|
5
|
-
* of speculators are using a stop-loss?"
|
|
6
|
-
* --- FIX ---
|
|
7
|
-
* - Logic changed to check 'StopLossRate > 0' instead of 'PctToStopLoss >= 0'
|
|
8
|
-
* to match schema.md.
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for speculator Stop Loss usage.
|
|
3
|
+
* REFACTORED: Uses context.math.extract.
|
|
9
4
|
*/
|
|
10
|
-
|
|
11
5
|
class SpeculatorStopLossPerAsset {
|
|
12
6
|
constructor() {
|
|
13
7
|
this.assets = new Map();
|
|
@@ -19,14 +13,12 @@ class SpeculatorStopLossPerAsset {
|
|
|
19
13
|
type: 'standard',
|
|
20
14
|
rootDataDependencies: ['portfolio'],
|
|
21
15
|
isHistorical: false,
|
|
22
|
-
userType: 'speculator',
|
|
16
|
+
userType: 'speculator',
|
|
23
17
|
category: 'core_speculator'
|
|
24
18
|
};
|
|
25
19
|
}
|
|
26
20
|
|
|
27
|
-
static getDependencies() {
|
|
28
|
-
return [];
|
|
29
|
-
}
|
|
21
|
+
static getDependencies() { return []; }
|
|
30
22
|
|
|
31
23
|
static getSchema() {
|
|
32
24
|
const tickerSchema = {
|
|
@@ -38,13 +30,7 @@ class SpeculatorStopLossPerAsset {
|
|
|
38
30
|
},
|
|
39
31
|
"required": ["sl_usage_pct", "sl_count", "total_count"]
|
|
40
32
|
};
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
"type": "object",
|
|
44
|
-
"description": "Calculates the percentage of speculators using a stop-loss per asset.",
|
|
45
|
-
"patternProperties": { "^.*$": tickerSchema },
|
|
46
|
-
"additionalProperties": tickerSchema
|
|
47
|
-
};
|
|
33
|
+
return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
|
|
48
34
|
}
|
|
49
35
|
|
|
50
36
|
_initAsset(instrumentId) {
|
|
@@ -53,43 +39,33 @@ class SpeculatorStopLossPerAsset {
|
|
|
53
39
|
}
|
|
54
40
|
}
|
|
55
41
|
|
|
56
|
-
process(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
42
|
+
process(context) {
|
|
43
|
+
const { extract } = context.math;
|
|
44
|
+
const { mappings, user } = context;
|
|
45
|
+
if (!this.tickerMap) this.tickerMap = mappings.instrumentToTicker;
|
|
60
46
|
|
|
61
|
-
const positions =
|
|
62
|
-
if (!positions || !Array.isArray(positions)) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
47
|
+
const positions = extract.getPositions(user.portfolio.today, user.type);
|
|
65
48
|
|
|
66
49
|
for (const pos of positions) {
|
|
67
|
-
const
|
|
68
|
-
if (!
|
|
50
|
+
const instId = extract.getInstrumentId(pos);
|
|
51
|
+
if (!instId) continue;
|
|
69
52
|
|
|
70
|
-
this._initAsset(
|
|
71
|
-
const assetData = this.assets.get(
|
|
53
|
+
this._initAsset(instId);
|
|
54
|
+
const assetData = this.assets.get(instId);
|
|
72
55
|
assetData.total++;
|
|
73
56
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// A rate > 0 indicates an SL is set.
|
|
77
|
-
if (pos.StopLossRate > 0) {
|
|
78
|
-
// --- END FIX ---
|
|
57
|
+
const slRate = extract.getStopLossRate(pos);
|
|
58
|
+
if (slRate > 0) {
|
|
79
59
|
assetData.with_sl++;
|
|
80
60
|
}
|
|
81
61
|
}
|
|
82
62
|
}
|
|
83
63
|
|
|
84
64
|
async getResult() {
|
|
85
|
-
if (!this.tickerMap) {
|
|
86
|
-
return {};
|
|
87
|
-
}
|
|
88
|
-
|
|
65
|
+
if (!this.tickerMap) return {};
|
|
89
66
|
const result = {};
|
|
90
|
-
for (const [
|
|
91
|
-
const ticker = this.tickerMap[
|
|
92
|
-
|
|
67
|
+
for (const [instId, data] of this.assets.entries()) {
|
|
68
|
+
const ticker = this.tickerMap[instId] || `id_${instId}`;
|
|
93
69
|
if (data.total > 0) {
|
|
94
70
|
result[ticker] = {
|
|
95
71
|
sl_usage_pct: (data.with_sl / data.total) * 100,
|
|
@@ -106,5 +82,4 @@ class SpeculatorStopLossPerAsset {
|
|
|
106
82
|
this.tickerMap = null;
|
|
107
83
|
}
|
|
108
84
|
}
|
|
109
|
-
|
|
110
85
|
module.exports = SpeculatorStopLossPerAsset;
|
|
@@ -1,42 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for speculator
|
|
3
|
-
*
|
|
4
|
-
* This metric answers: "For each asset, what percentage
|
|
5
|
-
* of speculators are using a take-profit?"
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for speculator Take Profit usage.
|
|
3
|
+
* REFACTORED: Uses context.math.extract to check for TP rates.
|
|
6
4
|
*/
|
|
7
|
-
// --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
|
|
8
|
-
|
|
9
5
|
class SpeculatorTakeProfitPerAsset {
|
|
10
6
|
constructor() {
|
|
11
|
-
// { [instrumentId]: { with_tp: 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',
|
|
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 SpeculatorTakeProfitPerAsset {
|
|
|
47
30
|
},
|
|
48
31
|
"required": ["tp_usage_pct", "tp_count", "total_count"]
|
|
49
32
|
};
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
"type": "object",
|
|
53
|
-
"description": "Calculates the percentage of speculators using a take-profit 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,34 @@ class SpeculatorTakeProfitPerAsset {
|
|
|
62
39
|
}
|
|
63
40
|
}
|
|
64
41
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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 =
|
|
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
|
|
79
|
-
if (!
|
|
50
|
+
const instId = extract.getInstrumentId(pos);
|
|
51
|
+
if (!instId) continue;
|
|
80
52
|
|
|
81
|
-
this._initAsset(
|
|
82
|
-
const assetData = this.assets.get(
|
|
53
|
+
this._initAsset(instId);
|
|
54
|
+
const assetData = this.assets.get(instId);
|
|
83
55
|
assetData.total++;
|
|
84
56
|
|
|
85
|
-
//
|
|
86
|
-
|
|
57
|
+
// Check if TakeProfitRate exists and is > 0
|
|
58
|
+
const tpRate = extract.getTakeProfitRate(pos);
|
|
59
|
+
if (tpRate > 0) {
|
|
87
60
|
assetData.with_tp++;
|
|
88
61
|
}
|
|
89
62
|
}
|
|
90
63
|
}
|
|
91
64
|
|
|
92
65
|
async getResult() {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// Failsafe check
|
|
96
|
-
if (!this.tickerMap) {
|
|
97
|
-
return {}; // process() must run first
|
|
98
|
-
}
|
|
99
|
-
|
|
66
|
+
if (!this.tickerMap) return {};
|
|
100
67
|
const result = {};
|
|
101
|
-
for (const [
|
|
102
|
-
|
|
103
|
-
const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
|
|
104
|
-
|
|
68
|
+
for (const [instId, data] of this.assets.entries()) {
|
|
69
|
+
const ticker = this.tickerMap[instId] || `id_${instId}`;
|
|
105
70
|
if (data.total > 0) {
|
|
106
71
|
result[ticker] = {
|
|
107
72
|
tp_usage_pct: (data.with_tp / data.total) * 100,
|
|
@@ -115,9 +80,7 @@ class SpeculatorTakeProfitPerAsset {
|
|
|
115
80
|
|
|
116
81
|
reset() {
|
|
117
82
|
this.assets.clear();
|
|
118
|
-
// --- STANDARD 0: RENAMED ---
|
|
119
83
|
this.tickerMap = null;
|
|
120
84
|
}
|
|
121
85
|
}
|
|
122
|
-
|
|
123
86
|
module.exports = SpeculatorTakeProfitPerAsset;
|