quantitivecalc
Version:
A TypeScript library providing advanced quantitative finance functions for risk analysis, performance metrics, and technical indicators. (Currently in development)
88 lines (87 loc) • 4.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateVaR = calculateVaR;
const getZScore_1 = require("./getZScore");
/**
* Calculates Value at Risk (VaR) for a time series of returns using parametric, historical, or Monte Carlo methods.
*
* @param data - Array of objects representing time series data, each containing a column with returns.
* @param returnsColumn - The key in each data object that contains the return value.
* @param resultColumn - The key in each data object where the calculated VaR will be stored.
* @param confidenceLevel - The confidence level for VaR calculation (e.g., 0.05 for 5% VaR, default is 0.05).
* @param windowSize - The number of periods to use for the rolling window calculation (default is 252).
* @param method - The method to use for VaR calculation: 'parametric', 'historical', or 'monteCarlo' (default is 'historical').
* @returns A new array of objects with VaR values added in the specified result column. If insufficient data is available for a window, the result is `null`.
*/
function calculateVaR(data, returnsColumn, resultColumn, confidenceLevel = 0.05, // 5% VaR (95% confidence)
windowSize = 252, method = 'historical') {
if (!data || data.length === 0) {
return [];
}
const result = data.map(row => ({ ...row }));
for (let i = 0; i < result.length; i++) {
if (i < windowSize - 1) {
result[i][resultColumn] = null;
}
else {
// Get returns for the window
const windowReturns = [];
for (let j = i - windowSize + 1; j <= i; j++) {
const returnValue = result[j][returnsColumn];
if (typeof returnValue === 'number' && !isNaN(returnValue)) {
windowReturns.push(returnValue);
}
}
if (windowReturns.length > 10) {
let varValue;
switch (method) {
case 'parametric': {
// Assume normal distribution
const mean = windowReturns.reduce((sum, val) => sum + val, 0) / windowReturns.length;
const variance = windowReturns.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (windowReturns.length - 1);
const stdDev = Math.sqrt(variance);
// Z-score for confidence level (e.g., -1.645 for 5% VaR)
const zScore = (0, getZScore_1.getZScore)(confidenceLevel);
varValue = mean + zScore * stdDev;
break;
}
case 'historical': {
// Sort returns and take percentile
const sortedReturns = [...windowReturns].sort((a, b) => a - b);
// Use Math.ceil to ensure we don't go below the actual percentile
const index = Math.max(0, Math.ceil(confidenceLevel * sortedReturns.length) - 1);
varValue = sortedReturns[index];
break;
}
case 'monteCarlo': {
// Simple Monte Carlo simulation
const mcMean = windowReturns.reduce((sum, val) => sum + val, 0) / windowReturns.length;
const mcVariance = windowReturns.reduce((sum, val) => sum + Math.pow(val - mcMean, 2), 0) / (windowReturns.length - 1);
const mcStdDev = Math.sqrt(mcVariance);
// Generate random scenarios
const simulations = 10000;
const scenarios = [];
for (let k = 0; k < simulations; k++) {
// Box-Muller transform for normal random numbers
const u1 = Math.random();
const u2 = Math.random();
const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
scenarios.push(mcMean + z * mcStdDev);
}
scenarios.sort((a, b) => a - b);
const mcIndex = Math.max(0, Math.ceil(confidenceLevel * scenarios.length) - 1);
varValue = scenarios[mcIndex];
break;
}
default:
throw new Error(`Unknown VaR method: ${method}`);
}
result[i][resultColumn] = varValue;
}
else {
result[i][resultColumn] = null;
}
}
}
return result;
}