bollinger-bands
Version:
Fintach math utility to calculate bollinger bands.
199 lines (142 loc) • 3.24 kB
JavaScript
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;
;