UNPKG

quantitivecalc

Version:

A TypeScript library providing advanced quantitative finance functions for risk analysis, performance metrics, and technical indicators. (Currently in development)

61 lines (60 loc) 3.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateSharpeRatio = calculateSharpeRatio; /** * Calculates the rolling Sharpe ratio for a given dataset. * * The Sharpe ratio is computed over a moving window of specified size, using the provided returns column. * The result is stored in a new column for each row, with `null` for rows where there is insufficient data. * * @param data - Array of data objects containing return values. * @param returnsColumn - The key in each data object representing the return value. * @param resultColumn - The key to store the calculated Sharpe ratio in each data object. * @param windowSize - The number of periods to use for the rolling window (default: 252, typical for daily data over one year). * @param riskFreeRate - The annual risk-free rate to use in the calculation (default: 0.02, or 2%). * @returns A new array of data objects with the Sharpe ratio added to each row under `resultColumn`. * * @remarks * - The Sharpe ratio is annualized by multiplying by `sqrt(252)`. * - If there is insufficient data in the window, the result is `null` for that row. * - Assumes daily data; adjust `windowSize` and risk-free rate conversion for other frequencies. */ function calculateSharpeRatio(data, returnsColumn, resultColumn, windowSize = 252, // 1 year for daily data riskFreeRate = 0.02) { if (!data || data.length === 0) { return []; } const result = data.map(row => ({ ...row })); const dailyRiskFreeRate = riskFreeRate / 252; // Convert annual to daily 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 > 1) { // Calculate excess returns (returns - risk-free rate) const excessReturns = windowReturns.map(r => r - dailyRiskFreeRate); // Calculate mean and standard deviation of excess returns const meanExcessReturn = excessReturns.reduce((sum, val) => sum + val, 0) / excessReturns.length; const variance = excessReturns.reduce((sum, val) => sum + Math.pow(val - meanExcessReturn, 2), 0) / (excessReturns.length - 1); const stdDev = Math.sqrt(variance); // Sharpe ratio = mean excess return / standard deviation // Annualize by multiplying by sqrt(252) const sharpeRatio = stdDev > 0 ? (meanExcessReturn / stdDev) * Math.sqrt(252) : 0; result[i][resultColumn] = sharpeRatio; } else { result[i][resultColumn] = null; } } } return result; }