UNPKG

quantitivecalc

Version:

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

64 lines (63 loc) 3.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateSortinoRatio = calculateSortinoRatio; /** * Calculates the Sortino Ratio for a rolling window over a dataset. * * The Sortino Ratio measures risk-adjusted return, penalizing only downside volatility. * It is computed as: (Mean Return - Target Return) / Downside Deviation (annualized). * * @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 Sortino Ratio in each result object. * @param windowSize - Number of periods in the rolling window (default: 252). * @param riskFreeRate - Annual risk-free rate used as the default target return (default: 0.02). * @param targetReturn - Optional annual target return. If null, uses risk-free rate. * @returns Array of data objects with the Sortino Ratio added in the specified result column. */ function calculateSortinoRatio(data, returnsColumn, resultColumn, windowSize = 252, riskFreeRate = 0.02, targetReturn = null) { if (!data || data.length === 0) { return []; } const result = data.map(row => ({ ...row })); const dailyRiskFreeRate = riskFreeRate / 252; const dailyTargetReturn = targetReturn ? targetReturn / 252 : dailyRiskFreeRate; for (let i = 0; i < result.length; i++) { if (i < windowSize - 1) { result[i][resultColumn] = null; } else { const windowReturns = []; const downsideReturns = []; // Collect returns and downside returns for (let j = i - windowSize + 1; j <= i; j++) { const returnValue = result[j][returnsColumn]; if (typeof returnValue === 'number' && !isNaN(returnValue)) { windowReturns.push(returnValue); // Only include returns below target for downside deviation if (returnValue < dailyTargetReturn) { downsideReturns.push(returnValue - dailyTargetReturn); } } } if (windowReturns.length > 1) { // Calculate mean return const meanReturn = windowReturns.reduce((sum, val) => sum + val, 0) / windowReturns.length; // Calculate downside deviation let downsideDeviation = 0; if (downsideReturns.length > 0) { const downsideVariance = downsideReturns.reduce((sum, val) => sum + val * val, 0) / windowReturns.length; downsideDeviation = Math.sqrt(downsideVariance); } // Sortino Ratio = (Mean Return - Target Return) / Downside Deviation (annualized) const excessReturn = meanReturn - dailyTargetReturn; const sortinoRatio = downsideDeviation > 0 ? (excessReturn / downsideDeviation) * Math.sqrt(252) : 0; result[i][resultColumn] = sortinoRatio; } else { result[i][resultColumn] = null; } } } return result; }