ohlcv-indicators 3.2.7 → 3.2.9
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
|
@@ -431,7 +431,7 @@ export default class OHLCV_INDICATORS {
|
|
|
431
431
|
throw new Error('"size" must be a positive number greater than 0 in candleVectors.');
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
const { stdDev = 1, lag = 0, scale = 0.
|
|
434
|
+
const { stdDev = 1, lag = 0, scale = 0.001, patternSize = 0, autoMinMax = false } = options;
|
|
435
435
|
|
|
436
436
|
|
|
437
437
|
if (typeof stdDev !== 'number' || stdDev <= 0) {
|
|
@@ -443,9 +443,9 @@ export default class OHLCV_INDICATORS {
|
|
|
443
443
|
throw new Error(`"scale" value in candleVectors must be any of the following numbers: ${validMagnitudeValues.join(', ')}`);
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
if (typeof patternSize !== 'number' || !Number.isInteger(patternSize) || patternSize <
|
|
446
|
+
if (typeof patternSize !== 'number' || !Number.isInteger(patternSize) || patternSize < 0 ) {
|
|
447
447
|
|
|
448
|
-
throw new Error(`"patternSize" value in candleVectors must be
|
|
448
|
+
throw new Error(`"patternSize" value in candleVectors must be a positive integer.`);
|
|
449
449
|
}
|
|
450
450
|
if (typeof autoMinMax !== 'boolean') {
|
|
451
451
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ohlcv-indicators",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.9",
|
|
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,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import {FasterEMA, FasterSMA, FasterBollingerBands} from 'trading-signals';
|
|
3
|
-
import { classifyBoll } from '../utilities/classification.js'
|
|
3
|
+
import { classifyBoll, calcZScore } from '../utilities/classification.js'
|
|
4
4
|
|
|
5
5
|
const indicatorClasses = {ema: FasterEMA, sma: FasterSMA}
|
|
6
6
|
|
|
@@ -26,7 +26,8 @@ export const movingAverages = (main, index, indicatorName, size, { target, diff,
|
|
|
26
26
|
|
|
27
27
|
// Create the main moving average instance.
|
|
28
28
|
instances[keyName] = {
|
|
29
|
-
maInstance: new indicatorClasses[indicatorName](size)
|
|
29
|
+
maInstance: new indicatorClasses[indicatorName](size),
|
|
30
|
+
arrayChunk: {[diffKeyName]: []}
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
verticalOhlcv[keyName] = [...nullArray];
|
|
@@ -63,7 +64,7 @@ export const movingAverages = (main, index, indicatorName, size, { target, diff,
|
|
|
63
64
|
|
|
64
65
|
// Retrieve the current price value.
|
|
65
66
|
const value = verticalOhlcv[target][index];
|
|
66
|
-
const { maInstance, diffInstance } = instances[keyName];
|
|
67
|
+
const { maInstance, diffInstance, arrayChunk } = instances[keyName];
|
|
67
68
|
|
|
68
69
|
// Update the moving average instance.
|
|
69
70
|
maInstance.update(value, lastIndexReplace);
|
|
@@ -82,6 +83,7 @@ export const movingAverages = (main, index, indicatorName, size, { target, diff,
|
|
|
82
83
|
for (const targetKey of diff.targets) {
|
|
83
84
|
// Compute diffValue only if we have a valid MA value.
|
|
84
85
|
let diffValue = null;
|
|
86
|
+
let zScore = null
|
|
85
87
|
if (currMa !== null && typeof currMa === 'number') {
|
|
86
88
|
diffValue = verticalOhlcv[targetKey][index] - currMa;
|
|
87
89
|
}
|
|
@@ -89,6 +91,8 @@ export const movingAverages = (main, index, indicatorName, size, { target, diff,
|
|
|
89
91
|
// Update the diff indicator only if diffValue is a valid number.
|
|
90
92
|
if (diffValue !== null && typeof diffValue === 'number') {
|
|
91
93
|
diffInstance.update(Math.abs(diffValue), lastIndexReplace);
|
|
94
|
+
|
|
95
|
+
zScore = calcZScore(arrayChunk, diffKeyName, diff.size, diffValue, lastIndexReplace)
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
let diffBoll = null;
|
|
@@ -102,7 +106,7 @@ export const movingAverages = (main, index, indicatorName, size, { target, diff,
|
|
|
102
106
|
main.pushToMain({
|
|
103
107
|
index,
|
|
104
108
|
key: `${diffKeyName}_${targetKey}`,
|
|
105
|
-
value:
|
|
109
|
+
value: zScore
|
|
106
110
|
});
|
|
107
111
|
}
|
|
108
112
|
}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import { classifyBoll } from '../utilities/classification.js'
|
|
1
|
+
const diff = (a, b) => (a - b)
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
import { calcZScore } from "../utilities/classification.js"
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
// Las diferencias estarán basadas en (objetivo - lower) / (upper - lower). Esto arrojará un valor entre -1 y 1
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export const candleVectors = (main, index, size, {stdDev, patternSize, lag, scale, autoMinMax}) => {
|
|
5
|
+
export const candleVectors = (main, index, size, {patternSize, lag, autoMinMax}) => {
|
|
11
6
|
|
|
12
7
|
const { verticalOhlcv, instances, lastIndexReplace } = main
|
|
13
|
-
const calcSize = (di, bo) => classifyBoll(di, bo, scale, autoMinMax)
|
|
14
8
|
|
|
15
9
|
if(index === 0)
|
|
16
10
|
{
|
|
@@ -74,7 +68,7 @@ export const candleVectors = (main, index, size, {stdDev, patternSize, lag, scal
|
|
|
74
68
|
bodyVectors,
|
|
75
69
|
lookBackVectors,
|
|
76
70
|
keyNames,
|
|
77
|
-
|
|
71
|
+
arrayChunk: {...Object.fromEntries(keyNames.map(v => [v, []]))}
|
|
78
72
|
}
|
|
79
73
|
})
|
|
80
74
|
|
|
@@ -85,33 +79,19 @@ export const candleVectors = (main, index, size, {stdDev, patternSize, lag, scal
|
|
|
85
79
|
|
|
86
80
|
}
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const {bodyVectors, lookBackVectors, bodyInstance} = instances.candleVectors
|
|
92
|
-
|
|
93
|
-
let bodyBoll = null
|
|
94
|
-
const currOpen = verticalOhlcv.open[index]
|
|
95
|
-
const currClose = verticalOhlcv.close[index]
|
|
96
|
-
const bodySize = diff(currClose, currOpen)
|
|
97
|
-
|
|
98
|
-
// Update instances with current absolute values
|
|
99
|
-
bodyInstance.update(Math.abs(bodySize), lastIndexReplace)
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
bodyBoll = bodyInstance.getResult()
|
|
103
|
-
} catch (err) {
|
|
104
|
-
// If there's not enough data, means remain null
|
|
105
|
-
}
|
|
106
|
-
|
|
82
|
+
const {bodyVectors, lookBackVectors, arrayChunk} = instances.candleVectors
|
|
107
83
|
|
|
108
84
|
for(let x = 0; x < bodyVectors.length; x++)
|
|
109
85
|
{
|
|
110
86
|
const [k2, k1] = bodyVectors[x]
|
|
111
87
|
const v2 = verticalOhlcv[k2][index]
|
|
112
88
|
const v1 = verticalOhlcv[k1][index]
|
|
89
|
+
const key = `candle_body_${k2}_${k1}`
|
|
90
|
+
const difference = diff(v2, v1)
|
|
113
91
|
|
|
114
|
-
|
|
92
|
+
const zScore = calcZScore(arrayChunk, key, size, difference, lastIndexReplace)
|
|
93
|
+
|
|
94
|
+
main.pushToMain({index, key, value: zScore})
|
|
115
95
|
}
|
|
116
96
|
|
|
117
97
|
for(let x = 0; x < patternSize; x++)
|
|
@@ -120,12 +100,18 @@ export const candleVectors = (main, index, size, {stdDev, patternSize, lag, scal
|
|
|
120
100
|
{
|
|
121
101
|
const currV = verticalOhlcv[currK][index]
|
|
122
102
|
const prevV = verticalOhlcv[prevK][index-(x+1)]
|
|
103
|
+
const key = `candle_change_${x+1}_${currK}_${prevK}`
|
|
104
|
+
|
|
105
|
+
if(typeof prevV === 'undefined')
|
|
106
|
+
{
|
|
107
|
+
main.pushToMain({index, key, value: null})
|
|
108
|
+
continue
|
|
109
|
+
}
|
|
123
110
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
})
|
|
111
|
+
const difference = diff(currV, prevV)
|
|
112
|
+
const zScore = calcZScore(arrayChunk, key, size, difference, lastIndexReplace)
|
|
113
|
+
|
|
114
|
+
main.pushToMain({index, key, value: zScore})
|
|
129
115
|
}
|
|
130
116
|
}
|
|
131
117
|
|
|
@@ -47,3 +47,31 @@ export const classifyBoll = (value, bollingerBands, scale = 0.05, autoMinMax = f
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
export const calcZScore = (arrayChunk, key, size, difference, lastIndexReplace) => {
|
|
53
|
+
|
|
54
|
+
if(lastIndexReplace)
|
|
55
|
+
{
|
|
56
|
+
arrayChunk[key][arrayChunk[key].length - 1] = difference
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
{
|
|
60
|
+
arrayChunk[key].push(difference)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if (arrayChunk[key].length > size) {
|
|
65
|
+
arrayChunk[key].shift(); // Removes the first element to maintain array size
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if(arrayChunk.length < size) return null
|
|
69
|
+
|
|
70
|
+
const mean = arrayChunk[key].reduce((sum, value) => sum + value, 0) / size
|
|
71
|
+
|
|
72
|
+
const stdDev = Math.sqrt(
|
|
73
|
+
arrayChunk[key].reduce((sum, value) => sum + (value - mean) ** 2, 0) / size
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return (difference - mean) / stdDev
|
|
77
|
+
}
|
|
@@ -30,7 +30,7 @@ export const pushToMain = ({main, index, key, value}) => {
|
|
|
30
30
|
}
|
|
31
31
|
else if(key.startsWith('candle_') && keyInAutoMinMax)
|
|
32
32
|
{
|
|
33
|
-
minMaxRanges[key] = { min: -
|
|
33
|
+
minMaxRanges[key] = { min: -3, max: 3}
|
|
34
34
|
}
|
|
35
35
|
else if(key.includes('_range_') && keyInAutoMinMax)
|
|
36
36
|
{
|