ohlcv-indicators 1.9.8 → 2.0.0
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 +114 -62
- package/package.json +1 -1
- package/src/moving-averages/bollingerBands.js +40 -31
- package/src/moving-averages/donchianChannel.js +4 -8
- package/src/moving-averages/ema.js +2 -2
- package/src/moving-averages/macd.js +4 -4
- package/src/moving-averages/relativeVolume.js +13 -8
- package/src/moving-averages/sma.js +2 -2
- package/src/oscillators/rsi.js +4 -4
- package/src/oscillators/volumeOscillator.js +3 -3
- package/src/studies/candleStudies.js +20 -20
- package/src/studies/dateTime.js +86 -0
- package/src/studies/findCrosses.js +34 -22
- package/src/studies/lag.js +31 -22
- package/src/studies/priceVariations.js +22 -0
- package/src/utilities/parsing-utilities.js +48 -215
- package/src/utilities/setIndicatorsFromInputParams.js +2 -2
- package/src/utilities/validators.js +20 -0
package/index.js
CHANGED
|
@@ -1,39 +1,28 @@
|
|
|
1
|
-
import { parseOhlcvToVertical
|
|
1
|
+
import { parseOhlcvToVertical } from './src/utilities/parsing-utilities.js'
|
|
2
2
|
import { correlation } from './src/studies/correlation.js'
|
|
3
3
|
import { setIndicatorsFromInputParams } from './src/utilities/setIndicatorsFromInputParams.js'
|
|
4
|
+
import { validateDate } from './src/utilities/validators.js'
|
|
5
|
+
import { isAlreadyComputed } from './src/utilities/validators.js'
|
|
4
6
|
|
|
5
7
|
export default class OHLCV_INDICATORS {
|
|
6
|
-
constructor({input, ticker = null
|
|
8
|
+
constructor({input, ticker = null}) {
|
|
7
9
|
|
|
8
|
-
if(!Array.isArray(input)) throw Error('input
|
|
9
|
-
if(input.length === 0) throw Error('input
|
|
10
|
-
if(!input[0].hasOwnProperty('close')) throw Error('input
|
|
10
|
+
if(!Array.isArray(input)) throw Error('input OHLCV must be an array: ' + ticker)
|
|
11
|
+
if(input.length === 0) throw Error('input OHLCV must not be empty: ' + ticker)
|
|
12
|
+
if(!input[0].hasOwnProperty('close')) throw Error('input OHLCV array objects require at least close property: ' + ticker)
|
|
11
13
|
|
|
12
14
|
this.lastComputedIndex = 0
|
|
13
15
|
|
|
14
16
|
this.input = input
|
|
15
|
-
this.priceBased = ['open', 'high', 'low', 'close'
|
|
17
|
+
this.priceBased = ['open', 'high', 'low', 'close']
|
|
16
18
|
this.len = input.length
|
|
17
|
-
this.
|
|
19
|
+
this.lastIndexReplace = false
|
|
18
20
|
this.instances = {}
|
|
19
21
|
this.crossPairsList = []
|
|
20
22
|
this.verticalOhlcv = {}
|
|
21
23
|
|
|
22
|
-
this.inputParams =
|
|
23
|
-
crossPairs: null,
|
|
24
|
-
lag: null,
|
|
25
|
-
relativeVolume: null,
|
|
26
|
-
ema: null,
|
|
27
|
-
sma: null,
|
|
28
|
-
macd: null,
|
|
29
|
-
bollingerBands: null,
|
|
30
|
-
rsi: null,
|
|
31
|
-
donchianChannels: null,
|
|
32
|
-
candlesStudies: null,
|
|
33
|
-
volumeOscillator: null,
|
|
34
|
-
}
|
|
24
|
+
this.inputParams = []
|
|
35
25
|
|
|
36
|
-
|
|
37
26
|
this.studies = {}
|
|
38
27
|
this.utilities = {
|
|
39
28
|
correlation
|
|
@@ -44,9 +33,11 @@ export default class OHLCV_INDICATORS {
|
|
|
44
33
|
|
|
45
34
|
return this
|
|
46
35
|
}
|
|
47
|
-
|
|
36
|
+
|
|
37
|
+
|
|
48
38
|
getData() {
|
|
49
39
|
|
|
40
|
+
//getData method returns the last object (row) of the new OHLCV with indicators: {open, high, low, close, rsi_14, bollinger_bands_upper}
|
|
50
41
|
this.compute()
|
|
51
42
|
|
|
52
43
|
const {verticalOhlcv} = this
|
|
@@ -94,30 +85,57 @@ export default class OHLCV_INDICATORS {
|
|
|
94
85
|
}
|
|
95
86
|
|
|
96
87
|
compute(change) {
|
|
97
|
-
|
|
88
|
+
|
|
89
|
+
//checks the first row in OHLCV input to verify if the date property is valid
|
|
90
|
+
this.isValidDate = this.input[0].hasOwnProperty('date') && validateDate(this.input[0].date)
|
|
91
|
+
|
|
92
|
+
//compute method can be used to process indicators if no arguments are provided
|
|
93
|
+
//compute method can be called to access the .verticalOhlcv object
|
|
94
|
+
//compute method is called automatically if getLastValues or getDate methods are called
|
|
95
|
+
if (this.len > this.lastComputedIndex && !change) {
|
|
96
|
+
parseOhlcvToVertical(this.input, this, 0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//compute method can be used to add new or update the last datapoints if a new OHLCV object is passed with a valid date property
|
|
100
|
+
//valid date properties: "2024-12-16 15:45:00" or "2024-12-16"
|
|
101
|
+
if (change && typeof change === 'object') {
|
|
102
|
+
|
|
103
|
+
if (!['open', 'high', 'low', 'close', 'volume', 'date'].every(f => Object.keys(change).includes(f))) {
|
|
104
|
+
throw Error('Invalid OHLCV object sent in "compute". Correct usage: .compute({open: 108.25, high: 108.410004, low: 108.25, close: 99999999, volume: 875903, date: "2024-12-16 15:45:00" || "2024-12-16"})');
|
|
105
|
+
}
|
|
106
|
+
if(!this.isValidDate)
|
|
107
|
+
{
|
|
108
|
+
throw Error('All the OHLCV rows require a valid date property to access the compute change method. Correct date format: "2024-12-16 15:45:00" or "2024-12-16"')
|
|
109
|
+
}
|
|
110
|
+
if(!validateDate(change.date))
|
|
111
|
+
{
|
|
112
|
+
throw Error('The date in the new OHLCV row is invalid. Correct date format: "2024-12-16 15:45:00" or "2024-12-16"')
|
|
113
|
+
}
|
|
114
|
+
|
|
98
115
|
const { date: changeDate } = change;
|
|
99
116
|
const lastIndex = this.len - 1;
|
|
100
117
|
const inputDate = this.input[lastIndex]?.date;
|
|
101
118
|
|
|
119
|
+
//fallback if .compute(change) is triggered before .compute() alone
|
|
102
120
|
if (this.lastComputedIndex === 0) {
|
|
103
|
-
this.compute()
|
|
121
|
+
this.compute()
|
|
104
122
|
}
|
|
105
|
-
|
|
123
|
+
|
|
124
|
+
|
|
106
125
|
if (inputDate !== changeDate) {
|
|
107
126
|
// Add new item
|
|
108
|
-
this.len
|
|
109
|
-
this.input.push(change)
|
|
110
|
-
parseOhlcvToVertical(this.input, this, this.len)
|
|
127
|
+
this.len++
|
|
128
|
+
this.input.push(change)
|
|
129
|
+
parseOhlcvToVertical(this.input, this, this.len)
|
|
111
130
|
} else {
|
|
112
131
|
// Modify the last item
|
|
113
|
-
this.input[lastIndex] = change
|
|
114
|
-
parseOhlcvToVertical(this.input, this, lastIndex)
|
|
132
|
+
this.input[lastIndex] = change
|
|
133
|
+
parseOhlcvToVertical(this.input, this, lastIndex)
|
|
115
134
|
}
|
|
135
|
+
|
|
116
136
|
}
|
|
117
137
|
|
|
118
|
-
|
|
119
|
-
parseOhlcvToVertical(this.input, this, 0);
|
|
120
|
-
}
|
|
138
|
+
|
|
121
139
|
|
|
122
140
|
return this;
|
|
123
141
|
}
|
|
@@ -126,9 +144,11 @@ export default class OHLCV_INDICATORS {
|
|
|
126
144
|
|
|
127
145
|
crossPairs(arr)
|
|
128
146
|
{
|
|
147
|
+
isAlreadyComputed(this)
|
|
148
|
+
|
|
129
149
|
this.crossPairsList = [...this.crossPairsList, ...arr]
|
|
130
|
-
|
|
131
|
-
this.inputParams.
|
|
150
|
+
|
|
151
|
+
this.inputParams.push({key: 'crossPairs', params: [this.crossPairsList]})
|
|
132
152
|
|
|
133
153
|
return this
|
|
134
154
|
}
|
|
@@ -136,8 +156,9 @@ export default class OHLCV_INDICATORS {
|
|
|
136
156
|
|
|
137
157
|
lag(colKeys = ['close'], lags = 1) {
|
|
138
158
|
|
|
139
|
-
this
|
|
140
|
-
|
|
159
|
+
isAlreadyComputed(this)
|
|
160
|
+
|
|
161
|
+
this.inputParams.push({key: 'lag', params: [colKeys, lags]})
|
|
141
162
|
|
|
142
163
|
for(let x = 0; x < colKeys.length; x++)
|
|
143
164
|
{
|
|
@@ -154,38 +175,44 @@ export default class OHLCV_INDICATORS {
|
|
|
154
175
|
|
|
155
176
|
relativeVolume(size) {
|
|
156
177
|
|
|
157
|
-
this
|
|
158
|
-
|
|
178
|
+
isAlreadyComputed(this)
|
|
179
|
+
|
|
180
|
+
this.inputParams.push({key: 'relativeVolume', params: [size]})
|
|
159
181
|
|
|
160
182
|
return this
|
|
161
183
|
}
|
|
162
184
|
|
|
163
185
|
ema(size) {
|
|
164
186
|
|
|
187
|
+
isAlreadyComputed(this)
|
|
188
|
+
|
|
165
189
|
if (typeof size !== 'number' || size <= 0) {
|
|
166
190
|
throw new Error('"size" must be a positive number in ema.');
|
|
167
191
|
}
|
|
168
192
|
|
|
169
|
-
this.inputParams.ema
|
|
170
|
-
this.inputParams.ema.push([size])
|
|
193
|
+
this.inputParams.push({key: 'ema', params: [size]})
|
|
171
194
|
this.priceBased.push(`ema_${size}`)
|
|
172
195
|
|
|
173
196
|
return this
|
|
174
197
|
}
|
|
175
198
|
sma(size) {
|
|
176
199
|
|
|
200
|
+
isAlreadyComputed(this)
|
|
201
|
+
|
|
177
202
|
if (typeof size !== 'number' || size <= 0) {
|
|
178
203
|
throw new Error('"size" must be a positive number in sma.');
|
|
179
204
|
}
|
|
180
205
|
|
|
181
|
-
|
|
182
|
-
this.inputParams.
|
|
206
|
+
|
|
207
|
+
this.inputParams.push({key: 'sma', params: [size]})
|
|
183
208
|
this.priceBased.push(`sma_${size}`)
|
|
184
209
|
|
|
185
210
|
return this
|
|
186
211
|
}
|
|
187
212
|
macd(fast = 12, slow = 26, signal = 9) {
|
|
188
213
|
|
|
214
|
+
isAlreadyComputed(this)
|
|
215
|
+
|
|
189
216
|
if (typeof fast !== 'number' || fast <= 0) {
|
|
190
217
|
throw new Error('"fast" must be a positive number in macd.');
|
|
191
218
|
}
|
|
@@ -196,23 +223,32 @@ export default class OHLCV_INDICATORS {
|
|
|
196
223
|
throw new Error('"signal" must be a positive number in macd.');
|
|
197
224
|
}
|
|
198
225
|
|
|
199
|
-
this.inputParams.macd
|
|
200
|
-
this.inputParams.macd.push([fast, slow, signal])
|
|
226
|
+
this.inputParams.push({key: 'macd', params: [fast, slow, signal]})
|
|
201
227
|
|
|
202
228
|
return this
|
|
203
229
|
|
|
204
230
|
}
|
|
205
|
-
bollingerBands(size = 20,
|
|
231
|
+
bollingerBands(size = 20, stdDev = 2, options = {}) {
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
isAlreadyComputed(this)
|
|
235
|
+
|
|
236
|
+
if(!options || typeof options !== 'object')
|
|
237
|
+
{
|
|
238
|
+
throw new Error('"options" must be an object in bollingerBands. eg: {target, height, range}');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const {target = 'close', height = false, range = false} = options
|
|
242
|
+
|
|
206
243
|
// Validate size and times
|
|
207
244
|
if (typeof size !== 'number' || size <= 0) {
|
|
208
|
-
throw new Error('
|
|
245
|
+
throw new Error('"size" must be a positive number in bollingerBands.');
|
|
209
246
|
}
|
|
210
|
-
if (typeof
|
|
211
|
-
throw new Error('
|
|
247
|
+
if (typeof stdDev !== 'number' || stdDev <= 0) {
|
|
248
|
+
throw new Error('"stdDev" must be a positive number in bollingerBands.');
|
|
212
249
|
}
|
|
213
250
|
|
|
214
|
-
this.inputParams.bollingerBands
|
|
215
|
-
this.inputParams.bollingerBands.push([size, times, bollingerBandsStudies]);
|
|
251
|
+
this.inputParams.push({key: 'bollingerBands', params: [size, stdDev, {target, height, range}]});
|
|
216
252
|
this.priceBased.push('bollinger_bands_middle', 'bollinger_bands_upper', 'bollinger_bands_lower');
|
|
217
253
|
|
|
218
254
|
return this;
|
|
@@ -220,18 +256,21 @@ export default class OHLCV_INDICATORS {
|
|
|
220
256
|
|
|
221
257
|
rsi(size)
|
|
222
258
|
{
|
|
259
|
+
isAlreadyComputed(this)
|
|
260
|
+
|
|
223
261
|
// Validate size and times
|
|
224
262
|
if (typeof size !== 'number' || size <= 0) {
|
|
225
263
|
throw new Error('"size" must be a positive number in rsi.');
|
|
226
264
|
}
|
|
227
265
|
|
|
228
|
-
this.inputParams.rsi
|
|
229
|
-
this.inputParams.rsi.push([size])
|
|
266
|
+
this.inputParams.push({key: 'rsi', params: [size]})
|
|
230
267
|
|
|
231
268
|
return this
|
|
232
269
|
}
|
|
233
270
|
donchianChannels(size = 20, offset = 0)
|
|
234
271
|
{
|
|
272
|
+
isAlreadyComputed(this)
|
|
273
|
+
|
|
235
274
|
if (typeof size !== 'number' || size <= 0) {
|
|
236
275
|
throw new Error('"size" must be a positive number or 0 in donchianChannels.');
|
|
237
276
|
}
|
|
@@ -240,31 +279,32 @@ export default class OHLCV_INDICATORS {
|
|
|
240
279
|
throw new Error('"offset" must be a positive number or 0 in donchianChannels.');
|
|
241
280
|
}
|
|
242
281
|
|
|
243
|
-
this.inputParams.donchianChannels
|
|
244
|
-
this.inputParams.donchianChannels.push([size, offset])
|
|
282
|
+
this.inputParams.push({key: 'donchianChannels', params: [size, offset]})
|
|
245
283
|
this.priceBased.push('donchian_channel_upper', 'donchian_channel_lower', 'donchian_channel_basis')
|
|
246
284
|
|
|
247
285
|
return this
|
|
248
286
|
}
|
|
249
|
-
|
|
287
|
+
candleStudies(size = 20, classify = true, classificationLevels)
|
|
250
288
|
{
|
|
251
289
|
|
|
290
|
+
isAlreadyComputed(this)
|
|
291
|
+
|
|
252
292
|
if (typeof size !== 'number' || size <= 0) {
|
|
253
|
-
throw new Error('"size" must be a positive number or 0 in
|
|
293
|
+
throw new Error('"size" must be a positive number or 0 in candleStudies.');
|
|
254
294
|
}
|
|
255
295
|
|
|
256
296
|
if (typeof classify !== 'boolean') {
|
|
257
|
-
throw new Error('"classify" must be a true or false in
|
|
297
|
+
throw new Error('"classify" must be a true or false in candleStudies.');
|
|
258
298
|
}
|
|
259
299
|
|
|
260
|
-
this.inputParams.
|
|
261
|
-
this.inputParams.candlesStudies.push([size, classify, classificationLevels])
|
|
300
|
+
this.inputParams.push({key: 'candleStudies', params: [size, classify, classificationLevels]})
|
|
262
301
|
return this
|
|
263
302
|
}
|
|
264
303
|
|
|
265
304
|
volumeOscillator(fastSize = 5, slowSize = 10)
|
|
266
305
|
{
|
|
267
306
|
|
|
307
|
+
isAlreadyComputed(this)
|
|
268
308
|
|
|
269
309
|
if (typeof fastSize !== 'number' || fastSize <= 0) {
|
|
270
310
|
throw new Error('fastSize" must be a positive number in volumeOscillator.');
|
|
@@ -274,9 +314,21 @@ export default class OHLCV_INDICATORS {
|
|
|
274
314
|
throw new Error('"slowSize" must be a positive number greater than the "fastSize" in volumeOscillator.');
|
|
275
315
|
}
|
|
276
316
|
|
|
317
|
+
this.inputParams.push({key: 'volumeOscillator', params: [fastSize, slowSize]})
|
|
318
|
+
return this
|
|
319
|
+
}
|
|
320
|
+
dateTime()
|
|
321
|
+
{
|
|
322
|
+
isAlreadyComputed(this)
|
|
323
|
+
|
|
324
|
+
this.inputParams.push({key: 'dateTime', params: []})
|
|
325
|
+
return this
|
|
326
|
+
}
|
|
327
|
+
priceVariations()
|
|
328
|
+
{
|
|
329
|
+
isAlreadyComputed(this)
|
|
277
330
|
|
|
278
|
-
this.inputParams.
|
|
279
|
-
this.inputParams.volumeOscillator.push([fastSize, slowSize])
|
|
331
|
+
this.inputParams.push({key: 'priceVariations', params: []})
|
|
280
332
|
return this
|
|
281
333
|
}
|
|
282
334
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ohlcv-indicators",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A JavaScript library featuring optimized trading indicators for OHLCV arrays [{open, high, low, close, value}]. This library is optimized for backtesting and trading bot development.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -1,35 +1,44 @@
|
|
|
1
1
|
import {FasterBollingerBands, FasterSMA} from 'trading-signals';
|
|
2
2
|
import { classifySize } from '../utilities/classification.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
let defaultTarget = 'close'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
export const bollingerBands = (main, index, size, times, options) => {
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const {height, range, target} = options
|
|
9
|
+
let suffix = (target === defaultTarget) ? '' : `_${target}`
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
instance: new FasterBollingerBands(size, times),
|
|
12
|
-
heightInstance: bollingerBandsStudies ? new FasterSMA(size) : null
|
|
13
|
-
}})
|
|
11
|
+
if (index === 0) {
|
|
14
12
|
|
|
13
|
+
if(!main.verticalOhlcv.hasOwnProperty(target))
|
|
14
|
+
{
|
|
15
|
+
throw new Error(`bollingerBands could not find target "${target}"`)
|
|
16
|
+
}
|
|
15
17
|
|
|
16
|
-
Object.assign(main.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
Object.assign(main.instances, {
|
|
19
|
+
[`bollinger_bands${suffix}`]: {
|
|
20
|
+
instance: new FasterBollingerBands(size, times),
|
|
21
|
+
heightInstance: height ? new FasterSMA(size) : null
|
|
22
|
+
}
|
|
20
23
|
})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
|
|
25
|
+
Object.assign(main.verticalOhlcv, {
|
|
26
|
+
[`bollinger_bands_upper${suffix}`]: [...main.nullArray],
|
|
27
|
+
[`bollinger_bands_middle${suffix}`]: [...main.nullArray],
|
|
28
|
+
[`bollinger_bands_lower${suffix}`]: [...main.nullArray],
|
|
29
|
+
...(height && {
|
|
30
|
+
[`bollinger_bands_height${suffix}`]: [...main.nullArray]
|
|
31
|
+
}),
|
|
32
|
+
...(range && {
|
|
33
|
+
[`bollinger_bands_range${suffix}`]: [...main.nullArray],
|
|
27
34
|
})
|
|
28
|
-
}
|
|
35
|
+
})
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
instance.
|
|
38
|
+
|
|
39
|
+
const { instance, heightInstance } = main.instances[`bollinger_bands${suffix}`]
|
|
40
|
+
const value = main.verticalOhlcv[target][index]
|
|
41
|
+
instance.update(value, main.lastIndexReplace)
|
|
33
42
|
|
|
34
43
|
let result;
|
|
35
44
|
try {
|
|
@@ -41,20 +50,20 @@ export const bollingerBands = (main, index, size, times, bollingerBandsStudies =
|
|
|
41
50
|
if(!result) return true
|
|
42
51
|
|
|
43
52
|
const { upper, middle, lower } = result;
|
|
44
|
-
main.verticalOhlcv
|
|
45
|
-
main.verticalOhlcv
|
|
46
|
-
main.verticalOhlcv
|
|
53
|
+
main.verticalOhlcv[`bollinger_bands_upper${suffix}`][index] = upper;
|
|
54
|
+
main.verticalOhlcv[`bollinger_bands_middle${suffix}`][index] = middle;
|
|
55
|
+
main.verticalOhlcv[`bollinger_bands_lower${suffix}`][index] = lower;
|
|
47
56
|
|
|
48
|
-
if (!
|
|
57
|
+
if (!height && !range) return true;
|
|
49
58
|
|
|
50
|
-
let
|
|
51
|
-
let
|
|
59
|
+
let rangeValue = null;
|
|
60
|
+
let heightValue = null;
|
|
52
61
|
let heightMean;
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
rangeValue = (value - lower) / (upper - lower);
|
|
64
|
+
heightValue = upper - lower;
|
|
56
65
|
|
|
57
|
-
heightInstance.update(
|
|
66
|
+
heightInstance.update(heightValue, main.lastIndexReplace);
|
|
58
67
|
|
|
59
68
|
try {
|
|
60
69
|
heightMean = heightInstance.getResult();
|
|
@@ -62,11 +71,11 @@ export const bollingerBands = (main, index, size, times, bollingerBandsStudies =
|
|
|
62
71
|
//do nothing
|
|
63
72
|
}
|
|
64
73
|
|
|
65
|
-
main.verticalOhlcv
|
|
74
|
+
main.verticalOhlcv[`bollinger_bands_range${suffix}`][index] = rangeValue;
|
|
66
75
|
|
|
67
76
|
if(heightMean)
|
|
68
77
|
{
|
|
69
|
-
main.verticalOhlcv
|
|
78
|
+
main.verticalOhlcv[`bollinger_bands_height${suffix}`][index] = classifySize(heightValue, heightMean, 1.5);
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
return true;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const avg = (h, l) => (h + l) / 2;
|
|
2
|
-
|
|
3
1
|
export const donchianChannels = (main, index, size, offset) => {
|
|
4
2
|
|
|
5
3
|
const highs = main.verticalOhlcv.high;
|
|
@@ -7,13 +5,11 @@ export const donchianChannels = (main, index, size, offset) => {
|
|
|
7
5
|
|
|
8
6
|
// Ensure that the required arrays exist
|
|
9
7
|
if (index === 0) {
|
|
10
|
-
|
|
11
|
-
main.instances['donchian_channels'] = {};
|
|
12
8
|
|
|
13
9
|
Object.assign(main.verticalOhlcv, {
|
|
14
|
-
donchian_channel_upper:
|
|
15
|
-
donchian_channel_basis:
|
|
16
|
-
donchian_channel_lower:
|
|
10
|
+
donchian_channel_upper: [...main.nullArray],
|
|
11
|
+
donchian_channel_basis: [...main.nullArray],
|
|
12
|
+
donchian_channel_lower: [...main.nullArray],
|
|
17
13
|
})
|
|
18
14
|
}
|
|
19
15
|
|
|
@@ -32,7 +28,7 @@ export const donchianChannels = (main, index, size, offset) => {
|
|
|
32
28
|
// Compute the Donchian channels
|
|
33
29
|
const upper = Math.max(...highChunk);
|
|
34
30
|
const lower = Math.min(...lowChunk);
|
|
35
|
-
const basis =
|
|
31
|
+
const basis = (upper + lower) / 2;
|
|
36
32
|
|
|
37
33
|
// Place the result at index
|
|
38
34
|
const placementIndex = index;
|
|
@@ -8,11 +8,11 @@ export const ema = (main, index, size) => {
|
|
|
8
8
|
if(index === 0)
|
|
9
9
|
{
|
|
10
10
|
main.instances[`ema_${size}`] = new FasterEMA(size)
|
|
11
|
-
main.verticalOhlcv[`ema_${size}`] =
|
|
11
|
+
main.verticalOhlcv[`ema_${size}`] = [...main.nullArray]
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
let currSma
|
|
15
|
-
main.instances[`ema_${size}`].update(value)
|
|
15
|
+
main.instances[`ema_${size}`].update(value, main.lastIndexReplace)
|
|
16
16
|
|
|
17
17
|
try{
|
|
18
18
|
currSma = main.instances[`ema_${size}`].getResult()
|
|
@@ -15,14 +15,14 @@ export const macd = (main, index, fast, slow, signal) => {
|
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
Object.assign(main.verticalOhlcv, {
|
|
18
|
-
macd_diff:
|
|
19
|
-
macd_dea:
|
|
20
|
-
macd_histogram:
|
|
18
|
+
macd_diff: [...main.nullArray],
|
|
19
|
+
macd_dea: [...main.nullArray],
|
|
20
|
+
macd_histogram: [...main.nullArray],
|
|
21
21
|
})
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const macdInstance = main.instances[`macd`];
|
|
25
|
-
macdInstance.update(value);
|
|
25
|
+
macdInstance.update(value, main.lastIndexReplace);
|
|
26
26
|
|
|
27
27
|
let macdResult;
|
|
28
28
|
|
|
@@ -5,16 +5,18 @@ export const relativeVolume = (main, index, size = 10) => {
|
|
|
5
5
|
const value = main.verticalOhlcv.volume[index]
|
|
6
6
|
|
|
7
7
|
if (index === 0) {
|
|
8
|
-
main.instances[`relative_volume_${size}`] =
|
|
8
|
+
main.instances[`relative_volume_${size}`] = {
|
|
9
|
+
instance: new FasterSMA(size),
|
|
10
|
+
prevRelativeVolumeSma: null
|
|
11
|
+
}
|
|
9
12
|
|
|
10
13
|
Object.assign(main.verticalOhlcv, {
|
|
11
|
-
[`relative_volume_${size}`]:
|
|
12
|
-
[`relative_volume_sma_${size}`]: new Array(main.len).fill(null)
|
|
14
|
+
[`relative_volume_${size}`]: [...main.nullArray],
|
|
13
15
|
})
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
const smaInstance = main.instances[`relative_volume_${size}`]
|
|
17
|
-
smaInstance.update(value)
|
|
18
|
+
const smaInstance = main.instances[`relative_volume_${size}`].instance
|
|
19
|
+
smaInstance.update(value, main.lastIndexReplace)
|
|
18
20
|
|
|
19
21
|
let smaValue;
|
|
20
22
|
try {
|
|
@@ -23,13 +25,16 @@ export const relativeVolume = (main, index, size = 10) => {
|
|
|
23
25
|
//do nothing
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
main.
|
|
28
|
+
const {prevRelativeVolumeSma} = main.instances[`relative_volume_${size}`]
|
|
27
29
|
|
|
28
|
-
if (smaValue !== null &&
|
|
29
|
-
main.verticalOhlcv[`relative_volume_${size}`][index] = value /
|
|
30
|
+
if (smaValue !== null && prevRelativeVolumeSma !== null) {
|
|
31
|
+
main.verticalOhlcv[`relative_volume_${size}`][index] = value / prevRelativeVolumeSma;
|
|
30
32
|
} else {
|
|
31
33
|
main.verticalOhlcv[`relative_volume_${size}`][index] = null;
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
|
|
37
|
+
main.instances[`relative_volume_${size}`].prevRelativeVolumeSma = smaValue
|
|
38
|
+
|
|
34
39
|
return true;
|
|
35
40
|
};
|
|
@@ -8,11 +8,11 @@ export const sma = (main, index, size) => {
|
|
|
8
8
|
if(index === 0)
|
|
9
9
|
{
|
|
10
10
|
main.instances[`sma_${size}`] = new FasterSMA(size)
|
|
11
|
-
main.verticalOhlcv[`sma_${size}`] =
|
|
11
|
+
main.verticalOhlcv[`sma_${size}`] = [...main.nullArray]
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
let currSma
|
|
15
|
-
main.instances[`sma_${size}`].update(value)
|
|
15
|
+
main.instances[`sma_${size}`].update(value, main.lastIndexReplace)
|
|
16
16
|
|
|
17
17
|
try{
|
|
18
18
|
currSma = main.instances[`sma_${size}`].getResult()
|
package/src/oscillators/rsi.js
CHANGED
|
@@ -16,15 +16,15 @@ export const rsi = (main, index, size) => {
|
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
Object.assign(main.verticalOhlcv, {
|
|
19
|
-
[`rsi_${size}`]:
|
|
20
|
-
[`rsi_sma_${size}`]:
|
|
19
|
+
[`rsi_${size}`]: [...main.nullArray],
|
|
20
|
+
[`rsi_sma_${size}`]: [...main.nullArray]
|
|
21
21
|
})
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
let currentRsi
|
|
25
25
|
let smoothedRsi
|
|
26
26
|
|
|
27
|
-
main.instances[`rsi_${size}`].update(value)
|
|
27
|
+
main.instances[`rsi_${size}`].update(value, main.lastIndexReplace)
|
|
28
28
|
|
|
29
29
|
try
|
|
30
30
|
{
|
|
@@ -36,7 +36,7 @@ export const rsi = (main, index, size) => {
|
|
|
36
36
|
if(currentRsi)
|
|
37
37
|
{
|
|
38
38
|
main.verticalOhlcv[`rsi_${size}`][index] = currentRsi
|
|
39
|
-
main.instances[`rsi_sma_${size}`].update(currentRsi)
|
|
39
|
+
main.instances[`rsi_sma_${size}`].update(currentRsi, main.lastIndexReplace)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
try
|
|
@@ -13,14 +13,14 @@ export const volumeOscillator = (main, index, fast, slow) => {
|
|
|
13
13
|
}
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
main.verticalOhlcv[`volume_oscillator`] =
|
|
16
|
+
main.verticalOhlcv[`volume_oscillator`] = [...main.nullArray];
|
|
17
17
|
main.crossPairsList.push({ fast: `volume_oscillator`, slow: 0 });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const { fastEMA, slowEMA } = main.instances[`volume_oscillator`];
|
|
21
21
|
|
|
22
|
-
fastEMA.update(value);
|
|
23
|
-
slowEMA.update(value);
|
|
22
|
+
fastEMA.update(value, main.lastIndexReplace);
|
|
23
|
+
slowEMA.update(value, main.lastIndexReplace);
|
|
24
24
|
|
|
25
25
|
let fastValue = null;
|
|
26
26
|
let slowValue = null;
|