aiden-shared-calculations-unified 1.0.95 → 1.0.96

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.
Files changed (54) hide show
  1. package/calculations/capitulation/asset-volatility-estimator.js +1 -2
  2. package/calculations/capitulation/retail-capitulation-risk-forecast.js +1 -2
  3. package/calculations/ghost-book/cost-basis-density.js +1 -2
  4. package/calculations/ghost-book/liquidity-vacuum.js +1 -2
  5. package/calculations/ghost-book/retail-gamma-exposure.js +0 -1
  6. package/calculations/predicative-alpha/cognitive-dissonance.js +1 -2
  7. package/calculations/predicative-alpha/diamond-hand-fracture.js +1 -2
  8. package/calculations/predicative-alpha/mimetic-latency.js +1 -2
  9. package/package.json +1 -1
  10. package/calculations/legacy/activity_by_pnl_status.js +0 -119
  11. package/calculations/legacy/asset_crowd_flow.js +0 -163
  12. package/calculations/legacy/capital_deployment_strategy.js +0 -108
  13. package/calculations/legacy/capital_liquidation_performance.js +0 -139
  14. package/calculations/legacy/capital_vintage_performance.js +0 -136
  15. package/calculations/legacy/cash-flow-deployment.js +0 -144
  16. package/calculations/legacy/cash-flow-liquidation.js +0 -146
  17. package/calculations/legacy/crowd-cash-flow-proxy.js +0 -128
  18. package/calculations/legacy/crowd_conviction_score.js +0 -261
  19. package/calculations/legacy/crowd_sharpe_ratio_proxy.js +0 -137
  20. package/calculations/legacy/daily_asset_activity.js +0 -128
  21. package/calculations/legacy/daily_user_activity_tracker.js +0 -182
  22. package/calculations/legacy/deposit_withdrawal_percentage.js +0 -125
  23. package/calculations/legacy/diversification_pnl.js +0 -115
  24. package/calculations/legacy/drawdown_response.js +0 -137
  25. package/calculations/legacy/dumb-cohort-flow.js +0 -238
  26. package/calculations/legacy/gain_response.js +0 -137
  27. package/calculations/legacy/historical_performance_aggregator.js +0 -85
  28. package/calculations/legacy/in_loss_asset_crowd_flow.js +0 -168
  29. package/calculations/legacy/in_profit_asset_crowd_flow.js +0 -168
  30. package/calculations/legacy/negative_expectancy_cohort_flow.js +0 -232
  31. package/calculations/legacy/new_allocation_percentage.js +0 -98
  32. package/calculations/legacy/paper_vs_diamond_hands.js +0 -107
  33. package/calculations/legacy/position_count_pnl.js +0 -120
  34. package/calculations/legacy/positive_expectancy_cohort_flow.js +0 -232
  35. package/calculations/legacy/profit_cohort_divergence.js +0 -115
  36. package/calculations/legacy/profitability_migration.js +0 -104
  37. package/calculations/legacy/reallocation_increase_percentage.js +0 -104
  38. package/calculations/legacy/risk_appetite_change.js +0 -97
  39. package/calculations/legacy/sector_rotation.js +0 -117
  40. package/calculations/legacy/shark_attack_signal.js +0 -112
  41. package/calculations/legacy/smart-cohort-flow.js +0 -238
  42. package/calculations/legacy/smart-dumb-divergence-index.js +0 -143
  43. package/calculations/legacy/smart_dumb_divergence_index_v2.js +0 -138
  44. package/calculations/legacy/smart_money_flow.js +0 -198
  45. package/calculations/legacy/social-predictive-regime-state.js +0 -102
  46. package/calculations/legacy/social-topic-driver-index.js +0 -147
  47. package/calculations/legacy/social-topic-predictive-potential.js +0 -461
  48. package/calculations/legacy/social_flow_correlation.js +0 -112
  49. package/calculations/legacy/speculator_adjustment_activity.js +0 -103
  50. package/calculations/legacy/strategy-performance.js +0 -265
  51. package/calculations/legacy/tsl_effectiveness.js +0 -85
  52. package/calculations/legacy/user-investment-profile.js +0 -313
  53. package/calculations/legacy/user_expectancy_score.js +0 -106
  54. package/calculations/legacy/user_profitability_tracker.js +0 -131
