UNPKG

quantitivecalc

Version:

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

68 lines (67 loc) 3.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateCalmarRatio = calculateCalmarRatio; /** * Calculates the Calmar Ratio for a rolling window over a dataset. * * The Calmar Ratio is defined as the annualized return divided by the maximum drawdown * over a specified window. This function computes the ratio for each row in the data, * using the specified columns for returns and prices, and stores the result in a new column. * * @param data - Array of data objects containing price and return information. * @param returnsColumn - The key in each data object representing the periodic return value. * @param priceColumn - The key in each data object representing the price value. * @param resultColumn - The key to store the calculated Calmar Ratio in each data object. * @param windowSize - The number of periods to use for the rolling window (default is 252). * @returns A new array of data objects with the Calmar Ratio added to each row in the specified result column. * * @remarks * - If there is insufficient data for the window, or if the maximum drawdown is zero, the result will be `null`. * - Assumes daily data; annualization uses 252 trading days. */ function calculateCalmarRatio(data, returnsColumn, priceColumn, resultColumn, windowSize = 252) { 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 { // Calculate annualized return 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); } } // Calculate maximum drawdown for the window let peak = -Infinity; let maxDrawdown = 0; for (let j = i - windowSize + 1; j <= i; j++) { const price = result[j][priceColumn]; if (typeof price === 'number' && !isNaN(price)) { if (price > peak) peak = price; const drawdown = (peak - price) / peak; if (drawdown > maxDrawdown) maxDrawdown = drawdown; } } if (windowReturns.length > 0 && maxDrawdown > 0) { // Annualized return const avgReturn = windowReturns.reduce((sum, val) => sum + val, 0) / windowReturns.length; const annualizedReturn = avgReturn * 252; // Calmar Ratio = Annualized Return / Maximum Drawdown const calmarRatio = annualizedReturn / maxDrawdown; result[i][resultColumn] = calmarRatio; } else { result[i][resultColumn] = null; } } } return result; }