@railpath/finance-toolkit
Version:
Production-ready finance library for portfolio construction, risk analytics, quantitative metrics, and ML-based regime detection
67 lines (66 loc) • 2.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateCovarianceMatrix = calculateCovarianceMatrix;
const CovarianceMatrixOptionsSchema_1 = require("../schemas/CovarianceMatrixOptionsSchema");
const CovarianceMatrixResultSchema_1 = require("../schemas/CovarianceMatrixResultSchema");
/**
* Calculate Covariance Matrix
*
* Cov(X,Y) = E[(X - μ_X)(Y - μ_Y)]
*
* Measures how two variables move together.
* Diagonal = variances
* Off-diagonal = covariances
*
* @param options - Array of return series and optional labels
* @returns Covariance matrix with variances
*/
function calculateCovarianceMatrix(options) {
const { returns, labels } = CovarianceMatrixOptionsSchema_1.CovarianceMatrixOptionsSchema.parse(options);
const n = returns.length;
// Validate all series have same length
const seriesLength = returns[0].length;
if (returns.some((series) => series.length !== seriesLength)) {
throw new Error('All return series must have the same length');
}
if (seriesLength < 2) {
throw new Error('Each return series must have at least 2 data points');
}
// Generate labels if not provided
const finalLabels = labels && labels.length === n
? labels
: Array.from({ length: n }, (_, i) => `Asset ${i + 1}`);
// Calculate means
const means = returns.map((series) => series.reduce((sum, r) => sum + r, 0) / seriesLength);
// Calculate covariance matrix
const matrix = Array.from({ length: n }, () => Array(n).fill(0));
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
let covariance = 0;
for (let k = 0; k < seriesLength; k++) {
covariance +=
(returns[i][k] - means[i]) * (returns[j][k] - means[j]);
}
covariance /= seriesLength - 1; // Sample covariance
matrix[i][j] = covariance;
}
}
// Extract variances (diagonal)
const variances = matrix.map((row, i) => row[i]);
// Calculate average covariance (off-diagonal only)
const offDiagonal = [];
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
offDiagonal.push(matrix[i][j]);
}
}
const averageCovariance = offDiagonal.length > 0
? offDiagonal.reduce((sum, c) => sum + c, 0) / offDiagonal.length
: 0;
return CovarianceMatrixResultSchema_1.CovarianceMatrixResultSchema.parse({
matrix,
labels: finalLabels,
variances,
averageCovariance,
});
}