-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathembedded-functions-backup.js
More file actions
197 lines (161 loc) · 6.26 KB
/
embedded-functions-backup.js
File metadata and controls
197 lines (161 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/**
* Backup of Embedded Calculation Functions from index_template.html
* These functions were originally embedded in the Vue component methods
* Created as backup before switching to external JS libraries
*/
// ====================================
// OPTIMIZATION FUNCTIONS
// ====================================
/**
* Original embedded gradient descent optimization
*/
function backupGradientDescentOptimization() {
// This would contain the original function from the HTML
// Implementation moved to backup for reference
}
/**
* Original embedded calculate objective function
*/
function backupCalculateObjectiveFunction(weights) {
// Original implementation from HTML
}
/**
* Original embedded calculate gradients
*/
function backupCalculateGradients(weights, stepSize) {
// Original implementation from HTML
}
// ====================================
// PORTFOLIO METRICS FUNCTIONS
// ====================================
/**
* Original embedded calculate metrics for returns
*/
function backupCalculateMetricsForReturns(returns) {
if (!returns || returns.length === 0) {
return { cagr: 0, volatility: 0, sharpe: 0, sortino: 0, cvar: 0, maxDrawdown: 0 };
}
// Convert monthly returns to decimal form
const monthlyReturns = returns.map(r => r / 100);
// Calculate annualized return (CAGR)
const totalReturn = monthlyReturns.reduce((acc, ret) => acc * (1 + ret), 1);
const years = returns.length / 12;
const cagr = years > 0 ? (Math.pow(totalReturn, 1/years) - 1) * 100 : 0;
// Calculate volatility (annualized standard deviation)
const meanReturn = monthlyReturns.reduce((a, b) => a + b, 0) / monthlyReturns.length;
const variance = monthlyReturns.reduce((acc, ret) => acc + Math.pow(ret - meanReturn, 2), 0) / monthlyReturns.length;
const volatility = Math.sqrt(variance * 12) * 100; // Annualized
// Calculate Sharpe ratio (assuming 2% risk-free rate)
const riskFreeRate = 0.02;
const sharpe = volatility > 0 ? (cagr - riskFreeRate) / volatility : 0;
// Calculate Sortino ratio (downside deviation)
const downsideReturns = monthlyReturns.filter(ret => ret < meanReturn);
const downsideVariance = downsideReturns.length > 0 ?
downsideReturns.reduce((acc, ret) => acc + Math.pow(ret - meanReturn, 2), 0) / downsideReturns.length : 0;
const downsideDeviation = Math.sqrt(downsideVariance * 12) * 100;
const sortino = downsideDeviation > 0 ? (cagr - riskFreeRate) / downsideDeviation : 0;
// Calculate CVaR (5% worst returns)
const sortedReturns = [...monthlyReturns].sort((a, b) => a - b);
const cvarIndex = Math.floor(sortedReturns.length * 0.05);
const cvar = cvarIndex > 0 ?
sortedReturns.slice(0, cvarIndex).reduce((a, b) => a + b, 0) / cvarIndex * 100 : 0;
// Calculate maximum drawdown
let peak = 1;
let maxDrawdown = 0;
let cumulative = 1;
monthlyReturns.forEach(ret => {
cumulative *= (1 + ret);
if (cumulative > peak) peak = cumulative;
const drawdown = (peak - cumulative) / peak;
if (drawdown > maxDrawdown) maxDrawdown = drawdown;
});
return {
cagr: parseFloat(cagr.toFixed(2)),
volatility: parseFloat(volatility.toFixed(2)),
sharpe: parseFloat(sharpe.toFixed(2)),
sortino: parseFloat(sortino.toFixed(2)),
cvar: parseFloat(cvar.toFixed(2)),
maxDrawdown: parseFloat((maxDrawdown * 100).toFixed(2))
};
}
// ====================================
// UTILITY FUNCTIONS
// ====================================
/**
* Original embedded is valid weight allocation
*/
function backupIsValidWeightAllocation(weights) {
const sum = Object.values(weights).reduce((a, b) => (parseFloat(a) || 0) + (parseFloat(b) || 0), 0);
return Math.abs(sum - 100) < 0.01 && Object.values(weights).every(w => (parseFloat(w) || 0) >= 0);
}
/**
* Original embedded is metric improvement
*/
function backupIsMetricImprovement(newMetric, currentBest) {
if (this.optimizationObjective === 'risk' || this.optimizationObjective === 'cvar') {
return newMetric < currentBest; // Lower is better for risk measures
} else {
return newMetric > currentBest; // Higher is better for return/ratio measures
}
}
/**
* Original embedded normalize weights
*/
function backupNormalizeWeights(weights) {
const normalizedWeights = { ...weights };
// Calculate sum and normalize
const sum = Object.values(normalizedWeights).reduce((a, b) => (parseFloat(a) || 0) + (parseFloat(b) || 0), 0);
if (sum > 0) {
Object.keys(normalizedWeights).forEach(asset => {
normalizedWeights[asset] = (parseFloat(normalizedWeights[asset]) || 0) * 100 / sum;
});
}
return normalizedWeights;
}
/**
* Original embedded calculate portfolio returns
*/
function backupCalculatePortfolioReturns(indices, weights) {
const returns = [];
const totalWeight = Object.values(weights).reduce((sum, weight) => sum + parseFloat(weight || 0), 0);
if (totalWeight === 0) return indices.map(() => 0);
// Get filtered data based on current date range
const filteredData = this.getFilteredReturnsData();
if (!filteredData.assets) return indices.map(() => 0);
indices.forEach(index => {
let portfolioReturn = 0;
let totalValidWeight = 0;
Object.keys(weights).forEach(asset => {
const weight = parseFloat(weights[asset]);
if (weight > 0 && filteredData.assets[asset] && filteredData.assets[asset][index] !== null) {
portfolioReturn += (weight / 100) * filteredData.assets[asset][index];
totalValidWeight += weight;
}
});
// Normalize if some assets were missing
if (totalValidWeight > 0 && totalValidWeight !== 100) {
portfolioReturn = portfolioReturn * (100 / totalValidWeight);
}
returns.push(portfolioReturn);
});
return returns;
}
/**
* Original embedded calculate cumulative returns
*/
function backupCalculateCumulativeReturns(returns) {
if (!returns || returns.length === 0) return [];
let cumulative = 0;
const result = [];
for (let i = 0; i < returns.length; i++) {
if (i === 0) {
result.push(0);
} else {
cumulative = (1 + cumulative / 100) * (1 + returns[i-1] / 100) * 100 - 100;
result.push(cumulative);
}
}
return result;
}
// Note: This file serves as a backup of the original embedded functions
// before they were replaced with calls to external JS libraries