aiden-shared-calculations-unified 1.0.98 → 1.0.100
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/capitulation/asset-volatility-estimator.js +9 -20
- package/calculations/core/Insights-total-long-per-stock.js +27 -45
- package/calculations/core/asset-pnl-status.js +7 -19
- package/calculations/core/insights-daily-bought-vs-sold-count.js +30 -5
- package/calculations/core/insights-daily-ownership-delta.js +31 -5
- package/calculations/core/insights-sentimet-per-stock.js +33 -6
- package/calculations/core/insights-total-long-per-sector.js +3 -8
- package/calculations/core/insights-total-positions-held.js +25 -4
- package/calculations/ghost-book/cost-basis-density.js +7 -19
- package/calculations/ghost-book/liquidity-vacuum.js +4 -5
- package/calculations/ghost-book/retail-gamma-exposure.js +5 -9
- package/calculations/predicative-alpha/cognitive-dissonance.js +10 -16
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview CORE Product Line (Pass 1 - Meta)
|
|
3
3
|
* Calculates annualized volatility.
|
|
4
|
-
*
|
|
4
|
+
* Clean: System automatically handles sharding for large result sets.
|
|
5
5
|
*/
|
|
6
6
|
class AssetVolatilityEstimator {
|
|
7
7
|
constructor() {
|
|
@@ -37,16 +37,10 @@ class AssetVolatilityEstimator {
|
|
|
37
37
|
const { compute, priceExtractor } = math;
|
|
38
38
|
|
|
39
39
|
if (!prices || !prices.history) return;
|
|
40
|
-
|
|
41
|
-
// Efficiently extract only histories present in this shard/context
|
|
42
40
|
const allHistories = priceExtractor.getAllHistories(prices);
|
|
43
41
|
|
|
44
|
-
const batchResult = {};
|
|
45
|
-
|
|
46
42
|
for (const [key, candles] of allHistories.entries()) {
|
|
47
43
|
let ticker = key;
|
|
48
|
-
|
|
49
|
-
// Resolve ticker logic
|
|
50
44
|
if (prices.history[key] && prices.history[key].instrumentId) {
|
|
51
45
|
const instId = prices.history[key].instrumentId;
|
|
52
46
|
if (mappings && mappings.instrumentToTicker && mappings.instrumentToTicker[instId]) {
|
|
@@ -54,7 +48,6 @@ class AssetVolatilityEstimator {
|
|
|
54
48
|
}
|
|
55
49
|
}
|
|
56
50
|
|
|
57
|
-
// Guard: Need enough data for a trend
|
|
58
51
|
if (!candles || candles.length < 10) continue;
|
|
59
52
|
|
|
60
53
|
const logReturns = [];
|
|
@@ -63,36 +56,32 @@ class AssetVolatilityEstimator {
|
|
|
63
56
|
for (let i = 1; i < candles.length; i++) {
|
|
64
57
|
const prev = candles[i-1].price;
|
|
65
58
|
const curr = candles[i].price;
|
|
66
|
-
|
|
67
|
-
// Guard: Prevent log(0) or log(negative) errors
|
|
68
59
|
if (prev > 0 && curr > 0) {
|
|
69
60
|
logReturns.push(Math.log(curr / prev));
|
|
70
61
|
lastPrice = curr;
|
|
71
62
|
}
|
|
72
63
|
}
|
|
73
64
|
|
|
74
|
-
const
|
|
75
|
-
const relevantReturns = logReturns.slice(-LOOKBACK);
|
|
76
|
-
|
|
77
|
-
// Guard: Need enough returns for Standard Deviation
|
|
65
|
+
const relevantReturns = logReturns.slice(-30);
|
|
78
66
|
if (relevantReturns.length < 5) continue;
|
|
79
67
|
|
|
80
68
|
const stdDev = compute.standardDeviation(relevantReturns);
|
|
81
69
|
const annualizedVol = stdDev * Math.sqrt(365);
|
|
82
70
|
|
|
83
|
-
|
|
71
|
+
this.result[ticker] = {
|
|
84
72
|
volatility_30d: Number(annualizedVol.toFixed(4)),
|
|
85
73
|
last_price: lastPrice,
|
|
86
74
|
data_points: relevantReturns.length
|
|
87
75
|
};
|
|
88
76
|
}
|
|
89
|
-
|
|
90
|
-
// Accumulate results (handling batched execution)
|
|
91
|
-
Object.assign(this.result, batchResult);
|
|
92
77
|
}
|
|
93
78
|
|
|
94
|
-
async getResult() {
|
|
79
|
+
async getResult() {
|
|
80
|
+
// No manual sharding needed.
|
|
81
|
+
// If this object > 1MB, the system auto-shards it.
|
|
82
|
+
return this.result;
|
|
83
|
+
}
|
|
84
|
+
|
|
95
85
|
reset() { this.result = {}; }
|
|
96
86
|
}
|
|
97
|
-
|
|
98
87
|
module.exports = AssetVolatilityEstimator;
|
|
@@ -1,56 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
class InsightsTotalPositionsHeld {
|
|
2
|
+
constructor() { this.totalPositions = 0; }
|
|
3
|
+
|
|
4
|
+
static getMetadata() {
|
|
5
|
+
return {
|
|
6
|
+
type: 'meta',
|
|
7
|
+
rootDataDependencies: ['insights'],
|
|
8
|
+
isHistorical: false,
|
|
9
|
+
userType: 'n/a',
|
|
10
|
+
category: 'Global-Platform-Metrics'
|
|
11
|
+
};
|
|
9
12
|
}
|
|
10
|
-
|
|
11
|
-
static getMetadata() {
|
|
12
|
-
return {
|
|
13
|
-
type: 'meta',
|
|
14
|
-
rootDataDependencies: ['insights'],
|
|
15
|
-
isHistorical: false,
|
|
16
|
-
category: 'core_sentiment'
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
13
|
+
|
|
20
14
|
static getDependencies() { return []; }
|
|
21
|
-
|
|
22
|
-
static getSchema() {
|
|
23
|
-
return {
|
|
24
|
-
"type": "object",
|
|
25
|
-
"properties": {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
"required": ["total_long_exposure_weight", "total_positions_count"]
|
|
30
|
-
};
|
|
15
|
+
|
|
16
|
+
static getSchema() {
|
|
17
|
+
return {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": { "total_positions_count": { "type": "number" } },
|
|
20
|
+
"required": ["total_positions_count"]
|
|
21
|
+
};
|
|
31
22
|
}
|
|
32
|
-
|
|
23
|
+
|
|
33
24
|
process(context) {
|
|
34
25
|
const { insights: insightsHelper } = context.math;
|
|
35
|
-
const insights = insightsHelper.getInsights(context);
|
|
26
|
+
const insights = insightsHelper.getInsights(context); // FIXED: Direct call
|
|
36
27
|
|
|
37
|
-
if (
|
|
28
|
+
if (insights.length === 0) return;
|
|
38
29
|
|
|
39
30
|
for (const insight of insights) {
|
|
40
|
-
this.totalPositions += insightsHelper.
|
|
31
|
+
this.totalPositions += insightsHelper.getTotalOwners(insight);
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
|
-
|
|
44
|
-
getResult() {
|
|
45
|
-
|
|
46
|
-
total_long_exposure_weight: 0, // Not available in Insights
|
|
47
|
-
total_positions_count: this.totalPositions
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
reset() {
|
|
52
|
-
this.totalPositions = 0;
|
|
53
|
-
}
|
|
34
|
+
|
|
35
|
+
getResult() { return { total_positions_count: this.totalPositions }; }
|
|
36
|
+
reset() { this.totalPositions = 0; }
|
|
54
37
|
}
|
|
55
|
-
|
|
56
|
-
module.exports = InsightsTotalLongFigures;
|
|
38
|
+
module.exports = InsightsTotalPositionsHeld;
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Core Metric (Pass 2)
|
|
3
|
-
*
|
|
4
|
-
* - Pivots data to be User-Centric (User -> Winners/Losers).
|
|
5
|
-
* - Removes sharding complexity (fits within 1MB via structure optimization).
|
|
3
|
+
* Clean: System automatically handles sharding (e.g. 20k users).
|
|
6
4
|
*/
|
|
7
5
|
class AssetPnlStatus {
|
|
8
6
|
constructor() {
|
|
9
|
-
// Map<UserId, { winners: Set<String>, losers: Set<String> }>
|
|
10
7
|
this.userStats = new Map();
|
|
11
8
|
}
|
|
12
9
|
|
|
@@ -28,9 +25,8 @@ class AssetPnlStatus {
|
|
|
28
25
|
"properties": {
|
|
29
26
|
"by_user": {
|
|
30
27
|
"type": "object",
|
|
31
|
-
"description": "Map of User IDs to their winning/losing assets and sectors.",
|
|
32
28
|
"patternProperties": {
|
|
33
|
-
"^[0-9]+$": {
|
|
29
|
+
"^[0-9]+$": {
|
|
34
30
|
"type": "object",
|
|
35
31
|
"properties": {
|
|
36
32
|
"winners": { "type": "array", "items": { "type": "string" } },
|
|
@@ -56,11 +52,9 @@ class AssetPnlStatus {
|
|
|
56
52
|
const { mappings, user } = context;
|
|
57
53
|
const userId = user.id;
|
|
58
54
|
|
|
59
|
-
// 1. Get Positions using the standard extractor
|
|
60
55
|
const positions = extract.getPositions(user.portfolio.today, user.type);
|
|
61
56
|
if (!positions || positions.length === 0) return;
|
|
62
57
|
|
|
63
|
-
// 2. Lazy init stats only if needed
|
|
64
58
|
let stats = null;
|
|
65
59
|
|
|
66
60
|
for (const pos of positions) {
|
|
@@ -68,7 +62,7 @@ class AssetPnlStatus {
|
|
|
68
62
|
if (!instId) continue;
|
|
69
63
|
|
|
70
64
|
const pnl = extract.getNetProfit(pos);
|
|
71
|
-
if (pnl === 0) continue;
|
|
65
|
+
if (pnl === 0) continue;
|
|
72
66
|
|
|
73
67
|
const ticker = mappings.instrumentToTicker[instId];
|
|
74
68
|
const sector = mappings.instrumentToSector[instId];
|
|
@@ -76,15 +70,11 @@ class AssetPnlStatus {
|
|
|
76
70
|
|
|
77
71
|
if (ticker || sector) {
|
|
78
72
|
if (!stats) stats = this._initUser(userId);
|
|
79
|
-
|
|
80
73
|
if (ticker) {
|
|
81
|
-
if (isWinner) stats.winners.add(ticker);
|
|
82
|
-
else stats.losers.add(ticker);
|
|
74
|
+
if (isWinner) stats.winners.add(ticker); else stats.losers.add(ticker);
|
|
83
75
|
}
|
|
84
|
-
|
|
85
76
|
if (sector) {
|
|
86
|
-
if (isWinner) stats.winners.add(sector);
|
|
87
|
-
else stats.losers.add(sector);
|
|
77
|
+
if (isWinner) stats.winners.add(sector); else stats.losers.add(sector);
|
|
88
78
|
}
|
|
89
79
|
}
|
|
90
80
|
}
|
|
@@ -94,7 +84,6 @@ class AssetPnlStatus {
|
|
|
94
84
|
const byUser = {};
|
|
95
85
|
|
|
96
86
|
for (const [userId, stats] of this.userStats) {
|
|
97
|
-
// Only include users who actually have relevant P&L data
|
|
98
87
|
if (stats.winners.size > 0 || stats.losers.size > 0) {
|
|
99
88
|
byUser[userId] = {
|
|
100
89
|
winners: Array.from(stats.winners),
|
|
@@ -103,12 +92,11 @@ class AssetPnlStatus {
|
|
|
103
92
|
}
|
|
104
93
|
}
|
|
105
94
|
|
|
95
|
+
// Return flat object. Orchestrator handles 1MB limit.
|
|
106
96
|
return { by_user: byUser };
|
|
107
97
|
}
|
|
108
98
|
|
|
109
|
-
reset() {
|
|
110
|
-
this.userStats.clear();
|
|
111
|
-
}
|
|
99
|
+
reset() { this.userStats.clear(); }
|
|
112
100
|
}
|
|
113
101
|
|
|
114
102
|
module.exports = AssetPnlStatus;
|
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
class InsightsDailyBoughtVsSoldCount {
|
|
2
2
|
constructor() { this.results = {}; }
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
static getMetadata() {
|
|
5
|
+
return {
|
|
6
|
+
type: 'meta',
|
|
7
|
+
rootDataDependencies: ['insights'],
|
|
8
|
+
isHistorical: true,
|
|
9
|
+
userType: 'n/a',
|
|
10
|
+
category: 'core_metrics'
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
4
14
|
static getDependencies() { return []; }
|
|
15
|
+
|
|
5
16
|
static getSchema() {
|
|
6
|
-
const tickerSchema = {
|
|
17
|
+
const tickerSchema = {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"positions_bought": { "type": "number" },
|
|
21
|
+
"positions_sold": { "type": "number" },
|
|
22
|
+
"net_change": { "type": "number" }
|
|
23
|
+
},
|
|
24
|
+
"required": ["positions_bought", "positions_sold", "net_change"]
|
|
25
|
+
};
|
|
7
26
|
return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
|
|
8
27
|
}
|
|
28
|
+
|
|
9
29
|
process(context) {
|
|
10
30
|
const { insights: insightsHelper } = context.math;
|
|
11
|
-
const insights = insightsHelper.getInsights(context);
|
|
31
|
+
const insights = insightsHelper.getInsights(context); // FIXED: Direct call
|
|
12
32
|
const { mappings } = context;
|
|
13
33
|
const tickerMap = mappings.instrumentToTicker || {};
|
|
14
34
|
|
|
15
|
-
if (
|
|
35
|
+
if (insights.length === 0) return;
|
|
16
36
|
|
|
17
37
|
for (const insight of insights) {
|
|
18
38
|
const instId = insight.instrumentId;
|
|
@@ -22,10 +42,15 @@ class InsightsDailyBoughtVsSoldCount {
|
|
|
22
42
|
const sold = netChange < 0 ? Math.abs(netChange) : 0;
|
|
23
43
|
|
|
24
44
|
if (bought > 0 || sold > 0) {
|
|
25
|
-
this.results[ticker] = {
|
|
45
|
+
this.results[ticker] = {
|
|
46
|
+
positions_bought: bought,
|
|
47
|
+
positions_sold: sold,
|
|
48
|
+
net_change: netChange
|
|
49
|
+
};
|
|
26
50
|
}
|
|
27
51
|
}
|
|
28
52
|
}
|
|
53
|
+
|
|
29
54
|
async getResult() { return this.results; }
|
|
30
55
|
reset() { this.results = {}; }
|
|
31
56
|
}
|
|
@@ -1,30 +1,56 @@
|
|
|
1
1
|
class InsightsDailyOwnershipDelta {
|
|
2
2
|
constructor() { this.results = {}; }
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
static getMetadata() {
|
|
5
|
+
return {
|
|
6
|
+
type: 'meta',
|
|
7
|
+
rootDataDependencies: ['insights'],
|
|
8
|
+
isHistorical: true,
|
|
9
|
+
userType: 'n/a',
|
|
10
|
+
category: 'core_metrics'
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
4
14
|
static getDependencies() { return []; }
|
|
15
|
+
|
|
5
16
|
static getSchema() {
|
|
6
|
-
const tickerSchema = {
|
|
17
|
+
const tickerSchema = {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"owners_added": { "type": "number" },
|
|
21
|
+
"owners_removed": { "type": "number" },
|
|
22
|
+
"net_ownership_change": { "type": "number" }
|
|
23
|
+
},
|
|
24
|
+
"required": ["owners_added", "owners_removed", "net_ownership_change"]
|
|
25
|
+
};
|
|
7
26
|
return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
|
|
8
27
|
}
|
|
28
|
+
|
|
9
29
|
process(context) {
|
|
10
30
|
const { insights: insightsHelper } = context.math;
|
|
11
|
-
const insights = insightsHelper.getInsights(context);
|
|
31
|
+
const insights = insightsHelper.getInsights(context); // FIXED: Direct call
|
|
12
32
|
const { mappings } = context;
|
|
13
33
|
const tickerMap = mappings.instrumentToTicker || {};
|
|
14
34
|
|
|
15
|
-
if (
|
|
35
|
+
if (insights.length === 0) return;
|
|
16
36
|
|
|
17
37
|
for (const insight of insights) {
|
|
18
38
|
const netChange = insightsHelper.getNetOwnershipChange(insight);
|
|
19
39
|
if (netChange === 0) continue;
|
|
40
|
+
|
|
20
41
|
const instId = insight.instrumentId;
|
|
21
42
|
const ticker = tickerMap[instId] || `id_${instId}`;
|
|
22
43
|
const added = netChange > 0 ? netChange : 0;
|
|
23
44
|
const removed = netChange < 0 ? Math.abs(netChange) : 0;
|
|
24
45
|
|
|
25
|
-
this.results[ticker] = {
|
|
46
|
+
this.results[ticker] = {
|
|
47
|
+
owners_added: added,
|
|
48
|
+
owners_removed: removed,
|
|
49
|
+
net_ownership_change: netChange
|
|
50
|
+
};
|
|
26
51
|
}
|
|
27
52
|
}
|
|
53
|
+
|
|
28
54
|
async getResult() { return this.results; }
|
|
29
55
|
reset() { this.results = {}; }
|
|
30
56
|
}
|
|
@@ -1,30 +1,57 @@
|
|
|
1
1
|
class InsightsSentimentPerStock {
|
|
2
2
|
constructor() { this.results = {}; }
|
|
3
|
+
|
|
3
4
|
static getSchema() {
|
|
4
|
-
const tickerSchema = {
|
|
5
|
+
const tickerSchema = {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"long_count": { "type": "number" },
|
|
9
|
+
"short_count": { "type": "number" },
|
|
10
|
+
"sentiment_ratio": { "type": ["number", "null"] }
|
|
11
|
+
},
|
|
12
|
+
"required": ["long_count", "short_count", "sentiment_ratio"]
|
|
13
|
+
};
|
|
5
14
|
return { "type": "object", "patternProperties": { "^.*$": tickerSchema } };
|
|
6
15
|
}
|
|
7
|
-
|
|
16
|
+
|
|
17
|
+
static getMetadata() {
|
|
18
|
+
return {
|
|
19
|
+
type: 'meta',
|
|
20
|
+
rootDataDependencies: ['insights'],
|
|
21
|
+
isHistorical: false,
|
|
22
|
+
userType: 'n/a',
|
|
23
|
+
category: 'core_sentiment'
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
8
27
|
static getDependencies() { return []; }
|
|
28
|
+
|
|
9
29
|
process(context) {
|
|
10
30
|
const { insights: insightsHelper } = context.math;
|
|
11
|
-
const insights = insightsHelper.getInsights(context);
|
|
31
|
+
const insights = insightsHelper.getInsights(context); // FIXED: Direct call
|
|
12
32
|
const { mappings } = context;
|
|
13
33
|
const tickerMap = mappings.instrumentToTicker || {};
|
|
14
34
|
|
|
15
|
-
if (
|
|
35
|
+
if (insights.length === 0) return;
|
|
16
36
|
|
|
17
37
|
for (const insight of insights) {
|
|
18
38
|
const longCount = insightsHelper.getLongCount(insight);
|
|
19
39
|
const shortCount = insightsHelper.getShortCount(insight);
|
|
40
|
+
|
|
20
41
|
if (longCount === 0 && shortCount === 0) continue;
|
|
42
|
+
|
|
21
43
|
const instId = insight.instrumentId;
|
|
22
44
|
const ticker = tickerMap[instId] || `id_${instId}`;
|
|
23
45
|
|
|
24
|
-
this.results[ticker] = {
|
|
46
|
+
this.results[ticker] = {
|
|
47
|
+
long_count: longCount,
|
|
48
|
+
short_count: shortCount,
|
|
49
|
+
sentiment_ratio: (shortCount > 0) ? (longCount / shortCount) : null
|
|
50
|
+
};
|
|
25
51
|
}
|
|
26
52
|
}
|
|
53
|
+
|
|
27
54
|
async getResult() { return this.results; }
|
|
28
55
|
reset() { this.results = {}; }
|
|
29
56
|
}
|
|
30
|
-
module.exports = InsightsSentimentPerStock;
|
|
57
|
+
module.exports = InsightsSentimentPerStock;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Calculation (Pass 1) for long figures per sector.
|
|
3
|
-
* REFACTORED: Uses INSIGHTS DATA.
|
|
4
|
-
* TYPE: META
|
|
5
|
-
*/
|
|
6
1
|
class InsightsTotalLongPerSector {
|
|
7
2
|
constructor() {
|
|
8
3
|
this.sectorData = new Map();
|
|
@@ -13,6 +8,7 @@ class InsightsTotalLongPerSector {
|
|
|
13
8
|
type: 'meta',
|
|
14
9
|
rootDataDependencies: ['insights'],
|
|
15
10
|
isHistorical: false,
|
|
11
|
+
userType: 'n/a',
|
|
16
12
|
category: 'core_sentiment'
|
|
17
13
|
};
|
|
18
14
|
}
|
|
@@ -33,11 +29,11 @@ class InsightsTotalLongPerSector {
|
|
|
33
29
|
|
|
34
30
|
process(context) {
|
|
35
31
|
const { insights: insightsHelper } = context.math;
|
|
36
|
-
const insights = insightsHelper.getInsights(context);
|
|
32
|
+
const insights = insightsHelper.getInsights(context); // FIXED: Direct call
|
|
37
33
|
const { mappings } = context;
|
|
38
34
|
const sectorMap = mappings.instrumentToSector || {};
|
|
39
35
|
|
|
40
|
-
if (
|
|
36
|
+
if (insights.length === 0) return;
|
|
41
37
|
|
|
42
38
|
for (const insight of insights) {
|
|
43
39
|
const longCount = insightsHelper.getLongCount(insight);
|
|
@@ -58,7 +54,6 @@ class InsightsTotalLongPerSector {
|
|
|
58
54
|
for (const [sector, data] of this.sectorData.entries()) {
|
|
59
55
|
if (data.count > 0) {
|
|
60
56
|
result[sector] = {
|
|
61
|
-
total_long_exposure_weight: 0, // Not available
|
|
62
57
|
total_positions_count: data.count
|
|
63
58
|
};
|
|
64
59
|
}
|
|
@@ -1,18 +1,39 @@
|
|
|
1
1
|
class InsightsTotalPositionsHeld {
|
|
2
2
|
constructor() { this.totalPositions = 0; }
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
static getMetadata() {
|
|
5
|
+
return {
|
|
6
|
+
type: 'meta',
|
|
7
|
+
rootDataDependencies: ['insights'],
|
|
8
|
+
isHistorical: false,
|
|
9
|
+
userType: 'n/a',
|
|
10
|
+
category: 'Global-Platform-Metrics'
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
4
14
|
static getDependencies() { return []; }
|
|
5
|
-
|
|
15
|
+
|
|
16
|
+
static getSchema() {
|
|
17
|
+
return {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": { "total_positions_count": { "type": "number" } },
|
|
20
|
+
"required": ["total_positions_count"]
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
6
24
|
process(context) {
|
|
7
25
|
const { insights: insightsHelper } = context.math;
|
|
8
|
-
const
|
|
26
|
+
const rawInsights = insightsHelper.getInsights(context);
|
|
27
|
+
|
|
28
|
+
const insights = insightsHelper.getInsights(context); // FIXED: Direct call
|
|
9
29
|
|
|
10
|
-
if (
|
|
30
|
+
if (insights.length === 0) return;
|
|
11
31
|
|
|
12
32
|
for (const insight of insights) {
|
|
13
33
|
this.totalPositions += insightsHelper.getTotalOwners(insight);
|
|
14
34
|
}
|
|
15
35
|
}
|
|
36
|
+
|
|
16
37
|
getResult() { return { total_positions_count: this.totalPositions }; }
|
|
17
38
|
reset() { this.totalPositions = 0; }
|
|
18
39
|
}
|
|
@@ -8,7 +8,10 @@ class CostBasisDensity {
|
|
|
8
8
|
static getMetadata() {
|
|
9
9
|
return {
|
|
10
10
|
type: 'meta', // Runs ONCE per day
|
|
11
|
-
dependencies: ['asset-cost-basis-profile']
|
|
11
|
+
dependencies: ['asset-cost-basis-profile'],
|
|
12
|
+
userType: 'n/a', // FIXED: Added missing field
|
|
13
|
+
isHistorical: false, // FIXED: Explicitly defined
|
|
14
|
+
category: 'ghost_book'
|
|
12
15
|
};
|
|
13
16
|
}
|
|
14
17
|
|
|
@@ -34,37 +37,30 @@ class CostBasisDensity {
|
|
|
34
37
|
const { computed, math } = context;
|
|
35
38
|
const { signals: SignalPrimitives } = math;
|
|
36
39
|
|
|
37
|
-
// 1. Get Union of Tickers (Safe Iteration)
|
|
38
40
|
const tickers = SignalPrimitives.getUnionKeys(computed, ['asset-cost-basis-profile']);
|
|
39
41
|
|
|
40
42
|
for (const ticker of tickers) {
|
|
41
|
-
// 2. Safe Data Access
|
|
42
43
|
const data = computed['asset-cost-basis-profile'][ticker];
|
|
43
44
|
|
|
44
|
-
// Check for 'profile' specifically as it contains the density curve
|
|
45
45
|
if (!data || !Array.isArray(data.profile) || data.profile.length < 3) {
|
|
46
46
|
continue;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const profile = data.profile;
|
|
49
|
+
const profile = data.profile;
|
|
50
50
|
const currentPrice = data.current_price;
|
|
51
51
|
|
|
52
52
|
const resistance = [];
|
|
53
53
|
const support = [];
|
|
54
54
|
let maxDensity = 0;
|
|
55
55
|
|
|
56
|
-
// 3. Peak Detection Algorithm
|
|
57
|
-
// Iterate through the KDE curve to find local maxima
|
|
58
56
|
for (let i = 1; i < profile.length - 1; i++) {
|
|
59
57
|
const prev = profile[i-1].density;
|
|
60
58
|
const curr = profile[i].density;
|
|
61
59
|
const next = profile[i+1].density;
|
|
62
60
|
|
|
63
|
-
// Simple Peak Check
|
|
64
61
|
if (curr > prev && curr > next) {
|
|
65
62
|
const priceVal = Number(profile[i].price.toFixed(2));
|
|
66
63
|
|
|
67
|
-
// Classify as Resistance (Overhead Supply) or Support (Underlying Demand)
|
|
68
64
|
if (profile[i].price > currentPrice) {
|
|
69
65
|
resistance.push(priceVal);
|
|
70
66
|
} else {
|
|
@@ -75,20 +71,12 @@ class CostBasisDensity {
|
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
73
|
|
|
78
|
-
// 4. Sort Walls by proximity to current price?
|
|
79
|
-
// Currently slice(0,3) takes the first found, which are lower prices in a sorted KDE.
|
|
80
|
-
// Support: We want HIGHEST prices below current (closest to current).
|
|
81
|
-
// Resistance: We want LOWEST prices above current (closest to current).
|
|
82
|
-
|
|
83
|
-
// Sort Descending (Highest Price First)
|
|
84
74
|
support.sort((a, b) => b - a);
|
|
85
|
-
|
|
86
|
-
// Sort Ascending (Lowest Price First)
|
|
87
75
|
resistance.sort((a, b) => a - b);
|
|
88
76
|
|
|
89
77
|
this.walls[ticker] = {
|
|
90
|
-
resistance_zones: resistance.slice(0, 3),
|
|
91
|
-
support_zones: support.slice(0, 3),
|
|
78
|
+
resistance_zones: resistance.slice(0, 3),
|
|
79
|
+
support_zones: support.slice(0, 3),
|
|
92
80
|
nearest_wall_strength: Number(maxDensity.toFixed(4))
|
|
93
81
|
};
|
|
94
82
|
}
|
|
@@ -4,7 +4,10 @@ class LiquidityVacuum {
|
|
|
4
4
|
static getMetadata() {
|
|
5
5
|
return {
|
|
6
6
|
type: 'meta',
|
|
7
|
-
dependencies: ['asset-cost-basis-profile']
|
|
7
|
+
dependencies: ['asset-cost-basis-profile'],
|
|
8
|
+
userType: 'n/a', // FIXED: Added missing field
|
|
9
|
+
isHistorical: false, // FIXED: Explicitly defined
|
|
10
|
+
category: 'ghost_book'
|
|
8
11
|
};
|
|
9
12
|
}
|
|
10
13
|
|
|
@@ -22,16 +25,12 @@ class LiquidityVacuum {
|
|
|
22
25
|
|
|
23
26
|
for (const ticker of tickers) {
|
|
24
27
|
const data = computed['asset-cost-basis-profile'][ticker];
|
|
25
|
-
// BUG FIX: Ensure data and profile exist before accessing length/integration
|
|
26
28
|
if (!data || !data.profile || !Array.isArray(data.profile)) continue;
|
|
27
29
|
|
|
28
30
|
const current = data.current_price;
|
|
29
31
|
const totalInv = data.total_inventory_weight;
|
|
30
32
|
|
|
31
|
-
// Integrate Danger Zone (0% to -5% drop)
|
|
32
33
|
const riskVol = distribution.integrateProfile(data.profile, current * 0.95, current);
|
|
33
|
-
|
|
34
|
-
// Ratio: At-Risk Inventory / Total Inventory
|
|
35
34
|
const ratio = (totalInv > 0) ? (riskVol / totalInv) * 10 : 0;
|
|
36
35
|
|
|
37
36
|
let status = "STABLE";
|
|
@@ -10,6 +10,8 @@ class RetailGammaExposure {
|
|
|
10
10
|
type: 'meta',
|
|
11
11
|
dependencies: ['skilled-cohort-flow', 'instrument-price-change-1d'],
|
|
12
12
|
isHistorical: true, // Requires t-1, t-2... for rolling regression
|
|
13
|
+
userType: 'n/a', // FIXED: Added missing field
|
|
14
|
+
category: 'ghost_book'
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -33,20 +35,16 @@ class RetailGammaExposure {
|
|
|
33
35
|
|
|
34
36
|
process(context) {
|
|
35
37
|
const { computed, previousComputed, math } = context;
|
|
36
|
-
// FIX: Destructure correct keys from context.math
|
|
37
|
-
// 'signals' maps to SignalPrimitives, 'distribution' maps to DistributionAnalytics
|
|
38
38
|
const { signals, distribution } = math;
|
|
39
39
|
|
|
40
40
|
const tickers = signals.getUnionKeys(computed, ['skilled-cohort-flow']);
|
|
41
41
|
|
|
42
42
|
for (const ticker of tickers) {
|
|
43
|
-
// 1. Inputs
|
|
44
43
|
const flow = signals.getMetric(computed, 'skilled-cohort-flow', ticker, 'net_flow_pct', 0);
|
|
45
44
|
const priceChange = signals.getMetric(computed, 'instrument-price-change-1d', ticker, 'change_1d_pct', 0);
|
|
46
45
|
|
|
47
|
-
// 2. State Management (Rolling Window)
|
|
48
46
|
const prevResult = signals.getPreviousState(previousComputed, 'retail-gamma-exposure', ticker);
|
|
49
|
-
const bufferSize = 14;
|
|
47
|
+
const bufferSize = 14;
|
|
50
48
|
|
|
51
49
|
let flowBuffer = prevResult?._state?.flow_buffer || [];
|
|
52
50
|
let priceBuffer = prevResult?._state?.price_buffer || [];
|
|
@@ -59,14 +57,12 @@ class RetailGammaExposure {
|
|
|
59
57
|
priceBuffer.shift();
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
// 3. Regression: Flow ~ Alpha + Beta * PriceChange
|
|
63
60
|
const regression = distribution.linearRegression(priceBuffer, flowBuffer);
|
|
64
61
|
const beta = regression.slope;
|
|
65
62
|
|
|
66
|
-
// 4. Regime Logic
|
|
67
63
|
let regime = "NEUTRAL";
|
|
68
|
-
if (beta > 0.5) regime = "ACCELERANT";
|
|
69
|
-
else if (beta < -0.5) regime = "STABILIZER";
|
|
64
|
+
if (beta > 0.5) regime = "ACCELERANT";
|
|
65
|
+
else if (beta < -0.5) regime = "STABILIZER";
|
|
70
66
|
|
|
71
67
|
this.gammaResults[ticker] = {
|
|
72
68
|
gamma_beta: Number(beta.toFixed(4)),
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Cognitive Dissonance Arbitrage (CDA) v2.2
|
|
3
|
-
*
|
|
3
|
+
* Clean: System automatically handles sharding.
|
|
4
4
|
*/
|
|
5
5
|
class CognitiveDissonance {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.cdaResults = {};
|
|
8
|
-
this.alpha = 2 / (20 + 1);
|
|
8
|
+
this.alpha = 2 / (20 + 1);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
static getMetadata() {
|
|
12
12
|
return {
|
|
13
|
-
type: 'meta',
|
|
13
|
+
type: 'meta',
|
|
14
14
|
rootDataDependencies: [],
|
|
15
|
-
isHistorical: true,
|
|
15
|
+
isHistorical: true,
|
|
16
16
|
userType: 'aggregate'
|
|
17
17
|
};
|
|
18
18
|
}
|
|
@@ -22,7 +22,6 @@ class CognitiveDissonance {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
static getSchema() {
|
|
25
|
-
// Schema remains strictly compliant with user definition
|
|
26
25
|
const metricSchema = {
|
|
27
26
|
"type": "object",
|
|
28
27
|
"properties": {
|
|
@@ -31,7 +30,7 @@ class CognitiveDissonance {
|
|
|
31
30
|
"z_sentiment": { "type": "number" },
|
|
32
31
|
"z_flow": { "type": "number" },
|
|
33
32
|
"price_confirmation": { "type": "boolean" },
|
|
34
|
-
"_state": { "type": "object" }
|
|
33
|
+
"_state": { "type": "object" }
|
|
35
34
|
}
|
|
36
35
|
};
|
|
37
36
|
return { "type": "object", "patternProperties": { "^.*$": metricSchema } };
|
|
@@ -44,28 +43,24 @@ class CognitiveDissonance {
|
|
|
44
43
|
const tickers = SignalPrimitives.getUnionKeys(computed, CognitiveDissonance.getDependencies());
|
|
45
44
|
|
|
46
45
|
for (const ticker of tickers) {
|
|
47
|
-
// 1. Get Metrics (Safe Access)
|
|
48
|
-
// MAP: 'social-topic-sentiment-matrix' uses 'net_sentiment' NOT 'sentiment_score'
|
|
49
46
|
const rawSentiment = SignalPrimitives.getMetric(computed, 'social-topic-sentiment-matrix', ticker, 'net_sentiment', 0);
|
|
50
47
|
const rawFlow = SignalPrimitives.getMetric(computed, 'skilled-cohort-flow', ticker, 'net_flow_pct', 0);
|
|
51
|
-
const priceChange = SignalPrimitives.getMetric(computed, 'instrument-price-change-1d', ticker, 'change_1d_pct', 0);
|
|
48
|
+
const priceChange = SignalPrimitives.getMetric(computed, 'instrument-price-change-1d', ticker, 'change_1d_pct', 0);
|
|
52
49
|
|
|
53
|
-
//
|
|
50
|
+
// Transparent State Access
|
|
51
|
+
// The system has already re-assembled previousComputed from shards if necessary.
|
|
54
52
|
const prevResult = SignalPrimitives.getPreviousState(previousComputed, 'cognitive-dissonance', ticker);
|
|
55
53
|
const prevState = prevResult ? prevResult._state : { sent_mean: 0, sent_var: 1, flow_mean: 0, flow_var: 1 };
|
|
56
54
|
|
|
57
|
-
// 3. Update Statistics (Math Layer)
|
|
58
55
|
const sentStats = TimeSeries.updateEMAState(rawSentiment, { mean: prevState.sent_mean, variance: prevState.sent_var }, this.alpha);
|
|
59
56
|
const flowStats = TimeSeries.updateEMAState(rawFlow, { mean: prevState.flow_mean, variance: prevState.flow_var }, this.alpha);
|
|
60
57
|
|
|
61
58
|
const sentStdDev = Math.sqrt(sentStats.variance);
|
|
62
59
|
const flowStdDev = Math.sqrt(flowStats.variance);
|
|
63
60
|
|
|
64
|
-
// 4. Compute Z-Scores
|
|
65
61
|
const zSentiment = (sentStdDev > 0.001) ? (rawSentiment - sentStats.mean) / sentStdDev : 0;
|
|
66
62
|
const zFlow = (flowStdDev > 0.001) ? (rawFlow - flowStats.mean) / flowStdDev : 0;
|
|
67
63
|
|
|
68
|
-
// 5. Logic (Voice vs Hands)
|
|
69
64
|
const interaction = zSentiment * zFlow;
|
|
70
65
|
let cdaScore = 0;
|
|
71
66
|
let regime = "NEUTRAL";
|
|
@@ -76,8 +71,7 @@ class CognitiveDissonance {
|
|
|
76
71
|
const activeHands = Math.abs(zFlow) > 0.5;
|
|
77
72
|
|
|
78
73
|
if (disagree && loudVoice && activeHands) {
|
|
79
|
-
cdaScore = -interaction;
|
|
80
|
-
|
|
74
|
+
cdaScore = -interaction;
|
|
81
75
|
const priceAgreesWithSentiment = (Math.sign(priceChange) === Math.sign(zSentiment));
|
|
82
76
|
const priceIsFlat = Math.abs(priceChange) < 0.5;
|
|
83
77
|
|
|
@@ -106,7 +100,7 @@ class CognitiveDissonance {
|
|
|
106
100
|
}
|
|
107
101
|
}
|
|
108
102
|
|
|
109
|
-
getResult() { return this.cdaResults; }
|
|
103
|
+
async getResult() { return this.cdaResults; }
|
|
110
104
|
reset() { this.cdaResults = {}; }
|
|
111
105
|
}
|
|
112
106
|
module.exports = CognitiveDissonance;
|