@@ -1,261 +0,0 @@
1
- /**
2
- * @fileoverview Calculation (Pass 2) for crowd conviction.
3
- *
4
- * This metric answers: "What is the 'Crowd Conviction Score'
5
- * for each instrument?"
6
- *
7
- * It's based on factors like:
8
- * 1. Holding Duration (longer = more conviction)
9
- * 2. P&L % (positive = more conviction)
10
- * 3. Risk/Reward Ratio (higher = more conviction)
11
- * 4. Leverage (lower = more conviction)
12
- *
13
- * This is a *stateful* calculation that computes a 30-day
14
- * rolling average of these metrics to build the score.
15
- */
16
- const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
17
-
18
- class CrowdConvictionScore {
19
- constructor() {
20
- // { [instrumentId]: { metrics: [], history: [] } }
21
- this.assetData = new Map();
22
- this.mappings = null;
23
- }
24
-
25
- /**
26
- * Defines the output schema for this calculation.
27
- * @returns {object} JSON Schema object
28
- */
29
- static getSchema() {
30
- const historyItemSchema = {
31
- "type": "object",
32
- "properties": {
33
- "avg_holding_duration": { "type": "number" },
34
- "avg_pnl": { "type": "number" },
35
- "avg_rr": { "type": "number" },
36
- "avg_leverage": { "type": "number" }
37
- },
38
- "required": ["avg_holding_duration", "avg_pnl", "avg_rr", "avg_leverage"]
39
- };
40
-
41
- const tickerSchema = {
42
- "type": "object",
43
- "description": "Crowd conviction score and its components for a specific asset.",
44
- "properties": {
45
- "conviction_score": {
46
- "type": "number",
47
- "description": "Final conviction score (0-100), based on 30-day rolling averages."
48
- },
49
- "roll_avg_holding_duration": {
50
- "type": "number",
51
- "description": "30-day rolling average of holding duration (hours)."
52
- },
53
- "roll_avg_pnl": {
54
- "type": "number",
55
- "description": "30-day rolling average of P&L percentage."
56
- },
57
- "roll_avg_rr": {
58
- "type": "number",
59
- "description": "30-day rolling average of risk/reward ratio."
60
- },
61
- "roll_avg_leverage": {
62
- "type": "number",
63
- "description": "30-day rolling average of leverage."
64
- },
65
- "avg_holding_duration": {
66
- "type": "number",
67
- "description": "Today's average holding duration."
68
- },
69
- "avg_pnl": {
70
- "type": "number",
71
- "description": "Today's average P&L percentage."
72
- },
73
- "avg_rr": {
74
- "type": "number",
75
- "description": "Today's average risk/reward ratio."
76
- },
77
- "avg_leverage": {
78
- "type": "number",
79
- "description": "Today's average leverage."
80
- },
81
- "history": {
82
- "type": "array",
83
- "description": "30-day history of daily average metrics.",
84
- "items": historyItemSchema
85
- }
86
- },
87
- "required": [
88
- "conviction_score", "roll_avg_holding_duration", "roll_avg_pnl",
89
- "roll_avg_rr", "roll_avg_leverage", "avg_holding_duration",
90
- "avg_pnl", "avg_rr", "avg_leverage", "history"
91
- ]
92
- };
93
-
94
- return {
95
- "type": "object",
96
- "description": "Calculates a 30-day rolling 'Crowd Conviction Score' (0-100) for each asset.",
97
- "patternProperties": {
98
- "^.*$": tickerSchema // Ticker
99
- },
100
- "additionalProperties": tickerSchema
101
- };
102
- }
103
-
104
- _initAsset(instrumentId) {
105
- if (!this.assetData.has(instrumentId)) {
106
- // metrics: Stores *today's* raw values before averaging
107
- // history: Stores *yesterday's* 30-day history
108
- this.assetData.set(instrumentId, {
109
- metrics: [],
110
- history: []
111
- });
112
- }
113
- }
114
-
115
- _getHoldingDurationHours(openDateStr) {
116
- if (!openDateStr) return 0;
117
- try {
118
- const openDate = new Date(openDateStr);
119
- const diffMs = new Date().getTime() - openDate.getTime();
120
- return diffMs / (1000 * 60 * 60);
121
- } catch (e) {
122
- return 0;
123
- }
124
- }
125
-
126
- // Simple min-max normalization helper
127
- _normalize(value, min, max) {
128
- if (max === min) return 0.5; // Avoid division by zero
129
- const normalized = (value - min) / (max - min);
130
- return Math.max(0, Math.min(1, normalized)); // Clamp between 0 and 1
131
- }
132
-
133
- process(portfolioData, yesterdayPortfolio, userId, context) {
134
- // This score is based on speculator actions
135
- if (portfolioData?.context?.userType !== 'speculator') {
136
- return;
137
- }
138
-
139
- // 1. Get this metric's history from yesterday (pre-loaded)
140
- if (this.assetData.size === 0) { // Only run once
141
- const yHistoryData = context.yesterdaysDependencyData['crowd_conviction_score'];
142
- if (yHistoryData) {
143
- if (!this.mappings) {
144
- // We need mappings to convert *yesterday's* tickers back to IDs
145
- this.mappings = context.mappings;
146
- }
147
- for (const [ticker, data] of Object.entries(yHistoryData)) {
148
- const instrumentId = this.mappings.tickerToInstrument[ticker];
149
- if (instrumentId) {
150
- this._initAsset(instrumentId);
151
- this.assetData.get(instrumentId).history = data.history || [];
152
- }
153
- }
154
- }
155
- }
156
-
157
- const positions = portfolioData.PublicPositions;
158
- if (!positions || !Array.isArray(positions)) {
159
- return;
160
- }
161
-
162
- for (const pos of positions) {
163
- const instrumentId = pos.InstrumentID;
164
- if (!instrumentId) continue;
165
-
166
- this._initAsset(instrumentId);
167
-
168
- const pnl_percent = (pos.NetProfit || 0) / (pos.Amount || 1);
169
- const holding_duration = this._getHoldingDurationHours(pos.OpenDateTime);
170
- const leverage = pos.Leverage || 1;
171
-
172
- const sl_rate = pos.StopLossRate || 0;
173
- const tp_rate = pos.TakeProfitRate || 0;
174
- const open_rate = pos.OpenRate || 1;
175
-
176
- let rr_ratio = 0;
177
- if (sl_rate > 0 && tp_rate > 0) {
178
- const risk = Math.abs(open_rate - sl_rate);
179
- const reward = Math.abs(tp_rate - open_rate);
180
- if (risk > 0) {
181
- rr_ratio = reward / risk;
182
- }
183
- }
184
-
185
- this.assetData.get(instrumentId).metrics.push({
186
- holding_duration,
187
- pnl_percent,
188
- rr_ratio,
189
- leverage
190
- });
191
- }
192
- }
193
-
194
- async getResult() {
195
- if (!this.mappings) {
196
- this.mappings = await loadInstrumentMappings();
197
- }
198
-
199
- const result = {};
200
- for (const [instrumentId, data] of this.assetData.entries()) {
201
- const ticker = this.mappings.instrumentToTicker[instrumentId] || `id_${instrumentId}`;
202
- const metrics = data.metrics;
203
- const yHistory = data.history; // Yesterday's 30-day history
204
-
205
- if (metrics.length === 0) continue;
206
-
207
- // 1. Calculate today's averages
208
- const count = metrics.length;
209
- const avg_holding_duration = metrics.reduce((s, m) => s + m.holding_duration, 0) / count;
210
- const avg_pnl = metrics.reduce((s, m) => s + m.pnl_percent, 0) / count;
211
- const avg_rr = metrics.reduce((s, m) => s + m.rr_ratio, 0) / count;
212
- const avg_leverage = metrics.reduce((s, m) => s + m.leverage, 0) / count;
213
-
214
- const todayMetrics = { avg_holding_duration, avg_pnl, avg_rr, avg_leverage };
215
-
216
- // 2. Create new 30-day history
217
- const newHistory = [todayMetrics, ...yHistory].slice(0, 30);
218
-
219
- // 3. Calculate 30-day rolling averages
220
- const historyCount = newHistory.length;
221
- const roll_avg_duration = newHistory.reduce((s, m) => s + m.avg_holding_duration, 0) / historyCount;
222
- const roll_avg_pnl = newHistory.reduce((s, m) => s + m.avg_pnl, 0) / historyCount;
223
- const roll_avg_rr = newHistory.reduce((s, m) => s + m.avg_rr, 0) / historyCount;
224
- const roll_avg_leverage = newHistory.reduce((s, m) => s + m.avg_leverage, 0) / historyCount;
225
-
226
- // 4. Calculate Conviction Score (example normalization)
227
- // (Assumes a 0-1 range for normalization, then scales to 0-100)
228
- const norm_duration = this._normalize(roll_avg_duration, 0, 240); // 0-10 days
229
- const norm_pnl = this._normalize(roll_avg_pnl, -0.5, 0.5); // -50% to +50%
230
- const norm_rr = this._normalize(roll_avg_rr, 0, 3); // 0 to 3 R:R
231
- const norm_leverage = 1 - this._normalize(roll_avg_leverage, 1, 10); // 1x to 10x (inverted)
232
-
233
- // Combine scores (equal weight for this example)
234
- const score_pct = (norm_duration + norm_pnl + norm_rr + norm_leverage) / 4;
235
-
236
- result[ticker] = {
237
- conviction_score: score_pct * 100, // Final score 0-100
238
- roll_avg_holding_duration,
239
- roll_avg_pnl,
240
- roll_avg_rr,
241
- roll_avg_leverage,
242
-
243
- // Also include today's raw averages
244
- avg_holding_duration,
245
- avg_pnl,
246
- avg_rr,
247
- avg_leverage,
248
-
249
- history: newHistory
250
- };
251
- }
252
- return result;
253
- }
254
-
255
- reset() {
256
- this.assetData.clear();
257
- this.mappings = null;
258
- }
259
- }
260
-
261
- module.exports = CrowdConvictionScore;
@@ -1,137 +0,0 @@
1
- /**
2
- * @fileoverview Calculation (Pass 2) for crowd sharpe ratio proxy.
3
- *
4
- * This metric answers: "What is the crowd's risk-adjusted return
5
- * (Sharpe Ratio proxy) for each asset?"
6
- *
7
- * It uses the distribution of P&L from 'pnl_distribution_per_stock'
8
- * to calculate variance (risk).
9
- *
10
- * --- FIX: 2025-11-12 ---
11
- * Refactored this file to be a "meta" calculation.
12
- * 1. Removed constructor, getResult, reset, and the no-op 'process'.
13
- * 2. Added the required `async process(dStr, deps, config, fetchedDeps)` method.
14
- * 3. Moved all logic into `process`.
15
- * 4. Updated logic to read from `fetchedDeps['pnl_distribution_per_stock']`.
16
- * 5. Updated data access to read from the new `data.stats` object
17
- * provided by the fixed dependency.
18
- */
19
- const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
20
-
21
- class CrowdSharpeRatioProxy {
22
- /**
23
- * Defines the output schema for this calculation.
24
- * @returns {object} JSON Schema object
25
- */
26
- static getSchema() {
27
- const tickerSchema = {
28
- "type": "object",
29
- "description": "Sharpe Ratio proxy metrics for a specific asset.",
30
- "properties": {
31
- "sharpe_ratio_proxy": {
32
- "type": "number",
33
- "description": "Risk-adjusted return proxy (Mean P&L / StdDev P&L). Assumes risk-free rate is 0."
34
- },
35
- "average_pnl": { "type": "number" },
36
- "std_dev_pnl": { "type": "number" },
37
- "variance_pnl": { "type": "number" },
38
- "position_count": { "type": "number" }
39
- },
40
- "required": ["sharpe_ratio_proxy", "average_pnl", "std_dev_pnl", "position_count"]
41
- };
42
-
43
- return {
44
- "type": "object",
45
- "description": "Calculates a risk-adjusted return (Sharpe Ratio proxy) for each asset based on P&L distribution.",
46
- "patternProperties": {
47
- "^.*$": tickerSchema // Matches any string key (ticker)
48
- },
49
- "additionalProperties": tickerSchema
50
- };
51
- }
52
-
53
- /**
54
- * Statically declare dependencies.
55
- */
56
- static getDependencies() {
57
- return [
58
- 'pnl_distribution_per_stock' // Pass 1
59
- ];
60
- }
61
-
62
- /**
63
- * --- FIX: This is the new main execution method for meta-calcs ---
64
- * It receives all dependencies from the orchestrator.
65
- */
66
- async process(dateStr, dependencies, config, fetchedDependencies) {
67
- // --- FIX: Load dependency data from the argument ---
68
- const pnlDistData = fetchedDependencies['pnl_distribution_per_stock'];
69
-
70
- if (!pnlDistData) {
71
- dependencies.logger.log('WARN', `[crowd_sharpe_ratio_proxy] Missing dependency 'pnl_distribution_per_stock' for ${dateStr}. Skipping.`);
72
- return {};
73
- }
74
-
75
- // --- FIX: Load mappings inside the process method ---
76
- const mappings = await loadInstrumentMappings();
77
- if (!mappings || !mappings.instrumentToTicker) {
78
- dependencies.logger.log('ERROR', `[crowd_sharpe_ratio_proxy] Failed to load instrument mappings.`);
79
- return {};
80
- }
81
-
82
- const result = {};
83
-
84
- for (const [ticker, data] of Object.entries(pnlDistData)) {
85
-
86
- // --- FIX: Read from the new 'stats' sub-object ---
87
- if (!data.stats) {
88
- continue; // Skip if data is malformed
89
- }
90
-
91
- const { sum, sumSq, count } = data.stats;
92
-
93
- if (count < 2) {
94
- continue; // Need at least 2 data points for variance
95
- }
96
-
97
- // Calculate Mean (Average P&L)
98
- const mean = sum / count;
99
-
100
- // Calculate Variance
101
- // Var(X) = E[X^2] - (E[X])^2
102
- const meanSq = sumSq / count;
103
- const variance = meanSq - (mean * mean);
104
-
105
- // Handle potential float precision errors
106
- if (variance < 0) {
107
- continue;
108
- }
109
-
110
- // Calculate Standard Deviation (Risk)
111
- const stdDev = Math.sqrt(variance);
112
-
113
- if (stdDev === 0) {
114
- continue; // No risk, Sharpe ratio is infinite/undefined
115
- }
116
-
117
- // Calculate Sharpe Ratio Proxy (assuming risk-free rate = 0)
118
- // Sharpe = Mean(Return) / StdDev(Return)
119
- const sharpeProxy = mean / stdDev;
120
-
121
- // --- FIX: Data is already keyed by ticker, no mapping needed ---
122
- // const ticker = this.mappings.instrumentToTicker[instrumentId] || `id_${instrumentId}`;
123
-
124
- result[ticker] = {
125
- sharpe_ratio_proxy: sharpeProxy,
126
- average_pnl: mean,
127
- std_dev_pnl: stdDev,
128
- variance_pnl: variance,
129
- position_count: count
130
- };
131
- }
132
-
133
- return result;
134
- }
135
- }
136
-
137
- module.exports = CrowdSharpeRatioProxy;
@@ -1,128 +0,0 @@
1
- /**
2
- * @fileoverview Tracks the flow of unique users opening or closing positions
3
- * on a per-asset basis. This measures the "focus" of the crowd's activity.
4
- */
5
- const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
6
-
7
- class DailyAssetActivity {
8
- constructor() {
9
- // We will store { [instrumentId]: { new_users: Set(), closed_users: Set() } }
10
- this.assetActivity = new Map();
11
- this.mappings = null;
12
- }
13
-
14
- /**
15
- * Defines the output schema for this calculation.
16
- * @returns {object} JSON Schema object
17
- */
18
- static getSchema() {
19
- return {
20
- "type": "object",
21
- "description": "Tracks the net flow of unique users opening or closing positions per asset.",
22
- "patternProperties": {
23
- // This matches any string key (which will be a ticker)
24
- "^.*$": {
25
- "type": "object",
26
- "description": "User flow metrics for a specific asset ticker.",
27
- "properties": {
28
- "opened_by_user_count": {
29
- "type": "number",
30
- "description": "Count of unique users who opened a position in this asset."
31
- },
32
- "closed_by_user_count": {
33
- "type": "number",
34
- "description": "Count of unique users who closed their position in this asset."
35
- },
36
- "net_user_flow": {
37
- "type": "number",
38
- "description": "Net change in users (opened - closed)."
39
- }
40
- },
41
- "required": ["opened_by_user_count", "closed_by_user_count", "net_user_flow"]
42
- }
43
- },
44
- // Use 'additionalProperties' as a fallback for patternProperties
45
- "additionalProperties": {
46
- "type": "object",
47
- "properties": {
48
- "opened_by_user_count": { "type": "number" },
49
- "closed_by_user_count": { "type": "number" },
50
- "net_user_flow": { "type": "number" }
51
- }
52
- }
53
- };
54
- }
55
-
56
- _initAsset(instrumentId) {
57
- if (!this.assetActivity.has(instrumentId)) {
58
- this.assetActivity.set(instrumentId, {
59
- new_users: new Set(),
60
- closed_users: new Set()
61
- });
62
- }
63
- }
64
-
65
- _getInstrumentIds(portfolio) {
66
- const positions = portfolio?.AggregatedPositions || portfolio?.PublicPositions;
67
- if (!positions || !Array.isArray(positions)) {
68
- return new Set();
69
- }
70
- return new Set(positions.map(p => p.InstrumentID).filter(Boolean));
71
- }
72
-
73
- process(todayPortfolio, yesterdayPortfolio, userId) {
74
- if (!todayPortfolio || !yesterdayPortfolio) {
75
- return;
76
- }
77
-
78
- const yIds = this._getInstrumentIds(yesterdayPortfolio);
79
- const tIds = this._getInstrumentIds(todayPortfolio);
80
-
81
- // Find new positions (in today but not yesterday)
82
- for (const tId of tIds) {
83
- if (!yIds.has(tId)) {
84
- this._initAsset(tId);
85
- this.assetActivity.get(tId).new_users.add(userId);
86
- }
87
- }
88
-
89
- // Find closed positions (in yesterday but not today)
90
- for (const yId of yIds) {
91
- if (!tIds.has(yId)) {
92
- this._initAsset(yId);
93
- this.assetActivity.get(yId).closed_users.add(userId);
94
- }
95
- }
96
- }
97
-
98
- async getResult() {
99
- if (!this.mappings) {
100
- this.mappings = await loadInstrumentMappings();
101
- }
102
-
103
- const result = {};
104
- for (const [instrumentId, data] of this.assetActivity.entries()) {
105
- const ticker = this.mappings.instrumentToTicker[instrumentId] || `id_${instrumentId}`;
106
-
107
- const openCount = data.new_users.size;
108
- const closeCount = data.closed_users.size;
109
-
110
- if (openCount > 0 || closeCount > 0) {
111
- result[ticker] = {
112
- opened_by_user_count: openCount,
113
- closed_by_user_count: closeCount,
114
- // "Net User Flow" - positive means more users joined than left
115
- net_user_flow: openCount - closeCount
116
- };
117
- }
118
- }
119
- return result;
120
- }
121
-
122
- reset() {
123
- this.assetActivity.clear();
124
- this.mappings = null;
125
- }
126
- }
127
-
128
- module.exports = DailyAssetActivity;