ohlcv-indicators 1.9.3 → 1.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ohlcv-indicators.min.js +1 -1
- package/index.js +6 -12
- package/package.json +3 -2
- package/src/moving-averages/bollingerBands.js +35 -23
- package/src/moving-averages/donchianChannel.js +13 -12
- package/src/moving-averages/ema.js +1 -1
- package/src/moving-averages/macd.js +13 -17
- package/src/moving-averages/relativeVolume.js +7 -4
- package/src/moving-averages/sma.js +2 -2
- package/src/oscillators/rsi.js +12 -6
- package/src/oscillators/volumeOscillator.js +10 -6
- package/src/studies/candleStudies.js +46 -61
- package/src/studies/findCrosses.js +125 -150
- package/src/studies/lag.js +26 -19
- package/src/utilities/parsing-utilities.js +103 -60
package/src/oscillators/rsi.js
CHANGED
|
@@ -6,13 +6,19 @@ export const rsi = (main, index, size) => {
|
|
|
6
6
|
|
|
7
7
|
const value = main.verticalOhlcv.close[index]
|
|
8
8
|
|
|
9
|
-
if(
|
|
9
|
+
if(index === 0)
|
|
10
10
|
{
|
|
11
|
-
main.
|
|
12
|
-
|
|
13
|
-
main.instances
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
main.crossPairsList.push({fast: `rsi_${size}`, slow: `rsi_sma_${size}`})
|
|
12
|
+
|
|
13
|
+
Object.assign(main.instances, {
|
|
14
|
+
[`rsi_${size}`]: new FasterRSI(size),
|
|
15
|
+
[`rsi_sma_${size}`]: new FasterSMA(size)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
Object.assign(main.verticalOhlcv, {
|
|
19
|
+
[`rsi_${size}`]: new Array(main.len).fill(null),
|
|
20
|
+
[`rsi_sma_${size}`]: new Array(main.len).fill(null)
|
|
21
|
+
})
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
let currentRsi
|
|
@@ -4,13 +4,17 @@ export const volumeOscillator = (main, index, fastSize = 5, slowSize = 10) => {
|
|
|
4
4
|
|
|
5
5
|
const value = main.verticalOhlcv.volume[index]
|
|
6
6
|
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
if (index === 0) {
|
|
8
|
+
|
|
9
|
+
Object.assign(main.instances, {
|
|
10
|
+
volume_oscillator: {
|
|
11
|
+
fastEMA: new FasterEMA(fastSize),
|
|
12
|
+
slowEMA: new FasterEMA(slowSize)
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
12
16
|
main.verticalOhlcv[`volume_oscillator`] = new Array(main.len).fill(null);
|
|
13
|
-
main.
|
|
17
|
+
main.crossPairsList.push({ fast: `volume_oscillator`, slow: 0 });
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
const { fastEMA, slowEMA } = main.instances[`volume_oscillator`];
|
|
@@ -3,54 +3,39 @@ import { classifySize } from '../utilities/classification.js';
|
|
|
3
3
|
|
|
4
4
|
export const candlesStudies = (main, index, size, classify = true, classificationLevels = {}) => {
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
6
|
const { changeLevel = 7, sizeLevel = 5 } = classificationLevels;
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
for (const field of fields) {
|
|
24
|
-
if (!main.verticalOhlcv.hasOwnProperty(field)) {
|
|
25
|
-
main.verticalOhlcv[field] = new Array(main.len).fill(null);
|
|
26
|
-
}
|
|
8
|
+
if(index === 0)
|
|
9
|
+
{
|
|
10
|
+
Object.assign(main.verticalOhlcv, {
|
|
11
|
+
candle_gap_size: new Array(main.len).fill(null),
|
|
12
|
+
candle_body_size: new Array(main.len).fill(null),
|
|
13
|
+
candle_top_size: new Array(main.len).fill(null),
|
|
14
|
+
candle_bottom_size: new Array(main.len).fill(null),
|
|
15
|
+
candle_shadow_size: new Array(main.len).fill(null),
|
|
16
|
+
candle_close_direction: new Array(main.len).fill(null),
|
|
17
|
+
candle_high_direction: new Array(main.len).fill(null),
|
|
18
|
+
candle_low_direction: new Array(main.len).fill(null),
|
|
19
|
+
candle_open_direction: new Array(main.len).fill(null),
|
|
20
|
+
})
|
|
27
21
|
}
|
|
28
22
|
|
|
29
23
|
// Ensure instances exist if classification is enabled
|
|
30
|
-
if (classify) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Create a namespace for candle studies if it doesn't exist
|
|
44
|
-
if (!main.instances.hasOwnProperty('candleStudies')) {
|
|
45
|
-
main.instances.candleStudies = {};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Create instances if they don't exist
|
|
49
|
-
for (const name of instanceNames) {
|
|
50
|
-
if (!main.instances.candleStudies.hasOwnProperty(name)) {
|
|
51
|
-
main.instances.candleStudies[name] = new FasterSMA(size);
|
|
24
|
+
if (classify && index === 0) {
|
|
25
|
+
|
|
26
|
+
Object.assign(main.instances, {
|
|
27
|
+
candleStudies: {
|
|
28
|
+
topInstance: new FasterSMA(size),
|
|
29
|
+
bottomInstance: new FasterSMA(size),
|
|
30
|
+
gapInstance: new FasterSMA(size),
|
|
31
|
+
bodySizeInstance: new FasterSMA(size),
|
|
32
|
+
shadowSizeInstance: new FasterSMA(size),
|
|
33
|
+
closeDirectionInstance: new FasterSMA(size),
|
|
34
|
+
highDirectionInstance: new FasterSMA(size),
|
|
35
|
+
lowDirectionInstance: new FasterSMA(size),
|
|
36
|
+
openDirectionInstance: new FasterSMA(size)
|
|
52
37
|
}
|
|
53
|
-
}
|
|
38
|
+
})
|
|
54
39
|
}
|
|
55
40
|
|
|
56
41
|
// If we do not have a previous candle, we cannot compute differences
|
|
@@ -127,45 +112,45 @@ export const candlesStudies = (main, index, size, classify = true, classificatio
|
|
|
127
112
|
// If there's not enough data, means remain null
|
|
128
113
|
}
|
|
129
114
|
|
|
130
|
-
main.verticalOhlcv
|
|
115
|
+
main.verticalOhlcv.candle_body_size[index] = isUp
|
|
131
116
|
? classifySize(candleBodySize, bodySizeMean, 2, changeLevel)
|
|
132
117
|
: -Math.abs(classifySize(candleBodySize, bodySizeMean, 2, changeLevel)) || 0;
|
|
133
118
|
|
|
134
|
-
main.verticalOhlcv
|
|
119
|
+
main.verticalOhlcv.candle_gap_size[index] = isUp
|
|
135
120
|
? classifySize(gapSize, gapMean, 2, changeLevel)
|
|
136
121
|
: -Math.abs(classifySize(gapSize, gapMean, 2, changeLevel)) || 0;
|
|
137
122
|
|
|
138
|
-
main.verticalOhlcv
|
|
123
|
+
main.verticalOhlcv.candle_close_direction[index] = isUp
|
|
139
124
|
? classifySize(closeDirection, closeDirectionMean, 2, changeLevel)
|
|
140
125
|
: -Math.abs(classifySize(closeDirection, closeDirectionMean, 2, changeLevel)) || 0;
|
|
141
126
|
|
|
142
|
-
main.verticalOhlcv
|
|
127
|
+
main.verticalOhlcv.candle_high_direction[index] = isUp
|
|
143
128
|
? classifySize(highDirection, highDirectionMean, 2, changeLevel)
|
|
144
129
|
: -Math.abs(classifySize(highDirection, highDirectionMean, 2, changeLevel)) || 0;
|
|
145
130
|
|
|
146
|
-
main.verticalOhlcv
|
|
131
|
+
main.verticalOhlcv.candle_low_direction[index] = isUp
|
|
147
132
|
? classifySize(lowDirection, lowDirectionMean, 2, changeLevel)
|
|
148
133
|
: -Math.abs(classifySize(lowDirection, lowDirectionMean, 2, changeLevel)) || 0;
|
|
149
134
|
|
|
150
|
-
main.verticalOhlcv
|
|
135
|
+
main.verticalOhlcv.candle_open_direction[index] = isUp
|
|
151
136
|
? classifySize(openDirection, openDirectionMean, 2, changeLevel)
|
|
152
137
|
: -Math.abs(classifySize(openDirection, openDirectionMean, 2, changeLevel)) || 0;
|
|
153
138
|
|
|
154
|
-
main.verticalOhlcv
|
|
155
|
-
main.verticalOhlcv
|
|
156
|
-
main.verticalOhlcv
|
|
139
|
+
main.verticalOhlcv.candle_top_size[index] = classifySize(topSize, topSizeMean, 0.5, sizeLevel);
|
|
140
|
+
main.verticalOhlcv.candle_bottom_size[index] = classifySize(bottomSize, bottomSizeMean, 0.5, sizeLevel);
|
|
141
|
+
main.verticalOhlcv.candle_shadow_size[index] = classifySize(shadowSize, shadowSizeMean, 0.5, sizeLevel);
|
|
157
142
|
} else {
|
|
158
143
|
// Without classification, just store raw values
|
|
159
|
-
main.verticalOhlcv
|
|
160
|
-
main.verticalOhlcv
|
|
161
|
-
main.verticalOhlcv
|
|
162
|
-
main.verticalOhlcv
|
|
163
|
-
main.verticalOhlcv
|
|
164
|
-
main.verticalOhlcv
|
|
165
|
-
|
|
166
|
-
main.verticalOhlcv
|
|
167
|
-
main.verticalOhlcv
|
|
168
|
-
main.verticalOhlcv
|
|
144
|
+
main.verticalOhlcv.candle_body_size[index] = isUp ? candleBodySize : -candleBodySize;
|
|
145
|
+
main.verticalOhlcv.candle_gap_size[index] = isUp ? gapSize : -gapSize;
|
|
146
|
+
main.verticalOhlcv.candle_close_direction[index] = isUp ? closeDirection : -closeDirection;
|
|
147
|
+
main.verticalOhlcv.candle_high_direction[index] = isUp ? highDirection : -highDirection;
|
|
148
|
+
main.verticalOhlcv.candle_low_direction[index] = isUp ? lowDirection : -lowDirection;
|
|
149
|
+
main.verticalOhlcv.candle_open_direction[index] = isUp ? openDirection : -openDirection;
|
|
150
|
+
|
|
151
|
+
main.verticalOhlcv.candle_top_size[index] = topSize;
|
|
152
|
+
main.verticalOhlcv.candle_bottom_size[index] = bottomSize;
|
|
153
|
+
main.verticalOhlcv.candle_shadow_size[index] = shadowSize;
|
|
169
154
|
}
|
|
170
155
|
|
|
171
156
|
return true;
|
|
@@ -1,210 +1,185 @@
|
|
|
1
|
-
const eq = (
|
|
2
|
-
const gt = (
|
|
3
|
-
const lt = (
|
|
1
|
+
const eq = (fast, slow) => fast === slow
|
|
2
|
+
const gt = (fast, slow) => fast > slow
|
|
3
|
+
const lt = (fast, slow) => fast < slow
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
//this class counts how many intervals have passed between crosses: fast crossed slow line, high crossed slow line or low crossed slow line.
|
|
7
|
+
//interval === 0 for no crosses yet or the lines are equal
|
|
8
|
+
//interval >= 1 for an upwards crosses
|
|
9
|
+
//interval <= -1 from downward crosses
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
class CrossInstance {
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
constructor()
|
|
13
14
|
{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
this.interval = 0
|
|
16
|
+
this.prevState = 0.5
|
|
17
|
+
this.prevFast = null
|
|
18
|
+
this.prevSlow = null
|
|
19
|
+
this.prevHigh = null
|
|
20
|
+
this.prevLow = null
|
|
21
|
+
this.areHighAndLowUndefined = false
|
|
22
|
+
this.index = 0
|
|
23
|
+
this.crossIndexes = {
|
|
24
|
+
up: [],
|
|
25
|
+
down: []
|
|
26
|
+
}
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
}
|
|
29
|
+
update({fast, high, slow, low})
|
|
20
30
|
{
|
|
21
|
-
|
|
22
|
-
const f = fast[x]
|
|
23
|
-
const s = slow[x]
|
|
24
|
-
const hi = high?.[x]
|
|
25
|
-
const lo = low?.[x]
|
|
31
|
+
let currState = this.prevState
|
|
26
32
|
|
|
27
|
-
if(
|
|
33
|
+
if(!this.areHighAndLowUndefined)
|
|
28
34
|
{
|
|
29
|
-
if(typeof
|
|
35
|
+
if(typeof high === 'undefined' || typeof low === 'undefined')
|
|
36
|
+
{
|
|
37
|
+
this.areHighAndLowUndefined = true
|
|
38
|
+
}
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const prevLo = low?.[x-1]
|
|
35
|
-
|
|
36
|
-
if(high || low)
|
|
37
|
-
{
|
|
38
|
-
if(typeof prevHi === 'undefined' || typeof prevLo === 'undefined' || typeof prevS === 'undefined') continue
|
|
41
|
+
if(fast === null || slow === null){
|
|
42
|
+
currState = 0.5
|
|
39
43
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if(f === null || s === null) value = 0.5
|
|
44
|
-
|
|
45
|
-
else if(eq(f, s)) {
|
|
46
|
-
value = prevState
|
|
44
|
+
else if(eq(fast, slow)) {
|
|
45
|
+
currState = 0.5
|
|
47
46
|
}
|
|
48
|
-
else if(gt(
|
|
47
|
+
else if(gt(fast, slow)) {
|
|
49
48
|
|
|
50
|
-
if(
|
|
49
|
+
if(this.areHighAndLowUndefined)
|
|
51
50
|
{
|
|
52
|
-
|
|
51
|
+
currState = 1
|
|
53
52
|
}
|
|
54
53
|
else
|
|
55
54
|
{
|
|
56
|
-
|
|
55
|
+
if ([low, slow, this.prevLow, this.prevSlow].every(v => v !== null) && lt(low, slow) && gt(this.prevLow, this.prevSlow))
|
|
56
|
+
{
|
|
57
|
+
currState = 0
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
{
|
|
61
|
+
currState = 1
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
|
-
else if(lt(
|
|
65
|
+
else if(lt(fast, slow)) {
|
|
60
66
|
|
|
61
|
-
if(
|
|
67
|
+
if(this.areHighAndLowUndefined)
|
|
62
68
|
{
|
|
63
|
-
|
|
69
|
+
currState = 0
|
|
64
70
|
}
|
|
65
71
|
else
|
|
66
72
|
{
|
|
67
|
-
|
|
73
|
+
if([high, slow, this.prevHigh, this.prevSlow].every(v => v !== null) && gt(high, slow) && lt(this.prevHigh, this.prevSlow))
|
|
74
|
+
{
|
|
75
|
+
currState = 1
|
|
76
|
+
}
|
|
77
|
+
else
|
|
78
|
+
{
|
|
79
|
+
currState = 0
|
|
80
|
+
}
|
|
68
81
|
}
|
|
69
82
|
}
|
|
70
|
-
|
|
71
|
-
state[x] = value
|
|
72
|
-
}
|
|
73
|
-
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return groups.map((group, gIndex) => {
|
|
87
|
-
let initialValue = groupLengths[gIndex]
|
|
88
|
-
|
|
89
|
-
return group.map((s, i) => {
|
|
90
|
-
let v = initialValue - i
|
|
91
|
-
|
|
92
|
-
if(s === 0.5)
|
|
84
|
+
if(currState === 0.5)
|
|
85
|
+
{
|
|
86
|
+
this.interval = 0
|
|
87
|
+
}
|
|
88
|
+
else if(currState === 1)
|
|
89
|
+
{
|
|
90
|
+
if(this.prevState <= 0.5)
|
|
91
|
+
{
|
|
92
|
+
this.interval = 1
|
|
93
|
+
}
|
|
94
|
+
else
|
|
93
95
|
{
|
|
94
|
-
|
|
96
|
+
this.interval++
|
|
95
97
|
}
|
|
96
|
-
|
|
98
|
+
}
|
|
99
|
+
else if(currState === 0)
|
|
100
|
+
{
|
|
101
|
+
if(this.prevState >= 0.5)
|
|
97
102
|
{
|
|
98
|
-
|
|
103
|
+
this.interval = -1
|
|
99
104
|
}
|
|
100
|
-
|
|
105
|
+
else
|
|
101
106
|
{
|
|
102
|
-
|
|
107
|
+
this.interval--
|
|
103
108
|
}
|
|
104
|
-
|
|
105
|
-
return v
|
|
106
|
-
}).reverse()
|
|
107
|
-
}).flat()
|
|
108
|
-
}
|
|
109
|
+
}
|
|
109
110
|
|
|
110
111
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (arr.length === 0) return []
|
|
114
|
-
|
|
115
|
-
return arr.reduce((acc, currentValue, index, array) => {
|
|
116
|
-
if (index === 0) {
|
|
117
|
-
// Start the first group with the first element
|
|
118
|
-
acc.push([currentValue])
|
|
119
|
-
} else {
|
|
120
|
-
// Get the previous value
|
|
121
|
-
const prevValue = array[index - 1]
|
|
122
|
-
const currentGroup = acc[acc.length - 1]
|
|
123
|
-
|
|
124
|
-
// Check the direction of the previous and current values
|
|
125
|
-
if (currentValue !== prevValue) {
|
|
126
|
-
// Start a new group if the direction changes
|
|
127
|
-
acc.push([currentValue]);
|
|
128
|
-
} else {
|
|
129
|
-
// Otherwise, add to the current group
|
|
130
|
-
currentGroup.push(currentValue);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return acc
|
|
134
|
-
}, [])
|
|
135
|
-
}
|
|
112
|
+
if(this.interval === 1) this.crossIndexes.up.push(this.index)
|
|
113
|
+
if(this.interval === -1) this.crossIndexes.down.push(this.index)
|
|
136
114
|
|
|
115
|
+
//save prev state
|
|
116
|
+
this.index++
|
|
117
|
+
this.prevState = currState
|
|
118
|
+
this.prevFast = fast
|
|
119
|
+
this.prevSlow = slow
|
|
120
|
+
this.prevHigh = high
|
|
121
|
+
this.prevLow = low
|
|
122
|
+
}
|
|
137
123
|
|
|
124
|
+
getResult()
|
|
125
|
+
{
|
|
126
|
+
return this.interval
|
|
127
|
+
}
|
|
138
128
|
|
|
139
|
-
|
|
129
|
+
}
|
|
140
130
|
|
|
131
|
+
export const crossPairs = (main, index, arr) => {
|
|
141
132
|
|
|
133
|
+
const {len} = main
|
|
142
134
|
|
|
143
|
-
const {
|
|
144
|
-
|
|
145
|
-
const x = {}
|
|
146
|
-
const c = {}
|
|
135
|
+
for (const { fast, slow } of arr)
|
|
136
|
+
{
|
|
147
137
|
|
|
148
|
-
|
|
149
|
-
// Validate parameters
|
|
150
|
-
if (!fast || !slow) continue;
|
|
151
|
-
|
|
152
|
-
// Prepare slowNumArr if 'slow' is a number
|
|
153
|
-
if (typeof slow === 'number' && !slowNumArrCache[slow]) {
|
|
138
|
+
|
|
154
139
|
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const crossName = `${fast}_x_${slow}`
|
|
159
|
-
const countName = `${fast}_c_${slow}`
|
|
140
|
+
if (!fast || !slow) continue
|
|
160
141
|
|
|
161
|
-
|
|
142
|
+
let crossName = `${fast}_x_${slow}`
|
|
162
143
|
|
|
163
|
-
|
|
164
|
-
if(verticalOhlcv[crossName])
|
|
144
|
+
if(index === 0)
|
|
165
145
|
{
|
|
166
|
-
|
|
167
|
-
x[crossName] = cross
|
|
168
|
-
|
|
169
|
-
if(typeof count !== 'undefined')
|
|
146
|
+
if(typeof slow === 'number')
|
|
170
147
|
{
|
|
171
|
-
|
|
148
|
+
main.verticalOhlcv[slow] = new Array(len).fill(slow)
|
|
172
149
|
}
|
|
173
150
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
else if ((verticalOhlcv[fast] || fast === 'price') && verticalOhlcv[slow]) {
|
|
151
|
+
if(fast !== 'price' && !main.verticalOhlcv.hasOwnProperty(fast)) throw Error(`fast "${fast} not found in crossPairs"`)
|
|
152
|
+
if(!main.verticalOhlcv.hasOwnProperty(slow)) throw Error(`slow "${slow} not found in crossPairs"`)
|
|
177
153
|
|
|
178
|
-
const cross = (fast === 'price')
|
|
179
|
-
? findCrosses({
|
|
180
|
-
fast: verticalOhlcv.close,
|
|
181
|
-
high: verticalOhlcv.high,
|
|
182
|
-
low: verticalOhlcv.low,
|
|
183
|
-
slow: verticalOhlcv[slow]}
|
|
184
|
-
)
|
|
185
|
-
: findCrosses({fast: verticalOhlcv[fast], slow: verticalOhlcv[slow]})
|
|
186
154
|
|
|
187
|
-
|
|
155
|
+
main.instances[crossName] = new CrossInstance()
|
|
156
|
+
main.verticalOhlcv[crossName] = new Array(len).fill(null)
|
|
157
|
+
}
|
|
188
158
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
159
|
+
let fastValue
|
|
160
|
+
let closeValue
|
|
161
|
+
let highValue
|
|
162
|
+
let lowValue
|
|
163
|
+
let slowValue
|
|
193
164
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
165
|
+
if(fast === 'price')
|
|
166
|
+
{
|
|
167
|
+
closeValue = main.verticalOhlcv.close[index]
|
|
168
|
+
highValue = main.verticalOhlcv.high[index]
|
|
169
|
+
lowValue = main.verticalOhlcv.low[index]
|
|
170
|
+
slowValue = main.verticalOhlcv[slow][index]
|
|
199
171
|
|
|
200
|
-
|
|
201
|
-
c[countName] = splitCount(cross)
|
|
202
|
-
}
|
|
172
|
+
main.instances[crossName].update({fast: closeValue, slow: slowValue, high: highValue, low: lowValue})
|
|
203
173
|
|
|
204
|
-
} else
|
|
205
|
-
|
|
174
|
+
} else
|
|
175
|
+
{
|
|
176
|
+
fastValue = main.verticalOhlcv[fast][index]
|
|
177
|
+
slowValue = main.verticalOhlcv[slow][index]
|
|
178
|
+
|
|
179
|
+
main.instances[crossName].update({fast: fastValue, slow: slowValue})
|
|
206
180
|
}
|
|
181
|
+
|
|
182
|
+
main.verticalOhlcv[crossName][index] = main.instances[crossName].getResult()
|
|
207
183
|
}
|
|
208
184
|
|
|
209
|
-
return {x, c}
|
|
210
185
|
}
|
package/src/studies/lag.js
CHANGED
|
@@ -1,27 +1,34 @@
|
|
|
1
|
-
export const lag = (main, index,
|
|
1
|
+
export const lag = (main, index, params) => {
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
for(let p = 0; p < params.length; p++)
|
|
4
|
+
{
|
|
5
|
+
const [colKeys, lags] = params[p]
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
// Ensure arrays exist for each lag key before we populate
|
|
8
|
+
for (let x = 0; x < colKeys.length; x++) {
|
|
9
|
+
for (let lag = 1; lag <= lags; lag++) {
|
|
10
|
+
const key = `${colKeys[x]}_lag_${lag}`;
|
|
11
|
+
// If the array does not exist, initialize it
|
|
12
|
+
if (index === 0) {
|
|
13
|
+
main.verticalOhlcv[key] = new Array(main.len).fill(null)
|
|
14
|
+
}
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
// Compute the lagged index
|
|
17
|
+
const laggedIndex = index - lag;
|
|
18
|
+
|
|
19
|
+
// If laggedIndex is negative, we don't have a previous value
|
|
20
|
+
const value = (laggedIndex >= 0)
|
|
21
|
+
? main.verticalOhlcv[colKeys[x]][laggedIndex]
|
|
22
|
+
: null;
|
|
23
|
+
|
|
24
|
+
main.verticalOhlcv[key][index] = value;
|
|
25
|
+
}
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
26
33
|
return true;
|
|
27
34
|
};
|