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/index.js CHANGED
@@ -1,39 +1,28 @@
1
- import { parseOhlcvToVertical, defaultStudyOptions } from './src/utilities/parsing-utilities.js'
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, studyOptions = null}) {
8
+ constructor({input, ticker = null}) {
7
9
 
8
- if(!Array.isArray(input)) throw Error('input ohlcv must be an array: ' + ticker)
9
- if(input.length === 0) throw Error('input ohlcv must not be empty: ' + ticker)
10
- if(!input[0].hasOwnProperty('close')) throw Error('input ohlcv array objects require at least close property: ' + ticker)
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', 'mid_price_open_close', 'mid_price_high_low']
17
+ this.priceBased = ['open', 'high', 'low', 'close']
16
18
  this.len = input.length
17
- this.studyOptions = (studyOptions === null) ? defaultStudyOptions : studyOptions
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
- if (change) {
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
- if (this.len > this.lastComputedIndex && !change) {
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
- this.inputParams.crossPairs ??= []
131
- this.inputParams.crossPairs.push([this.crossPairsList])
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.inputParams.lag ??= []
140
- this.inputParams.lag.push([colKeys, lags])
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.inputParams.relativeVolume ??= []
158
- this.inputParams.relativeVolume.push([size])
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
- this.inputParams.sma ??= []
182
- this.inputParams.sma.push([size])
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, times = 2, bollingerBandsStudies) {
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('Invalid parameter: "size" must be a positive number in bollingerBands.');
245
+ throw new Error('"size" must be a positive number in bollingerBands.');
209
246
  }
210
- if (typeof times !== 'number' || times <= 0) {
211
- throw new Error('Invalid parameter: "times" must be a positive number in bollingerBands.');
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
- candlesStudies(size = 20, classify = true, classificationLevels)
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 candlesStudies.');
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 candlesStudies.');
297
+ throw new Error('"classify" must be a true or false in candleStudies.');
258
298
  }
259
299
 
260
- this.inputParams.candlesStudies ??= []
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.volumeOscillator ??= []
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": "1.9.8",
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
- export const bollingerBands = (main, index, size, times, bollingerBandsStudies = false) => {
4
+ let defaultTarget = 'close'
5
5
 
6
- const value = main.verticalOhlcv.close[index]
6
+ export const bollingerBands = (main, index, size, times, options) => {
7
7
 
8
- if (index === 0) {
8
+ const {height, range, target} = options
9
+ let suffix = (target === defaultTarget) ? '' : `_${target}`
9
10
 
10
- Object.assign(main.instances, {bollinger_bands: {
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.verticalOhlcv, {
17
- bollinger_bands_upper: new Array(main.len).fill(null),
18
- bollinger_bands_middle: new Array(main.len).fill(null),
19
- bollinger_bands_lower: new Array(main.len).fill(null)
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
- if (bollingerBandsStudies) {
23
-
24
- Object.assign(main.verticalOhlcv, {
25
- bollinger_bands_range: new Array(main.len).fill(null),
26
- bollinger_bands_height: new Array(main.len).fill(null),
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
- const { instance, heightInstance } = main.instances[`bollinger_bands`];
32
- instance.update(value);
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.bollinger_bands_upper[index] = upper;
45
- main.verticalOhlcv.bollinger_bands_middle[index] = middle;
46
- main.verticalOhlcv.bollinger_bands_lower[index] = lower;
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 (!bollingerBandsStudies) return true;
57
+ if (!height && !range) return true;
49
58
 
50
- let range = null;
51
- let height = null;
59
+ let rangeValue = null;
60
+ let heightValue = null;
52
61
  let heightMean;
53
62
 
54
- range = (value - lower) / (upper - lower);
55
- height = upper - lower;
63
+ rangeValue = (value - lower) / (upper - lower);
64
+ heightValue = upper - lower;
56
65
 
57
- heightInstance.update(height);
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.bollinger_bands_range[index] = range;
74
+ main.verticalOhlcv[`bollinger_bands_range${suffix}`][index] = rangeValue;
66
75
 
67
76
  if(heightMean)
68
77
  {
69
- main.verticalOhlcv.bollinger_bands_height[index] = classifySize(height, heightMean, 1.5);
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: new Array(main.len).fill(null),
15
- donchian_channel_basis: new Array(main.len).fill(null),
16
- donchian_channel_lower: new Array(main.len).fill(null),
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 = avg(upper, lower);
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}`] = new Array(main.len).fill(null)
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: new Array(main.len).fill(null),
19
- macd_dea: new Array(main.len).fill(null),
20
- macd_histogram: new Array(main.len).fill(null),
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}`] = new FasterSMA(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}`]: new Array(main.len).fill(null),
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.verticalOhlcv[`relative_volume_sma_${size}`][index] = smaValue;
28
+ const {prevRelativeVolumeSma} = main.instances[`relative_volume_${size}`]
27
29
 
28
- if (smaValue !== null && typeof main.verticalOhlcv[`relative_volume_sma_${size}`][index - 1] === 'number') {
29
- main.verticalOhlcv[`relative_volume_${size}`][index] = value / main.verticalOhlcv[`relative_volume_sma_${size}`][index - 1];
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}`] = new Array(main.len).fill(null)
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()
@@ -16,15 +16,15 @@ export const rsi = (main, index, size) => {
16
16
  })
17
17
 
18
18
  Object.assign(main.verticalOhlcv, {
19
- [`rsi_${size}`]: new Array(main.len).fill(null),
20
- [`rsi_sma_${size}`]: new Array(main.len).fill(null)
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`] = new Array(main.len).fill(null);
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;