aiden-shared-calculations-unified 1.0.94 → 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 (55) 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/gauss/cohort-definer.js +24 -2
  4. package/calculations/ghost-book/cost-basis-density.js +1 -2
  5. package/calculations/ghost-book/liquidity-vacuum.js +1 -2
  6. package/calculations/ghost-book/retail-gamma-exposure.js +0 -1
  7. package/calculations/predicative-alpha/cognitive-dissonance.js +1 -2
  8. package/calculations/predicative-alpha/diamond-hand-fracture.js +1 -2
  9. package/calculations/predicative-alpha/mimetic-latency.js +1 -2
  10. package/package.json +1 -1
  11. package/calculations/legacy/activity_by_pnl_status.js +0 -119
  12. package/calculations/legacy/asset_crowd_flow.js +0 -163
  13. package/calculations/legacy/capital_deployment_strategy.js +0 -108
  14. package/calculations/legacy/capital_liquidation_performance.js +0 -139
  15. package/calculations/legacy/capital_vintage_performance.js +0 -136
  16. package/calculations/legacy/cash-flow-deployment.js +0 -144
  17. package/calculations/legacy/cash-flow-liquidation.js +0 -146
  18. package/calculations/legacy/crowd-cash-flow-proxy.js +0 -128
  19. package/calculations/legacy/crowd_conviction_score.js +0 -261
  20. package/calculations/legacy/crowd_sharpe_ratio_proxy.js +0 -137
  21. package/calculations/legacy/daily_asset_activity.js +0 -128
  22. package/calculations/legacy/daily_user_activity_tracker.js +0 -182
  23. package/calculations/legacy/deposit_withdrawal_percentage.js +0 -125
  24. package/calculations/legacy/diversification_pnl.js +0 -115
  25. package/calculations/legacy/drawdown_response.js +0 -137
  26. package/calculations/legacy/dumb-cohort-flow.js +0 -238
  27. package/calculations/legacy/gain_response.js +0 -137
  28. package/calculations/legacy/historical_performance_aggregator.js +0 -85
  29. package/calculations/legacy/in_loss_asset_crowd_flow.js +0 -168
  30. package/calculations/legacy/in_profit_asset_crowd_flow.js +0 -168
  31. package/calculations/legacy/negative_expectancy_cohort_flow.js +0 -232
  32. package/calculations/legacy/new_allocation_percentage.js +0 -98
  33. package/calculations/legacy/paper_vs_diamond_hands.js +0 -107
  34. package/calculations/legacy/position_count_pnl.js +0 -120
  35. package/calculations/legacy/positive_expectancy_cohort_flow.js +0 -232
  36. package/calculations/legacy/profit_cohort_divergence.js +0 -115
  37. package/calculations/legacy/profitability_migration.js +0 -104
  38. package/calculations/legacy/reallocation_increase_percentage.js +0 -104
  39. package/calculations/legacy/risk_appetite_change.js +0 -97
  40. package/calculations/legacy/sector_rotation.js +0 -117
  41. package/calculations/legacy/shark_attack_signal.js +0 -112
  42. package/calculations/legacy/smart-cohort-flow.js +0 -238
  43. package/calculations/legacy/smart-dumb-divergence-index.js +0 -143
  44. package/calculations/legacy/smart_dumb_divergence_index_v2.js +0 -138
  45. package/calculations/legacy/smart_money_flow.js +0 -198
  46. package/calculations/legacy/social-predictive-regime-state.js +0 -102
  47. package/calculations/legacy/social-topic-driver-index.js +0 -147
  48. package/calculations/legacy/social-topic-predictive-potential.js +0 -461
  49. package/calculations/legacy/social_flow_correlation.js +0 -112
  50. package/calculations/legacy/speculator_adjustment_activity.js +0 -103
  51. package/calculations/legacy/strategy-performance.js +0 -265
  52. package/calculations/legacy/tsl_effectiveness.js +0 -85
  53. package/calculations/legacy/user-investment-profile.js +0 -313
  54. package/calculations/legacy/user_expectancy_score.js +0 -106
  55. 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;