ohlcv-indicators 3.5.0 → 3.5.2
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/dist/ohlcv-indicators.min.js +1 -4225
- package/index.js +11 -5
- package/package.json +4 -2
- package/src/core-functions/mainLoop.js +6 -2
- package/src/machine-learning/pca.js +69 -0
- package/src/{studies → machine-learning}/scaler.js +7 -1
- package/src/volatility/atr.js +34 -14
- package/webpack.config.js +3 -3
package/index.js
CHANGED
|
@@ -67,6 +67,7 @@ export default class OHLCV_INDICATORS {
|
|
|
67
67
|
this.precision = precision
|
|
68
68
|
this.precisionMultiplier = calcPrecisionMultiplier(this, this.firstRow)
|
|
69
69
|
this.scaledGroups = {}
|
|
70
|
+
this.scaledLabels = new Set()
|
|
70
71
|
|
|
71
72
|
this.pushToMain = ({index, key, value}) => pushToMain({main: this, index, key, value})
|
|
72
73
|
|
|
@@ -268,12 +269,15 @@ export default class OHLCV_INDICATORS {
|
|
|
268
269
|
validateNumber(size, {min: 1, max: this.len, allowDecimals: false}, 'size', methodName)
|
|
269
270
|
validateObject(options, 'options', methodName)
|
|
270
271
|
|
|
271
|
-
const {lag = 0,
|
|
272
|
+
const {lag = 0, percentage = false, upper = null, lower = null} = options
|
|
272
273
|
|
|
273
274
|
validateNumber(lag, {min: 0, max: this.len, allowDecimals: false}, 'options.lag', methodName)
|
|
274
|
-
|
|
275
|
+
validateBoolean(percentage, 'options.percentage', 'atr')
|
|
275
276
|
|
|
276
|
-
|
|
277
|
+
if(upper !== null) validateNumber(upper, {min: 0.001, max: 100, allowDecimals: true}, 'options.upper', 'atr')
|
|
278
|
+
if(lower !== null) validateNumber(lower, {min: 0.001, max: 100, allowDecimals: true}, 'options.lower', 'atr')
|
|
279
|
+
|
|
280
|
+
this.inputParams.push({key: methodName, params: [size, {lag, percentage, upper, lower}]})
|
|
277
281
|
|
|
278
282
|
return this
|
|
279
283
|
}
|
|
@@ -453,9 +457,11 @@ export default class OHLCV_INDICATORS {
|
|
|
453
457
|
validateNumber(size, {min: 1, max: this.len, allowDecimals: false}, 'size', methodName)
|
|
454
458
|
validateArray(colKeys, 'colKeys', methodName)
|
|
455
459
|
|
|
456
|
-
const {group = false, range = [0, 1], lag = 0, type = '
|
|
460
|
+
const {group = false, range = [0, 1], lag = 0, type = 'zscore', decimals = null, pca = false, pcaSource = false} = options
|
|
457
461
|
|
|
458
462
|
validateBoolean(group, 'options.group', methodName)
|
|
463
|
+
validateBoolean(pca, 'options.pca', methodName)
|
|
464
|
+
validateBoolean(pcaSource, 'options.pcaSource', methodName)
|
|
459
465
|
validateArrayOfRanges(range, 'options.range', methodName)
|
|
460
466
|
validateArrayOptions(['minmax', 'zscore'], type, 'options.type', methodName)
|
|
461
467
|
|
|
@@ -465,7 +471,7 @@ export default class OHLCV_INDICATORS {
|
|
|
465
471
|
const groupKeyLen = colKeys.length
|
|
466
472
|
const precomputed = {groupKey, groupKeyLen}
|
|
467
473
|
|
|
468
|
-
this.inputParams.push({key: methodName, params: [size, colKeys, {type, group, range, lag, precomputed, decimals}]})
|
|
474
|
+
this.inputParams.push({key: methodName, params: [size, colKeys, {type, group, range, lag, precomputed, decimals, pca, pcaSource}]})
|
|
469
475
|
return this
|
|
470
476
|
}
|
|
471
477
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ohlcv-indicators",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.2",
|
|
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,7 +12,9 @@
|
|
|
12
12
|
"author": "https://jaimelias.com/",
|
|
13
13
|
"license": "ISC",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"
|
|
15
|
+
"ml-pca": "^4.1.1",
|
|
16
|
+
"trading-signals": "^5.0.4",
|
|
17
|
+
"xy-scale": "^1.4.1"
|
|
16
18
|
},
|
|
17
19
|
"devDependencies": {
|
|
18
20
|
"@babel/core": "^7.25.2",
|
|
@@ -9,13 +9,15 @@ import { volumeOscillator } from "../oscillators/volumeOscillator.js";
|
|
|
9
9
|
import { lag } from "../studies/lag.js";
|
|
10
10
|
import { crossPairs } from "../studies/findCrosses.js";
|
|
11
11
|
import { dateTime } from "../studies/dateTime.js";
|
|
12
|
-
import { scaler } from "../
|
|
12
|
+
import { scaler } from "../machine-learning/scaler.js";
|
|
13
13
|
import { atr } from "../volatility/atr.js";
|
|
14
14
|
|
|
15
15
|
import { buildArray } from "../utilities/assignTypes.js";
|
|
16
16
|
import { numberFormater } from "../utilities/numberUtilities.js";
|
|
17
17
|
import { dateFormaters } from "../utilities/dateUtilities.js";
|
|
18
18
|
|
|
19
|
+
import { pca } from "../machine-learning/pca.js";
|
|
20
|
+
|
|
19
21
|
// Map indicator keys to their respective functions
|
|
20
22
|
const indicatorFunctions = {
|
|
21
23
|
dateTime,
|
|
@@ -33,7 +35,7 @@ const indicatorFunctions = {
|
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
export const mainLoop = (input, main) => {
|
|
36
|
-
const { len, inputParams, priceBased, precisionMultiplier, arrayTypes, verticalOhlcv, verticalOhlcvKeyNames, inputTypes, chunkProcess } = main;
|
|
38
|
+
const { len, inputParams, priceBased, precisionMultiplier, arrayTypes, verticalOhlcv, verticalOhlcvKeyNames, inputTypes, chunkProcess, scaledGroups } = main;
|
|
37
39
|
|
|
38
40
|
validateInputParams(inputParams, len)
|
|
39
41
|
|
|
@@ -89,5 +91,7 @@ export const mainLoop = (input, main) => {
|
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
pca(main)
|
|
95
|
+
|
|
92
96
|
verticalOhlcvKeyNames.push(...Object.keys(verticalOhlcv))
|
|
93
97
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { PCA } from "ml-pca";
|
|
2
|
+
|
|
3
|
+
export const pca = main => {
|
|
4
|
+
|
|
5
|
+
const {inputParams, invalidValueIndex, len, verticalOhlcv} = main
|
|
6
|
+
const startIndex = invalidValueIndex + 1
|
|
7
|
+
|
|
8
|
+
for(const rowParams of inputParams)
|
|
9
|
+
{
|
|
10
|
+
const {key: indicatorName, params} = rowParams
|
|
11
|
+
|
|
12
|
+
if(indicatorName !== 'scaler') continue
|
|
13
|
+
|
|
14
|
+
const [size, keyNames, options] = params
|
|
15
|
+
|
|
16
|
+
const {type, group, lag, pca: pcaBoolean, pcaSource} = options
|
|
17
|
+
|
|
18
|
+
if(!group || !pcaBoolean) continue
|
|
19
|
+
|
|
20
|
+
const scaledKeyNames = keyNames.map(v => `${type}_${size}_${v}`)
|
|
21
|
+
const laggedKeys = []
|
|
22
|
+
|
|
23
|
+
for (const k of scaledKeyNames) {
|
|
24
|
+
for (let step = 1; step <= lag; step++) {
|
|
25
|
+
laggedKeys.push(`${k}_lag_${step}`)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
scaledKeyNames.push(...laggedKeys)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
const diffLen = len - startIndex
|
|
33
|
+
const numCols = scaledKeyNames.length
|
|
34
|
+
const tempArr = new Array(diffLen)
|
|
35
|
+
|
|
36
|
+
for (let i = startIndex; i < len; i++) {
|
|
37
|
+
|
|
38
|
+
const row = new Float64Array(numCols);
|
|
39
|
+
|
|
40
|
+
let j = 0
|
|
41
|
+
|
|
42
|
+
for (const key of scaledKeyNames) {
|
|
43
|
+
row[j++] = verticalOhlcv[key][i]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
tempArr[i - startIndex] = row
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if(!pcaSource)
|
|
50
|
+
{
|
|
51
|
+
for (const key of scaledKeyNames) {
|
|
52
|
+
delete verticalOhlcv[key]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const pca = new PCA(tempArr)
|
|
57
|
+
const predictions = [...pca.predict(tempArr)]
|
|
58
|
+
|
|
59
|
+
const verticalKey = `pca_${type}_${size}`
|
|
60
|
+
verticalOhlcv[verticalKey] = new Array(len).fill(null)
|
|
61
|
+
|
|
62
|
+
for(let x = 0; x < predictions.length; x++)
|
|
63
|
+
{
|
|
64
|
+
verticalOhlcv[verticalKey][x + startIndex + 1] = predictions[x]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
@@ -19,7 +19,13 @@ export const scaler = (main, index, size, colKeys, {type, group, range, lag, pre
|
|
|
19
19
|
const prefix = `${type}_${size}`;
|
|
20
20
|
|
|
21
21
|
if (index === 0) {
|
|
22
|
-
const { len } = main;
|
|
22
|
+
const { len, scaledLabels } = main;
|
|
23
|
+
|
|
24
|
+
if(scaledLabels.has(prefix))
|
|
25
|
+
{
|
|
26
|
+
throw new Error(`Method "scaler" cannot have both "size" and "options.type" parameters specified together.`)
|
|
27
|
+
}
|
|
28
|
+
scaledLabels.add(prefix)
|
|
23
29
|
|
|
24
30
|
if(!instances.hasOwnProperty('scaler'))
|
|
25
31
|
{
|
package/src/volatility/atr.js
CHANGED
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
|
|
2
2
|
import {FasterATR, FasterWSMA} from 'trading-signals';
|
|
3
3
|
|
|
4
|
-
export const atr = (main, index, size, {lag,
|
|
4
|
+
export const atr = (main, index, size, {lag, percentage, upper, lower}) => {
|
|
5
5
|
const { verticalOhlcv, instances } = main
|
|
6
|
-
const
|
|
6
|
+
const baseKeyName = `atr_${size}`
|
|
7
7
|
|
|
8
8
|
if (index === 0) {
|
|
9
9
|
|
|
10
10
|
const {instances, verticalOhlcv, arrayTypes, len, priceBased} = main
|
|
11
11
|
|
|
12
|
-
instances[
|
|
12
|
+
instances[baseKeyName] = new FasterATR(size, FasterWSMA)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const keyNames = [baseKeyName]
|
|
15
|
+
|
|
16
|
+
if(percentage) keyNames.push(`${baseKeyName}_percentage`)
|
|
17
|
+
if(upper !== null) keyNames.push(`${baseKeyName}_upper`)
|
|
18
|
+
if(lower !== null) keyNames.push(`${baseKeyName}_lower`)
|
|
19
|
+
|
|
20
|
+
for(const k of keyNames)
|
|
15
21
|
{
|
|
16
|
-
|
|
22
|
+
if(!k.endsWith('_percentage'))
|
|
23
|
+
{
|
|
24
|
+
priceBased.add(k)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
verticalOhlcv[k] = new Float64Array(len).fill(NaN)
|
|
28
|
+
arrayTypes[k] = 'Float64Array'
|
|
17
29
|
}
|
|
18
|
-
|
|
19
|
-
verticalOhlcv[keyName] = new Float64Array(len).fill(NaN)
|
|
20
|
-
arrayTypes[keyName] = 'Float64Array'
|
|
21
|
-
|
|
30
|
+
|
|
22
31
|
if(lag > 0)
|
|
23
32
|
{
|
|
24
|
-
main.lag(
|
|
33
|
+
main.lag(keyNames, lag)
|
|
25
34
|
}
|
|
26
35
|
}
|
|
27
36
|
|
|
@@ -31,7 +40,7 @@ export const atr = (main, index, size, {lag, type}) => {
|
|
|
31
40
|
low: verticalOhlcv.low[index],
|
|
32
41
|
close: verticalOhlcv.close[index],
|
|
33
42
|
}
|
|
34
|
-
const instance = instances[
|
|
43
|
+
const instance = instances[baseKeyName]
|
|
35
44
|
|
|
36
45
|
// Update the moving average instance.
|
|
37
46
|
instance.update(curr);
|
|
@@ -42,13 +51,24 @@ export const atr = (main, index, size, {lag, type}) => {
|
|
|
42
51
|
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
if(
|
|
54
|
+
if(percentage)
|
|
55
|
+
{
|
|
56
|
+
const percentageValue = (Number.isNaN(currAtr)) ? NaN : (currAtr / curr.close)
|
|
57
|
+
main.pushToMain({ index, key: `${baseKeyName}_percentage`, value: percentageValue });
|
|
58
|
+
}
|
|
59
|
+
if(upper !== null)
|
|
60
|
+
{
|
|
61
|
+
const upperValue = (Number.isNaN(currAtr)) ? NaN : (curr.close + (currAtr * upper))
|
|
62
|
+
main.pushToMain({ index, key: `${baseKeyName}_upper`, value: upperValue });
|
|
63
|
+
}
|
|
64
|
+
if(lower !== null)
|
|
46
65
|
{
|
|
47
|
-
|
|
66
|
+
const lowerValue = (Number.isNaN(currAtr)) ? NaN : (curr.close - (currAtr * lower))
|
|
67
|
+
main.pushToMain({ index, key: `${baseKeyName}_lower`, value: lowerValue });
|
|
48
68
|
}
|
|
49
69
|
|
|
50
70
|
// Always push the MA value (even if NaN).
|
|
51
|
-
main.pushToMain({ index, key:
|
|
71
|
+
main.pushToMain({ index, key: baseKeyName, value: currAtr });
|
|
52
72
|
|
|
53
73
|
return true;
|
|
54
74
|
}
|
package/webpack.config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolve, dirname } from 'path';
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
|
-
import TerserPlugin from 'terser-webpack-plugin';
|
|
3
|
+
//import TerserPlugin from 'terser-webpack-plugin';
|
|
4
4
|
|
|
5
5
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ export default {
|
|
|
16
16
|
output,
|
|
17
17
|
mode: 'production',
|
|
18
18
|
target: 'web',
|
|
19
|
-
|
|
19
|
+
/* optimization: { //TerserPlugin start
|
|
20
20
|
minimize: true,
|
|
21
21
|
minimizer: [
|
|
22
22
|
new TerserPlugin({
|
|
@@ -28,7 +28,7 @@ export default {
|
|
|
28
28
|
},
|
|
29
29
|
}),
|
|
30
30
|
],
|
|
31
|
-
}, // TerserPlugin end
|
|
31
|
+
}, // TerserPlugin end */
|
|
32
32
|
module: {
|
|
33
33
|
rules: [
|
|
34
34
|
{
|