aiden-shared-calculations-unified 1.0.64 → 1.0.66
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/README.MD +1 -1
- package/calculations/activity/historical/activity_by_pnl_status.js +33 -0
- package/calculations/activity/historical/daily_asset_activity.js +42 -0
- package/calculations/activity/historical/daily_user_activity_tracker.js +37 -0
- package/calculations/activity/historical/speculator_adjustment_activity.js +26 -0
- package/calculations/asset_metrics/asset_position_size.js +36 -0
- package/calculations/backtests/strategy-performance.js +41 -0
- package/calculations/behavioural/historical/asset_crowd_flow.js +124 -127
- package/calculations/behavioural/historical/drawdown_response.js +113 -35
- package/calculations/behavioural/historical/dumb-cohort-flow.js +191 -171
- package/calculations/behavioural/historical/gain_response.js +113 -34
- package/calculations/behavioural/historical/historical_performance_aggregator.js +63 -48
- package/calculations/behavioural/historical/in_loss_asset_crowd_flow.js +159 -63
- package/calculations/behavioural/historical/in_profit_asset_crowd_flow.js +159 -64
- package/calculations/behavioural/historical/paper_vs_diamond_hands.js +86 -19
- package/calculations/behavioural/historical/position_count_pnl.js +91 -39
- package/calculations/behavioural/historical/smart-cohort-flow.js +192 -172
- package/calculations/behavioural/historical/smart_money_flow.js +160 -151
- package/calculations/capital_flow/historical/crowd-cash-flow-proxy.js +95 -89
- package/calculations/capital_flow/historical/deposit_withdrawal_percentage.js +88 -81
- package/calculations/capital_flow/historical/new_allocation_percentage.js +75 -26
- package/calculations/capital_flow/historical/reallocation_increase_percentage.js +73 -32
- package/calculations/insights/daily_buy_sell_sentiment_count.js +47 -32
- package/calculations/insights/daily_total_positions_held.js +28 -24
- package/calculations/insights/historical/daily_bought_vs_sold_count.js +101 -36
- package/calculations/insights/historical/daily_ownership_delta.js +95 -32
- package/calculations/meta/capital_deployment_strategy.js +78 -110
- package/calculations/meta/capital_liquidation_performance.js +114 -111
- package/calculations/meta/cash-flow-deployment.js +114 -107
- package/calculations/meta/cash-flow-liquidation.js +114 -107
- package/calculations/meta/crowd_sharpe_ratio_proxy.js +94 -54
- package/calculations/meta/negative_expectancy_cohort_flow.js +185 -177
- package/calculations/meta/positive_expectancy_cohort_flow.js +186 -181
- package/calculations/meta/profit_cohort_divergence.js +83 -59
- package/calculations/meta/shark_attack_signal.js +91 -39
- package/calculations/meta/smart-dumb-divergence-index.js +114 -98
- package/calculations/meta/smart_dumb_divergence_index_v2.js +109 -98
- package/calculations/meta/social-predictive-regime-state.js +76 -155
- package/calculations/meta/social-topic-driver-index.js +74 -127
- package/calculations/meta/user_expectancy_score.js +83 -31
- package/calculations/pnl/asset_pnl_status.js +120 -31
- package/calculations/pnl/average_daily_pnl_all_users.js +42 -27
- package/calculations/pnl/average_daily_pnl_per_sector.js +84 -26
- package/calculations/pnl/average_daily_pnl_per_stock.js +71 -29
- package/calculations/pnl/average_daily_position_pnl.js +49 -21
- package/calculations/pnl/historical/profitability_migration.js +81 -35
- package/calculations/pnl/historical/user_profitability_tracker.js +107 -104
- package/calculations/pnl/pnl_distribution_per_stock.js +65 -45
- package/calculations/pnl/profitability_ratio_per_stock.js +78 -21
- package/calculations/pnl/profitability_skew_per_stock.js +86 -31
- package/calculations/pnl/profitable_and_unprofitable_status.js +45 -45
- package/calculations/sanity/users_processed.js +24 -1
- package/calculations/sectors/historical/diversification_pnl.js +104 -42
- package/calculations/sectors/historical/sector_rotation.js +94 -45
- package/calculations/sectors/total_long_per_sector.js +55 -20
- package/calculations/sectors/total_short_per_sector.js +55 -20
- package/calculations/sentiment/historical/crowd_conviction_score.js +233 -53
- package/calculations/short_and_long_stats/long_position_per_stock.js +50 -14
- package/calculations/short_and_long_stats/sentiment_per_stock.js +76 -19
- package/calculations/short_and_long_stats/short_position_per_stock.js +50 -13
- package/calculations/short_and_long_stats/total_long_figures.js +34 -13
- package/calculations/short_and_long_stats/total_short_figures.js +34 -14
- package/calculations/socialPosts/social-asset-posts-trend.js +96 -29
- package/calculations/socialPosts/social-top-mentioned-words.js +95 -74
- package/calculations/socialPosts/social-topic-interest-evolution.js +92 -29
- package/calculations/socialPosts/social-topic-sentiment-matrix.js +70 -78
- package/calculations/socialPosts/social-word-mentions-trend.js +96 -38
- package/calculations/socialPosts/social_activity_aggregation.js +106 -77
- package/calculations/socialPosts/social_sentiment_aggregation.js +115 -86
- package/calculations/speculators/distance_to_stop_loss_per_leverage.js +82 -43
- package/calculations/speculators/distance_to_tp_per_leverage.js +81 -42
- package/calculations/speculators/entry_distance_to_sl_per_leverage.js +80 -44
- package/calculations/speculators/entry_distance_to_tp_per_leverage.js +81 -44
- package/calculations/speculators/historical/risk_appetite_change.js +89 -32
- package/calculations/speculators/historical/tsl_effectiveness.js +57 -47
- package/calculations/speculators/holding_duration_per_asset.js +83 -23
- package/calculations/speculators/leverage_per_asset.js +68 -19
- package/calculations/speculators/leverage_per_sector.js +86 -25
- package/calculations/speculators/risk_reward_ratio_per_asset.js +82 -28
- package/calculations/speculators/speculator_asset_sentiment.js +100 -48
- package/calculations/speculators/speculator_danger_zone.js +101 -33
- package/calculations/speculators/stop_loss_distance_by_sector_short_long_breakdown.js +93 -66
- package/calculations/speculators/stop_loss_distance_by_ticker_short_long_breakdown.js +94 -47
- package/calculations/speculators/stop_loss_per_asset.js +94 -26
- package/calculations/speculators/take_profit_per_asset.js +95 -27
- package/calculations/speculators/tsl_per_asset.js +77 -23
- package/package.json +1 -1
- package/utils/price_data_provider.js +142 -142
- package/utils/sector_mapping_provider.js +74 -74
|
@@ -1,139 +1,146 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
3
|
-
* that are being sold (liquidated) to fund those withdrawals.
|
|
2
|
+
* @fileoverview Calculation (Pass 3) for cash flow liquidation.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* This metric answers: "Following a net withdrawal event, what percentage
|
|
5
|
+
* of that withdrawal was funded by selling *today*, and which assets
|
|
6
|
+
* are being liquidated the most?"
|
|
7
|
+
*
|
|
8
|
+
* It *depends* on 'crowd-cash-flow-proxy' (to know if it's a
|
|
9
|
+
* withdrawal day) and 'asset_crowd_flow' (to see where flow went).
|
|
8
10
|
*/
|
|
9
|
-
|
|
10
|
-
const { FieldValue } = require('@google-cloud/firestore');
|
|
11
|
-
|
|
12
11
|
class CashFlowLiquidation {
|
|
12
|
+
constructor() {
|
|
13
|
+
// No per-user processing
|
|
14
|
+
}
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
|
-
*
|
|
17
|
+
* Defines the output schema for this calculation.
|
|
18
|
+
* @returns {object} JSON Schema object
|
|
16
19
|
*/
|
|
17
|
-
static
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
static getSchema() {
|
|
21
|
+
const assetFlowSchema = {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"properties": {
|
|
24
|
+
"ticker": { "type": "string" },
|
|
25
|
+
"net_flow_contribution": { "type": "number" },
|
|
26
|
+
"percent_of_total_outflow": { "type": "number" }
|
|
27
|
+
},
|
|
28
|
+
"required": ["ticker", "net_flow_contribution", "percent_of_total_outflow"]
|
|
29
|
+
};
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
return {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"description": "On net withdrawal days, tracks % of withdrawal funded by selling and which assets were sold.",
|
|
34
|
+
"properties": {
|
|
35
|
+
"is_net_withdrawal_day": {
|
|
36
|
+
"type": "boolean",
|
|
37
|
+
"description": "True if today was a net withdrawal day."
|
|
38
|
+
},
|
|
39
|
+
"net_cash_flow_proxy": {
|
|
40
|
+
"type": "number",
|
|
41
|
+
"description": "The total estimated net cash flow (negative)."
|
|
42
|
+
},
|
|
43
|
+
"total_net_capital_flow": {
|
|
44
|
+
"type": "number",
|
|
45
|
+
"description": "The sum of all *negative* net capital flows from assets (total liquidation)."
|
|
46
|
+
},
|
|
47
|
+
"funding_percentage": {
|
|
48
|
+
"type": ["number", "null"],
|
|
49
|
+
"description": "Percentage of net cash flow funded by selling (Total Net Flow / Net Cash Flow). Null if no cash flow."
|
|
50
|
+
},
|
|
51
|
+
"top_outflow_assets": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"description": "Top 5 assets being liquidated.",
|
|
54
|
+
"items": assetFlowSchema
|
|
55
|
+
},
|
|
56
|
+
"asset_flow_details": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"description": "Full list of all assets and their outflows.",
|
|
59
|
+
"items": assetFlowSchema
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"required": ["is_net_withdrawal_day", "net_cash_flow_proxy", "total_net_capital_flow", "funding_percentage", "top_outflow_assets", "asset_flow_details"]
|
|
63
|
+
};
|
|
32
64
|
}
|
|
33
65
|
|
|
34
66
|
/**
|
|
35
|
-
*
|
|
36
|
-
* @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
|
|
37
|
-
* @param {object} dependencies The shared dependencies (db, logger).
|
|
38
|
-
* @param {object} config The computation system configuration.
|
|
39
|
-
* @param {object} fetchedDependencies In-memory results from previous passes.
|
|
40
|
-
* @returns {Promise<object|null>} The analysis result or null.
|
|
67
|
+
* Statically declare dependencies.
|
|
41
68
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
69
|
+
static getDependencies() {
|
|
70
|
+
return [
|
|
71
|
+
'crowd-cash-flow-proxy', // Pass 2
|
|
72
|
+
'asset_crowd_flow' // Pass 2
|
|
73
|
+
];
|
|
74
|
+
}
|
|
47
75
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
76
|
+
process() {
|
|
77
|
+
// No-op
|
|
78
|
+
}
|
|
51
79
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
80
|
+
getResult(fetchedDependencies) {
|
|
81
|
+
const cashFlowData = fetchedDependencies['crowd-cash-flow-proxy'];
|
|
82
|
+
const assetFlowData = fetchedDependencies['asset_crowd_flow'];
|
|
83
|
+
|
|
84
|
+
const defaults = {
|
|
85
|
+
is_net_withdrawal_day: false,
|
|
86
|
+
net_cash_flow_proxy: 0,
|
|
87
|
+
total_net_capital_flow: 0,
|
|
88
|
+
funding_percentage: null,
|
|
89
|
+
top_outflow_assets: [],
|
|
90
|
+
asset_flow_details: []
|
|
91
|
+
};
|
|
56
92
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const checkDate = this._getDateStr(dateStr, i);
|
|
61
|
-
dates.push({ date: checkDate, category: 'capital_flow', computation: 'crowd-cash-flow-proxy' });
|
|
93
|
+
if (!cashFlowData || !assetFlowData || cashFlowData.net_cash_flow_proxy >= 0) {
|
|
94
|
+
// Not a net withdrawal day
|
|
95
|
+
return defaults;
|
|
62
96
|
}
|
|
63
|
-
const refs = dates.map(d =>
|
|
64
|
-
db.collection(collection).doc(d.date)
|
|
65
|
-
.collection(resultsSub).doc(d.category)
|
|
66
|
-
.collection(compsSub).doc(d.computation)
|
|
67
|
-
);
|
|
68
|
-
const snapshots = await db.getAll(...refs);
|
|
69
|
-
const dataMap = new Map();
|
|
70
|
-
snapshots.forEach((snap, idx) => {
|
|
71
|
-
if (snap.exists) dataMap.set(idx, snap.data());
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// 2. Find the withdrawal signal
|
|
75
|
-
let withdrawalSignal = null;
|
|
76
|
-
let withdrawalSignalDay = null;
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
98
|
+
const netCashFlow = cashFlowData.net_cash_flow_proxy; // This is a negative number
|
|
99
|
+
let totalNetOutflow = 0;
|
|
100
|
+
const allFlows = [];
|
|
101
|
+
|
|
102
|
+
for (const [ticker, data] of Object.entries(assetFlowData)) {
|
|
103
|
+
// We only care about *negative* flow (liquidation)
|
|
104
|
+
if (data.net_flow_contribution < 0) {
|
|
105
|
+
totalNetOutflow += data.net_flow_contribution; // Summing negative numbers
|
|
106
|
+
allFlows.push({
|
|
107
|
+
ticker: ticker,
|
|
108
|
+
net_flow_contribution: data.net_flow_contribution
|
|
109
|
+
});
|
|
86
110
|
}
|
|
87
111
|
}
|
|
88
112
|
|
|
89
|
-
if (
|
|
113
|
+
if (totalNetOutflow === 0) {
|
|
114
|
+
// Net withdrawal day, but no negative flow detected
|
|
90
115
|
return {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
116
|
+
...defaults,
|
|
117
|
+
is_net_withdrawal_day: true,
|
|
118
|
+
net_cash_flow_proxy: netCashFlow,
|
|
119
|
+
funding_percentage: 0
|
|
94
120
|
};
|
|
95
121
|
}
|
|
96
122
|
|
|
97
|
-
//
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
signal_day: withdrawalSignalDay,
|
|
104
|
-
days_since_signal: daysSinceSignal
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// 4. Use in-memory data for today's analysis
|
|
109
|
-
// 'trading_effect' will be negative if the crowd is net-selling
|
|
110
|
-
const netSellPct = cashFlowData.components?.trading_effect || 0;
|
|
111
|
-
const netWithdrawalPct = Math.abs(withdrawalSignal.cash_flow_effect_proxy);
|
|
112
|
-
|
|
113
|
-
// INVERTED LOGIC: Find top *sells*
|
|
114
|
-
const topLiquidations = Object.entries(assetFlowData)
|
|
115
|
-
.filter(([ticker, data]) => data.net_crowd_flow_pct < 0) // Find assets with negative flow
|
|
116
|
-
.sort(([, a], [, b]) => a.net_crowd_flow_pct - b.net_crowd_flow_pct) // Sort ascending (most negative first)
|
|
117
|
-
.slice(0, 10)
|
|
118
|
-
.map(([ticker, data]) => ({
|
|
119
|
-
ticker,
|
|
120
|
-
net_flow_pct: data.net_crowd_flow_pct
|
|
121
|
-
}));
|
|
123
|
+
// Calculate percent_of_total_outflow for each
|
|
124
|
+
const asset_flow_details = allFlows.map(flow => ({
|
|
125
|
+
...flow,
|
|
126
|
+
// (Negative / Negative) * 100 = Positive %
|
|
127
|
+
percent_of_total_outflow: (flow.net_flow_contribution / totalNetOutflow) * 100
|
|
128
|
+
})).sort((a, b) => a.net_flow_contribution - b.net_flow_contribution); // Sort ascending (most negative first)
|
|
122
129
|
|
|
123
130
|
return {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
top_liquidation_assets: topLiquidations
|
|
131
|
+
is_net_withdrawal_day: true,
|
|
132
|
+
net_cash_flow_proxy: netCashFlow,
|
|
133
|
+
total_net_capital_flow: totalNetOutflow,
|
|
134
|
+
// (Negative / Negative) * 100 = Positive %
|
|
135
|
+
funding_percentage: (netCashFlow < 0) ? (totalNetOutflow / netCashFlow) * 100 : null,
|
|
136
|
+
top_outflow_assets: asset_flow_details.slice(0, 5),
|
|
137
|
+
asset_flow_details: asset_flow_details
|
|
132
138
|
};
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
reset() {
|
|
142
|
+
// No state
|
|
143
|
+
}
|
|
137
144
|
}
|
|
138
145
|
|
|
139
146
|
module.exports = CashFlowLiquidation;
|
|
@@ -1,84 +1,124 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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).
|
|
6
9
|
*/
|
|
10
|
+
const { loadInstrumentMappings } = require('../../utils/sector_mapping_provider');
|
|
7
11
|
|
|
8
12
|
class CrowdSharpeRatioProxy {
|
|
9
|
-
constructor() {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.mappings = null;
|
|
15
|
+
}
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
|
-
*
|
|
13
|
-
* @
|
|
14
|
-
* @param {object} config The computation system configuration.
|
|
15
|
-
* @param {object} computedDependencies In-memory results from previous passes.
|
|
16
|
-
* @returns {Promise<object|null>} The analysis result or null.
|
|
18
|
+
* Defines the output schema for this calculation.
|
|
19
|
+
* @returns {object} JSON Schema object
|
|
17
20
|
*/
|
|
18
|
-
|
|
19
|
-
const
|
|
21
|
+
static getSchema() {
|
|
22
|
+
const tickerSchema = {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"description": "Sharpe Ratio proxy metrics for a specific asset.",
|
|
25
|
+
"properties": {
|
|
26
|
+
"sharpe_ratio_proxy": {
|
|
27
|
+
"type": "number",
|
|
28
|
+
"description": "Risk-adjusted return proxy (Mean P&L / StdDev P&L). Assumes risk-free rate is 0."
|
|
29
|
+
},
|
|
30
|
+
"average_pnl": { "type": "number" },
|
|
31
|
+
"std_dev_pnl": { "type": "number" },
|
|
32
|
+
"variance_pnl": { "type": "number" },
|
|
33
|
+
"position_count": { "type": "number" }
|
|
34
|
+
},
|
|
35
|
+
"required": ["sharpe_ratio_proxy", "average_pnl", "std_dev_pnl", "position_count"]
|
|
36
|
+
};
|
|
20
37
|
|
|
21
|
-
|
|
22
|
-
|
|
38
|
+
return {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"description": "Calculates a risk-adjusted return (Sharpe Ratio proxy) for each asset based on P&L distribution.",
|
|
41
|
+
"patternProperties": {
|
|
42
|
+
"^.*$": tickerSchema // Matches any string key (ticker)
|
|
43
|
+
},
|
|
44
|
+
"additionalProperties": tickerSchema
|
|
45
|
+
};
|
|
46
|
+
}
|
|
23
47
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Statically declare dependencies.
|
|
50
|
+
*/
|
|
51
|
+
static getDependencies() {
|
|
52
|
+
return [
|
|
53
|
+
'pnl_distribution_per_stock' // Pass 1
|
|
54
|
+
];
|
|
55
|
+
}
|
|
29
56
|
|
|
30
|
-
|
|
57
|
+
process() {
|
|
58
|
+
// No-op
|
|
59
|
+
}
|
|
31
60
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
61
|
+
async getResult(fetchedDependencies) {
|
|
62
|
+
const pnlDistData = fetchedDependencies['pnl_distribution_per_stock'];
|
|
63
|
+
|
|
64
|
+
if (!pnlDistData) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!this.mappings) {
|
|
69
|
+
this.mappings = await loadInstrumentMappings();
|
|
35
70
|
}
|
|
36
71
|
|
|
37
|
-
const
|
|
72
|
+
const result = {};
|
|
38
73
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const stats = pnlDistribution[ticker];
|
|
42
|
-
const N = stats.position_count;
|
|
74
|
+
for (const [instrumentId, data] of Object.entries(pnlDistData)) {
|
|
75
|
+
const { sum, sumSq, count } = data;
|
|
43
76
|
|
|
44
|
-
|
|
45
|
-
|
|
77
|
+
if (count < 2) {
|
|
78
|
+
continue; // Need at least 2 data points for variance
|
|
79
|
+
}
|
|
46
80
|
|
|
47
|
-
|
|
48
|
-
const
|
|
81
|
+
// Calculate Mean (Average P&L)
|
|
82
|
+
const mean = sum / count;
|
|
49
83
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
sharpe_ratio_proxy: 0,
|
|
58
|
-
position_count: N
|
|
59
|
-
};
|
|
84
|
+
// Calculate Variance
|
|
85
|
+
// Var(X) = E[X^2] - (E[X])^2
|
|
86
|
+
const meanSq = sumSq / count;
|
|
87
|
+
const variance = meanSq - (mean * mean);
|
|
88
|
+
|
|
89
|
+
// Handle potential float precision errors
|
|
90
|
+
if (variance < 0) {
|
|
60
91
|
continue;
|
|
61
92
|
}
|
|
62
93
|
|
|
63
|
-
|
|
94
|
+
// Calculate Standard Deviation (Risk)
|
|
95
|
+
const stdDev = Math.sqrt(variance);
|
|
96
|
+
|
|
97
|
+
if (stdDev === 0) {
|
|
98
|
+
continue; // No risk, Sharpe ratio is infinite/undefined
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Calculate Sharpe Ratio Proxy (assuming risk-free rate = 0)
|
|
102
|
+
// Sharpe = Mean(Return) / StdDev(Return)
|
|
103
|
+
const sharpeProxy = mean / stdDev;
|
|
64
104
|
|
|
65
|
-
|
|
66
|
-
// (Assuming 0 risk-free rate)
|
|
67
|
-
const sharpe_proxy = mean / std_dev;
|
|
105
|
+
const ticker = this.mappings.instrumentToTicker[instrumentId] || `id_${instrumentId}`;
|
|
68
106
|
|
|
69
|
-
|
|
107
|
+
result[ticker] = {
|
|
108
|
+
sharpe_ratio_proxy: sharpeProxy,
|
|
70
109
|
average_pnl: mean,
|
|
71
|
-
std_dev_pnl:
|
|
72
|
-
|
|
73
|
-
position_count:
|
|
110
|
+
std_dev_pnl: stdDev,
|
|
111
|
+
variance_pnl: variance,
|
|
112
|
+
position_count: count
|
|
74
113
|
};
|
|
75
114
|
}
|
|
76
|
-
|
|
77
|
-
return
|
|
115
|
+
|
|
116
|
+
return result;
|
|
78
117
|
}
|
|
79
118
|
|
|
80
|
-
|
|
81
|
-
|
|
119
|
+
reset() {
|
|
120
|
+
this.mappings = null;
|
|
121
|
+
}
|
|
82
122
|
}
|
|
83
123
|
|
|
84
124
|
module.exports = CrowdSharpeRatioProxy;
|