ohlcv-indicators 3.5.56 → 3.5.60

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
@@ -15,35 +15,25 @@ import { pushToMain } from './src/core-functions/pushToMain.js'
15
15
  import { assignTypes } from './src/utilities/assignTypes.js'
16
16
  import { dateOutputFormaters } from './src/utilities/dateUtilities.js'
17
17
  import { defaultMapColsCallback } from './src/studies/mapCols.js'
18
- import { getOrderFromArray } from './src/utilities/order.js'
19
18
  import { calcPrecisionMultiplier } from './src/utilities/precisionMultiplier.js'
20
19
 
21
- import {
22
- defaultYCallback,
23
- validRegressors,
24
- validClassifiers,
25
- exportTrainedModels
26
- } from './src/machine-learning/ml-config.js'
27
-
28
20
  import { normalizeMinMax } from './src/machine-learning/ml-utilities.js'
29
21
 
30
22
  /**
31
23
  * Class OHLCV_INDICATORS
32
24
  *
33
25
  * This class provides methods for calculating and managing technical indicators
34
- * on financial OHLCV (Open, High, Low, Close, Volume) data. It enables users
35
- * to parallel compute various technical indicators in 1 single loop for standard indicators and a second loop for ML regressors and classifier.
26
+ * on financial OHLCV (Open, High, Low, Close, Volume) data. It enables users
36
27
  * OHLCV datasets.
37
28
  */
38
29
 
