aiden-shared-calculations-unified 1.0.92 → 1.0.93
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.
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview CORE Product Line (Pass 1 - Meta)
|
|
3
3
|
* Calculates annualized volatility using the new priceExtractor.
|
|
4
|
+
* FIXED: Supports Sharded/Batched Execution (Accumulates results).
|
|
4
5
|
*/
|
|
5
6
|
class AssetVolatilityEstimator {
|
|
6
7
|
constructor() {
|
|
@@ -33,21 +34,20 @@ class AssetVolatilityEstimator {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
process(context) {
|
|
36
|
-
// FIXED: Destructure 'mappings' to resolve real tickers
|
|
37
37
|
const { math, prices, mappings } = context;
|
|
38
|
-
|
|
39
|
-
// FIXED: Destructure 'priceExtractor' directly (matches worker.js injection)
|
|
40
38
|
const { compute, priceExtractor } = math;
|
|
39
|
+
|
|
40
|
+
if (!prices || !prices.history) return;
|
|
41
41
|
|
|
42
|
-
// 1. Get
|
|
42
|
+
// 1. Get THIS SHARD'S histories
|
|
43
43
|
const allHistories = priceExtractor.getAllHistories(prices);
|
|
44
44
|
|
|
45
|
+
const batchResult = {};
|
|
46
|
+
|
|
45
47
|
for (const [key, candles] of allHistories.entries()) {
|
|
46
|
-
// RESOLUTION FIX:
|
|
47
|
-
// 'key' is likely an index string ("0") because mock data is an array.
|
|
48
|
-
// We must resolve this to the real Ticker Symbol for the result map.
|
|
49
48
|
let ticker = key;
|
|
50
49
|
|
|
50
|
+
// Resolve ticker (logic maintained from original)
|
|
51
51
|
if (prices.history && prices.history[key] && prices.history[key].instrumentId) {
|
|
52
52
|
const instId = prices.history[key].instrumentId;
|
|
53
53
|
if (mappings && mappings.instrumentToTicker && mappings.instrumentToTicker[instId]) {
|
|
@@ -57,7 +57,6 @@ class AssetVolatilityEstimator {
|
|
|
57
57
|
|
|
58
58
|
if (candles.length < 10) continue;
|
|
59
59
|
|
|
60
|
-
// 2. Calculate Log Returns
|
|
61
60
|
const logReturns = [];
|
|
62
61
|
let lastPrice = 0;
|
|
63
62
|
|
|
@@ -71,22 +70,23 @@ class AssetVolatilityEstimator {
|
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
// 3. Filter 30-Day Lookback
|
|
75
73
|
const LOOKBACK = 30;
|
|
76
74
|
const relevantReturns = logReturns.slice(-LOOKBACK);
|
|
77
75
|
|
|
78
76
|
if (relevantReturns.length < 5) continue;
|
|
79
77
|
|
|
80
|
-
// 4. Calculate Stats
|
|
81
78
|
const stdDev = compute.standardDeviation(relevantReturns);
|
|
82
79
|
const annualizedVol = stdDev * Math.sqrt(365);
|
|
83
80
|
|
|
84
|
-
|
|
81
|
+
batchResult[ticker] = {
|
|
85
82
|
volatility_30d: annualizedVol,
|
|
86
83
|
last_price: lastPrice,
|
|
87
84
|
data_points: relevantReturns.length
|
|
88
85
|
};
|
|
89
86
|
}
|
|
87
|
+
|
|
88
|
+
// Accumulate
|
|
89
|
+
Object.assign(this.result, batchResult);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
async getResult() { return this.result; }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Calculation (Pass 1 - Meta) for 1-day price change.
|
|
3
|
-
* FIXED:
|
|
3
|
+
* FIXED: Supports Sharded/Batched Execution (Accumulates results).
|
|
4
4
|
*/
|
|
5
5
|
class InstrumentPriceChange1D {
|
|
6
6
|
constructor() {
|
|
@@ -36,7 +36,7 @@ class InstrumentPriceChange1D {
|
|
|
36
36
|
const { priceExtractor } = math;
|
|
37
37
|
|
|
38
38
|
if (!prices || !prices.history) {
|
|
39
|
-
|
|
39
|
+
// Do NOT reset result here, just return if this shard is empty
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -46,34 +46,37 @@ class InstrumentPriceChange1D {
|
|
|
46
46
|
yesterdayDate.setUTCDate(yesterdayDate.getUTCDate() - 1);
|
|
47
47
|
const yesterdayStr = yesterdayDate.toISOString().slice(0, 10);
|
|
48
48
|
|
|
49
|
-
const
|
|
49
|
+
const batchResults = {};
|
|
50
50
|
|
|
51
|
-
// Iterate over
|
|
51
|
+
// Iterate over THIS SHARD'S instruments
|
|
52
52
|
for (const [instrumentId, priceData] of Object.entries(prices.history)) {
|
|
53
53
|
const ticker = instrumentToTicker[instrumentId];
|
|
54
54
|
if (!ticker) continue;
|
|
55
55
|
|
|
56
|
+
// Note: getHistory works on the partial 'prices' object just fine
|
|
56
57
|
const history = priceExtractor.getHistory(prices, instrumentId);
|
|
57
58
|
if (history.length === 0) continue;
|
|
58
59
|
|
|
59
|
-
// Find today's and yesterday's prices
|
|
60
60
|
const todayPrice = priceData.prices?.[todayStr];
|
|
61
61
|
const yesterdayPrice = priceData.prices?.[yesterdayStr];
|
|
62
62
|
|
|
63
63
|
if (todayPrice && yesterdayPrice && yesterdayPrice > 0) {
|
|
64
64
|
const changePct = ((todayPrice - yesterdayPrice) / yesterdayPrice) * 100;
|
|
65
|
-
|
|
65
|
+
batchResults[ticker] = {
|
|
66
66
|
change_1d_pct: isFinite(changePct) ? changePct : 0
|
|
67
67
|
};
|
|
68
68
|
} else {
|
|
69
|
-
|
|
69
|
+
batchResults[ticker] = { change_1d_pct: 0 };
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
// Merge batch results into main result
|
|
74
|
+
Object.assign(this.result, batchResults);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
async getResult() { return this.result; }
|
|
78
|
+
|
|
79
|
+
// Explicit reset only called by system between full runs
|
|
77
80
|
reset() { this.result = {}; }
|
|
78
81
|
}
|
|
79
82
|
module.exports = InstrumentPriceChange1D;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Calculation (Pass 1 - Meta) for 20-day momentum.
|
|
3
|
-
* FIXED:
|
|
3
|
+
* FIXED: Supports Sharded/Batched Execution (Accumulates results).
|
|
4
4
|
*/
|
|
5
5
|
class InstrumentPriceMomentum20D {
|
|
6
6
|
constructor() {
|
|
@@ -49,7 +49,6 @@ class InstrumentPriceMomentum20D {
|
|
|
49
49
|
const { instrumentToTicker } = mappings;
|
|
50
50
|
|
|
51
51
|
if (!prices || !prices.history) {
|
|
52
|
-
this.result = {};
|
|
53
52
|
return;
|
|
54
53
|
}
|
|
55
54
|
|
|
@@ -59,9 +58,9 @@ class InstrumentPriceMomentum20D {
|
|
|
59
58
|
twentyDaysAgo.setUTCDate(todayDate.getUTCDate() - 20);
|
|
60
59
|
const oldStr = twentyDaysAgo.toISOString().slice(0, 10);
|
|
61
60
|
|
|
62
|
-
const
|
|
61
|
+
const batchResults = {};
|
|
63
62
|
|
|
64
|
-
// Iterate over
|
|
63
|
+
// Iterate over THIS SHARD'S instruments
|
|
65
64
|
for (const [instrumentId, priceData] of Object.entries(prices.history)) {
|
|
66
65
|
const ticker = instrumentToTicker[instrumentId];
|
|
67
66
|
if (!ticker) continue;
|
|
@@ -71,15 +70,16 @@ class InstrumentPriceMomentum20D {
|
|
|
71
70
|
|
|
72
71
|
if (currentPrice && oldPrice && oldPrice > 0) {
|
|
73
72
|
const momPct = ((currentPrice - oldPrice) / oldPrice) * 100;
|
|
74
|
-
|
|
73
|
+
batchResults[ticker] = {
|
|
75
74
|
momentum_20d_pct: isFinite(momPct) ? momPct : 0
|
|
76
75
|
};
|
|
77
76
|
} else {
|
|
78
|
-
|
|
77
|
+
batchResults[ticker] = { momentum_20d_pct: 0 };
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
// Merge
|
|
82
|
+
Object.assign(this.result, batchResults);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
async getResult() { return this.result; }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Calculation (Pass 1 - Meta) for historical price metrics.
|
|
3
|
-
*
|
|
3
|
+
* FIXED: Supports Sharded/Batched Execution.
|
|
4
|
+
* MOVED: Sector aggregation logic moved to getResult() to handle sharding correctly.
|
|
4
5
|
*/
|
|
5
6
|
const RANGES = [7, 30, 90, 365];
|
|
6
7
|
const TRADING_DAYS_PER_YEAR = 252;
|
|
@@ -8,6 +9,8 @@ const TRADING_DAYS_PER_YEAR = 252;
|
|
|
8
9
|
class CorePriceMetrics {
|
|
9
10
|
constructor() {
|
|
10
11
|
this.result = { by_instrument: {}, by_sector: {} };
|
|
12
|
+
// We persist mappings here because we process shard-by-shard
|
|
13
|
+
this.mappings = null;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
static getMetadata() {
|
|
@@ -87,25 +90,22 @@ class CorePriceMetrics {
|
|
|
87
90
|
|
|
88
91
|
process(context) {
|
|
89
92
|
const { mappings, prices, date } = context;
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
const { instrumentToTicker } = mappings;
|
|
94
|
+
|
|
95
|
+
// Save mappings for the final aggregation step
|
|
96
|
+
if (!this.mappings) this.mappings = mappings;
|
|
92
97
|
|
|
93
98
|
const priceData = prices?.history;
|
|
94
99
|
const todayDateStr = date.today;
|
|
95
100
|
|
|
96
101
|
if (!priceData || !todayDateStr) {
|
|
97
|
-
this.result = { by_instrument: {}, by_sector: {} };
|
|
98
102
|
return;
|
|
99
103
|
}
|
|
100
104
|
|
|
101
|
-
|
|
102
|
-
const tickerToInstrument = {};
|
|
103
|
-
|
|
104
|
-
// FIX 2: Iterate over Object.values() since priceData is a map, not an array
|
|
105
|
+
// Iterate over THIS SHARD'S data
|
|
105
106
|
for (const p of Object.values(priceData)) {
|
|
106
107
|
const ticker = instrumentToTicker[p.instrumentId];
|
|
107
108
|
if (!ticker) continue;
|
|
108
|
-
tickerToInstrument[ticker] = p.instrumentId;
|
|
109
109
|
|
|
110
110
|
const metrics = {};
|
|
111
111
|
for (const range of RANGES) {
|
|
@@ -119,14 +119,26 @@ class CorePriceMetrics {
|
|
|
119
119
|
? (stats.mean / stats.stdDev) * Math.sqrt(TRADING_DAYS_PER_YEAR)
|
|
120
120
|
: 0;
|
|
121
121
|
}
|
|
122
|
-
|
|
122
|
+
// Accumulate into by_instrument
|
|
123
|
+
this.result.by_instrument[ticker] = metrics;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async getResult() {
|
|
128
|
+
// Perform Sector Aggregation HERE (after all shards are processed)
|
|
129
|
+
const by_instrument = this.result.by_instrument;
|
|
130
|
+
const instrumentToSector = this.mappings?.instrumentToSector || {};
|
|
131
|
+
const instrumentToTicker = this.mappings?.instrumentToTicker || {};
|
|
132
|
+
|
|
133
|
+
// Reverse map ticker -> instrumentId
|
|
134
|
+
const tickerToInstrument = {};
|
|
135
|
+
for(const [id, tick] of Object.entries(instrumentToTicker)) {
|
|
136
|
+
tickerToInstrument[tick] = id;
|
|
123
137
|
}
|
|
124
138
|
|
|
125
|
-
// Sector Aggregation
|
|
126
139
|
const sectorAggs = {};
|
|
127
140
|
for (const ticker in by_instrument) {
|
|
128
141
|
const instId = tickerToInstrument[ticker];
|
|
129
|
-
// FIX 1 (Usage): Use the corrected variable name
|
|
130
142
|
const sector = instrumentToSector[instId] || "Unknown";
|
|
131
143
|
|
|
132
144
|
if (!sectorAggs[sector]) sectorAggs[sector] = { metrics: {}, counts: {} };
|
|
@@ -152,11 +164,14 @@ class CorePriceMetrics {
|
|
|
152
164
|
by_sector[sector][`average_${key}`] = count > 0 ? sectorAggs[sector].metrics[key] / count : null;
|
|
153
165
|
}
|
|
154
166
|
}
|
|
155
|
-
|
|
156
|
-
this.result =
|
|
167
|
+
|
|
168
|
+
this.result.by_sector = by_sector;
|
|
169
|
+
return this.result;
|
|
157
170
|
}
|
|
158
171
|
|
|
159
|
-
|
|
160
|
-
|
|
172
|
+
reset() {
|
|
173
|
+
this.result = { by_instrument: {}, by_sector: {} };
|
|
174
|
+
this.mappings = null;
|
|
175
|
+
}
|
|
161
176
|
}
|
|
162
177
|
module.exports = CorePriceMetrics;
|