aiden-shared-calculations-unified 1.0.45 → 1.0.46
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.
|
@@ -1,91 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* --- META REFACTOR (v2) ---
|
|
6
|
-
* This calculation is now stateless. It declares its dependencies and
|
|
7
|
-
* expects them to be passed to its `process` method.
|
|
2
|
+
* @fileoverview Aggregates P&L data points for statistical analysis.
|
|
3
|
+
* This calculation is a dependency for the 'Crowd Sharpe Ratio Proxy'.
|
|
4
|
+
* It gathers the sum, sum of squares, and count of P&L for each stock.
|
|
8
5
|
*/
|
|
6
|
+
const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
|
|
9
7
|
|
|
10
|
-
class
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*/
|
|
15
|
-
static getDependencies() {
|
|
16
|
-
return ['pnl-distribution-per-stock'];
|
|
8
|
+
class PnlDistributionPerStock {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.distributionData = {}; // { [instrumentId]: { pnl_sum: 0, pnl_sum_sq: 0, position_count: 0 } }
|
|
11
|
+
this.mappings = null;
|
|
17
12
|
}
|
|
18
13
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
|
|
24
|
-
* @param {object} dependencies The shared dependencies (db, logger).
|
|
25
|
-
* @param {object} config The computation system configuration.
|
|
26
|
-
* @param {object} fetchedDependencies In-memory results from previous passes.
|
|
27
|
-
* e.g., { 'pnl-distribution-per-stock': ... }
|
|
28
|
-
* @returns {Promise<object|null>} The analysis result or null.
|
|
29
|
-
*/
|
|
30
|
-
async process(dateStr, dependencies, config, fetchedDependencies) {
|
|
31
|
-
const { logger } = dependencies;
|
|
32
|
-
|
|
33
|
-
// 1. Get dependency from in-memory cache
|
|
34
|
-
const data = fetchedDependencies['pnl-distribution-per-stock'];
|
|
35
|
-
|
|
36
|
-
// 2. Handle missing dependency
|
|
37
|
-
if (!data) {
|
|
38
|
-
logger.log('WARN', `[CrowdSharpeRatioProxy] Missing dependency 'pnl-distribution-per-stock' for ${dateStr}. Skipping.`);
|
|
39
|
-
return null;
|
|
14
|
+
process(portfolioData, yesterdayPortfolio, userId, context) {
|
|
15
|
+
const positions = portfolioData.AggregatedPositions || portfolioData.PublicPositions;
|
|
16
|
+
if (!positions) {
|
|
17
|
+
return;
|
|
40
18
|
}
|
|
41
19
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const variance = mean_sq - (mean * mean);
|
|
62
|
-
|
|
63
|
-
if (variance <= 0) {
|
|
64
|
-
results[ticker] = {
|
|
65
|
-
average_pnl: mean,
|
|
66
|
-
std_dev_pnl: 0,
|
|
67
|
-
sharpe_ratio_proxy: 0,
|
|
68
|
-
position_count: N
|
|
69
|
-
};
|
|
70
|
-
continue;
|
|
20
|
+
for (const position of positions) {
|
|
21
|
+
const instrumentId = position.InstrumentID;
|
|
22
|
+
// Use NetProfit (which is the P&L value)
|
|
23
|
+
const netProfit = position.NetProfit;
|
|
24
|
+
|
|
25
|
+
// Ensure netProfit is a valid number
|
|
26
|
+
if (instrumentId && typeof netProfit === 'number' && isFinite(netProfit)) {
|
|
27
|
+
if (!this.distributionData[instrumentId]) {
|
|
28
|
+
this.distributionData[instrumentId] = {
|
|
29
|
+
pnl_sum: 0,
|
|
30
|
+
pnl_sum_sq: 0, // Sum of squares
|
|
31
|
+
position_count: 0
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.distributionData[instrumentId].pnl_sum += netProfit;
|
|
36
|
+
this.distributionData[instrumentId].pnl_sum_sq += (netProfit * netProfit); // Add the square
|
|
37
|
+
this.distributionData[instrumentId].position_count++;
|
|
71
38
|
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
72
41
|
|
|
73
|
-
|
|
74
|
-
|
|
42
|
+
async getResult() {
|
|
43
|
+
if (!this.mappings) {
|
|
44
|
+
this.mappings = await loadInstrumentMappings();
|
|
45
|
+
}
|
|
75
46
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
position_count: N
|
|
81
|
-
};
|
|
47
|
+
const result = {};
|
|
48
|
+
for (const instrumentId in this.distributionData) {
|
|
49
|
+
const ticker = this.mappings.instrumentToTicker[instrumentId] || instrumentId.toString();
|
|
50
|
+
result[ticker] = this.distributionData[instrumentId];
|
|
82
51
|
}
|
|
83
52
|
|
|
84
|
-
return
|
|
53
|
+
if (Object.keys(result).length === 0) return {};
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
pnl_distribution_by_asset: result
|
|
57
|
+
};
|
|
85
58
|
}
|
|
86
59
|
|
|
87
|
-
|
|
88
|
-
|
|
60
|
+
reset() {
|
|
61
|
+
this.distributionData = {};
|
|
62
|
+
this.mappings = null;
|
|
63
|
+
}
|
|
89
64
|
}
|
|
90
65
|
|
|
91
|
-
module.exports =
|
|
66
|
+
module.exports = PnlDistributionPerStock;
|