39
30
  export default class OHLCV_INDICATORS {
40
- constructor({input, ticker = null, inputParams = null, chunkProcess = 2000, ML = {}, precision = false}) {
31
+ constructor({input, ticker = null, inputParams = null, chunkProcess = 2000, precision = false}) {
41
32
 
42
33
  validateArray(input, 'input', (ticker !== null) ? `contructor ${ticker}` : 'constuctor')
43
34
  if(input.length === 0) throw Error('input OHLCV must not be empty: ' + ticker)
44
35
 
45
36
  validateNumber(chunkProcess, {min: 100, max: 50000, allowDecimals: false}, 'chunkProcess', 'constructor')
46
- validateObject(ML, 'ML', 'constructor')
47
37
  validateBoolean(precision, 'precision', 'contructor')
48
38
 
49
39
  this.chunkProcess = chunkProcess
@@ -78,24 +68,12 @@ export default class OHLCV_INDICATORS {
78
68
  this.scaledGroups = {}
79
69
  this.isAlreadyComputed = new Set()
80
70
 
81
- const {classes: mlClasses} = ML
82
-
83
- if(typeof mlClasses !== 'undefined') validateObject(mlClasses, 'ML.classes', 'constructor')
84
-
85
- this.ML = {
86
- models: {},
87
- classes: mlClasses,
88
- metrics: {},
89
- featureCols: {}
90
- }
91
- this.processSecondaryLoop = false
92
-
93
71
  this.pushToMain = ({index, key, value}) => pushToMain({main: this, index, key, value})
94
72
 
95
73
  if(inputParams !== null)
96
74
  {
97
75
  validateInputParams(inputParams, this.len)
98
- this.inputParams = inputParams
76
+ this.inputParams = inputParams.sort((a, b) => a.order - b.order)
99
77
  this.compute()
100
78
  }
101
79
  else
@@ -150,6 +128,8 @@ export default class OHLCV_INDICATORS {
150
128
  if (this.isComputed) {
151
129
  return this;
152
130
  }
131
+
132
+ this.inputParams = this.inputParams.sort((a, b) => a.order - b.order)
153
133
 
154
134
  // Mark as “in progress”
155
135
  this.isComputed = false;
@@ -208,9 +188,7 @@ export default class OHLCV_INDICATORS {
208
188
 
209
189
  this.isAlreadyComputed.add(methodName)
210
190
 
211
- const order = getOrderFromArray(orderArr, methodName)
212
-
213
- this.inputParams.push({key: methodName, order, params: [arr, {limit, oneHot}]})
191
+ this.inputParams.push({key: methodName, params: [arr, {limit, oneHot}]})
214
192
 
215
193
  return this
216
194
  }
@@ -224,8 +202,7 @@ export default class OHLCV_INDICATORS {
224
202
  validateArray(colKeys, 'colKeys', methodName)
225
203
  validateNumber(lookback, {min:1, max: this.len, allowDecimals: false}, 'lookback', methodName)
226
204
 
227
- const order = getOrderFromArray(colKeys, methodName)
228
- this.inputParams.push({key: methodName, order, params: [colKeys, lookback]})
205
+ this.inputParams.push({key: methodName, params: [colKeys, lookback]})
229
206
 
230
207
  return this;
231
208
  }
@@ -309,9 +286,7 @@ export default class OHLCV_INDICATORS {
309
286
  validateString(target, 'options.target', methodName)
310
287
  validateNumber(lag, {min: 0, max: this.len, allowDecimals: false}, 'options.lag', methodName)
311
288
 
312
- const order = getOrderFromArray([target], methodName)
313
-
314
- this.inputParams.push({key: methodName, order, params: [methodName, size, {target, lag}]})
289
+ this.inputParams.push({key: methodName, params: [methodName, size, {target, lag}]})
315
290
 
316
291
  return this
317
292
  }
@@ -329,9 +304,7 @@ export default class OHLCV_INDICATORS {
329
304
  validateString(target, 'options.target', methodName)
330
305
  validateNumber(lag, {min: 0, max: this.len, allowDecimals: false}, 'options.lag', methodName)
331
306
 
332
- const order = getOrderFromArray([target], methodName)
333
-
334
- this.inputParams.push({key: methodName, order, params: [methodName, size, {target, lag}]})
307
+ this.inputParams.push({key: methodName, params: [methodName, size, {target, lag}]})
335
308
 
336
309
  return this
337
310
  }
@@ -379,9 +352,7 @@ export default class OHLCV_INDICATORS {
379
352
  validateNumber(atrLength, {min: 2, max: this.len, allowDecimals: false}, 'options.atrLength', methodName)
380
353
  validateNumber(liquidityLookback, {min: 1, max: this.len, allowDecimals: false}, 'options.liquidityLookback', methodName)
381
354
 
382
- const order = getOrderFromArray([target], methodName)
383
-
384
- this.inputParams.push({key: methodName, order, params: [size, momentum, {target, lag}]})
355
+ this.inputParams.push({key: methodName, params: [size, momentum, {target, lag}]})
385
356
 
386
357
  return this
387
358
  }
@@ -443,9 +414,7 @@ export default class OHLCV_INDICATORS {
443
414
  const instanceKey = `${fast}_${slow}_${signal}${target === 'close' ? '' : `_${target}`}`
444
415
  const precomputed = {instanceKey}
445
416
 
446
- const order = getOrderFromArray([target], methodName)
447
-
448
- this.inputParams.push({key: methodName, order, params: [fast, slow, signal, {target, lag, precomputed}]})
417
+ this.inputParams.push({key: methodName, params: [fast, slow, signal, {target, lag, precomputed}]})
449
418
 
450
419
  return this
451
420
 
@@ -467,9 +436,7 @@ export default class OHLCV_INDICATORS {
467
436
  validateNumber(lag, {min: 0, max: this.len, allowDecimals: false}, 'options.lag', methodName)
468
437
  validateBoolean(height, 'options.height', methodName)
469
438
 
470
- const order = getOrderFromArray([target], methodName)
471
-
472
- this.inputParams.push({key: methodName, order, params: [size, stdDev, {target, height, range, lag}]});
439
+ this.inputParams.push({key: methodName, params: [size, stdDev, {target, height, range, lag}]});
473
440
 
474
441
  return this;
475
442
  }
@@ -505,9 +472,7 @@ export default class OHLCV_INDICATORS {
505
472
  prefix = 'minmax_'
506
473
  }
507
474
 
508
- const order = getOrderFromArray([target], methodName)
509
-
510
- this.inputParams.push({key: methodName, order, params: [size, {target, lag, parser, prefix, minmax}]})
475
+ this.inputParams.push({key: methodName, params: [size, {target, lag, parser, prefix, minmax}]})
511
476
 
512
477
  return this
513
478
  }
@@ -589,328 +554,89 @@ export default class OHLCV_INDICATORS {
589
554
  return this
590
555
  }
591
556
 
592
- scaler(type = 'zscore', size, options = {})
593
- {
594
- let methodName = 'scaler'
557
+ priceFeatures(options = {}) {
558
+ let methodName = 'priceFeatures'
595
559
 
596
560
  isAlreadyComputed(this)
597
561
 
598
- validateNumber(size, {min: 1, max: this.len, allowDecimals: false}, 'size', methodName)
599
-
600
562
  validateObject(options, 'options', methodName)
601
563
 
602
- const {group = false, range = [0, 1], lag = 0, colKeys = []} = options
564
+ const {lag = 0, colKeys = []} = options
603
565
 
566
+ validateNumber(lag, {min: 0, max: this.len, allowDecimals: false}, 'options.lag', methodName)
604
567
  validateArray(colKeys, 'options.colKeys', methodName)
605
- validateBoolean(group, 'options.group', methodName)
606
- validateArrayOfRanges(range, 'options.range', methodName)
607
- validateArrayOptions(['minmax', 'zscore'], type, 'options.type', methodName)
608
568
 
609
- const groupKey = `${type}_${size}`
610
- const groupKeyLen = colKeys.length
611
- const precomputed = {groupKey, groupKeyLen}
612
569
 
613
- let secondaryLoop = false
614
-
615
- const order = getOrderFromArray(colKeys, methodName)
616
-
617
- if(order >= 10)
618
- {
619
- secondaryLoop = true
620
- }
570
+ this.inputParams.push({key: methodName, params: [{lag, colKeys}]})
621
571
 
622
- this.inputParams.push({key: methodName, order, params: [size, colKeys, {type, group, range, lag, precomputed, secondaryLoop}]})
623
572
  return this
624
573
  }
625
574
 
626
- classifier(trainingSize = 200, options = {})
575
+ scaler(type = 'zscore', size, options = {})
627
576
  {
628
- isAlreadyComputed(this)
629
-
630
- const methodName = 'classifier'
631
- validateNumber(trainingSize, {max: this.len, allowDecimals: false}, 'trainingSize', methodName)
632
- validateObject(options, 'options', methodName)
633
-
634
- const {
635
- retrain = false,
636
- trainingCols = [],
637
- type = 'KNN',
638
- lookback = 0,
639
- findGroups = [],
640
- predictions = 2,
641
- horizon = 2,
642
- modelArgs = undefined,
643
- filterCallback = () => true
644
- } = options
645
-
646
- if (modelArgs !== undefined && (typeof modelArgs !== 'object' || modelArgs === null || Array.isArray(modelArgs))) throw new TypeError(`"modelArgs" must be either undefined or a plain object in ${type}`);
647
-
648
- const yCallback = options.yCallback ?? defaultYCallback
649
-
650
- if(typeof yCallback !== 'function')
651
- {
652
- throw new Error(`"yCallback" must be a function in the following format:\n\n---\n\nconst yCallback = ${defaultYCallback.toString()}\n\n---\n\n`)
653
- }
654
-
655
- validateArrayOptions(Object.keys(validClassifiers), type, 'options.type', methodName)
656
-
657
- if (!this.ML.classes.hasOwnProperty(type)) {
658
- throw new Error(
659
- `"${type}" isn’t available because its library wasn’t imported into OHLCV_INDICATORS.ML.`
660
- )
661
- }
662
-
663
- validateBoolean(retrain, 'options.retrain', methodName)
664
- validateArray(trainingCols, 'options.trainingCols', methodName)
665
- validateNumber(horizon, {min: 1, max: this.len, allowDecimals: false}, 'options.horizon', methodName)
666
- validateNumber(lookback, {max: 0, allowDecimals: false}, 'options.lookback', methodName)
667
- validateNumber(predictions, {min: 1, allowDecimals: false}, 'options.predictions', methodName)
668
-
669
- const orderArr = [...trainingCols]
670
-
671
- if(validateArray(findGroups, 'options.findGroups', 'scaler') && findGroups.length > 0)
672
- {
673
- for (const { type = '', size, groupName = '' } of findGroups) {
674
-
675
- if (!type || (!size && !groupName) || (size && groupName)) {
676
- throw new Error(`If "options.findGroups" array is set, each item must be an object that includes the "type" (mandatory) and either "size" or "groupName" (choose 1) used to locate previously scaled (minmax or zscore) groups.`);
677
- }
678
-
679
- orderArr.push(type.toString(), groupName.toString());
680
- }
681
- } else {
682
- if(trainingCols.length === 0)
683
- {
684
- throw new Error(`"trainingCols" array is empty in ${methodName}`)
685
- }
686
- }
687
-
688
- const {shortName, flatY} = validClassifiers[type]
577
+ let methodName = 'scaler'
689
578
 
690
- const prefix = `cla_${shortName}_${trainingSize}_prediction`
579
+ isAlreadyComputed(this)
691
580
 
692
- if(this.isAlreadyComputed.has(prefix))
693
- {
694
- throw new Error(
695
- `Each classifier must have a unique pair of “type” and trainingSize.\n` +
696
- `This rule ensures that your output columns are labeled unambiguously.\n` +
697
- `You provided a duplicate: type="${type}" with trainingSize=${trainingSize}.`
698
- );
699
- }
581
+ validateArrayOptions(['minmax', 'zscore', 'byfeature'], type, 'options.type', methodName)
582
+ validateNumber(size, {min: 1, max: this.len, allowDecimals: false}, 'size', methodName)
700
583
 
701
- const precompute = {
702
- lookbackAbs: Math.abs(lookback) + 1,
703
- flatY,
704
- prefix
705
- }
584
+ const longName = `${methodName}(${type}, ${size}, options = {})`
706
585
 
707
- this.isAlreadyComputed.add(prefix)
708
-
709
- const order = getOrderFromArray(orderArr, methodName)
710
-
711
- const modelConfig = validClassifiers[type]
712
- const modelClass = this.ML.classes[type]
713
-
714
- this.inputParams.push({key: methodName, order, params: [trainingSize, {yCallback, predictions, lookback, retrain, trainingCols, findGroups, horizon, type, modelArgs, precompute, filterCallback, modelConfig, modelClass}]})
715
-
586
+ validateObject(options, 'options', longName)
716
587
 
717
- return this
718
- }
719
-
720
- regressor(trainingSize = 200, options = {})
721
- {
722
- isAlreadyComputed(this)
588
+ const {minMaxRange = null, lag = false, colKeys = [], weights = {}, euclideanWeights = false, byFeatureRange = null} = options
723
589
 
724
- const methodName = 'regressor'
590
+ validateArray(colKeys, 'options.colKeys', longName)
591
+ validateBoolean(lag, 'options.lag', longName)
592
+
725
593
 
594
+ validateObject(weights, 'options.weights', longName)
726
595
 
727
- validateNumber(trainingSize, {max: this.len, allowDecimals: false}, 'trainingSize', methodName)
728
- validateObject(options, 'options', methodName)
596
+ const lookback = lag ? size - 1 : 0
729
597
 
730
- const {
731
- retrain = false,
732
- target = 'close',
733
- predictions = 1,
734
- trainingCols = [],
735
- type = 'SimpleLinearRegression',
736
- lookback = 0,
737
- findGroups = [],
738
- modelArgs = undefined,
739
- filterCallback = () => true
740
- } = options
741
-
742
- validateArrayOptions(Object.keys(validRegressors), type, 'type', methodName)
743
-
744
- if (!this.ML.classes.hasOwnProperty(type)) {
745
- throw new Error(
746
- `"${type}" isn’t available because its library wasn’t imported into OHLCV_INDICATORS.ML.`
747
- )
598
+ if(colKeys.length === 0) {
599
+ throw new Error(`The property "options.colKeys" must be an array with target keys in ${longName}.`)
748
600
  }
749
-
750
- //regressor
751
- validateBoolean(retrain, 'options.retrain', methodName)
752
- validateString(target, 'options.target', methodName)
753
- validateNumber(predictions, {min: 1, allowDecimals: false}, 'predictions', methodName)
754
- validateNumber(lookback, {max: 0, allowDecimals: false}, 'lookback', methodName)
755
- validateArray(trainingCols, 'options.trainingCols', methodName)
756
601
 
757
- const {shortName, flatX, flatY} = validRegressors[type]
758
- const prefix = `reg_${shortName}_${trainingSize}_${target}_prediction`
759
- const orderArr = [...trainingCols]
760
602
 
761
- if(validateArray(findGroups, 'options.findGroups', 'scaler') && findGroups.length > 0)
762
- {
763
- for (const { type = '', size, groupName = '' } of findGroups) {
764
603
 
765
- if (!type || (!size && !groupName) || (size && groupName)) {
766
- throw new Error(`If "options.findGroups" array is set, each item must be an object that includes the "type" (mandatory) and either "size" or "groupName" (choose 1) used to locate previously scaled (minmax or zscore) groups.`);
767
- }
604
+ for(const [key, arr] of Object.entries(weights)) {
605
+ validateArray(arr, `options.weights.${key}`)
768
606
 
769
- orderArr.push(type.toString(), groupName.toString());
607
+ if(!lag && arr.size > 0) {
608
+ throw new Error(`If "options.lag" is set to false "options.weights.${key}" can only contain 1 item (float) in ${longName}.`)
770
609
  }
771
610
 
772
- } else {
773
- if(trainingCols.length === 0 && flatX === false)
774
- {
775
- throw new Error(`"trainingCols" array is empty in ${methodName} ${type}`)
611
+ if(arr.length > size) {
612
+ throw new Error(`The length of the property "options.weights.${key}" can not be longer than "size" in ${longName}.`)
776
613
  }
777
- }
778
614
 
779
- if(flatX) {
780
- if(trainingCols.length > 0)
781
- {
782
- throw new Error(`If regressor type is ${type} then leave "options.trainingCols" array empty.`)
783
- }
784
- if(lookback > 0)
785
- {
786
- throw new Error(`If regressor type is ${type} then "options.lookback" must be 0.`)
615
+ for(let x = 0; x < arr.length; x++) {
616
+ const val = arr[x]
617
+ validateNumber(val, {min: 0.01, max: 10, allowDecimals: true}, `options.weights.${key}[${x}]`, longName)
787
618
  }
788
- if(findGroups.length > 0)
789
- {
790
- throw new Error(`If regressor type is ${type} then "options.findGroups" must be null.`)
791
- }
792
- else {
793
- trainingCols.push(target)
794
- }
795
- }
796
-
797
- if(this.isAlreadyComputed.has(prefix))
798
- {
799
- throw new Error(
800
- `Each regressor must have a unique "type", "trainingSize" and "target".\n` +
801
- `This rule ensures that your output columns are labeled unambiguously.\n` +
802
- `You provided a duplicate: type="${type}", trainingSize=${trainingSize} target=${target}.`
803
- );
804
- }
805
-
806
- const precompute = {
807
- lookbackAbs: Math.abs(lookback) + 1,
808
- flatX,
809
- flatY,
810
- prefix
811
- }
812
-
813
- this.isAlreadyComputed.add(prefix)
814
-
815
-
816
- const order = getOrderFromArray(orderArr, methodName)
817
-
818
- const modelConfig = validRegressors[type]
819
- const modelClass = this.ML.classes[type]
820
619
 
821
- this.inputParams.push({key: methodName, order, params: [trainingSize, {target, predictions, retrain, lookback, trainingCols, findGroups, type, modelArgs, precompute, filterCallback, modelConfig, modelClass}]})
822
-
823
- return this
824
- }
825
-
826
- pca(suffix, trainingSize, options = {})
827
- {
828
- const methodName = 'pca'
829
- validateNumber(trainingSize, {min: 1, max: this.len}, 'trainingSize', methodName)
830
- validateString(suffix, 'suffix', methodName)
831
- validateObject(options, 'options', methodName)
832
-
833
- const {
834
- findGroups = [],
835
- trainingCols = [],
836
- lookback = 0,
837
- filterCallback = () => true
838
- } = options
839
-
840
-
841
- validateArray(trainingCols, 'options.trainigCols', methodName)
842
- validateNumber(lookback, {min: 0, max: this.len, allowDecimals: false}, 'options.lookback', methodName)
843
- if(typeof options.modelArgs !== 'undefined') {
844
- validateObject(options.modelArgs, 'options.modelArgs', methodName)
845
- } else {
846
- options.modelArgs = {}
847
- }
848
-
849
- //modelArgs
850
-
851
- const modelArgs = {
852
- showSource: false,
853
- storeModel: false,
854
- isCovarianceMatrix: false,
855
- method: 'NIPALS', //SVD, covarianceMatrix or NIPALS
856
- center: true,
857
- scale: false,
858
- nCompNIPALS: 5,
859
- ignoreZeroVariance: false,
860
- ...options.modelArgs
861
620
  }
862
621
 
863
- validateBoolean(modelArgs.showSource, 'options.modelArgs.showSource', methodName)
864
- validateBoolean(modelArgs.storeModel, 'options.modelArgs.storeModel', methodName)
865
- validateBoolean(modelArgs.isCovarianceMatrix, 'options.modelArgs.isCovarianceMatrix', methodName)
866
- validateBoolean(modelArgs.center, 'options.modelArgs.center', methodName)
867
- validateBoolean(modelArgs.scale, 'options.modelArgs.scale', methodName)
868
- validateBoolean(modelArgs.ignoreZeroVariance, 'options.modelArgs.ignoreZeroVariance', methodName)
869
- validateArrayOptions(['SVD', 'NIPALS', 'covarianceMatrix'], modelArgs.method, 'options.modelArgs.method', methodName)
870
- validateNumber(modelArgs.nCompNIPALS, {min: 1}, 'options.modelArgs.nCompNIPALS', methodName)
871
-
622
+ if (type !== 'byfeature') {
872
623
 
873
-
874
-
875
- const orderArr = []
876
-
877
- if(validateArray(findGroups, 'options.findGroups', 'pca') && findGroups.length > 0)
878
- {
879
-
880
- for (const { type = '', size, groupName = '' } of findGroups) {
881
-
882
- if (!type || (!size && !groupName) || (size && groupName)) {
883
- throw new Error(`If "options.findGroups" array is set, each item must be an object that includes the "type" (mandatory) and either "size" or "groupName" (choose 1) used to locate previously scaled (minmax or zscore) groups.`);
884
- }
885
-
886
- orderArr.push(type.toString(), groupName.toString())
624
+ if(!byFeatureRange == null) {
625
+ throw new Error('"options.byFeatureRange" is only valid when "type" is "byfeature".')
887
626
  }
888
627
  }
889
-
890
- const order = getOrderFromArray(orderArr, methodName)
891
- const prefix = `pca_${suffix}_${trainingSize}`
892
-
893
- if(this.isAlreadyComputed.has(prefix)) {
894
- throw new Error(
895
- `Each regressor must have a unique "suffix" param.\n` +
896
- `This rule ensures that your output columns are labeled unambiguously.\n` +
897
- `You provided a duplicate: type="${suffix}".`
898
- )
628
+ else {
629
+ validateArrayOfRanges(byFeatureRange, 'options.byFeatureRange', longName)
630
+ }
631
+
632
+ if(['minmax', 'byfeature']) {
633
+ validateArrayOfRanges(minMaxRange, 'options.minMaxRange', longName)
899
634
  }
900
635
 
901
- const lookbackAbs = Math.abs(lookback) + 1
902
- this.isAlreadyComputed.add(prefix)
903
-
904
- this.inputParams.push({key: methodName, order, params: [{prefix, trainingSize, findGroups, trainingCols, lookbackAbs, modelArgs, filterCallback}]})
905
-
636
+ this.inputParams.push({key: methodName, params: [size, colKeys, {type, minMaxRange, lookback, weights, euclideanWeights, byFeatureRange}]})
906
637
  return this
907
638
  }
908
639
 
909
- exportTrainedModels()
910
- {
911
- return exportTrainedModels(this)
912
- }
913
-
914
640
  mapCols(newCols = ['change'], callback = null, options = {}) {
915
641
 
916
642
  isAlreadyComputed(this)
@@ -934,9 +660,7 @@ export default class OHLCV_INDICATORS {
934
660
  throw new Error(`Invalid param: If "mapCols.options.isPriceBased" is true, the "constructor.precision" param must be also true.`)
935
661
  }
936
662
 
937
- const order = getOrderFromArray(newCols, methodName)
938
-
939
- this.inputParams.push({key: methodName, order, params: [newCols, callback, {lag, isPriceBased}]})
663
+ this.inputParams.push({key: methodName, params: [newCols, callback, {lag, isPriceBased}]})
940
664
 
941
665
  return this
942
666
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ohlcv-indicators",
3
- "version": "3.5.56",
3
+ "version": "3.5.60",
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",
@@ -12,25 +12,14 @@
12
12
  "author": "https://jaimelias.com/",
13
13
  "license": "ISC",
14
14
  "dependencies": {
15
- "trading-signals": "^5.0.4",
16
- "xy-scale": "^1.4.1"
15
+ "trading-signals": "^5.0.4"
17
16
  },
18
17
  "devDependencies": {
19
18
  "@babel/core": "^7.25.2",
20
19
  "@babel/plugin-proposal-class-properties": "^7.18.6",
21
20
  "@babel/preset-env": "^7.25.3",
22
- "arima": "^0.2.5",
23
21
  "babel-loader": "^9.1.3",
24
22
  "dotenv": "^16.4.5",
25
- "merge-multi-timeframe": "^1.1.6",
26
- "ml-cart": "^2.1.1",
27
- "ml-fnn": "^5.0.0",
28
- "ml-knn": "^3.0.0",
29
- "ml-naivebayes": "^4.0.0",
30
- "ml-pca": "^4.1.1",
31
- "ml-random-forest": "^2.1.0",
32
- "ml-regression-multivariate-linear": "^2.0.4",
33
- "ml-regression-simple-linear": "^3.0.1",
34
23
  "terser-webpack-plugin": "^5.3.14",
35
24
  "webpack": "^5.93.0",
36
25
  "webpack-cli": "^5.1.4"
@@ -21,13 +21,12 @@ import { mapCols } from "../studies/mapCols.js";
21
21
  import { buildArray } from "../utilities/assignTypes.js";
22
22
  import { inputNumberFormatter } from "../utilities/numberUtilities.js";
23
23
  import { dateFormaters } from "../utilities/dateUtilities.js";
24
+ import { priceFeatures } from "../studies/priceFeatures.js";
24
25
 
25
- import { pca } from "../machine-learning/pca.js";
26
- import { regressor } from "../machine-learning/regressor.js";
27
- import { classifier } from "../machine-learning/classifier.js";
28
26
 
29
27
  // Map indicator keys to their respective functions
30
28
  const mainFunctions = {
29
+ priceFeatures,
31
30
  dateTime,
32
31
  heikenAshi,
33
32
  rsi,
@@ -49,17 +48,18 @@ const mainFunctions = {
49
48
  };
50
49
 
51
50
  export const mainLoop = (input, main) => {
52
- const { len,
53
- inputParams,
51
+ const {
52
+ len,
54
53
  arrayTypes,
55
54
  verticalOhlcv,
56
55
  verticalOhlcvKeyNames,
57
56
  inputTypes,
58
57
  chunkProcess,
59
- processSecondaryLoop,
60
- precisionMultiplier
58
+ precisionMultiplier,
59
+ inputParams
61
60
  } = main;
62
61
 
62
+
63
63
  validateInputParams(inputParams, len)
64
64
 
65
65
  for(const key of Object.keys(inputTypes))
@@ -96,15 +96,10 @@ export const mainLoop = (input, main) => {
96
96
  }
97
97
  }
98
98
 
99
- // Process these indicators separately (ensuring their execution order)
100
- for (const { key, params, order } of inputParams)
99
+ // Process these indicators separately (ensuring their execution in the order of initialization)
100
+ for (const { key, params} of inputParams)
101
101
  {
102
- for(let orderIdx = 0; orderIdx <= 9; orderIdx++)
103
- {
104
- if(typeof order !== 'number') throw new Error(`order property of ${key} not found: ${params}`)
105
- if(orderIdx !== order) continue
106
- mainFunctions[key](main, index, ...params)
107
- }
102
+ mainFunctions[key](main, index, ...params)
108
103
  }
109
104
 
110
105
  input[index] = null //flusing data
@@ -118,34 +113,7 @@ export const mainLoop = (input, main) => {
118
113
  }
119
114
  }
120
115
 
121
- const isSecondaryLoopNeeded = inputParams.some(({ key }) => key === 'regressor' || key === 'classifier' || key === 'pca')
122
-
123
- if(isSecondaryLoopNeeded || processSecondaryLoop)
124
- {
125
- secondaryLoop(main)
126
- }
127
116
 
128
117
  verticalOhlcvKeyNames.push(...Object.keys(verticalOhlcv))
129
118
 
130
119
  }
131
-
132
- export const secondaryLoop = (main) => {
133
- const {inputParams, len, invalidValueIndex} = main
134
-
135
- const startIndex = invalidValueIndex + 1
136
-
137
- for(let index = startIndex; index < len; index++)
138
- {
139
- for (const { key, params, order } of inputParams)
140
- {
141
- for(let orderIdx = 10; orderIdx <= 20; orderIdx++) {
142
- if(typeof order !== 'number') throw new Error(`order property of ${key} not found: ${params}`)
143
- if(orderIdx !== order) continue
144
- if(key === 'pca') pca(main, index, ...params)
145
- if(key === 'classifier') classifier(main, index, ...params)
146
- if(key === 'regressor') regressor(main, index, ...params)
147
- }
148
- }
149
- }
150
-
151
- }