ohlcv-indicators 3.5.2 → 3.5.4

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
@@ -68,6 +68,7 @@ export default class OHLCV_INDICATORS {
68
68
  this.precisionMultiplier = calcPrecisionMultiplier(this, this.firstRow)
69
69
  this.scaledGroups = {}
70
70
  this.scaledLabels = new Set()
71
+ this.models = {}
71
72
 
72
73
  this.pushToMain = ({index, key, value}) => pushToMain({main: this, index, key, value})
73
74
 
@@ -457,11 +458,10 @@ export default class OHLCV_INDICATORS {
457
458
  validateNumber(size, {min: 1, max: this.len, allowDecimals: false}, 'size', methodName)
458
459
  validateArray(colKeys, 'colKeys', methodName)
459
460
 
460
- const {group = false, range = [0, 1], lag = 0, type = 'zscore', decimals = null, pca = false, pcaSource = false} = options
461
+ const {group = false, range = [0, 1], lag = 0, type = 'zscore', decimals = null, pca = null} = options
461
462
 
462
463
  validateBoolean(group, 'options.group', methodName)
463
- validateBoolean(pca, 'options.pca', methodName)
464
- validateBoolean(pcaSource, 'options.pcaSource', methodName)
464
+ if(pca !== null) validateObject(pca, 'options.pca', methodName)
465
465
  validateArrayOfRanges(range, 'options.range', methodName)
466
466
  validateArrayOptions(['minmax', 'zscore'], type, 'options.type', methodName)
467
467
 
@@ -471,7 +471,7 @@ export default class OHLCV_INDICATORS {
471
471
  const groupKeyLen = colKeys.length
472
472
  const precomputed = {groupKey, groupKeyLen}
473
473
 
474
- this.inputParams.push({key: methodName, params: [size, colKeys, {type, group, range, lag, precomputed, decimals, pca, pcaSource}]})
474
+ this.inputParams.push({key: methodName, params: [size, colKeys, {type, group, range, lag, precomputed, decimals, pca}]})
475
475
  return this
476
476
  }
477
477
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ohlcv-indicators",
3
- "version": "3.5.2",
3
+ "version": "3.5.4",
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,4 +1,5 @@
1
1
  import { PCA } from "ml-pca";
2
+ import { validateBoolean, validateArrayOptions, validateNumber } from "../utilities/validators.js";
2
3
 
3
4
  export const pca = main => {
4
5
 
@@ -13,9 +14,29 @@ export const pca = main => {
13
14
 
14
15
  const [size, keyNames, options] = params
15
16
 
16
- const {type, group, lag, pca: pcaBoolean, pcaSource} = options
17
-
18
- if(!group || !pcaBoolean) continue
17
+ const {type, group, lag, pca: pcaOptions} = options
18
+
19
+ const {
20
+ showSource = false,
21
+ storeModel = false,
22
+ isCovarianceMatrix = false,
23
+ method = 'NIPALS', //SVD, covarianceMatrix or NIPALS
24
+ center = true,
25
+ scale = false,
26
+ nCompNIPALS = 2,
27
+ ignoreZeroVariance = false
28
+ } = pcaOptions
29
+
30
+ if(!group || pcaOptions === null) continue
31
+
32
+ validateBoolean(showSource, 'showSource', 'scaler.options.pca.showSource')
33
+ validateBoolean(storeModel, 'storeModel', 'scaler.options.pca.storeModel')
34
+ validateBoolean(isCovarianceMatrix, 'isCovarianceMatrix', 'scaler.options.pca.isCovarianceMatrix')
35
+ validateBoolean(center, 'center', 'scaler.options.pca.center')
36
+ validateBoolean(scale, 'scale', 'scaler.options.pca.scale')
37
+ validateBoolean(ignoreZeroVariance, 'ignoreZeroVariance', 'scaler.options.pca.ignoreZeroVariance')
38
+ validateArrayOptions(['SVD', 'NIPALS', 'covarianceMatrix'], method, 'scaler.options.pca.method')
39
+ validateNumber(nCompNIPALS, {min: 1}, 'nCompNIPALS', 'scaler.options.pca.nCompNIPALS')
19
40
 
20
41
  const scaledKeyNames = keyNames.map(v => `${type}_${size}_${v}`)
21
42
  const laggedKeys = []
@@ -28,7 +49,6 @@ export const pca = main => {
28
49
 
29
50
  scaledKeyNames.push(...laggedKeys)
30
51
 
31
-
32
52
  const diffLen = len - startIndex
33
53
  const numCols = scaledKeyNames.length
34
54
  const tempArr = new Array(diffLen)
@@ -46,22 +66,36 @@ export const pca = main => {
46
66
  tempArr[i - startIndex] = row
47
67
  }
48
68
 
49
- if(!pcaSource)
69
+ if(!showSource)
50
70
  {
51
71
  for (const key of scaledKeyNames) {
52
72
  delete verticalOhlcv[key]
53
73
  }
54
74
  }
55
75
 
56
- const pca = new PCA(tempArr)
57
- const predictions = [...pca.predict(tempArr)]
58
-
59
76
  const verticalKey = `pca_${type}_${size}`
77
+
78
+ const pca = new PCA(tempArr, {
79
+ isCovarianceMatrix,
80
+ method,
81
+ center,
82
+ scale,
83
+ nCompNIPALS,
84
+ ignoreZeroVariance
85
+ })
86
+
87
+ if(storeModel)
88
+ {
89
+ main.models[verticalKey] = pca.toJSON()
90
+ }
91
+
92
+ const predictions = pca.predict(tempArr).to2DArray()
93
+
60
94
  verticalOhlcv[verticalKey] = new Array(len).fill(null)
61
95
 
62
96
  for(let x = 0; x < predictions.length; x++)
63
97
  {
64
- verticalOhlcv[verticalKey][x + startIndex + 1] = predictions[x]
98
+ verticalOhlcv[verticalKey][x + startIndex] = predictions[x]
65
99
  }
66
100
 
67
101
  }
@@ -31,7 +31,7 @@ export const validateArray = (arr, paramName, callerName) => {
31
31
 
32
32
  export const validateObject = (obj, paramName, callerName) => {
33
33
 
34
- if(!Boolean(obj) || !typeof obj == 'object')
34
+ if(obj instanceof Object === false)
35
35
  {
36
36
  throw new Error(`Param "${paramName}" must be an object in "${callerName}".`)
37
37
  }
@@ -62,35 +62,54 @@ export const validateBoolean = (value, paramName, callerName) => {
62
62
  }
63
63
 
64
64
  export const validateNumber = (value, options, paramName, callerName) => {
65
+ validateObject(options, 'options', `${callerName}.${paramName}.validateNumber`);
66
+
67
+ const { allowDecimals = false, min, max } = options;
68
+ const label = allowDecimals ? 'number' : 'integer';
69
+
70
+ // 1) check that value is a number (and integer if decimals not allowed)
71
+ if (typeof value !== 'number' || (allowDecimals === false && !Number.isInteger(value))) {
72
+ throw new Error(
73
+ `Param "${paramName}" must be an ${label} in "${callerName}".`
74
+ );
75
+ }
76
+
77
+ // 2) validate types of min and max if they’re provided
78
+ if (min !== undefined && typeof min !== 'number') {
79
+ throw new Error(
80
+ `Param "min" must be a valid ${label} (if provided) in "${callerName}.${paramName}.validateNumber".`
81
+ );
82
+ }
83
+ if (max !== undefined && typeof max !== 'number') {
84
+ throw new Error(
85
+ `Param "max" must be a valid ${label} (if provided) in "${callerName}.${paramName}.validateNumber".`
86
+ );
87
+ }
88
+
89
+ // 3) if both were provided, ensure min < max
90
+ if (min !== undefined && max !== undefined && min >= max) {
91
+ throw new Error(
92
+ `Param "min" must be less than "max" in "${callerName}.${paramName}.validateNumber".`
93
+ );
94
+ }
95
+
96
+ // 4) check value against min (if set)
97
+ if (min !== undefined && value < min) {
98
+ throw new Error(
99
+ `Param "${paramName}" must be an ${label} ≥ ${min} in "${callerName}".`
100
+ );
101
+ }
102
+
103
+ // 5) check value against max (if set)
104
+ if (max !== undefined && value > max) {
105
+ throw new Error(
106
+ `Param "${paramName}" must be an ${label} ≤ ${max} in "${callerName}".`
107
+ );
108
+ }
109
+
110
+ return true;
111
+ };
65
112
 
66
- validateObject(options, 'options', `${callerName}.${paramName}.validateNumber`)
67
-
68
- const {allowDecimals = false, min, max} = options
69
-
70
- const label = (allowDecimals) ? 'number' : 'integer'
71
-
72
- if(typeof value !== 'number' || (allowDecimals === false && !Number.isInteger(value)))
73
- {
74
- throw new Error(`Param "${paramName}" must be an integer in "${callerName}".`)
75
- }
76
-
77
- if(typeof min !== 'number' || typeof max !== 'number' || min >= max)
78
- {
79
- throw new Error(`Param "min" must be a valid ${label} lower than "max" "${callerName}.${paramName}.validateNumber".`)
80
- }
81
-
82
- if(value < min)
83
- {
84
- throw new Error(`Param "${paramName}" must be an ${label} greater than or equal to ${min} in "${callerName}".`)
85
- }
86
-
87
- if(value > max)
88
- {
89
- throw new Error(`Param "${paramName}" must be an ${label} lower than or equal to ${max} in "${callerName}".`)
90
- }
91
-
92
- return true
93
- }
94
113
 
95
114
  export const validateArrayOfRanges = (range, paramName, callerName) => {
96
115