aiden-shared-calculations-unified 1.0.101 → 1.0.103

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.
@@ -11,6 +11,7 @@ class AssetCostBasisProfile {
11
11
  this.tickerMap = null;
12
12
  // Store function pointer to avoid serialization issues
13
13
  this.computeKDE_func = null;
14
+ this.updateforce = null;
14
15
  }
15
16
 
16
17
  static getMetadata() {
@@ -0,0 +1,72 @@
1
+ class CrowdCostBasis {
2
+ constructor() {
3
+ this.results = {};
4
+ }
5
+
6
+ static getMetadata() {
7
+ return {
8
+ name: 'crowd-cost-basis',
9
+ type: 'meta',
10
+ category: 'History Reconstruction',
11
+ userType: 'n/a', // <--- Works on dependency results
12
+ isHistorical: false,
13
+ rootDataDependencies: ['price']
14
+ };
15
+ }
16
+
17
+ static getDependencies() {
18
+ return ['user-history-reconstructor'];
19
+ }
20
+
21
+ async process(context) {
22
+ const { computed, prices, math } = context;
23
+
24
+ // 1. Access the output of the Standard calculation
25
+ const userReconstructions = computed['user-history-reconstructor'];
26
+ if (!userReconstructions) return;
27
+
28
+ const aggregator = {}; // { AAPL: { sumEntry: 0, count: 0 } }
29
+
30
+ // 2. Iterate over all users' reconstructed states
31
+ for (const userId in userReconstructions) {
32
+ const userPortfolio = userReconstructions[userId];
33
+
34
+ for (const ticker in userPortfolio) {
35
+ const position = userPortfolio[ticker];
36
+
37
+ if (!aggregator[ticker]) aggregator[ticker] = { sumEntry: 0, count: 0 };
38
+
39
+ // Aggregating global average entry
40
+ aggregator[ticker].sumEntry += position.avgEntry;
41
+ aggregator[ticker].count++;
42
+ }
43
+ }
44
+
45
+ // 3. Compute Global Average vs Current Price
46
+ for (const ticker in aggregator) {
47
+ const data = aggregator[ticker];
48
+ if (data.count < 10) continue; // Noise filter
49
+
50
+ const globalAvgEntry = data.sumEntry / data.count;
51
+
52
+ // Get today's closing price
53
+ const priceHistory = math.priceExtractor.getHistory(prices, ticker);
54
+ // The last item in price history for this context is "Today"
55
+ const lastPriceObj = priceHistory[priceHistory.length - 1];
56
+ const currentPrice = lastPriceObj ? lastPriceObj.price : globalAvgEntry;
57
+
58
+ const diffPct = ((currentPrice - globalAvgEntry) / globalAvgEntry) * 100;
59
+
60
+ this.results[ticker] = {
61
+ avgEntry: globalAvgEntry,
62
+ holderCount: data.count,
63
+ profitabilityPct: diffPct,
64
+ state: diffPct > 0 ? 'PROFIT_SUPPORT' : 'LOSS_RESISTANCE'
65
+ };
66
+ }
67
+ }
68
+
69
+ async getResult() { return this.results; }
70
+ }
71
+
72
+ module.exports = CrowdCostBasis;
@@ -0,0 +1,78 @@
1
+ class LeverageDivergence {
2
+ constructor() { this.results = {}; }
3
+
4
+ static getMetadata() {
5
+ return {
6
+ name: 'leverage-divergence',
7
+ type: 'meta',
8
+ category: 'History Reconstruction',
9
+ userType: 'n/a',
10
+ isHistorical: true, // <--- Needs yesterday's result
11
+ rootDataDependencies: []
12
+ };
13
+ }
14
+
15
+ static getDependencies() {
16
+ return ['user-history-reconstructor'];
17
+ }
18
+
19
+ async process(context) {
20
+ const { computed, previousComputed } = context;
21
+
22
+ const currentReconstruction = computed['user-history-reconstructor'];
23
+ // Access SELF from yesterday
24
+ const previousResult = previousComputed['leverage-divergence'];
25
+
26
+ const currentAgg = {}; // { AAPL: { levHolders: 0, spotHolders: 0 } }
27
+
28
+ // 1. Build Today's Aggregates
29
+ for (const userId in currentReconstruction) {
30
+ const userPortfolio = currentReconstruction[userId];
31
+ for (const ticker in userPortfolio) {
32
+ const pos = userPortfolio[ticker];
33
+
34
+ if (!currentAgg[ticker]) currentAgg[ticker] = { levHolders: 0, spotHolders: 0 };
35
+
36
+ // If avg leverage > 1.1, count as "Leveraged Holder"
37
+ if (pos.avgLeverage > 1.1) {
38
+ currentAgg[ticker].levHolders++;
39
+ } else {
40
+ currentAgg[ticker].spotHolders++;
41
+ }
42
+ }
43
+ }
44
+
45
+ // 2. Compare with Yesterday
46
+ for (const ticker in currentAgg) {
47
+ const curr = currentAgg[ticker];
48
+ const prev = previousResult ? previousResult[ticker] : null;
49
+
50
+ if (!prev) {
51
+ this.results[ticker] = { ...curr, levDelta: 0, spotDelta: 0, signal: 'NEW' };
52
+ continue;
53
+ }
54
+
55
+ const levDelta = curr.levHolders - prev.levHolders;
56
+ const spotDelta = curr.spotHolders - prev.spotHolders;
57
+
58
+ let signal = 'NEUTRAL';
59
+
60
+ // Retail (Spot) Buying + Speculators (Lev) Selling = Smart Money Exit
61
+ if (spotDelta > 0 && levDelta < 0) signal = 'SMART_EXIT';
62
+
63
+ // Retail (Spot) Selling + Speculators (Lev) Buying = High Conviction Pump
64
+ if (spotDelta < 0 && levDelta > 0) signal = 'SPECULATIVE_PUMP';
65
+
66
+ this.results[ticker] = {
67
+ ...curr,
68
+ levDelta,
69
+ spotDelta,
70
+ signal
71
+ };
72
+ }
73
+ }
74
+
75
+ async getResult() { return this.results; }
76
+ }
77
+
78
+ module.exports = LeverageDivergence;
@@ -0,0 +1,61 @@
1
+ class LiquidationCascade {
2
+ constructor() { this.results = {}; }
3
+
4
+ static getMetadata() {
5
+ return {
6
+ name: 'liquidation-cascade',
7
+ type: 'meta',
8
+ category: 'History Reconstruction',
9
+ userType: 'n/a',
10
+ isHistorical: false,
11
+ rootDataDependencies: []
12
+ };
13
+ }
14
+
15
+ static getDependencies() {
16
+ return ['user-history-reconstructor'];
17
+ }
18
+
19
+ async process(context) {
20
+ const { computed } = context;
21
+ const userReconstructions = computed['user-history-reconstructor'];
22
+ if (!userReconstructions) return;
23
+
24
+ const aggregator = {};
25
+
26
+ // 1. Aggregate Forced Exits
27
+ for (const userId in userReconstructions) {
28
+ const userPortfolio = userReconstructions[userId];
29
+
30
+ for (const ticker in userPortfolio) {
31
+ const position = userPortfolio[ticker];
32
+
33
+ if (position.closedToday > 0) {
34
+ if (!aggregator[ticker]) aggregator[ticker] = { closed: 0, forced: 0 };
35
+
36
+ aggregator[ticker].closed += position.closedToday;
37
+ aggregator[ticker].forced += position.forcedExits;
38
+ }
39
+ }
40
+ }
41
+
42
+ // 2. Calculate Pain Index
43
+ for (const ticker in aggregator) {
44
+ const data = aggregator[ticker];
45
+ if (data.closed < 5) continue;
46
+
47
+ const forcedRatio = data.forced / data.closed;
48
+
49
+ this.results[ticker] = {
50
+ totalClosures: data.closed,
51
+ forcedClosures: data.forced,
52
+ painIndex: forcedRatio, // 0.0 to 1.0
53
+ isFlushEvent: forcedRatio > 0.3 // Flag if >30% of selling was forced
54
+ };
55
+ }
56
+ }
57
+
58
+ async getResult() { return this.results; }
59
+ }
60
+
61
+ module.exports = LiquidationCascade;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @fileoverview Reconstructs a user's portfolio state for a specific date from their trade history.
3
+ * Acts as the "Map" phase for downstream Meta aggregations.
4
+ */
5
+ class UserHistoryReconstructor {
6
+ constructor() {
7
+ this.results = {}; // Output: { "user_id": { "AAPL": { ...stats... } } }
8
+ }
9
+
10
+ static getMetadata() {
11
+ return {
12
+ name: 'user-history-reconstructor',
13
+ type: 'standard',
14
+ category: 'History Reconstruction', // <--- Specific Category
15
+ userType: 'all', // <--- Processes User Data
16
+ isHistorical: false,
17
+ rootDataDependencies: ['history']
18
+ };
19
+ }
20
+
21
+ static getDependencies() { return []; }
22
+
23
+ static getSchema() {
24
+ return {
25
+ "USER_ID": {
26
+ "TICKER": {
27
+ "activeCount": 1,
28
+ "avgEntry": 0.0,
29
+ "avgLeverage": 1.0,
30
+ "closedToday": 0,
31
+ "forcedExits": 0
32
+ }
33
+ }
34
+ };
35
+ }
36
+
37
+ async process(context) {
38
+ const { user, math, mappings, date } = context;
39
+
40
+ // 1. Get History
41
+ const history = math.history.getDailyHistory(user);
42
+ const allTrades = history?.PublicHistoryPositions || [];
43
+
44
+ if (allTrades.length === 0) return;
45
+
46
+ // 2. Filter for Active Trades on this Date
47
+ const activeTrades = math.history.getActiveTradesForDate(allTrades, date.today);
48
+ if (activeTrades.length === 0) return;
49
+
50
+ // 3. Initialize User State
51
+ this.results[user.id] = {};
52
+ const userState = this.results[user.id];
53
+
54
+ const dayStart = new Date(date.today + "T00:00:00.000Z").getTime();
55
+ const dayEnd = new Date(date.today + "T23:59:59.999Z").getTime();
56
+
57
+ for (const trade of activeTrades) {
58
+ const instId = trade.InstrumentID;
59
+ const ticker = mappings.instrumentToTicker[instId];
60
+ if (!ticker) continue;
61
+
62
+ if (!userState[ticker]) {
63
+ userState[ticker] = {
64
+ activeCount: 0,
65
+ totalEntry: 0,
66
+ totalLev: 0,
67
+ closedToday: 0,
68
+ forcedExits: 0
69
+ };
70
+ }
71
+
72
+ const stats = userState[ticker];
73
+
74
+ // Accumulate Holding State
75
+ stats.activeCount++;
76
+ stats.totalEntry += (trade.OpenRate || 0);
77
+ stats.totalLev += (trade.Leverage || 1);
78
+
79
+ // Check for Closure Events happening TODAY
80
+ if (trade.CloseDateTime) {
81
+ const closeTime = new Date(trade.CloseDateTime).getTime();
82
+ if (closeTime >= dayStart && closeTime <= dayEnd) {
83
+ stats.closedToday++;
84
+ // CloseReason: 1 = Stop Loss, 5 = Take Profit, 0 = Manual
85
+ if (trade.CloseReason === 1) stats.forcedExits++;
86
+ }
87
+ }
88
+ }
89
+
90
+ // 4. Finalize Averages for this User
91
+ for (const ticker in userState) {
92
+ const stats = userState[ticker];
93
+ if (stats.activeCount > 0) {
94
+ stats.avgEntry = stats.totalEntry / stats.activeCount;
95
+ stats.avgLeverage = stats.totalLev / stats.activeCount;
96
+ }
97
+ // Cleanup intermediate sums
98
+ delete stats.totalEntry;
99
+ delete stats.totalLev;
100
+ }
101
+ }
102
+
103
+ async getResult() {
104
+ return this.results;
105
+ }
106
+ }
107
+
108
+ module.exports = UserHistoryReconstructor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiden-shared-calculations-unified",
3
- "version": "1.0.101",
3
+ "version": "1.0.103",
4
4
  "description": "Shared calculation modules for the BullTrackers Computation System.",
5
5
  "main": "index.js",
6
6
  "files": [
File without changes