ohlcv-indicators 3.5.2 → 3.5.3
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 +4 -4
- package/package.json +1 -1
- package/src/machine-learning/pca.js +43 -8
- package/src/utilities/validators.js +48 -29
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 =
|
|
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
|
-
|
|
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
|
|
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.
|
|
3
|
+
"version": "3.5.3",
|
|
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:
|
|
17
|
-
|
|
18
|
-
|
|
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 = []
|
|
@@ -46,22 +67,36 @@ export const pca = main => {
|
|
|
46
67
|
tempArr[i - startIndex] = row
|
|
47
68
|
}
|
|
48
69
|
|
|
49
|
-
if(!
|
|
70
|
+
if(!showSource)
|
|
50
71
|
{
|
|
51
72
|
for (const key of scaledKeyNames) {
|
|
52
73
|
delete verticalOhlcv[key]
|
|
53
74
|
}
|
|
54
75
|
}
|
|
55
76
|
|
|
56
|
-
const pca = new PCA(tempArr)
|
|
57
|
-
const predictions = [...pca.predict(tempArr)]
|
|
58
|
-
|
|
59
77
|
const verticalKey = `pca_${type}_${size}`
|
|
78
|
+
|
|
79
|
+
const pca = new PCA(tempArr, {
|
|
80
|
+
isCovarianceMatrix,
|
|
81
|
+
method,
|
|
82
|
+
center,
|
|
83
|
+
scale,
|
|
84
|
+
nCompNIPALS,
|
|
85
|
+
ignoreZeroVariance
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if(storeModel)
|
|
89
|
+
{
|
|
90
|
+
main.models[verticalKey] = pca.toJSON()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const predictions = pca.predict(tempArr).to2DArray()
|
|
94
|
+
|
|
60
95
|
verticalOhlcv[verticalKey] = new Array(len).fill(null)
|
|
61
96
|
|
|
62
97
|
for(let x = 0; x < predictions.length; x++)
|
|
63
98
|
{
|
|
64
|
-
verticalOhlcv[verticalKey][x + startIndex
|
|
99
|
+
verticalOhlcv[verticalKey][x + startIndex] = predictions[x]
|
|
65
100
|
}
|
|
66
101
|
|
|
67
102
|
}
|
|
@@ -31,7 +31,7 @@ export const validateArray = (arr, paramName, callerName) => {
|
|
|
31
31
|
|
|
32
32
|
export const validateObject = (obj, paramName, callerName) => {
|
|
33
33
|
|
|
34
|
-
if(
|
|
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
|
|