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
JavaScript
;
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;
});
}