bulltrackers-module 1.0.733 → 1.0.734
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/functions/computation-system-v2/README.md +152 -0
- package/functions/computation-system-v2/computations/PopularInvestorProfileMetrics.js +720 -0
- package/functions/computation-system-v2/computations/PopularInvestorRiskAssessment.js +176 -0
- package/functions/computation-system-v2/computations/PopularInvestorRiskMetrics.js +294 -0
- package/functions/computation-system-v2/computations/TestComputation.js +46 -0
- package/functions/computation-system-v2/computations/UserPortfolioSummary.js +172 -0
- package/functions/computation-system-v2/config/bulltrackers.config.js +317 -0
- package/functions/computation-system-v2/framework/core/Computation.js +73 -0
- package/functions/computation-system-v2/framework/core/Manifest.js +223 -0
- package/functions/computation-system-v2/framework/core/RuleInjector.js +53 -0
- package/functions/computation-system-v2/framework/core/Rules.js +231 -0
- package/functions/computation-system-v2/framework/core/RunAnalyzer.js +163 -0
- package/functions/computation-system-v2/framework/cost/CostTracker.js +154 -0
- package/functions/computation-system-v2/framework/data/DataFetcher.js +399 -0
- package/functions/computation-system-v2/framework/data/QueryBuilder.js +232 -0
- package/functions/computation-system-v2/framework/data/SchemaRegistry.js +287 -0
- package/functions/computation-system-v2/framework/execution/Orchestrator.js +498 -0
- package/functions/computation-system-v2/framework/execution/TaskRunner.js +35 -0
- package/functions/computation-system-v2/framework/execution/middleware/CostTrackerMiddleware.js +32 -0
- package/functions/computation-system-v2/framework/execution/middleware/LineageMiddleware.js +32 -0
- package/functions/computation-system-v2/framework/execution/middleware/Middleware.js +14 -0
- package/functions/computation-system-v2/framework/execution/middleware/ProfilerMiddleware.js +47 -0
- package/functions/computation-system-v2/framework/index.js +45 -0
- package/functions/computation-system-v2/framework/lineage/LineageTracker.js +147 -0
- package/functions/computation-system-v2/framework/monitoring/Profiler.js +80 -0
- package/functions/computation-system-v2/framework/resilience/Checkpointer.js +66 -0
- package/functions/computation-system-v2/framework/scheduling/ScheduleValidator.js +327 -0
- package/functions/computation-system-v2/framework/storage/StateRepository.js +286 -0
- package/functions/computation-system-v2/framework/storage/StorageManager.js +469 -0
- package/functions/computation-system-v2/framework/storage/index.js +9 -0
- package/functions/computation-system-v2/framework/testing/ComputationTester.js +86 -0
- package/functions/computation-system-v2/framework/utils/Graph.js +205 -0
- package/functions/computation-system-v2/handlers/dispatcher.js +109 -0
- package/functions/computation-system-v2/handlers/index.js +23 -0
- package/functions/computation-system-v2/handlers/onDemand.js +289 -0
- package/functions/computation-system-v2/handlers/scheduler.js +327 -0
- package/functions/computation-system-v2/index.js +163 -0
- package/functions/computation-system-v2/rules/index.js +49 -0
- package/functions/computation-system-v2/rules/instruments.js +465 -0
- package/functions/computation-system-v2/rules/metrics.js +304 -0
- package/functions/computation-system-v2/rules/portfolio.js +534 -0
- package/functions/computation-system-v2/rules/rankings.js +655 -0
- package/functions/computation-system-v2/rules/social.js +562 -0
- package/functions/computation-system-v2/rules/trades.js +545 -0
- package/functions/computation-system-v2/scripts/migrate-sectors.js +73 -0
- package/functions/computation-system-v2/test/test-dispatcher.js +317 -0
- package/functions/computation-system-v2/test/test-framework.js +500 -0
- package/functions/computation-system-v2/test/test-real-execution.js +166 -0
- package/functions/computation-system-v2/test/test-real-integration.js +194 -0
- package/functions/computation-system-v2/test/test-refactor-e2e.js +131 -0
- package/functions/computation-system-v2/test/test-results.json +31 -0
- package/functions/computation-system-v2/test/test-risk-metrics-computation.js +329 -0
- package/functions/computation-system-v2/test/test-scheduler.js +204 -0
- package/functions/computation-system-v2/test/test-storage.js +449 -0
- package/functions/orchestrator/index.js +18 -26
- package/package.json +3 -2
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Financial Metrics Business Rules
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for financial metric calculations.
|
|
5
|
+
* These rules are automatically injected into computations.
|
|
6
|
+
*
|
|
7
|
+
* Usage in computation:
|
|
8
|
+
* ```javascript
|
|
9
|
+
* const sharpe = rules.metrics.calculateSharpeRatio(returns, riskFreeRate);
|
|
10
|
+
* const sortino = rules.metrics.calculateSortinoRatio(returns, targetReturn);
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Calculate the mean (average) of an array of numbers.
|
|
16
|
+
*
|
|
17
|
+
* @param {number[]} values - Array of numbers
|
|
18
|
+
* @returns {number} Mean value
|
|
19
|
+
*/
|
|
20
|
+
function mean(values) {
|
|
21
|
+
if (!Array.isArray(values) || values.length === 0) return 0;
|
|
22
|
+
return values.reduce((sum, v) => sum + v, 0) / values.length;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Calculate the standard deviation of an array of numbers.
|
|
27
|
+
*
|
|
28
|
+
* @param {number[]} values - Array of numbers
|
|
29
|
+
* @param {boolean} [population=false] - Use population std dev (N) vs sample (N-1)
|
|
30
|
+
* @returns {number} Standard deviation
|
|
31
|
+
*/
|
|
32
|
+
function standardDeviation(values, population = false) {
|
|
33
|
+
if (!Array.isArray(values) || values.length < 2) return 0;
|
|
34
|
+
|
|
35
|
+
const avg = mean(values);
|
|
36
|
+
const squaredDiffs = values.map(v => Math.pow(v - avg, 2));
|
|
37
|
+
const divisor = population ? values.length : values.length - 1;
|
|
38
|
+
|
|
39
|
+
return Math.sqrt(squaredDiffs.reduce((sum, v) => sum + v, 0) / divisor);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Calculate the downside deviation (only negative returns).
|
|
44
|
+
*
|
|
45
|
+
* @param {number[]} returns - Array of return values
|
|
46
|
+
* @param {number} [targetReturn=0] - Minimum acceptable return
|
|
47
|
+
* @returns {number} Downside deviation
|
|
48
|
+
*/
|
|
49
|
+
function downsideDeviation(returns, targetReturn = 0) {
|
|
50
|
+
if (!Array.isArray(returns) || returns.length === 0) return 0;
|
|
51
|
+
|
|
52
|
+
const downsideReturns = returns
|
|
53
|
+
.filter(r => r < targetReturn)
|
|
54
|
+
.map(r => Math.pow(r - targetReturn, 2));
|
|
55
|
+
|
|
56
|
+
if (downsideReturns.length === 0) return 0;
|
|
57
|
+
|
|
58
|
+
return Math.sqrt(downsideReturns.reduce((sum, v) => sum + v, 0) / returns.length);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Calculate the Sharpe Ratio.
|
|
63
|
+
* Measures risk-adjusted return compared to risk-free rate.
|
|
64
|
+
*
|
|
65
|
+
* Formula: (Mean Return - Risk-Free Rate) / Standard Deviation
|
|
66
|
+
*
|
|
67
|
+
* @param {number[]} returns - Array of return values (as percentages)
|
|
68
|
+
* @param {number} [riskFreeRate=0] - Risk-free rate (annualized %)
|
|
69
|
+
* @param {number} [periodsPerYear=252] - Trading periods per year
|
|
70
|
+
* @returns {number} Sharpe ratio
|
|
71
|
+
*/
|
|
72
|
+
function calculateSharpeRatio(returns, riskFreeRate = 0, periodsPerYear = 252) {
|
|
73
|
+
if (!Array.isArray(returns) || returns.length < 2) return 0;
|
|
74
|
+
|
|
75
|
+
const meanReturn = mean(returns);
|
|
76
|
+
const stdDev = standardDeviation(returns);
|
|
77
|
+
|
|
78
|
+
if (stdDev === 0) return 0;
|
|
79
|
+
|
|
80
|
+
// Convert risk-free rate to per-period rate
|
|
81
|
+
const periodRiskFree = riskFreeRate / periodsPerYear;
|
|
82
|
+
|
|
83
|
+
// Calculate and annualize
|
|
84
|
+
const sharpe = (meanReturn - periodRiskFree) / stdDev;
|
|
85
|
+
return sharpe * Math.sqrt(periodsPerYear);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Calculate the Sortino Ratio.
|
|
90
|
+
* Like Sharpe but only penalizes downside volatility.
|
|
91
|
+
*
|
|
92
|
+
* Formula: (Mean Return - Target Return) / Downside Deviation
|
|
93
|
+
*
|
|
94
|
+
* @param {number[]} returns - Array of return values (as percentages)
|
|
95
|
+
* @param {number} [targetReturn=0] - Minimum acceptable return
|
|
96
|
+
* @param {number} [periodsPerYear=252] - Trading periods per year
|
|
97
|
+
* @returns {number} Sortino ratio
|
|
98
|
+
*/
|
|
99
|
+
function calculateSortinoRatio(returns, targetReturn = 0, periodsPerYear = 252) {
|
|
100
|
+
if (!Array.isArray(returns) || returns.length < 2) return 0;
|
|
101
|
+
|
|
102
|
+
const meanReturn = mean(returns);
|
|
103
|
+
const downside = downsideDeviation(returns, targetReturn);
|
|
104
|
+
|
|
105
|
+
if (downside === 0) {
|
|
106
|
+
// No downside deviation means all returns >= target
|
|
107
|
+
return meanReturn > targetReturn ? Infinity : 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const sortino = (meanReturn - targetReturn) / downside;
|
|
111
|
+
return sortino * Math.sqrt(periodsPerYear);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Calculate the Maximum Drawdown.
|
|
116
|
+
* The largest peak-to-trough decline.
|
|
117
|
+
*
|
|
118
|
+
* @param {number[]} values - Array of cumulative values or returns
|
|
119
|
+
* @returns {Object} { maxDrawdown, peakIndex, troughIndex }
|
|
120
|
+
*/
|
|
121
|
+
function calculateMaxDrawdown(values) {
|
|
122
|
+
if (!Array.isArray(values) || values.length < 2) {
|
|
123
|
+
return { maxDrawdown: 0, peakIndex: 0, troughIndex: 0 };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let peak = values[0];
|
|
127
|
+
let peakIndex = 0;
|
|
128
|
+
let maxDrawdown = 0;
|
|
129
|
+
let maxDrawdownPeak = 0;
|
|
130
|
+
let maxDrawdownTrough = 0;
|
|
131
|
+
|
|
132
|
+
for (let i = 1; i < values.length; i++) {
|
|
133
|
+
if (values[i] > peak) {
|
|
134
|
+
peak = values[i];
|
|
135
|
+
peakIndex = i;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const drawdown = peak > 0 ? (peak - values[i]) / peak : 0;
|
|
139
|
+
|
|
140
|
+
if (drawdown > maxDrawdown) {
|
|
141
|
+
maxDrawdown = drawdown;
|
|
142
|
+
maxDrawdownPeak = peakIndex;
|
|
143
|
+
maxDrawdownTrough = i;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
maxDrawdown: maxDrawdown * 100, // As percentage
|
|
149
|
+
peakIndex: maxDrawdownPeak,
|
|
150
|
+
troughIndex: maxDrawdownTrough
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Calculate the Calmar Ratio.
|
|
156
|
+
* Annualized return divided by maximum drawdown.
|
|
157
|
+
*
|
|
158
|
+
* @param {number[]} returns - Array of return values
|
|
159
|
+
* @param {number[]} values - Array of cumulative portfolio values
|
|
160
|
+
* @param {number} [periodsPerYear=252] - Trading periods per year
|
|
161
|
+
* @returns {number} Calmar ratio
|
|
162
|
+
*/
|
|
163
|
+
function calculateCalmarRatio(returns, values, periodsPerYear = 252) {
|
|
164
|
+
if (!Array.isArray(returns) || returns.length === 0) return 0;
|
|
165
|
+
|
|
166
|
+
const annualizedReturn = mean(returns) * periodsPerYear;
|
|
167
|
+
const { maxDrawdown } = calculateMaxDrawdown(values);
|
|
168
|
+
|
|
169
|
+
if (maxDrawdown === 0) return 0;
|
|
170
|
+
|
|
171
|
+
return annualizedReturn / maxDrawdown;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Calculate Value at Risk (VaR).
|
|
176
|
+
* The maximum loss at a given confidence level.
|
|
177
|
+
*
|
|
178
|
+
* @param {number[]} returns - Array of return values
|
|
179
|
+
* @param {number} [confidenceLevel=0.95] - Confidence level (e.g., 0.95 for 95%)
|
|
180
|
+
* @returns {number} VaR as positive number
|
|
181
|
+
*/
|
|
182
|
+
function calculateVaR(returns, confidenceLevel = 0.95) {
|
|
183
|
+
if (!Array.isArray(returns) || returns.length < 10) return 0;
|
|
184
|
+
|
|
185
|
+
const sorted = [...returns].sort((a, b) => a - b);
|
|
186
|
+
const index = Math.floor((1 - confidenceLevel) * sorted.length);
|
|
187
|
+
|
|
188
|
+
return -sorted[index]; // Return as positive number
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Calculate information ratio.
|
|
193
|
+
* Measures return above benchmark per unit of tracking error.
|
|
194
|
+
*
|
|
195
|
+
* @param {number[]} returns - Portfolio returns
|
|
196
|
+
* @param {number[]} benchmarkReturns - Benchmark returns
|
|
197
|
+
* @returns {number} Information ratio
|
|
198
|
+
*/
|
|
199
|
+
function calculateInformationRatio(returns, benchmarkReturns) {
|
|
200
|
+
if (!Array.isArray(returns) || !Array.isArray(benchmarkReturns)) return 0;
|
|
201
|
+
if (returns.length !== benchmarkReturns.length || returns.length < 2) return 0;
|
|
202
|
+
|
|
203
|
+
const excessReturns = returns.map((r, i) => r - benchmarkReturns[i]);
|
|
204
|
+
const meanExcess = mean(excessReturns);
|
|
205
|
+
const trackingError = standardDeviation(excessReturns);
|
|
206
|
+
|
|
207
|
+
if (trackingError === 0) return 0;
|
|
208
|
+
|
|
209
|
+
return meanExcess / trackingError;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Calculate beta (systematic risk).
|
|
214
|
+
*
|
|
215
|
+
* @param {number[]} returns - Asset returns
|
|
216
|
+
* @param {number[]} marketReturns - Market/benchmark returns
|
|
217
|
+
* @returns {number} Beta coefficient
|
|
218
|
+
*/
|
|
219
|
+
function calculateBeta(returns, marketReturns) {
|
|
220
|
+
if (!Array.isArray(returns) || !Array.isArray(marketReturns)) return 1;
|
|
221
|
+
if (returns.length !== marketReturns.length || returns.length < 2) return 1;
|
|
222
|
+
|
|
223
|
+
const meanAsset = mean(returns);
|
|
224
|
+
const meanMarket = mean(marketReturns);
|
|
225
|
+
|
|
226
|
+
let covariance = 0;
|
|
227
|
+
let marketVariance = 0;
|
|
228
|
+
|
|
229
|
+
for (let i = 0; i < returns.length; i++) {
|
|
230
|
+
const assetDiff = returns[i] - meanAsset;
|
|
231
|
+
const marketDiff = marketReturns[i] - meanMarket;
|
|
232
|
+
|
|
233
|
+
covariance += assetDiff * marketDiff;
|
|
234
|
+
marketVariance += marketDiff * marketDiff;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (marketVariance === 0) return 1;
|
|
238
|
+
|
|
239
|
+
return covariance / marketVariance;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Calculate alpha (excess return over expected).
|
|
244
|
+
*
|
|
245
|
+
* @param {number[]} returns - Asset returns
|
|
246
|
+
* @param {number[]} marketReturns - Market/benchmark returns
|
|
247
|
+
* @param {number} [riskFreeRate=0] - Risk-free rate
|
|
248
|
+
* @returns {number} Alpha
|
|
249
|
+
*/
|
|
250
|
+
function calculateAlpha(returns, marketReturns, riskFreeRate = 0) {
|
|
251
|
+
const beta = calculateBeta(returns, marketReturns);
|
|
252
|
+
const meanReturn = mean(returns);
|
|
253
|
+
const meanMarket = mean(marketReturns);
|
|
254
|
+
|
|
255
|
+
// Alpha = R - [Rf + Beta * (Rm - Rf)]
|
|
256
|
+
return meanReturn - (riskFreeRate + beta * (meanMarket - riskFreeRate));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Round a number to specified decimal places.
|
|
261
|
+
*
|
|
262
|
+
* @param {number} value - Value to round
|
|
263
|
+
* @param {number} [decimals=2] - Number of decimal places
|
|
264
|
+
* @returns {number} Rounded value
|
|
265
|
+
*/
|
|
266
|
+
function round(value, decimals = 2) {
|
|
267
|
+
if (typeof value !== 'number' || isNaN(value)) return 0;
|
|
268
|
+
return Number(value.toFixed(decimals));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Clamp a value between min and max.
|
|
273
|
+
*
|
|
274
|
+
* @param {number} value - Value to clamp
|
|
275
|
+
* @param {number} min - Minimum value
|
|
276
|
+
* @param {number} max - Maximum value
|
|
277
|
+
* @returns {number} Clamped value
|
|
278
|
+
*/
|
|
279
|
+
function clamp(value, min, max) {
|
|
280
|
+
return Math.min(Math.max(value, min), max);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = {
|
|
284
|
+
// Basic statistics
|
|
285
|
+
mean,
|
|
286
|
+
standardDeviation,
|
|
287
|
+
downsideDeviation,
|
|
288
|
+
|
|
289
|
+
// Risk-adjusted returns
|
|
290
|
+
calculateSharpeRatio,
|
|
291
|
+
calculateSortinoRatio,
|
|
292
|
+
calculateCalmarRatio,
|
|
293
|
+
calculateInformationRatio,
|
|
294
|
+
|
|
295
|
+
// Risk metrics
|
|
296
|
+
calculateMaxDrawdown,
|
|
297
|
+
calculateVaR,
|
|
298
|
+
calculateBeta,
|
|
299
|
+
calculateAlpha,
|
|
300
|
+
|
|
301
|
+
// Utilities
|
|
302
|
+
round,
|
|
303
|
+
clamp
|
|
304
|
+
};
|