-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.js
110 lines (99 loc) · 3.1 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
'use strict'
const async = require('async');
const Decimal = require('decimal.js');
class RSI {
constructor(values, period) {
this.values = values.reverse();
this.data = [];
this.period = period;
}
calculate(callback) {
async.series([
(next) => this.lossOrGain(next),
(next) => this.averageGain(next),
(next) => this.averageLoss(next),
(next) => this.calculateRS(next),
(next) => this.calculateRSI(next)
],
(err, results) => {
if (err) {
return callback(err);
}
callback(null, results[4]);
});
}
lossOrGain(callback) {
this.values.forEach((val, idx) => {
if (idx > 0) {
const prevVal = this.values[idx-1];
const change = Decimal.sub(val, prevVal);
this.data.push({
value: val,
change: change.toNumber(),
gain: (change.toNumber() > 0) ? change.toNumber() : 0,
loss: (change.toNumber() < 0) ? change.abs().toNumber() : 0
});
} else {
this.data.push({
value: val,
gain: 0,
loss: 0,
change: 0
})
}
});
callback(null, this.data);
}
averageGain(callback) {
this.getAverages('gain', callback)
}
averageLoss(callback) {
this.getAverages('loss', callback)
}
getAverages(key, callback) {
let sum = new Decimal(0);
let avg = 0;
let overallAvg = 0;
const upperCaseKey = key.charAt(0).toUpperCase() + key.substr(1);
this.data.forEach((val, idx) => {
if (idx < this.period) {
sum = sum.plus(val[key]);
} else if (idx === this.period) {
sum = sum.plus(val[key]);
avg = sum.dividedBy(this.period);
this.data[idx][`avg${upperCaseKey}`] =
avg.toNumber();
} else {
overallAvg =
Decimal.mul(this.data[idx-1][`avg${upperCaseKey}`], (this.period - 1))
.plus(val[key])
.dividedBy(this.period);
this.data[idx][`avg${upperCaseKey}`] =
overallAvg.toNumber();
}
});
callback(null, this.data);
}
calculateRS(callback) {
let rs = 0;
this.data.forEach((val, idx) => {
if (val.avgGain !== undefined && val.avgLoss !== undefined &&
!isNaN(parseFloat(val.avgGain)) && !isNaN(parseFloat(val.avgLoss))) {
val.rs = Decimal.div(val.avgGain, val.avgLoss).toNumber();
}
});
callback(null, this.data);
}
calculateRSI(callback) {
let rs = 0;
this.data.forEach((val, idx) => {
if (val.avgLoss) {
this.data[idx].rsi = Decimal.sub(100, Decimal.div(100, Decimal.add(1, val.rs))).toNumber();
} else if(val.rs != undefined) {
this.data[idx].rsi = 100;
}
});
return callback(null, this.data);
}
}
module.exports = RSI;