UNPKG

stock-indicator

Version:

Stock Indicator Library

340 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkArrayOfNumbers = checkArrayOfNumbers; exports.checkNumber = checkNumber; exports.funMS = funMS; exports.funMA = funMA; exports.funSMA = funSMA; exports.funEMA = funEMA; exports.funWMA = funWMA; exports.funSTD = funSTD; exports.funAVEDEV = funAVEDEV; exports.funArrSub = funArrSub; exports.funArrAdd = funArrAdd; exports.funArrDiv = funArrDiv; exports.funArrMul = funArrMul; exports.funArrAbs = funArrAbs; exports.funRound = funRound; exports.aGtB = aGtB; exports.aLtB = aLtB; exports.aEqB = aEqB; exports.aNeqB = aNeqB; /** * - check if the parameter is an array of numbers or null values * @param {number[]} arr - array to be checked * @param {string} parameName - name of the parameter */ function checkArrayOfNumbers(arr, parameName) { if (!Array.isArray(arr) || arr.some((item) => typeof item !== "number")) { throw new Error(`The ${parameName} parameter must be an array of numbers`); } } /** * - check if the parameter is a number between min and max * @param {number} num - number to be checked * @param {number} min - minimum value * @param {number} max - maximum value * @param {string} parameName - name of the parameter * @param {string} maxName - name of the array */ function checkNumber(num, min, max, parameName, maxName) { const maxStr = Array.isArray(max) ? `the length of the ${maxName} array` : maxName; if (typeof num !== "number" || num < min || num > (Array.isArray(max) ? max.length : max)) { throw new Error(`The ${parameName} parameter must be an array of numbers between ${min} and ${maxStr}`); } } /** * - Sum of n-period moving averages (SUM) * @param {TMixed[]} arr - closing prices of the stock * @param {number} n - number of periods to calculate the SUM, must be greater than 1 and less than the length of the CLOSE array */ function funMS(arr, n) { const doSum = (tArr) => { if (tArr.every((item) => item === null || isNaN(item))) { return null; } return tArr.reduce((acc, cur) => (cur !== null && !isNaN(cur) ? acc + cur : acc), 0); }; // calculate the SUM for each period, starting from the second period const result = []; for (let i = 0; i < arr.length; i++) { result.push(doSum(arr.slice(Math.max(0, i - n + 1), i + 1))); } return result; } /** * - Moving Average (MA) * @param {TMixed[]} arr - - closing prices of the stock * @param {number} n - - number of periods to calculate the moving average, must be between 2 and the length of the CLOSE array * @returns { TMixed[] } } - array of moving average values */ function funMA(arr, n) { const result = []; //对给定的数组arr进行检查,如果包含null,则返回null,否则计算n个周期的移动平均值 const doMA = (iarr, count) => { if (iarr.length < count) { return null; } let sum = 0; for (let i = 0; i < iarr.length; i++) { if (typeof iarr[i] === "number" && !isNaN(iarr[i])) { sum += iarr[i]; } else { return null; } } return sum / count; }; for (let i = 0; i < arr.length; i++) { result.push(doMA(arr.slice(Math.max(0, i - n + 1), i + 1), n)); } return result; } /** * SMA (Simple Moving Average) * @param {TMixed[]} arr - An array of the closing price of the stock * @param {number} n - The number of periods to calculate the SMA for. Must be between 2 and the length of the CLOSE array. * @param {number} m - The number of periods to calculate the SMA for. Must be between 0 and N-1. * @returns {{ SMA: TMixed[] }} - The SMA values for the given data and parameters */ function funSMA(arr, n, m) { return arr.slice(1).reduce((acc, cur, i) => { if (cur === null) { acc.push(null); } else if (i === 0 && (acc[0] === null || acc[0] === 0)) { acc.push(cur); } else { acc.push((cur * m + acc[i] * (n - m)) / n); } return acc; }, [arr[0]]); } /** * - Exponential Moving Average (EMA) * @param {TMixed[]} arr - closing prices of the stock * @param {number} n - number of periods to calculate the EMA,must be greater than 1 and less than the length of the CLOSE array * @param {number} m - number of periods to calculate the initial EMA, default is 1,must be less than N * @returns {{ EMA: TMixed[] }} - object with the EMA values */ function funEMA(arr, n, m = 1) { return arr.slice(1).reduce((acc, cur) => { var _a; acc.push(cur ? (cur * (m + 1) + ((_a = acc.slice(-1)[0]) !== null && _a !== void 0 ? _a : cur) * (n - m)) / (n + 1) : null); return acc; }, [arr[0]]); } /** * WMA - Weighted Moving Average * @param {TMixed[]} arr should be an array of numbers or null values * @param {number} n should be a number between 2 and the length of the data array * @returns {TMixed[]} WMA values */ function funWMA(arr, n) { // calculate WMA const cumsum = (arr) => { const sum = arr .slice(1) .reduce((acc, cur, i) => (acc && cur ? acc + cur * (i + 1) : null), arr[0]); return sum ? sum / ((arr.length * (arr.length + 1)) / 2) : null; }; return arr.reduce((acc, cur, i) => { if (i < n - 1) { acc.push(null); } else { const res = cumsum(arr.slice(i - n + 1, i + 1)); acc.push(res); } return acc; }, []); } /** * - Standard Deviation (STD) * @param {TMixed[]} arr - closing prices of the stock * @param {number} n - number of periods to calculate the STD, must be greater than 1 and less than the length of the CLOSE array * @returns { TMixed[] } - array of standard deviation values */ function funSTD(arr, n) { return arr.reduce((acc, cur, i) => { if (i < n - 1) { acc.push(null); } else { const mean = arr .slice(i - n + 1, i + 1) .reduce((acc, cur) => acc + (cur !== null && cur !== void 0 ? cur : 0), 0) / n; const variance = arr .slice(i - n + 1, i + 1) .reduce((acc, cur) => acc + ((cur !== null && cur !== void 0 ? cur : 0) - mean) ** 2 / (n - 1), 0); const std = Math.sqrt(variance); acc.push(std); } return acc; }, []); } /** * - Average Variance Enhanced (AVEDEV) * @param {TMixed[]} arr - closing prices of the stock * @param {number} n - number of periods to calculate the AVEDEV, must be greater than 1 and less than the length of the CLOSE array * @returns { TMixed[] } - array of average variance enhanced values */ function funAVEDEV(arr, n) { const result = []; for (let i = 0; i < arr.length; i++) { const curArr = arr.slice(Math.max(0, i - n + 1), i + 1); if (curArr.some((item) => item === null || isNaN(item)) || curArr.length < n) { result.push(null); continue; } const mean = curArr.reduce((acc, cur) => acc + (cur !== null && cur !== void 0 ? cur : 0), 0) / n; result.push(curArr.reduce((acc, cur) => acc + Math.abs(cur - mean), 0) / n); } return result; } /** * - subtract two arrays element by element * @param {TMixed[]} subtractor - array to be subtracted from * @param {TMixed[]} minuend - array to be subtracted * @returns {TMixed[]} - array of subtracted values */ function funArrSub(subtractor, minuend) { var _a, _b; const count = Math.max(subtractor.length, minuend.length); const results = []; for (let i = 0; i < count; i++) { results.push(subtractor[i] !== null && minuend[i] !== null ? ((_a = subtractor[i]) !== null && _a !== void 0 ? _a : 0) - ((_b = minuend[i]) !== null && _b !== void 0 ? _b : 0) : null); } return results; } /** * - add two or more arrays element by element * @param {TMixed[]}...args - arrays to be added * @returns {TMixed[]} - array of added values */ function funArrAdd(...args) { var _a; const result = []; const maxLength = args.reduce((p, v) => Math.max(p, v.length), 0); for (let i = 0; i < maxLength; i++) { let sum = 0; for (let j = 0; j < args.length; j++) { if (i < args[j].length) { sum += (_a = args[j][i]) !== null && _a !== void 0 ? _a : 0; } } result.push(sum); } return result; } /** * - divide two arrays element by element * @param {TMixed[]} divisor - array to be divided * @param {TMixed[]} dividend - array to divide by * @returns {TMixed[]}- array of divided values */ function funArrDiv(divisor, dividend) { const count = Math.max(divisor.length, dividend.length); const results = []; for (let i = 0; i < count; i++) { if (dividend[i] === null || divisor[i] === null || dividend[i] === 0) { results.push(null); continue; } else { results.push(divisor[i] / dividend[i]); } } return results; } /** * - multiply two arrays element by element * @param {TMixed[]} arr1 - first array to be multiplied * @param {TMixed[]} arr2 - second array to be multiplied * @returns {TMixed[]} - array of multiplied values */ function funArrMul(arr1, arr2) { const count = Math.max(arr1.length, arr2.length); const results = []; for (let i = 0; i < count; i++) { if (arr1[i] === null || arr2[i] === null) { results.push(null); continue; } else { results.push(arr1[i] * arr2[i]); } } return results; } /** * - absolute value of an array * @param {TMixed[]} arr - array to be absolute value of * @returns {TMixed[]} - array of absolute values */ function funArrAbs(arr) { return arr.map((v) => (v === null ? null : Math.abs(v))); } /** * - rounded to n decimal places * @param {number} num - number to be rounded * @param {number} n - number of decimal places to round to * @returns {number} - rounded number */ function funRound(num, n) { if (typeof num !== "number" || isNaN(num)) return null; return Math.round(num * Math.pow(10, n)) / Math.pow(10, n); } /** * - check if a is greater than b with a given precision * @param {number} a - first number * @param {number} b - second number * @param {number} precision - precision to compare the numbers * @returns {boolean} - true if a is greater than b, false otherwise */ function aGtB(a, b, precision = 0.0001) { return a - b > precision; } /** * - check if a is less than b with a given precision * @param {number} a - first number * @param {number} b - second number * @param {number} precision - precision to compare the numbers * @returns {boolean} - true if a is less than b, false otherwise */ function aLtB(a, b, precision = 0.0001) { return b - a > precision; } /** * - check if a is equal to b with a given precision * @param {number} a - first number * @param {number} b - second number * @param {number} precision - precision to compare the numbers * @returns {boolean} - true if a is equal to b, false otherwise */ function aEqB(a, b, precision = 0.0001) { return Math.abs(a - b) <= precision; } /** * - check if a is not equal to b with a given precision * @param {number} a - first number * @param {number} b - second number * @param {number} precision - precision to compare the numbers * @returns {boolean} - true if a is not equal to b, false otherwise */ function aNeqB(a, b, precision = 0.0001) { return Math.abs(a - b) > precision; } //# sourceMappingURL=index.js.map