quantitivecalc
Version:
A TypeScript library providing advanced quantitative finance functions for risk analysis, performance metrics, and technical indicators. (Currently in development)
103 lines (102 loc) • 4.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateRiskContribution = calculateRiskContribution;
const calculateCorrelationMatrix_1 = require("./calculateCorrelationMatrix");
/**
* Calculates the risk contribution of each asset in a portfolio based on historical returns, asset weights, and a specified window size.
*
* The function computes asset volatilities, the correlation matrix, portfolio volatility, and then derives
* the marginal risk, component risk, and percentage contribution for each asset.
* If insufficient data is provided, returns zeroed results for each asset.
*
* @param returns - Array of asset return objects, each representing a time period.
* @param weights - Object mapping asset names to their portfolio weights.
* @param returnColumns - Array of asset names to include in the calculation.
* @param windowSize - Number of periods to use for calculations (default: 252).
* @returns An object mapping each asset name to its risk contribution metrics:
* - volatility: Standard deviation of asset returns.
* - marginalRisk: Marginal risk contribution of the asset to the portfolio.
* - componentRisk: Component risk contribution (weight × marginal risk).
* - contributionPercent: Percentage contribution to total portfolio risk.
*/
function calculateRiskContribution(returns, weights, returnColumns, windowSize = 252) {
if (!returns || returns.length < windowSize || returnColumns.length === 0) {
const emptyResult = {};
returnColumns.forEach(asset => {
emptyResult[asset] = {
volatility: 0,
marginalRisk: 0,
componentRisk: 0,
contributionPercent: 0,
};
});
return emptyResult;
}
// Use the most recent window of data
const windowData = returns.slice(-windowSize);
// Calculate asset volatilities (standard deviation of returns)
const volatilities = {};
const assetReturns = {};
returnColumns.forEach(asset => {
const validReturns = [];
windowData.forEach(row => {
const ret = row[asset];
if (typeof ret === 'number' && !isNaN(ret)) {
validReturns.push(ret);
}
});
assetReturns[asset] = validReturns;
if (validReturns.length > 1) {
const mean = validReturns.reduce((sum, ret) => sum + ret, 0) / validReturns.length;
const variance = validReturns.reduce((sum, ret) => sum + Math.pow(ret - mean, 2), 0) / (validReturns.length - 1);
volatilities[asset] = Math.sqrt(variance);
}
else {
volatilities[asset] = 0;
}
});
// Calculate correlation matrix for the assets
const correlationMatrices = (0, calculateCorrelationMatrix_1.calculateCorrelationMatrix)(windowData, returnColumns, windowSize);
const correlationMatrix = correlationMatrices.length > 0 ? correlationMatrices[correlationMatrices.length - 1] : {};
// Calculate portfolio volatility
let portfolioVariance = 0;
returnColumns.forEach(asset1 => {
returnColumns.forEach(asset2 => {
const weight1 = weights[asset1] || 0;
const weight2 = weights[asset2] || 0;
const vol1 = volatilities[asset1] || 0;
const vol2 = volatilities[asset2] || 0;
const correlation = correlationMatrix[asset1] ? correlationMatrix[asset1][asset2] || 0 : 0;
portfolioVariance += weight1 * weight2 * vol1 * vol2 * correlation;
});
});
const portfolioVolatility = Math.sqrt(Math.max(0, portfolioVariance));
// Calculate risk contributions
const riskContribution = {};
returnColumns.forEach(asset => {
const assetWeight = weights[asset] || 0;
const assetVolatility = volatilities[asset] || 0;
// Calculate marginal risk contribution
let marginalRisk = 0;
if (portfolioVolatility > 0) {
returnColumns.forEach(otherAsset => {
const otherWeight = weights[otherAsset] || 0;
const otherVolatility = volatilities[otherAsset] || 0;
const correlation = correlationMatrix[asset] ? correlationMatrix[asset][otherAsset] || 0 : 0;
marginalRisk += otherWeight * otherVolatility * assetVolatility * correlation;
});
marginalRisk = marginalRisk / portfolioVolatility;
}
// Calculate component risk contribution
const componentRisk = assetWeight * marginalRisk;
// Calculate percentage contribution
const contributionPercent = portfolioVolatility > 0 ? (componentRisk / portfolioVolatility) * 100 : 0;
riskContribution[asset] = {
volatility: assetVolatility,
marginalRisk,
componentRisk,
contributionPercent,
};
});
return riskContribution;
}