ta-lib
Version:
A technical analysis library written entirely in JavaScript/TypeScript
295 lines (262 loc) • 8.06 kB
text/typescript
export interface IAroonResult {
up : number;
down : number;
}
export interface IMACDResult {
macd: Array<number>;
signal: Array<number>;
histogram: Array<number>;
}
export interface IAverage {
mean : number;
variance: number;
deviation : number;
}
export interface IBBANDSResult {
highband : Array<number>;
lowband : Array<number>;
middleband : Array<number>;
}
export interface IPPOResult {
ppo: Array<number>;
signal: Array<number>;
histogram: Array<number>;
}
export function arrayMax (array : Array<number>) : number {
return Math.max.apply(Math, array.filter(function (n) {
return !isNaN(n);
}));
}
export function arrayMin (array : Array<number>) : number {
return Math.min.apply(Math, array.filter(function (n) {
return !isNaN(n);
}));
}
export function upscale(number : number, places : number) : number {
return Math.round(number * Math.pow(10,places));
}
export function downscale(number:number, places:number) : number {
return number / Math.pow(10,places);
}
export function diff (x : number, y : number) : number {
return ((x - y) / ((x + y) / 2)) * 100;
}
export function average(a : Array<number>) : IAverage {
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;
}
export function BBANDS (array : Array<number>, period : number, deviation : number ) : IBBANDSResult{
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;
}
export function AROON (higharray : Array<number>, lowarray : Array<number>, period : number) : IAroonResult{
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
};
}
export function MFI (higharray : Array<number>, lowarray : Array<number>, closearray : Array<number>, volumearray : Array<number>, period : number) : number {
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))));
}
export function RSI (array : Array<number>, rsiperiod : number) : Array<number> {
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;
}
export function STOCHRSI(instruments : Array<number>, rsiperiod : number) : Array<number> {
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;
}
export function SMA (originalArray : Array<number>, smaLength : number) : Array<number>{
var array , sma = [], i;
for (i = smaLength-1; i >= 0 ; i--) {
array = originalArray.slice(i, i + smaLength);
sma[i] = array.reduce((a, b) => a + b) / array.length;
}
return sma;
}
export function EMA (originalArray : Array<number>, emaLength : number) : Array<number>{
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;
}
export function MACD (array : Array<number>, i12 : number, i26 : number, i9 : number) : IMACDResult{
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
};
}
export function PERCPRICEOSC(array: Array<number>, i12 : number, i26 : number, i9 : number): IPPOResult{
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
};
}
export function WILLR(highs: Array<number>,lows: Array<number>,closes: Array<number>,lookback: number): Array<number>{
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;
}
export function TRUERANGE(highs: Array<number>, lows: Array<number>, closes: Array<number>): Array<number>{
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;
}