ta-lib
Version:
A technical analysis library written entirely in JavaScript/TypeScript
241 lines (240 loc) • 7.92 kB
JavaScript
function arrayMax(array) {
return Math.max.apply(Math, array.filter(function (n) {
return !isNaN(n);
}));
}
exports.arrayMax = arrayMax;
function arrayMin(array) {
return Math.min.apply(Math, array.filter(function (n) {
return !isNaN(n);
}));
}
exports.arrayMin = arrayMin;
function upscale(number, places) {
return Math.round(number * Math.pow(10, places));
}
exports.upscale = upscale;
function downscale(number, places) {
return number / Math.pow(10, places);
}
exports.downscale = downscale;
function diff(x, y) {
return ((x - y) / ((x + y) / 2)) * 100;
}
exports.diff = diff;
function average(a) {
var r = { mean: 0, variance: 0, deviation: 0 }, t = a.length, m, l, s;
for (m, s = 0, l = t; l--; s += a[l]) {
}
for (m = r.mean = s / t, l = t, s = 0; l--; s += Math.pow(a[l] - m, 2)) {
}
return r.deviation = Math.sqrt(r.variance = s / t), r;
}
exports.average = average;
function BBANDS(array, period, deviation) {
var bbands = {
middleband: [],
lowband: [],
highband: []
}, sma = SMA(array, period), avg, i, arr;
if (isNaN(deviation))
deviation = 2;
for (i = period - 1; i >= 0; i--) {
arr = array.slice(i, i + period);
avg = average(arr);
bbands.highband[i] = sma[i] + (deviation * avg.deviation);
bbands.lowband[i] = sma[i] - (deviation * avg.deviation);
bbands.middleband[i] = sma[i];
}
return bbands;
}
exports.BBANDS = BBANDS;
function AROON(higharray, lowarray, period) {
var harr = higharray.slice(0, period), larr = lowarray.slice(0, period), hh = arrayMin(harr), hday = harr.indexOf(hh), ll = arrayMin(larr), lday = larr.indexOf(ll);
return {
up: ((period - hday) / period) * 100,
down: ((period - lday) / period) * 100
};
}
exports.AROON = AROON;
function MFI(higharray, lowarray, closearray, volumearray, period) {
var harr = higharray.slice(0, period).reverse(), larr = lowarray.slice(0, period).reverse(), clarr = closearray.slice(0, period).reverse(), vlarr = volumearray.slice(0, period).reverse(), lasttp = 0, first = true, posmf = 0, negmf = 0, i, tp;
for (i = 0; i < closearray.length; i++) {
if (first) {
lasttp = (harr[i] + larr[i] + clarr[i]) / 3;
first = false;
}
else {
tp = (harr[i] + larr[i] + clarr[i]) / 3;
if (tp > lasttp) {
posmf += (tp * vlarr[0]);
}
else if (tp < lasttp) {
negmf += (tp * vlarr[0]);
}
lasttp = tp;
}
}
return (100 - (100 / (1 + (posmf / negmf))));
}
exports.MFI = MFI;
function RSI(array, rsiperiod) {
var rsi = [], i, j, loss, gain, diff, avggain, avgloss, first = true;
for (i = rsiperiod - 1; i >= 0; i--) {
loss = gain = 0;
if (first) {
for (j = i + rsiperiod - 1; j >= i; j--) {
diff = array[j + 1] - array[j];
if (diff > 0) {
loss += Math.abs(diff);
}
else {
gain += Math.abs(diff);
}
}
first = false;
avggain = gain / rsiperiod;
avgloss = loss / rsiperiod;
}
else {
diff = array[i + 1] - array[i];
if (diff > 0) {
loss += Math.abs(diff);
}
else {
gain += Math.abs(diff);
}
avggain = ((avggain * (rsiperiod - 1)) + gain) / rsiperiod;
avgloss = ((avgloss * (rsiperiod - 1)) + loss) / rsiperiod;
}
//console.log("g", avggain, "l", avgloss);
if (avgloss == 0) {
rsi[i] = 100;
}
else {
rsi[i] = 100 - (100 / (1 + (avggain / avgloss)));
}
}
return rsi;
}
exports.RSI = RSI;
function STOCHRSI(instruments, rsiperiod) {
var stochrsi = [], rsiarray, rsimin, rsimax, i, arr;
for (i = rsiperiod - 1; i >= 0; i--) {
arr = instruments.slice(i);
rsiarray = RSI(arr, rsiperiod);
rsimin = arrayMin(rsiarray);
rsimax = arrayMax(rsiarray);
if (rsimax - rsimin == 0) {
stochrsi[i] = 100;
}
else {
stochrsi[i] = 100 * (rsiarray[0] - rsimin) / (rsimax - rsimin);
}
}
return stochrsi;
}
exports.STOCHRSI = STOCHRSI;
function SMA(originalArray, smaLength) {
var array, sma = [], i;
for (i = smaLength - 1; i >= 0; i--) {
array = originalArray.slice(i, i + smaLength);
sma[i] = array.reduce(function (a, b) { return a + b; }) / array.length;
}
return sma;
}
exports.SMA = SMA;
function EMA(originalArray, emaLength) {
var array = originalArray.slice().reverse(), iPos = 0, i, k, ema;
// trim initial NaN values
for (iPos = 0; iPos < array.length && isNaN(array[iPos]); iPos++) {
}
array = array.slice(iPos); // trim initial NaN values from array
ema = [];
k = 2 / (emaLength + 1);
for (i = 0; i < emaLength - 1; i++) {
ema[i] = NaN;
}
ema[emaLength - 1] = array.slice(0, emaLength).reduce(function (a, b) {
return a + b;
}) / emaLength;
for (i = emaLength; i < array.length; i++) {
ema[i] = array[i] * k + ema[i - 1] * (1 - k);
}
ema.reverse(); // reverse back for main consumption
for (i = 0; i < iPos; i++) {
ema.push(NaN);
}
return ema;
}
exports.EMA = EMA;
function MACD(array, i12, i26, i9) {
var ema12 = EMA(array, i12), ema26 = EMA(array, i26), macd = [], i, signal, histogram;
for (i = 0; i < ema12.length; i++) {
macd.push(ema12[i] - ema26[i]);
}
signal = EMA(macd, i9);
histogram = [];
for (i = 0; i < macd.length; i++) {
histogram.push(macd[i] - signal[i]);
}
return {
macd: macd,
signal: signal,
histogram: histogram
};
}
exports.MACD = MACD;
function PERCPRICEOSC(array, i12, i26, i9) {
var ema12 = EMA(array, 12), ema26 = EMA(array, 26), ppo = [], i, signal, histogram;
for (i = 0; i < ema12.length; i++) {
ppo.push((ema12[i] - ema26[i]) / ema26[i] * 100);
}
signal = EMA(ppo, 9);
histogram = [];
for (i = 0; i < ppo.length; i++) {
histogram.push(ppo[i] - signal[i]);
}
return {
ppo: ppo,
signal: signal,
histogram: histogram
};
}
exports.PERCPRICEOSC = PERCPRICEOSC;
function WILLR(highs, lows, closes, lookback) {
var willr = [], highest_high, lowest_low, curr_close, i;
// computing only if highs and lows arrays are of equal length
if (highs.length == lows.length && highs.length >= lookback) {
/*
* Willams %R exists only for the values which have atleast "lookback" values
* so we iterate till ((length )-lookback)to calculate Willams %R
*/
var limit = highs.length - lookback;
for (i = limit; i >= 0; i--) {
highest_high = arrayMax(highs.slice(i, i + lookback));
lowest_low = arrayMin(lows.slice(i, i + lookback));
curr_close = closes[i];
willr[i] = (highest_high - curr_close) / (highest_high - lowest_low) * -100;
}
}
return willr;
}
exports.WILLR = WILLR;
function TRUERANGE(highs, lows, closes) {
var tr = [], curr_diff, curr_high_diff, curr_low_diff, i;
if (highs.length != lows.length || highs.length != closes.length) {
//True ranges are found only when all arrays are of equal length
return tr;
}
tr[0] = highs[0] - lows[0];
for (i = highs.length - 1; i > 0; i--) {
var tmp = [];
tmp.push(highs[i] - lows[i]);
tmp.push(Math.abs(lows[i] - closes[i + 1]));
tmp.push(Math.abs(highs[i] - closes[i + 1]));
tr[i] = arrayMax(tmp);
}
return tr;
}
exports.TRUERANGE = TRUERANGE;