ohlcv-indicators 3.5.56 → 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.
@@ -1,227 +0,0 @@
1
- import { getFeaturedKeys, computeFlatFeaturesLen, logMlTraining, findGroupsFunc } from './ml-utilities.js'
2
- import { buildTrainX } from './trainX.js'
3
- import { areKeyValuesValid } from '../core-functions/pushToMain.js'
4
-
5
- const algo = 'regressor'
6
-
7
- export const regressor = (main, index, trainingSize, {target, predictions, retrain, trainingCols, findGroups, type, modelArgs, precompute, filterCallback, modelConfig, modelClass}) => {
8
-
9
- const {lookbackAbs, prefix, flatX, flatY} = precompute
10
- const {verticalOhlcv, len, instances, scaledGroups, invalidValueIndex, ML} = main
11
- const allModels = ML.models
12
- const startIndex = (invalidValueIndex + 1)
13
-
14
- if(index === startIndex)
15
- {
16
- if (!instances.hasOwnProperty(algo)) instances.regressor = {}
17
- if(!instances.regressor.hasOwnProperty(prefix)) instances.regressor[prefix] = {}
18
-
19
- const expectedLoops = (flatY) ? predictions : 1 //
20
-
21
- instances.regressor[prefix] = {
22
- expectedLoops,
23
- trainingSize,
24
- isTrained: new Array(expectedLoops).fill(false),
25
- shouldRetrain: retrain,
26
- featureCols: [],
27
- flatFeaturesColLen: 0,
28
- X: [],
29
- Y: Array.from({ length: expectedLoops }, () => []),
30
- }
31
-
32
- for(let x = 0; x < predictions; x++)
33
- {
34
- const predictionKey = `${prefix}_${(x+1)}`
35
- verticalOhlcv[predictionKey] = new Float64Array(len).fill(NaN)
36
-
37
- if(!allModels.hasOwnProperty(predictionKey))
38
- {
39
- allModels[predictionKey] = []
40
- }
41
- }
42
- }
43
- else if(index < startIndex || index < lookbackAbs)
44
- {
45
- return
46
- }
47
- else if(filterCallback(verticalOhlcv, index) === false)
48
- {
49
- return
50
- }
51
- else if(index + 1 === len)
52
- {
53
- if(instances.regressor[prefix].featureCols.length === 0)
54
- {
55
- const inputFeatures = [...trainingCols, ...(findGroupsFunc(findGroups, scaledGroups))]
56
-
57
- throw new Error(`Some of the provided features in ${prefix} features where not found in "verticalOhlcv": ${JSON.stringify(inputFeatures)}`)
58
- }
59
-
60
- //last execution
61
- for(const featureKey of instances.regressor[prefix].featureCols)
62
- {
63
- if(!verticalOhlcv.hasOwnProperty(featureKey)) throw new Error(`Feature "${featureKey}" not found in verticalOhlcv for ${prefix}.`)
64
- }
65
-
66
- if(instances.regressor[prefix].X.length < trainingSize)
67
- {
68
- const requiredDatapoints = instances.regressor[prefix].X.length - trainingSize
69
- throw new Error(`The current "trainingSize" at "${prefix}" requires at least ${requiredDatapoints} more datapoints. Try adding more input ohlcv rows or reducing the "trainingSize" by ${requiredDatapoints}.`)
70
- }
71
- }
72
-
73
- const dataSetInstance = instances.regressor[prefix]
74
-
75
- if(dataSetInstance.flatFeaturesColLen === 0)
76
- {
77
- dataSetInstance.featureCols = getFeaturedKeys({trainingCols, findGroups, verticalOhlcv, scaledGroups})
78
-
79
- if(areKeyValuesValid(main, index, dataSetInstance.featureCols))
80
- {
81
- dataSetInstance.flatFeaturesColLen = computeFlatFeaturesLen(dataSetInstance.featureCols, verticalOhlcv, index)
82
-
83
- logMlTraining({
84
- featureCols: dataSetInstance.featureCols,
85
- flatFeaturesColLen: dataSetInstance.flatFeaturesColLen,
86
- type,
87
- trainingSize
88
- })
89
-
90
- } else {
91
- return
92
- }
93
- }
94
-
95
- if(dataSetInstance.flatFeaturesColLen === 0) return
96
-
97
- if(!verticalOhlcv.hasOwnProperty(target))
98
- {
99
- throw new Error(`Target property "${target}" not found in verticalOhlcv for regressor.`)
100
- }
101
-
102
- const {
103
- expectedLoops,
104
- X: xRows,
105
- Y,
106
- flatFeaturesColLen,
107
- featureCols,
108
- shouldRetrain
109
- } = dataSetInstance
110
-
111
- if(!featureCols.includes(target))
112
- {
113
- throw new Error(`Target property "${target}" not found in ${type} features: ${JSON.stringify(featureCols)}`)
114
- }
115
-
116
- const trainX = (flatX) ? verticalOhlcv[target][index] : buildTrainX({featureCols, flatFeaturesColLen, type, index, lookbackAbs, main})
117
-
118
- if (flatX) {
119
- if (!Number.isFinite(trainX)) return; // or `trainX == null`
120
- } else {
121
- if (trainX == null) return;
122
- }
123
-
124
- let trainY = []
125
-
126
- for (let i = 0; i < predictions; i++) {
127
- const v = verticalOhlcv[target][index + i + 1]
128
-
129
- if (!Number.isFinite(v)) {
130
- break
131
- }
132
-
133
- trainY.push(v)
134
- }
135
-
136
- const {train, unsupervised} = modelConfig
137
-
138
- //if univariable Y (flatY) a model is created for each prediction
139
- for(let loopIdx = 0; loopIdx < expectedLoops; loopIdx++)
140
- {
141
- const predictionKey = `${prefix}_${(loopIdx+1)}`
142
- const yRows = Y[loopIdx]
143
- const currTrainY = (flatY) ? (typeof trainY[loopIdx] === 'undefined') ? null : trainY[loopIdx] : trainY
144
- const isTrained = dataSetInstance.isTrained[loopIdx]
145
-
146
- const shouldPredict = allModels.hasOwnProperty(predictionKey) && isTrained && allModels[predictionKey].length === expectedLoops
147
-
148
- //predicts using previously saved models even if current currTrainY is not available
149
- if(shouldPredict)
150
- {
151
- const currModel = allModels[predictionKey][0]
152
- const futureRow = (unsupervised) ? currModel.predict(predictions)[0] : currModel.predict([trainX])[0]
153
-
154
- if(flatY)
155
- {
156
- if(Number.isNaN(futureRow)) throw new Error(`Prediction of ${type} at index ${index} was expecting a number.`)
157
-
158
- main.pushToMain({index, key: predictionKey, value: futureRow})
159
- }
160
- else {
161
-
162
- if (!Array.isArray(futureRow) || futureRow.length !== predictions) {
163
- throw new Error(
164
- `Prediction output of "${type}" at index ${index} was expecting an array of values.`
165
- )
166
- }
167
-
168
- for(let preIdx = 0; preIdx < predictions; preIdx++) {
169
- main.pushToMain({index, key: `${prefix}_${(preIdx+1)}`, value: futureRow[preIdx]})
170
- }
171
- }
172
- }
173
-
174
- if((index + predictions + 1) > len) continue
175
- if(trainY.length < predictions) continue
176
- if(currTrainY === null) continue
177
-
178
- if(flatY)
179
- {
180
- if (typeof currTrainY !== 'number' || Number.isNaN(currTrainY))
181
- {
182
- throw new Error(`currTrainY must return number, got ${typeof currTrainY} at index ${index}`)
183
- }
184
- } else {
185
- if (!Array.isArray(currTrainY)) {
186
- throw new Error(`currTrainY must return an array, got ${typeof currTrainY} at index ${index}`)
187
- }
188
-
189
- if ((currTrainY.length !== predictions)) {
190
-
191
- throw new Error(`currTrainY length (${currTrainY.length}) ≠ "options.predictions" (${predictions}) for regressor "${type}"`)
192
- }
193
- }
194
-
195
- // enqueue
196
- yRows.push(currTrainY)
197
- if (yRows.length > trainingSize) yRows.shift()
198
-
199
- if(loopIdx === 0)
200
- {
201
- xRows.push(trainX)
202
- if (xRows.length > trainingSize) xRows.shift()
203
- }
204
-
205
- const shouldTrainModel = shouldRetrain || !isTrained
206
-
207
- if (shouldTrainModel && xRows.length === trainingSize && yRows.length === trainingSize) {
208
-
209
- const trainedModel = train({modelClass, xRows, yRows, modelArgs, uniqueLabels: 0})
210
-
211
- if(unsupervised)
212
- {
213
- allModels[predictionKey] = [trainedModel]
214
- } else {
215
- allModels[predictionKey].push(trainedModel)
216
-
217
- if(allModels[predictionKey].length > predictions)
218
- {
219
- allModels[predictionKey].shift()
220
- }
221
- }
222
-
223
- dataSetInstance.isTrained[loopIdx] = true
224
- }
225
-
226
- }
227
- }
@@ -1,73 +0,0 @@
1
- /**
2
- * Builds a flattened lookback feature vector or returns null if any value is non‐finite.
3
- *
4
- * @param {string[]} featureCols – list of feature column keys
5
- * @param {Object} instances – your instances object (with crossPairs)
6
- * @param {number} flatFeaturesColLen – total number of flattened feature slots
7
- * @param {string} type – a string used only for error reporting
8
- * @param {number} index – current time index
9
- * @param {number} lookbackAbs – number of lags to include
10
- * @param {Object} verticalOhlcv – an object mapping each key to its time series array
11
- * @returns {number[]\|null} – the feature vector or null if exiting early
12
- */
13
- export const buildTrainX = ({
14
- featureCols,
15
- flatFeaturesColLen,
16
- type,
17
- index,
18
- lookbackAbs,
19
- main
20
- }) => {
21
-
22
- const {verticalOhlcv} = main
23
-
24
- let shouldExit = false
25
-
26
- // --- BUILD A FLATTENED LIST OF “COLUMN SLOTS” ---
27
- const slots = [];
28
- for (const key of featureCols) {
29
- if (key.startsWith('one_hot_') || key.startsWith('pca_')) {
30
-
31
- const colSize = verticalOhlcv[key][index].length
32
-
33
- for (let bit = 0; bit < colSize; bit++) {
34
- slots.push({ key, bit });
35
- }
36
- } else {
37
- slots.push({ key });
38
- }
39
- }
40
-
41
- if (slots.length !== flatFeaturesColLen) {
42
- throw new Error(
43
- `slots (${slots.length}) ≠ flatFeaturesColLen (${flatFeaturesColLen}) in ${type} index ${index}`
44
- );
45
- }
46
-
47
- // --- ALLOCATE AND FILL trainX ---
48
- const trainX = new Array(flatFeaturesColLen * lookbackAbs).fill(NaN);
49
-
50
- for (let lag = 0; lag < lookbackAbs; lag++) {
51
- const tIdx = index - lag;
52
-
53
- for (let s = 0; s < slots.length; s++) {
54
- const { key, bit } = slots[s];
55
- const cell = verticalOhlcv[key][tIdx];
56
- const value = (bit != null) ? cell[bit] : cell;
57
-
58
- if (!Number.isFinite(value)) {
59
- shouldExit = true;
60
- break;
61
- }
62
- trainX[lag * flatFeaturesColLen + s] = value;
63
- }
64
-
65
- if (shouldExit) break;
66
- }
67
-
68
- if (shouldExit) {
69
- return null;
70
- }
71
-
72
- return trainX;
73
- };
@@ -1,51 +0,0 @@
1
-
2
- import { validateArray, validateString } from "./validators.js"
3
-
4
- export const getOrderFromArray = (arr, methodName) => {
5
-
6
- validateArray(arr, 'arr', 'getOrderFromArray')
7
- validateString(methodName, 'methodName', 'getOrderFromArray')
8
-
9
- const level2Methods = ['regressor', 'classifier', 'pca']
10
- const baseKeys = ['open', 'high', 'low', 'close', 'volume', 'date']
11
-
12
- // 1. Level-2: does this method live in your level-2 list?
13
- const isSecondary = level2Methods.includes(methodName);
14
-
15
- // 2. Level-0: is every field one of the primitives *and* not level-2?
16
- const isPrimary = arr.every(v => baseKeys.includes(v)) && !isSecondary;
17
-
18
- if(isPrimary)
19
- {
20
- return 0
21
- }
22
-
23
- let order = 1
24
- const level1Prefixes = ['_x_', 'zscore_', 'minmax_', 'lag_']
25
-
26
- for(const k of level1Prefixes)
27
- {
28
- if(arr.some(v => v.includes(k)))
29
- {
30
- order++
31
- }
32
- }
33
-
34
- if(!isSecondary)
35
- {
36
- return order
37
- }
38
-
39
- const level2Prefixes = ['prediction_', 'reg_', 'cla_', 'pca_']
40
- order = 10
41
-
42
- for(const k of level2Prefixes)
43
- {
44
- if(arr.some(v => v.includes(k)))
45
- {
46
- order++
47
- }
48
- }
49
-
50
- return order
51
- }