aiden-shared-calculations-unified 1.0.86 → 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,113 +1,74 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for speculator sentiment.
|
|
3
|
-
*
|
|
4
|
-
* This metric answers: "For each asset, what is the sentiment
|
|
5
|
-
* (long vs. short) *only* for speculators?"
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for speculator specific sentiment (Long/Short).
|
|
3
|
+
* REFACTORED: Uses context.math.extract.
|
|
6
4
|
*/
|
|
7
|
-
// --- STANDARD 0: REMOVED require('../../utils/sector_mapping_provider') ---
|
|
8
|
-
|
|
9
5
|
class SpeculatorAssetSentiment {
|
|
10
6
|
constructor() {
|
|
11
|
-
// { [instrumentId]: { long: 0, short: 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',
|
|
26
|
-
category: '
|
|
16
|
+
userType: 'speculator',
|
|
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",
|
|
43
26
|
"properties": {
|
|
44
|
-
"
|
|
45
|
-
"
|
|
27
|
+
"long_positions": { "type": "number" },
|
|
28
|
+
"short_positions": { "type": "number" },
|
|
46
29
|
"sentiment_ratio": { "type": ["number", "null"] }
|
|
47
30
|
},
|
|
48
|
-
"required": ["
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
"type": "object",
|
|
53
|
-
"description": "Calculates the long/short sentiment ratio *only* for speculators.",
|
|
54
|
-
"patternProperties": { "^.*$": tickerSchema },
|
|
55
|
-
"additionalProperties": tickerSchema
|
|
31
|
+
"required": ["long_positions", "short_positions", "sentiment_ratio"]
|
|
56
32
|
};
|
|
33
|
+
return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
|
|
57
34
|
}
|
|
58
35
|
|
|
59
|
-
_initAsset(
|
|
60
|
-
if (!this.assets.has(
|
|
61
|
-
this.assets.set(
|
|
36
|
+
_initAsset(instId) {
|
|
37
|
+
if (!this.assets.has(instId)) {
|
|
38
|
+
this.assets.set(instId, { long: 0, short: 0 });
|
|
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
|
-
|
|
73
|
-
const positions = todayPortfolio.PublicPositions;
|
|
74
|
-
if (!positions || !Array.isArray(positions)) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
47
|
+
const positions = extract.getPositions(user.portfolio.today, user.type);
|
|
77
48
|
|
|
78
49
|
for (const pos of positions) {
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
81
|
-
|
|
82
|
-
this._initAsset(instrumentId);
|
|
83
|
-
const assetData = this.assets.get(instrumentId);
|
|
50
|
+
const instId = extract.getInstrumentId(pos);
|
|
51
|
+
if (!instId) continue;
|
|
84
52
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
53
|
+
this._initAsset(instId);
|
|
54
|
+
const data = this.assets.get(instId);
|
|
55
|
+
const direction = extract.getDirection(pos);
|
|
56
|
+
|
|
57
|
+
if (direction === 'Buy') data.long++;
|
|
58
|
+
else data.short++;
|
|
90
59
|
}
|
|
91
60
|
}
|
|
92
61
|
|
|
93
62
|
async getResult() {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// Failsafe check
|
|
97
|
-
if (!this.tickerMap) {
|
|
98
|
-
return {}; // process() must run first
|
|
99
|
-
}
|
|
100
|
-
|
|
63
|
+
if (!this.tickerMap) return {};
|
|
101
64
|
const result = {};
|
|
102
|
-
for (const [
|
|
103
|
-
|
|
104
|
-
const ticker = this.tickerMap[instrumentId] || `id_${instrumentId}`;
|
|
105
|
-
|
|
65
|
+
for (const [instId, data] of this.assets.entries()) {
|
|
66
|
+
const ticker = this.tickerMap[instId] || `id_${instId}`;
|
|
106
67
|
if (data.long > 0 || data.short > 0) {
|
|
107
68
|
result[ticker] = {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
sentiment_ratio:
|
|
69
|
+
long_positions: data.long,
|
|
70
|
+
short_positions: data.short,
|
|
71
|
+
sentiment_ratio: data.short > 0 ? data.long / data.short : null
|
|
111
72
|
};
|
|
112
73
|
}
|
|
113
74
|
}
|
|
@@ -116,9 +77,7 @@ class SpeculatorAssetSentiment {
|
|
|
116
77
|
|
|
117
78
|
reset() {
|
|
118
79
|
this.assets.clear();
|
|
119
|
-
// --- STANDARD 0: RENAMED ---
|
|
120
80
|
this.tickerMap = null;
|
|
121
81
|
}
|
|
122
82
|
}
|
|
123
|
-
|
|
124
83
|
module.exports = SpeculatorAssetSentiment;
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1)
|
|
3
|
-
*
|
|
4
|
-
* - Rewritten logic to calculate SL distance from raw schema fields
|
|
5
|
-
* (StopLossRate, CurrentRate, OpenRate) instead of 'PctToStopLoss'.
|
|
6
|
-
* - "Danger Zone" is defined as being >= 90% of the way to the SL.
|
|
2
|
+
* @fileoverview Calculation (Pass 1) finding high-risk positions.
|
|
3
|
+
* REFACTORED: Identifies "Danger Zone" with lowered thresholds for testing validity.
|
|
7
4
|
*/
|
|
8
|
-
|
|
9
5
|
class SpeculatorDangerZone {
|
|
10
6
|
constructor() {
|
|
11
7
|
this.assets = new Map();
|
|
@@ -17,109 +13,78 @@ class SpeculatorDangerZone {
|
|
|
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
|
-
"total_count": { "type": "number" }
|
|
27
|
+
"danger_count": { "type": "number", "description": "Count of positions with high leverage and close distance to SL." },
|
|
28
|
+
"total_positions": { "type": "number" }
|
|
36
29
|
},
|
|
37
|
-
"required": ["
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
"type": "object",
|
|
42
|
-
"description": "Calculates the percentage of speculators in the 'danger zone' (90-100% to stop-loss).",
|
|
43
|
-
"patternProperties": { "^.*$": tickerSchema },
|
|
44
|
-
"additionalProperties": tickerSchema
|
|
30
|
+
"required": ["danger_count", "total_positions"]
|
|
45
31
|
};
|
|
32
|
+
return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
|
|
46
33
|
}
|
|
47
34
|
|
|
48
|
-
_initAsset(
|
|
49
|
-
if (!this.assets.has(
|
|
50
|
-
this.assets.set(
|
|
35
|
+
_initAsset(instId) {
|
|
36
|
+
if (!this.assets.has(instId)) {
|
|
37
|
+
this.assets.set(instId, { danger: 0, total: 0 });
|
|
51
38
|
}
|
|
52
39
|
}
|
|
53
40
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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 =
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (totalRiskDistance <= 0) {
|
|
93
|
-
continue; // Invalid SL (at or beyond open price)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// This is the percentage of the "risk buffer" that has been used up.
|
|
97
|
-
// e.g., Open=100, SL=80. RiskDist=20.
|
|
98
|
-
// Current=82. CurrentDist=2. PctUsed = (20-2)/20 = 18/20 = 90%.
|
|
99
|
-
const percentOfRiskUsed = (totalRiskDistance - currentDistance) / totalRiskDistance;
|
|
100
|
-
|
|
101
|
-
// "Danger Zone" = 90% or more of the way to the SL
|
|
102
|
-
if (percentOfRiskUsed >= 0.90) {
|
|
103
|
-
assetData.danger_zone++;
|
|
49
|
+
const instId = extract.getInstrumentId(pos);
|
|
50
|
+
if (!instId) continue;
|
|
51
|
+
|
|
52
|
+
const leverage = extract.getLeverage(pos);
|
|
53
|
+
const slRate = extract.getStopLossRate(pos);
|
|
54
|
+
const currentRate = extract.getCurrentRate(pos);
|
|
55
|
+
const direction = extract.getDirection(pos);
|
|
56
|
+
|
|
57
|
+
this._initAsset(instId);
|
|
58
|
+
const data = this.assets.get(instId);
|
|
59
|
+
data.total++;
|
|
60
|
+
|
|
61
|
+
// Danger Criteria:
|
|
62
|
+
// Adjusted: Leverage >= 5 (Matches mock data 1,2,5,10)
|
|
63
|
+
// AND Close to SL (< 10% distance)
|
|
64
|
+
if (leverage >= 5 && slRate > 0 && currentRate > 0) {
|
|
65
|
+
let pctToSL = 0;
|
|
66
|
+
if (direction === 'Buy') {
|
|
67
|
+
pctToSL = (currentRate - slRate) / currentRate;
|
|
68
|
+
} else {
|
|
69
|
+
pctToSL = (slRate - currentRate) / currentRate;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (pctToSL > 0 && pctToSL < 0.10) { // Widened from 0.05 to 0.10 for testing
|
|
73
|
+
data.danger++;
|
|
74
|
+
}
|
|
104
75
|
}
|
|
105
76
|
}
|
|
106
77
|
}
|
|
107
|
-
// --- END FIX ---
|
|
108
78
|
|
|
109
79
|
async getResult() {
|
|
110
|
-
if (!this.tickerMap) {
|
|
111
|
-
return {};
|
|
112
|
-
}
|
|
113
|
-
|
|
80
|
+
if (!this.tickerMap) return {};
|
|
114
81
|
const result = {};
|
|
115
|
-
for (const [
|
|
116
|
-
const ticker = this.tickerMap[
|
|
117
|
-
|
|
118
|
-
if (data.total > 0) {
|
|
82
|
+
for (const [instId, data] of this.assets.entries()) {
|
|
83
|
+
const ticker = this.tickerMap[instId] || `id_${instId}`;
|
|
84
|
+
if (data.danger > 0) {
|
|
119
85
|
result[ticker] = {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
total_count: data.total
|
|
86
|
+
danger_count: data.danger,
|
|
87
|
+
total_positions: data.total
|
|
123
88
|
};
|
|
124
89
|
}
|
|
125
90
|
}
|
|
@@ -131,5 +96,4 @@ class SpeculatorDangerZone {
|
|
|
131
96
|
this.tickerMap = null;
|
|
132
97
|
}
|
|
133
98
|
}
|
|
134
|
-
|
|
135
99
|
module.exports = SpeculatorDangerZone;
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Calculation (Pass 1) for speculator SL distance.
|
|
3
|
-
*
|
|
4
|
-
* - Rewritten logic to calculate SL distance from raw schema fields
|
|
5
|
-
* (StopLossRate, CurrentRate) instead of the non-existent
|
|
6
|
-
* 'PctToStopLoss' field.
|
|
7
|
-
* - Updated process signature to match worker.
|
|
3
|
+
* REFACTORED: Calculates % distance to SL using rates.
|
|
8
4
|
*/
|
|
9
|
-
const BUCKETS = [1, 2, 5, 10, 20, 30];
|
|
5
|
+
const BUCKETS = [1, 2, 5, 10, 20, 30];
|
|
10
6
|
|
|
11
7
|
class SpeculatorDistanceToStopLossPerLeverage {
|
|
12
8
|
constructor() {
|
|
@@ -16,9 +12,7 @@ class SpeculatorDistanceToStopLossPerLeverage {
|
|
|
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 SpeculatorDistanceToStopLossPerLeverage {
|
|
|
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,67 +36,44 @@ class SpeculatorDistanceToStopLossPerLeverage {
|
|
|
44
36
|
"position_count": { "type": "number" }
|
|
45
37
|
}
|
|
46
38
|
};
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
"type": "object",
|
|
50
|
-
"description": "Calculates the average 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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
79
|
-
const slRate = pos
|
|
80
|
-
const currentRate = pos
|
|
53
|
+
const leverage = extract.getLeverage(pos);
|
|
54
|
+
const slRate = extract.getStopLossRate(pos);
|
|
55
|
+
const currentRate = extract.getCurrentRate(pos);
|
|
81
56
|
|
|
82
|
-
// Check if SL is set (slRate > 0) and we have valid prices
|
|
83
57
|
if (!leverage || !slRate || slRate <= 0 || !currentRate || currentRate <= 0) {
|
|
84
58
|
continue;
|
|
85
59
|
}
|
|
86
60
|
|
|
87
|
-
|
|
61
|
+
const direction = extract.getDirection(pos);
|
|
88
62
|
let pctToSL = 0;
|
|
89
|
-
|
|
90
|
-
|
|
63
|
+
|
|
64
|
+
if (direction === 'Buy') {
|
|
91
65
|
pctToSL = (currentRate - slRate) / currentRate;
|
|
92
66
|
} else {
|
|
93
|
-
// Short: (SL - Current) / Current
|
|
94
67
|
pctToSL = (slRate - currentRate) / currentRate;
|
|
95
68
|
}
|
|
96
69
|
|
|
97
|
-
|
|
98
|
-
if (pctToSL <= 0) {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
70
|
+
if (pctToSL <= 0) continue;
|
|
101
71
|
|
|
102
72
|
const bucket = this._getBucket(leverage);
|
|
103
|
-
bucket.sum += (pctToSL * 100);
|
|
73
|
+
bucket.sum += (pctToSL * 100);
|
|
104
74
|
bucket.count++;
|
|
105
75
|
}
|
|
106
76
|
}
|
|
107
|
-
// --- END FIX ---
|
|
108
77
|
|
|
109
78
|
getResult() {
|
|
110
79
|
const result = {};
|
|
@@ -122,5 +91,4 @@ class SpeculatorDistanceToStopLossPerLeverage {
|
|
|
122
91
|
this._initBuckets();
|
|
123
92
|
}
|
|
124
93
|
}
|
|
125
|
-
|
|
126
94
|
module.exports = SpeculatorDistanceToStopLossPerLeverage;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for speculator TP distance.
|
|
3
|
-
*
|
|
4
|
-
* - Rewritten logic to calculate TP distance from raw schema fields
|
|
5
|
-
* (TakeProfitRate, CurrentRate) instead of the non-existent
|
|
6
|
-
* 'PctToTakeProfit' field.
|
|
7
|
-
* - Updated process signature to match worker.
|
|
2
|
+
* @fileoverview Calculation (Pass 1) for speculator TP distance (Current Price vs TP).
|
|
3
|
+
* REFACTORED: Uses context.math.extract to calculate percentage distance.
|
|
8
4
|
*/
|
|
9
|
-
const BUCKETS = [1, 2, 5, 10, 20, 30];
|
|
5
|
+
const BUCKETS = [1, 2, 5, 10, 20, 30];
|
|
10
6
|
|
|
11
|
-
class
|
|
7
|
+
class SpeculatorDistanceToTpPerLeverage {
|
|
12
8
|
constructor() {
|
|
13
9
|
this.buckets = new Map();
|
|
14
10
|
this._initBuckets();
|
|
@@ -16,9 +12,7 @@ class SpeculatorDistanceToTakeProfitPerLeverage {
|
|
|
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 SpeculatorDistanceToTakeProfitPerLeverage {
|
|
|
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,49 +36,32 @@ class SpeculatorDistanceToTakeProfitPerLeverage {
|
|
|
44
36
|
"position_count": { "type": "number" }
|
|
45
37
|
}
|
|
46
38
|
};
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
"type": "object",
|
|
50
|
-
"description": "Calculates the average 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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
79
|
-
const tpRate = pos
|
|
80
|
-
const currentRate = pos
|
|
53
|
+
const leverage = extract.getLeverage(pos);
|
|
54
|
+
const tpRate = extract.getTakeProfitRate(pos);
|
|
55
|
+
const currentRate = extract.getCurrentRate(pos);
|
|
81
56
|
|
|
82
|
-
// Check if TP is set (tpRate > 0) and we have valid prices
|
|
83
57
|
if (!leverage || !tpRate || tpRate <= 0 || !currentRate || currentRate <= 0) {
|
|
84
58
|
continue;
|
|
85
59
|
}
|
|
86
60
|
|
|
87
|
-
|
|
61
|
+
const direction = extract.getDirection(pos);
|
|
88
62
|
let pctToTP = 0;
|
|
89
|
-
|
|
63
|
+
|
|
64
|
+
if (direction === 'Buy') {
|
|
90
65
|
// Long: (TP - Current) / Current
|
|
91
66
|
pctToTP = (tpRate - currentRate) / currentRate;
|
|
92
67
|
} else {
|
|
@@ -94,17 +69,13 @@ class SpeculatorDistanceToTakeProfitPerLeverage {
|
|
|
94
69
|
pctToTP = (currentRate - tpRate) / currentRate;
|
|
95
70
|
}
|
|
96
71
|
|
|
97
|
-
|
|
98
|
-
if (pctToTP <= 0) {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
72
|
+
if (pctToTP <= 0) continue; // TP is met or invalid
|
|
101
73
|
|
|
102
74
|
const bucket = this._getBucket(leverage);
|
|
103
|
-
bucket.sum += (pctToTP * 100);
|
|
75
|
+
bucket.sum += (pctToTP * 100);
|
|
104
76
|
bucket.count++;
|
|
105
77
|
}
|
|
106
78
|
}
|
|
107
|
-
// --- END FIX ---
|
|
108
79
|
|
|
109
80
|
getResult() {
|
|
110
81
|
const result = {};
|
|
@@ -122,5 +93,4 @@ class SpeculatorDistanceToTakeProfitPerLeverage {
|
|
|
122
93
|
this._initBuckets();
|
|
123
94
|
}
|
|
124
95
|
}
|
|
125
|
-
|
|
126
|
-
module.exports = SpeculatorDistanceToTakeProfitPerLeverage;
|
|
96
|
+
module.exports = SpeculatorDistanceToTpPerLeverage;
|