UNPKG

bollinger-bands

Version:

Fintach math utility to calculate bollinger bands.

199 lines (142 loc) 3.24 kB
'use strict'; const isNumber = subject => typeof subject === 'number'; // Dynamic Weighted Moving Average // @param {Number|Array.<Number>} alpha // Smoothed moving average // Exponential moving average with 86% total weight // simple moving average var ma = (data, size) => { const length = data.length; if (!size) { return data.reduce((a, b) => a + b) / length } if (size <= 1) { return data.slice() } if (size > length) { return Array(length) } const prepare = size - 1; const ret = []; let sum = 0; let i = 0; let counter = 0; let datum; for (; i < length && counter < prepare; i ++) { datum = data[i]; if (isNumber(datum)) { sum += datum; counter ++; } } for (; i < length; i ++) { datum = data[i]; if (isNumber(datum)) { sum += datum; } if (isNumber(data[i - size])) { sum -= data[i - size]; } ret[i] = sum / size; } return ret }; // Weighted moving average var deviation = (data, size) => { const length = data.length; const avg = ma(data, size); const ret = []; let i = size - 1; let j; let sum; for (; i < length; i ++) { sum = 0; j = i - size + 1; for (; j <= i; j ++) { sum += Math.pow(data[j] - avg[i], 2); } ret[i] = Math.sqrt(sum / size); } return ret }; const error = ( message // code ) => { const e = new Error(message); // if (code) { // e.code = code // } throw e }; const manipulate2Array = (a, b, mutator) => { if (a.length !== b.length) { error('the length of arrays not match'); } return a.map((x, i) => mutator(x, b[i])) }; const manipulateArray = (a, b, mutator) => { return a.map(x => mutator(x, b)) }; const isArray$1 = (a, b) => [a, b].map(Array.isArray); const cleanArray = (array) => { array.forEach((item, i) => { if (item !== item) { delete array[i]; } }); }; const orderUnaware = ( a, b, mutator, mutatorReverse, ensureNumber ) => { const [A, B] = isArray$1(a, b); const ret = A ? B ? manipulate2Array(a, b, mutator) : manipulateArray(a, b, mutator) : B ? manipulateArray(b, a, mutatorReverse) : error('at least one array is required'); if (ensureNumber) { cleanArray(ret); } return ret }; const orderAware = ( a, b, mutator, ensureNumber ) => { const [A, B] = isArray$1(a, b); const ret = A ? B ? manipulate2Array(a, b, mutator) : manipulateArray(a, b, mutator) : error('the first argument must be an array'); if (ensureNumber) { cleanArray(ret); } return ret }; const add = (a, b) => a + b; const addReverse = (a, b) => b + a; var add$1 = (a, b, n) => orderUnaware(a, b, add, addReverse, n); const sub = (a, b) => a - b; var sub$1 = (a, b, n) => orderAware(a, b, sub, n); const mul = (a, b) => a * b; var mul$1 = (a, b, n) => orderUnaware(a, b, mul, mul, n); var index = ((datum, size = 20, times = 2, { ma: avg, sd } = {}) => { avg = avg || ma(datum, size); sd = sd || deviation(datum, size); const timesSd = mul$1(sd, times); return { upper: add$1(avg, timesSd), mid: avg, lower: sub$1(avg, timesSd) }; }); module.exports = index;