UNPKG

quantitivecalc

Version:

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

74 lines (73 loc) 3.17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateStochasticOscillator = calculateStochasticOscillator; const calculateMovingAverage_1 = require("./calculateMovingAverage"); /** * Calculates the Stochastic Oscillator (%K and %D) for a given dataset. * * The Stochastic Oscillator is a momentum indicator comparing a particular closing price of a security to a range of its prices over a certain period of time. * * @param data - Array of data objects containing price information. * @param highColumn - The key in each data object representing the high price. * @param lowColumn - The key in each data object representing the low price. * @param closeColumn - The key in each data object representing the close price. * @param kColumn - The key to store the calculated %K value (default: 'stoch_k'). * @param dColumn - The key to store the calculated %D value (default: 'stoch_d'). * @param kPeriod - The lookback period for %K calculation (default: 14). * @param dPeriod - The period for %D (moving average of %K) calculation (default: 3). * @returns A new array of data objects with %K and %D values added. If insufficient data is available for a calculation, the corresponding value will be `null`. */ function calculateStochasticOscillator(data, highColumn, lowColumn, closeColumn, kColumn = 'stoch_k', dColumn = 'stoch_d', kPeriod = 14, dPeriod = 3) { if (!data || data.length === 0) { return []; } // Calculate %K const withK = data.map((row, i) => { if (i < kPeriod - 1) { return { ...row, [kColumn]: null, }; } let highestHigh = -Infinity; let lowestLow = Infinity; let validData = false; // Find highest high and lowest low over the period for (let j = i - kPeriod + 1; j <= i; j++) { const high = data[j][highColumn]; const low = data[j][lowColumn]; if (typeof high === 'number' && typeof low === 'number' && !isNaN(high) && !isNaN(low)) { highestHigh = Math.max(highestHigh, high); lowestLow = Math.min(lowestLow, low); validData = true; } } if (!validData || highestHigh === lowestLow) { return { ...row, [kColumn]: null, }; } const currentClose = row[closeColumn]; if (typeof currentClose !== 'number' || isNaN(currentClose)) { return { ...row, [kColumn]: null, }; } const kValue = ((currentClose - lowestLow) / (highestHigh - lowestLow)) * 100; return { ...row, [kColumn]: kValue, __temp_k: kValue, }; }); // Calculate %D (Simple Moving Average of %K) const withD = (0, calculateMovingAverage_1.calculateMovingAverage)(withK, '__temp_k', dColumn, dPeriod, 'simple'); // Clean up temporary column return withD.map(row => { const cleanRow = { ...row }; delete cleanRow.__temp_k; return cleanRow; }); }