ohlcv-indicators 3.1.9 → 3.2.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
@@ -5,6 +5,16 @@ import { isAlreadyComputed } from './src/utilities/validators.js'
5
5
  import { divideByMultiplier } from './src/utilities/numberUtilities.js'
6
6
  import { getMovingAveragesParams } from './src/moving-averages/movingAverages.js'
7
7
  import { verticalToHorizontal } from './src/utilities/dataParsingUtilities.js'
8
+ import { pushToMain } from './src/utilities/pushToMain.js'
9
+
10
+ /**
11
+ * Class OHLCV_INDICATORS
12
+ *
13
+ * This class provides methods for calculating and managing technical indicators
14
+ * on financial OHLCV (Open, High, Low, Close, Volume) data. It enables users
15
+ * to parallel compute various technical indicators in 1 single loop.
16
+ * OHLCV datasets.
17
+ */
8
18
 
9
19
  const validMagnitudeValues = [0.001, 0.002, 0.0025, 0.005, 0.01, 0.02, 0.025, 0.05, 0.1, 0.20, 0.25, 0.5, 1, 2, 2.5, 5, 10]
10
20
 
@@ -27,8 +37,6 @@ export default class OHLCV_INDICATORS {
27
37
  this.crossPairsList = []
28
38
  this.verticalOhlcv = {}
29
39
 
30
-
31
-
32
40
  this.studies = {}
33
41
  this.utilities = {
34
42
  correlation
@@ -39,6 +47,7 @@ export default class OHLCV_INDICATORS {
39
47
  this.precision = precision
40
48
  this.precisionMultiplier = (this.precision === true) ? 0 : 1
41
49
 
50
+ this.autoMinMaxKeys = []
42
51
  this.minMaxRanges = {}
43
52
 
44
53
 
@@ -51,60 +60,13 @@ export default class OHLCV_INDICATORS {
51
60
  this.inputParams = []
52
61
  }
53
62
 
54
- return this
55
- }
56
-
57
- pushToMain({index, key, value})
58
- {
59
- if(value === null || typeof value === 'undefined')
60
- {
61
- this.invalidValueIndex = index
62
-
63
- for(let k in this.minMaxRanges)
64
- {
65
- this.minMaxRanges[k] = {min: Infinity, max: -Infinity}
66
- }
67
- }
63
+ this.pushToMain = ({index, key, value}) => pushToMain({main: this, index, key, value})
68
64
 
69
- this.verticalOhlcv[key][index] = value
70
65
 
71
- if(typeof value === 'number')
72
- {
73
- if(key.includes('_diff_'))
74
- {
75
- if(!this.minMaxRanges.hasOwnProperty(key) || (this.minMaxRanges[key].min === Infinity || this.minMaxRanges[key].max === -Infinity))
76
- {
77
- this.minMaxRanges[key] = { min: -1, max: 1}
78
- }
79
- }
80
- else if(key.startsWith('candle_'))
81
- {
82
- this.minMaxRanges[key] = { min: -1, max: 1}
83
- }
84
- else if(key.includes('_range_') && (key.startsWith('bollinger_bands_') || key.startsWith('donchian_channel_')))
85
- {
86
- this.minMaxRanges[key] = { min: 0, max: 1 }
87
- }
88
- else if(!key.includes('_x_')) {
89
- const newValue = (this.precision && this.priceBased.includes(key)) ? (value / this.precisionMultiplier) : value
90
-
91
- if(!this.minMaxRanges.hasOwnProperty(key))
92
- {
93
- this.minMaxRanges[key] = { min: Infinity, max: -Infinity }
94
- }
95
-
96
- if(newValue < this.minMaxRanges[key].min)
97
- {
98
- this.minMaxRanges[key].min = newValue
99
- }
100
- if(newValue > this.minMaxRanges[key].max)
101
- {
102
- this.minMaxRanges[key].max = newValue
103
- }
104
- }
105
- }
66
+ return this
106
67
  }
107
68
 
69
+
108
70
  getDataAsCols(skipNull = true) {
109
71
  this.compute();
110
72
 
@@ -350,7 +312,7 @@ export default class OHLCV_INDICATORS {
350
312
  throw new Error('"options" must be an object in bollingerBands. eg: {target, height, range}');
351
313
  }
352
314
 
353
- const {target = 'close', height = false, range = [], scale = null, lag = 0} = options
315
+ const {target = 'close', height = false, range = [], scale = null, lag = 0, autoMinMax} = options
354
316
 
355
317
  // Validate size and times
356
318
  if (typeof size !== 'number' || size <= 0) {
@@ -366,6 +328,12 @@ export default class OHLCV_INDICATORS {
366
328
 
367
329
  throw new Error(`"lag" value in rsi must be a number in bollingerBands.`);
368
330
  }
331
+
332
+ if (typeof autoMinMax !== 'boolean') {
333
+
334
+ throw new Error(`"autoMinMax" value in rsi must be a number in bollingerBands.`);
335
+ }
336
+
369
337
  if (typeof height !== 'boolean') {
370
338
  throw new Error('"height" must be a boolean in bollingerBands.');
371
339
  }
@@ -377,7 +345,7 @@ export default class OHLCV_INDICATORS {
377
345
  }
378
346
  }
379
347
 
380
- this.inputParams.push({key: 'bollingerBands', params: [size, stdDev, {target, height, scale, range, lag}]});
348
+ this.inputParams.push({key: 'bollingerBands', params: [size, stdDev, {target, height, scale, range, lag, autoMinMax}]});
381
349
 
382
350
  return this;
383
351
  }
@@ -391,7 +359,7 @@ export default class OHLCV_INDICATORS {
391
359
  throw new Error('"size" must be a positive number in rsi.');
392
360
  }
393
361
 
394
- const {scale = null, target = 'close', lag = 0} = options
362
+ const {scale = null, target = 'close', lag = 0, autoMinMax = false} = options
395
363
 
396
364
  if (typeof scale === 'number' && !validMagnitudeValues.includes(scale)) {
397
365
 
@@ -403,7 +371,12 @@ export default class OHLCV_INDICATORS {
403
371
  throw new Error(`"lag" value in rsi must be a number in rsi.`);
404
372
  }
405
373
 
406
- this.inputParams.push({key: 'rsi', params: [size, {scale, target, lag}]})
374
+ if (typeof autoMinMax !== 'boolean') {
375
+
376
+ throw new Error(`"autoMinMax" value in rsi must be a number in rsi.`);
377
+ }
378
+
379
+ this.inputParams.push({key: 'rsi', params: [size, {scale, target, lag, autoMinMax}]})
407
380
 
408
381
  return this
409
382
  }
@@ -418,7 +391,7 @@ export default class OHLCV_INDICATORS {
418
391
  throw new Error('"offset" must be a number greater than or equal to 0 in donchianChannels.');
419
392
  }
420
393
 
421
- const { height = false, range = [], scale = null, lag = 0} = options;
394
+ const { height = false, range = [], scale = null, lag = 0, autoMinMax = false} = options;
422
395
 
423
396
  if (!Array.isArray(range)) {
424
397
  throw new Error('If set, "range" must be an array of column names in donchianChannels.');
@@ -427,6 +400,11 @@ export default class OHLCV_INDICATORS {
427
400
  if (typeof lag !== 'number') {
428
401
  throw new Error(`"lag" value in rsi must be a number in donchianChannels.`);
429
402
  }
403
+
404
+ if (typeof autoMinMax !== 'boolean') {
405
+
406
+ throw new Error(`"autoMinMax" value in rsi must be a number in donchianChannels.`);
407
+ }
430
408
 
431
409
  if (typeof height !== 'boolean') {
432
410
  throw new Error('"height" must be a boolean in donchianChannels.');
@@ -440,37 +418,41 @@ export default class OHLCV_INDICATORS {
440
418
  }
441
419
  }
442
420
 
443
- this.inputParams.push({ key: 'donchianChannels', params: [size, offset, { height, range, scale, lag }] });
421
+ this.inputParams.push({ key: 'donchianChannels', params: [size, offset, { height, range, scale, lag, autoMinMax }] });
444
422
 
445
423
  return this;
446
424
  }
447
425
 
448
426
 
449
- candleStudies(size = 20, options = {}) {
427
+ candleVectors(size = 20, options = {}) {
450
428
  isAlreadyComputed(this);
451
429
 
452
430
  if (typeof size !== 'number' || size <= 0) {
453
- throw new Error('"size" must be a positive number greater than 0 in candleStudies.');
431
+ throw new Error('"size" must be a positive number greater than 0 in candleVectors.');
454
432
  }
455
433
 
456
- const { stdDev = 0.5, lag = 0, scale = 0.05, patternSize = 1 } = options;
434
+ const { stdDev = 0.5, lag = 0, scale = 0.05, patternSize = 1, autoMinMax = false } = options;
457
435
 
458
436
 
459
437
  if (typeof stdDev !== 'number' || stdDev <= 0) {
460
- throw new Error('"stdDev" must be a positive number greater than 0 in candleStudies.');
438
+ throw new Error('"stdDev" must be a positive number greater than 0 in candleVectors.');
461
439
  }
462
440
 
463
441
  if (typeof scale === 'number' && !validMagnitudeValues.includes(scale)) {
464
442
 
465
- throw new Error(`"scale" value in candleStudies must be any of the following numbers: ${validMagnitudeValues.join(', ')}`);
443
+ throw new Error(`"scale" value in candleVectors must be any of the following numbers: ${validMagnitudeValues.join(', ')}`);
466
444
  }
467
445
 
468
446
  if (typeof patternSize !== 'number' || !Number.isInteger(patternSize) || patternSize < 1 ) {
469
447
 
470
- throw new Error(`"patternSize" value in candleStudies must be an integer greater than 0.}`);
448
+ throw new Error(`"patternSize" value in candleVectors must be an integer greater than 0.`);
449
+ }
450
+ if (typeof autoMinMax !== 'boolean') {
451
+
452
+ throw new Error(`"autoMinMax" value in candleVectors must be boolean`);
471
453
  }
472
454
 
473
- this.inputParams.push({ key: 'candleStudies', params: [size, {stdDev, patternSize, lag, scale}] });
455
+ this.inputParams.push({ key: 'candleVectors', params: [size, {stdDev, patternSize, lag, scale, autoMinMax}] });
474
456
  return this;
475
457
  }
476
458
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ohlcv-indicators",
3
- "version": "3.1.9",
3
+ "version": "3.2.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",
@@ -22,6 +22,7 @@
22
22
  "@babel/preset-env": "^7.25.3",
23
23
  "babel-loader": "^9.1.3",
24
24
  "dotenv": "^16.4.5",
25
+ "terser-webpack-plugin": "^5.3.14",
25
26
  "webpack": "^5.93.0",
26
27
  "webpack-cli": "^5.1.4"
27
28
  }
@@ -3,7 +3,7 @@ import { calcMagnitude } from '../utilities/numberUtilities.js';
3
3
 
4
4
  const defaultTarget = 'close'
5
5
 
6
- export const bollingerBands = (main, index, size, stdDev, { height, range = [], target, scale, lag }) => {
6
+ export const bollingerBands = (main, index, size, stdDev, { height, range = [], target, scale, lag, autoMinMax }) => {
7
7
  const { verticalOhlcv, instances, lastIndexReplace } = main;
8
8
  const suffix = target === defaultTarget ? '' : `_${target}`;
9
9
  const indicatorKey = `${size}_${stdDev}${suffix}`;
@@ -11,6 +11,7 @@ export const bollingerBands = (main, index, size, stdDev, { height, range = [],
11
11
 
12
12
  // Initialization on the first call.
13
13
  if (index === 0) {
14
+
14
15
  const { priceBased, inputParams, nullArray, verticalOhlcv } = main;
15
16
 
16
17
  if (!(target in verticalOhlcv)) {
@@ -49,6 +50,12 @@ export const bollingerBands = (main, index, size, stdDev, { height, range = [],
49
50
  throw new Error(`Invalid range item value "${rangeKey}" property for bollingerBands. Only price based key names are accepted:\n${JSON.stringify(priceBased)}`);
50
51
  }
51
52
  keyNames.push(`${prefix}_range_${rangeKey}`)
53
+
54
+ if(autoMinMax)
55
+ {
56
+ main.autoMinMaxKeys.push(`${prefix}_range_${rangeKey}`)
57
+ }
58
+
52
59
  }
53
60
 
54
61
  const verticalOhlcvSetup = Object.fromEntries(keyNames.map(v => [v, [...nullArray]]))
@@ -106,7 +113,11 @@ export const bollingerBands = (main, index, size, stdDev, { height, range = [],
106
113
  let rangeValue = null;
107
114
  const priceValue = verticalOhlcv[rangeKey][index];
108
115
  if (typeof priceValue === 'number' && typeof lower === 'number' && typeof upper === 'number' && (upper - lower) !== 0) {
109
- rangeValue = Math.max(Math.min((priceValue - lower) / (upper - lower), 1), 0);
116
+ rangeValue = (autoMinMax)
117
+ ? Math.max(Math.min((priceValue - lower) / (upper - lower), 1), 0)
118
+ : (priceValue - lower) / (upper - lower)
119
+
120
+
110
121
  if (scale) {
111
122
  rangeValue = calcMagnitude(rangeValue, scale);
112
123
  }
@@ -1,6 +1,6 @@
1
1
  import { calcMagnitude } from "../utilities/numberUtilities.js"
2
2
 
3
- export const donchianChannels = (main, index, size, offset, { height, range, scale, lag }) => {
3
+ export const donchianChannels = (main, index, size, offset, { height, range, scale, lag, autoMinMax }) => {
4
4
  const indicatorKey = `${size}_${offset}`;
5
5
  const { verticalOhlcv, instances, len } = main;
6
6
 
@@ -32,6 +32,12 @@ export const donchianChannels = (main, index, size, offset, { height, range, sca
32
32
  throw new Error(`Invalid range item value "${rangeKey}" property for donchianChannels. Only price based key names are accepted:\n${JSON.stringify(priceBased)}`);
33
33
  }
34
34
  keyNames.push(`${prefix}_range_${rangeKey}`)
35
+
36
+ if(autoMinMax)
37
+ {
38
+ main.autoMinMaxKeys.push(`${prefix}_range_${rangeKey}`)
39
+ }
40
+
35
41
  }
36
42
 
37
43
  const verticalOhlcvSetup = Object.fromEntries(keyNames.map(v => [v, [...nullArray]]))
@@ -125,7 +131,10 @@ export const donchianChannels = (main, index, size, offset, { height, range, sca
125
131
  typeof lower === 'number' &&
126
132
  (upper - lower) !== 0
127
133
  ) {
128
- rangeValue = Math.max(Math.min((priceValue - lower) / (upper - lower), 1), 0);
134
+ rangeValue = (autoMinMax)
135
+ ? Math.max(Math.min((priceValue - lower) / (upper - lower), 1), 0)
136
+ : (priceValue - lower) / (upper - lower)
137
+
129
138
  if (scale) {
130
139
  rangeValue = calcMagnitude(rangeValue, scale);
131
140
  }
@@ -4,7 +4,7 @@ import { classifyBoll } from '../utilities/classification.js'
4
4
 
5
5
  const indicatorClasses = {ema: FasterEMA, sma: FasterSMA}
6
6
 
7
- export const movingAverages = (main, index, indicatorName, size, { target, diff }) => {
7
+ export const movingAverages = (main, index, indicatorName, size, { target, diff, autoMinMax }) => {
8
8
  const { verticalOhlcv, instances, priceBased, lastIndexReplace } = main;
9
9
  let suffix =
10
10
  typeof target === 'string' &&
@@ -43,6 +43,11 @@ export const movingAverages = (main, index, indicatorName, size, { target, diff
43
43
  for (const targetKey of diff.targets) {
44
44
  verticalOhlcv[`${diffKeyName}_${targetKey}`] = [...nullArray];
45
45
 
46
+ if(diff.autoMinMax)
47
+ {
48
+ main.autoMinMaxKeys.push(`${diffKeyName}_${targetKey}`)
49
+ }
50
+
46
51
  if (diff.lag > 0) {
47
52
  lagDiffArr.push(`${diffKeyName}_${targetKey}`);
48
53
  }
@@ -93,7 +98,7 @@ export const movingAverages = (main, index, indicatorName, size, { target, diff
93
98
  diffBoll = null;
94
99
  }
95
100
 
96
- const classified = classifyBoll(diffValue, diffBoll, diff.scale);
101
+ const classified = classifyBoll(diffValue, diffBoll, diff.scale, diff.autoMinMax);
97
102
  main.pushToMain({
98
103
  index,
99
104
  key: `${diffKeyName}_${targetKey}`,
@@ -134,7 +139,8 @@ export const getMovingAveragesParams = (indicatorName, size, options, validMagni
134
139
  scale = 0.05,
135
140
  targets = ['close'],
136
141
  size: diffSize = size,
137
- lag = 0
142
+ lag = 0,
143
+ autoMinMax = false
138
144
  } = diff;
139
145
 
140
146
  if (typeof stdDev !== 'number' || stdDev <= 0) {
@@ -157,7 +163,11 @@ export const getMovingAveragesParams = (indicatorName, size, options, validMagni
157
163
  throw new Error(`"diff.lag" must be an integer greater than 0 in ${indicatorName}.`);
158
164
  }
159
165
 
160
- optionArgs.diff = { stdDev, scale, size: diffSize, targets, lag };
166
+ if (typeof autoMinMax !== 'boolean') {
167
+ throw new Error(`"diff.autoMinMax" must be an boolean in ${indicatorName}.`);
168
+ }
169
+
170
+ optionArgs.diff = { stdDev, scale, size: diffSize, targets, lag, autoMinMax};
161
171
  }
162
172
 
163
173
  return optionArgs;
@@ -4,7 +4,7 @@ import { calcMagnitude } from '../utilities/numberUtilities.js';
4
4
 
5
5
  const defaultTarget = 'close';
6
6
 
7
- export const rsi = (main, index, size, { scale, target, lag }) => {
7
+ export const rsi = (main, index, size, { scale, target, lag, autoMinMax }) => {
8
8
  const { verticalOhlcv, instances, lastIndexReplace } = main;
9
9
  const suffix = target === defaultTarget ? '' : `_${target}`;
10
10
  const rsiKey = `rsi_${size}${suffix}`;
@@ -12,6 +12,7 @@ export const rsi = (main, index, size, { scale, target, lag }) => {
12
12
 
13
13
  // Initialization on the first index.
14
14
  if (index === 0) {
15
+
15
16
  const { crossPairsList, nullArray } = main;
16
17
 
17
18
  if (!verticalOhlcv.hasOwnProperty(target)) {
@@ -34,6 +35,12 @@ export const rsi = (main, index, size, { scale, target, lag }) => {
34
35
  {
35
36
  main.lag([rsiKey, rsiSmaKey], lag)
36
37
  }
38
+
39
+ if(autoMinMax)
40
+ {
41
+ main.autoMinMaxKeys.push(rsiKey, rsiSmaKey)
42
+ }
43
+
37
44
  }
38
45
 
39
46
  const value = verticalOhlcv[target][index];
@@ -7,13 +7,15 @@ const diff = (a, b) => (a - b) / b
7
7
  // Las diferencias estarán basadas en (objetivo - lower) / (upper - lower). Esto arrojará un valor entre -1 y 1
8
8
 
9
9
 
10
- export const candleStudies = (main, index, size, {stdDev, patternSize, lag, scale}) => {
10
+ export const candleVectors = (main, index, size, {stdDev, patternSize, lag, scale, autoMinMax}) => {
11
11
 
12
12
  const { verticalOhlcv, instances, lastIndexReplace } = main
13
- const calcSize = (di, bo) => classifyBoll(di, bo, scale)
13
+ const calcSize = (di, bo) => classifyBoll(di, bo, scale, autoMinMax)
14
14
 
15
15
  if(index === 0)
16
16
  {
17
+
18
+ console.log({autoMinMax})
17
19
  const {nullArray} = main
18
20
 
19
21
  const bodyVectors = [
@@ -42,6 +44,11 @@ export const candleStudies = (main, index, size, {stdDev, patternSize, lag, scal
42
44
  {
43
45
  lookBackVectorKeyNames.push(`candle_change_${x+1}_${currK}_${prevK}`)
44
46
  lookBackVectorsSetup[`candle_change_${x+1}_${currK}_${prevK}`] = [...nullArray]
47
+
48
+ if(autoMinMax)
49
+ {
50
+ main.autoMinMaxKeys.push(`candle_change_${x+1}_${currK}_${prevK}`)
51
+ }
45
52
  }
46
53
  }
47
54
 
@@ -53,6 +60,11 @@ export const candleStudies = (main, index, size, {stdDev, patternSize, lag, scal
53
60
  {
54
61
  bodyVectorKeyNames.push(`candle_body_${a}_${b}`)
55
62
  bodyVectorSetup[`candle_body_${a}_${b}`] = [...nullArray]
63
+
64
+ if(autoMinMax)
65
+ {
66
+ main.autoMinMaxKeys.push(`candle_body_${a}_${b}`)
67
+ }
56
68
  }
57
69
 
58
70
  const keyNames = [...bodyVectorKeyNames, ...lookBackVectorKeyNames]
@@ -60,7 +72,7 @@ export const candleStudies = (main, index, size, {stdDev, patternSize, lag, scal
60
72
  Object.assign(verticalOhlcv, {...bodyVectorSetup, ...lookBackVectorsSetup})
61
73
 
62
74
  Object.assign(instances, {
63
- candleStudies: {
75
+ candleVectors: {
64
76
  bodyVectors,
65
77
  lookBackVectors,
66
78
  keyNames,
@@ -78,7 +90,7 @@ export const candleStudies = (main, index, size, {stdDev, patternSize, lag, scal
78
90
  if (index === 0) return true
79
91
 
80
92
 
81
- const {bodyVectors, lookBackVectors, bodyInstance} = instances.candleStudies
93
+ const {bodyVectors, lookBackVectors, bodyInstance} = instances.candleVectors
82
94
 
83
95
  let bodyBoll = null
84
96
  const currOpen = verticalOhlcv.open[index]
@@ -20,7 +20,7 @@ import { calcMagnitude } from "./numberUtilities.js"
20
20
  */
21
21
 
22
22
 
23
- export const classifyBoll = (value, bollingerBands, scale = 0.05) => {
23
+ export const classifyBoll = (value, bollingerBands, scale = 0.05, autoMinMax = false) => {
24
24
 
25
25
  // Validate that value and bollingerBands are not null/undefined
26
26
  if (value == null || bollingerBands == null) return null
@@ -28,23 +28,17 @@ export const classifyBoll = (value, bollingerBands, scale = 0.05) => {
28
28
  const positive = value >= 0
29
29
  const absValue = Math.abs(value)
30
30
 
31
- const { upper, middle, lower } = bollingerBands
32
-
33
- // Handle values outside the Bollinger bands
34
- if (absValue < lower) return 0
35
- if (absValue > upper) return positive ? 1 : -1
36
-
37
- // Use a tolerance for floating point comparisons
38
- const epsilon = Number.EPSILON * Math.max(absValue, Math.abs(middle))
39
- if (Math.abs(absValue - middle) < epsilon) return positive ? 0.5 : -0.5
40
-
41
- // Prevent division by zero if upper and lower are equal
42
- if (upper === lower) return null
31
+ const { upper, lower } = bollingerBands
43
32
 
44
33
  const rangeValue = (absValue - lower) / (upper - lower)
45
34
  let magnitude = calcMagnitude(rangeValue, scale)
46
35
 
47
- //magnitude = Math.min(Math.max(magnitude, 0), 1)
36
+ if(autoMinMax)
37
+ {
38
+ return positive ? Math.min(magnitude, 1) : Math.max(-magnitude, -1)
39
+ }
40
+ else {
41
+ return positive ? magnitude : -magnitude
42
+ }
48
43
 
49
- return positive ? Math.min(magnitude, 1) : Math.max(-magnitude, -1)
50
44
  }
@@ -6,7 +6,7 @@ import { relativeVolume } from "../moving-averages/relativeVolume.js";
6
6
  import { donchianChannels } from "../moving-averages/donchianChannel.js";
7
7
  import { bollingerBands } from "../moving-averages/bollingerBands.js";
8
8
  import { volumeOscillator } from "../oscillators/volumeOscillator.js";
9
- import { candleStudies } from "../studies/candleStudies.js";
9
+ import { candleVectors } from "../studies/candleVectors.js";
10
10
  import { lag } from "../studies/lag.js";
11
11
  import { crossPairs } from "../studies/findCrosses.js";
12
12
  import { dateTime } from "../studies/dateTime.js";
@@ -25,7 +25,7 @@ const indicatorFunctions = {
25
25
  donchianChannels,
26
26
  bollingerBands,
27
27
  volumeOscillator,
28
- candleStudies
28
+ candleVectors
29
29
  };
30
30
 
31
31
  // Processes the inputParams into a list of indicator calls
@@ -0,0 +1,61 @@
1
+ export const pushToMain = ({main, index, key, value}) => {
2
+
3
+ const {precision, priceBased, minMaxRanges, verticalOhlcv, autoMinMaxKeys} = main
4
+ let {invalidValueIndex } = main
5
+
6
+ if(value === null || typeof value === 'undefined')
7
+ {
8
+ invalidValueIndex = index
9
+
10
+ for(let k in minMaxRanges)
11
+ {
12
+ minMaxRanges[k] = {min: Infinity, max: -Infinity}
13
+ }
14
+ }
15
+
16
+ verticalOhlcv[key][index] = value
17
+
18
+ if(typeof value === 'number' && !key.includes('_x_'))
19
+ {
20
+ const keyInAutoMinMax = autoMinMaxKeys.includes(key)
21
+
22
+ if(key.includes('_diff_') && keyInAutoMinMax)
23
+ {
24
+ if(!minMaxRanges.hasOwnProperty(key) || (minMaxRanges[key].min === Infinity || minMaxRanges[key].max === -Infinity))
25
+ {
26
+ minMaxRanges[key] = { min: -1, max: 1}
27
+ }
28
+ }
29
+ else if(key.startsWith('candle_') && keyInAutoMinMax)
30
+ {
31
+ minMaxRanges[key] = { min: -1, max: 1}
32
+ }
33
+ else if(key.includes('_range_') && keyInAutoMinMax)
34
+ {
35
+ minMaxRanges[key] = { min: 0, max: 1 }
36
+ }
37
+ else if(key.startsWith('rsi_') && keyInAutoMinMax)
38
+ {
39
+ minMaxRanges[key] = { min: 0, max: 1 }
40
+ }
41
+ else {
42
+ const newValue = (precision && priceBased.includes(key)) ? (value / precisionMultiplier) : value
43
+
44
+ if(!minMaxRanges.hasOwnProperty(key))
45
+ {
46
+ minMaxRanges[key] = { min: Infinity, max: -Infinity }
47
+ }
48
+
49
+ if(newValue < minMaxRanges[key].min)
50
+ {
51
+ minMaxRanges[key].min = newValue
52
+ }
53
+ if(newValue > minMaxRanges[key].max)
54
+ {
55
+ minMaxRanges[key].max = newValue
56
+ }
57
+ }
58
+ }
59
+
60
+ return true
61
+ }
package/webpack.config.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { resolve, dirname } from 'path';
2
2
  import { fileURLToPath } from 'url';
3
+ import TerserPlugin from 'terser-webpack-plugin';
4
+
3
5
  const __dirname = dirname(fileURLToPath(import.meta.url));
4
6
 
5
7
  const entry = './index.js';
@@ -14,6 +16,19 @@ export default {
14
16
  output,
15
17
  mode: 'production',
16
18
  target: 'web',
19
+ optimization: { //TerserPlugin start
20
+ minimize: true,
21
+ minimizer: [
22
+ new TerserPlugin({
23
+ terserOptions: {
24
+ output: {
25
+ beautify: true, // Beautify the output
26
+ comments: true, // Preserve comments
27
+ },
28
+ },
29
+ }),
30
+ ],
31
+ }, // TerserPlugin end
17
32
  module: {
18
33
  rules: [
19
34
  {