ohlcv-indicators 3.5.55 → 3.5.59

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,67 @@ 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
-
609
- const groupKey = `${type}_${size}`
610
- const groupKeyLen = colKeys.length
611
- const precomputed = {groupKey, groupKeyLen}
612
568
 
613
- let secondaryLoop = false
614
569
 
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]
689
-
690
- const prefix = `cla_${shortName}_${trainingSize}_prediction`
691
-
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
- }
700
-
701
- const precompute = {
702
- lookbackAbs: Math.abs(lookback) + 1,
703
- flatY,
704
- prefix
705
- }
706
-
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
-
716
-
717
- return this
718
- }
577
+ let methodName = 'scaler'
719
578
 
720
- regressor(trainingSize = 200, options = {})
721
- {
722
579
  isAlreadyComputed(this)
723
580
 
724
- const methodName = 'regressor'
581
+ validateNumber(size, {min: 1, max: this.len, allowDecimals: false}, 'size', methodName)
725
582
 
726
-
727
- validateNumber(trainingSize, {max: this.len, allowDecimals: false}, 'trainingSize', methodName)
728
583
  validateObject(options, 'options', methodName)
729
584
 
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
- )
748
- }
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)
585
+ const {range = [0, 1], lag = false, colKeys = [], weights = {}, euclideanWeights = false} = options
756
586
 
757
- const {shortName, flatX, flatY} = validRegressors[type]
758
- const prefix = `reg_${shortName}_${trainingSize}_${target}_prediction`
759
- const orderArr = [...trainingCols]
587
+ validateArray(colKeys, 'options.colKeys', methodName)
588
+ validateBoolean(lag, 'options.lag', methodName)
589
+ validateArrayOfRanges(range, 'options.range', methodName)
590
+ validateArrayOptions(['minmax', 'zscore'], type, 'options.type', methodName)
591
+ validateObject(weights, 'options.weights', methodName)
760
592
 
761
- if(validateArray(findGroups, 'options.findGroups', 'scaler') && findGroups.length > 0)
762
- {
763
- for (const { type = '', size, groupName = '' } of findGroups) {
593
+ const lookback = lag ? size - 1 : 0
764
594
 
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
- }
768
595
 
769
- orderArr.push(type.toString(), groupName.toString());
770
- }
596
+ for(const [key, arr] of Object.entries(weights)) {
597
+ validateArray(arr, `options.weights.${key}`)
771
598
 
772
- } else {
773
- if(trainingCols.length === 0 && flatX === false)
774
- {
775
- throw new Error(`"trainingCols" array is empty in ${methodName} ${type}`)
599
+ if(!lag && arr.size > 0) {
600
+ throw new Error(`If "options.lag" is set to false "options.weights.${key}" can only contain 1 item (float).`)
776
601
  }
777
- }
778
602
 
779
- if(flatX) {
780
- if(trainingCols.length > 0)
781
- {
782
- throw new Error(`If regressor type is ${type} then leave "options.trainingCols" array empty.`)
603
+ if(arr.length > size) {
604
+ throw new Error(`The length of the property "options.weights.${key}" can not be longer than "size" in ${methodName}.`)
783
605
  }
784
- if(lookback > 0)
785
- {
786
- throw new Error(`If regressor type is ${type} then "options.lookback" must be 0.`)
787
- }
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
606
 
818
- const modelConfig = validRegressors[type]
819
- const modelClass = this.ML.classes[type]
820
-
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
- }
862
-
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
-
872
-
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())
607
+ for(let x = 0; x < arr.length; x++) {
608
+ const val = arr[x]
609
+ validateNumber(val, {min: 0.01, max: 10, allowDecimals: true}, `options.weights.${key}[${x}]`, methodName)
887
610
  }
888
- }
889
611
 
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
- )
899
612
  }
900
613
 
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
-
614
+ this.inputParams.push({key: methodName, params: [size, colKeys, {type, range, lookback, weights, euclideanWeights}]})
906
615
  return this
907
616
  }
908
617
 
909
- exportTrainedModels()
910
- {
911
- return exportTrainedModels(this)
912
- }
913
-
914
618
  mapCols(newCols = ['change'], callback = null, options = {}) {
915
619
 
916
620
  isAlreadyComputed(this)
@@ -934,9 +638,7 @@ export default class OHLCV_INDICATORS {
934
638
  throw new Error(`Invalid param: If "mapCols.options.isPriceBased" is true, the "constructor.precision" param must be also true.`)
935
639
  }
936
640
 
937
- const order = getOrderFromArray(newCols, methodName)
938
-
939
- this.inputParams.push({key: methodName, order, params: [newCols, callback, {lag, isPriceBased}]})
641
+ this.inputParams.push({key: methodName, params: [newCols, callback, {lag, isPriceBased}]})
940
642
 
941
643
  return this
942
644
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ohlcv-indicators",
3
- "version": "3.5.55",
3
+ "version": "3.5.59",
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
- }