-
Notifications
You must be signed in to change notification settings - Fork 0
/
squeezeMomentumIndicator.js
105 lines (82 loc) · 3.33 KB
/
squeezeMomentumIndicator.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
// Squeeze Momentum Indicator
const { roundNumber } = require("./utils");
function avg(...args) {
const sum = args.reduce((acc, value) => acc + value, 0);
return sum / args.length;
}
function highest(arr, n) {
return arr.slice(-n).reduce((max, value) => Math.max(max, value), -Infinity);
}
function lowest(arr, n) {
return arr.slice(-n).reduce((min, value) => Math.min(min, value), Infinity);
}
function sma(arr, length) {
const slice = arr.slice(-length);
const sum = slice.reduce((acc, value) => acc + value, 0);
return sum / length;
}
function linreg(source, length, offset) {
const n = length;
const sumX = n * (n - 1) / 2;
const sumY = source.reduce((acc, value) => acc + value, 0);
const sumXY = source.reduce((acc, value, i) => acc + i * value, 0);
const sumX2 = n * (n - 1) * (2 * n - 1) / 6;
const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
const intercept = (sumY - slope * sumX) / n;
return intercept + slope * (length - 1 - offset);
}
function calculateSqueezeMomentum(candles, lengthKC) {
const resultCalc = [];
for (let i = lengthKC - 1; i < candles.length; i++) {
const currentCandle = candles[i];
const { time, open, high, low, close, volume } = currentCandle;
const candleSlice = candles.slice(i - lengthKC + 1, i + 1);
const highKC = highest(candleSlice.map(c => c.high), lengthKC);
const lowKC = lowest(candleSlice.map(c => c.low), lengthKC);
const smaClose = sma(candleSlice.map(c => c.close), lengthKC);
const avg1 = avg(highKC, lowKC);
const calc = avg(avg1, smaClose);
// const calc = parseFloat(Number(avgHighLowSma).toFixed(2));
resultCalc.push({
time,
open,
high,
low,
close,
volume,
calc,
});
}
const finalResult = [];
for (let index = 0; index < resultCalc.length; index++) {
const currentCandle = resultCalc[index];
const { time, open, high, low, close, volume, calc } = currentCandle;
const candleSlice = resultCalc.slice(index - lengthKC + 1, index + 1);
// const source = candleSlice.map((c) => parseFloat(Number(c.close - c.calc).toFixed(2)));
const source = candleSlice.map((c) => c.close - c.calc);
// const val = parseFloat(Number(linreg(source, lengthKC, 0).toFixed(2)));
const val = linreg(source, lengthKC, 0);
const prevVal = finalResult.length > 0 ? finalResult[finalResult.length - 1].val : 0;
const signalColor =
val > 0 ? (val > prevVal ? 'lime' : 'green') : val < prevVal ? 'red' : 'maroon';
// const signalBuy = val > 0 ? (val > prevVal ? true : false) : false;
const signalBuy = val > 0 ? true : false;
// console.log("val: ", val, prevVal); // DEBUG
// const signal = parseFloat(Number(val).toFixed(8));
const signal = roundNumber(val, close);
finalResult.push({
// time, open, high, low, close, volume,
...currentCandle,
val,
calcSqueeze: calc,
valSqueeze: val,
signalSqueeze: signal,
signalColorSqueeze: signalColor,
signalBuySqueeze: signalBuy
});
}
return finalResult;
}
module.exports = {
calculateSqueezeMomentum,
}