ohlcv-indicators 3.4.5 → 3.4.7
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 +1121 -1077
- package/index.js +50 -15
- package/package.json +1 -1
- package/src/moving-averages/bollingerBands.js +4 -3
- package/src/moving-averages/donchianChannel.js +7 -13
- package/src/studies/scaler.js +6 -2
- package/src/utilities/dateUtilities.js +7 -0
- package/src/utilities/numberUtilities.js +8 -0
- package/src/utilities/verticalToHorizontal.js +16 -8
package/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { pushToMain } from './src/core-functions/pushToMain.js'
|
|
|
15
15
|
import { assignTypes } from './src/utilities/assignTypes.js'
|
|
16
16
|
import { calcPrecisionMultiplier } from './src/utilities/precisionMultiplier.js'
|
|
17
17
|
import { buildArray } from './src/utilities/assignTypes.js'
|
|
18
|
-
|
|
18
|
+
import { dateOutputFormaters } from './src/utilities/dateUtilities.js'
|
|
19
19
|
|
|
20
20
|
//precomputed
|
|
21
21
|
import { precomputeMovingAverages } from './src/moving-averages/movingAverages.js'
|
|
@@ -86,8 +86,13 @@ export default class OHLCV_INDICATORS {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
getDataAsCols(
|
|
89
|
+
getDataAsCols(options = {}) {
|
|
90
90
|
this.compute();
|
|
91
|
+
|
|
92
|
+
const {skipNull = true, dateFormat = 'string'} = options
|
|
93
|
+
|
|
94
|
+
validateArrayOptions(Object.keys(dateOutputFormaters), dateFormat, 'dateFormat', 'getDataAsCols')
|
|
95
|
+
validateObject(options, 'options', 'getDataAsCols')
|
|
91
96
|
|
|
92
97
|
const {
|
|
93
98
|
precisionMultiplier,
|
|
@@ -112,9 +117,17 @@ export default class OHLCV_INDICATORS {
|
|
|
112
117
|
|
|
113
118
|
for (let x = startIndex; x < len; x++)
|
|
114
119
|
{
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
if(shouldApplyPrecision)
|
|
121
|
+
{
|
|
122
|
+
result[key][x] = arr[x] / precisionMultiplier
|
|
123
|
+
}
|
|
124
|
+
else if(key === 'date')
|
|
125
|
+
{
|
|
126
|
+
result[key][x] = dateOutputFormaters[dateFormat](arr[x])
|
|
127
|
+
}
|
|
128
|
+
else{
|
|
129
|
+
result[key][x] = arr[x]
|
|
130
|
+
}
|
|
118
131
|
}
|
|
119
132
|
|
|
120
133
|
}
|
|
@@ -123,20 +136,38 @@ export default class OHLCV_INDICATORS {
|
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
|
|
126
|
-
getData(
|
|
139
|
+
getData(options = {}) {
|
|
127
140
|
|
|
128
141
|
//getData method returns the last object (row) of the new OHLCV with indicators: {open, high, low, close, rsi_14, bollinger_bands_upper}
|
|
129
142
|
this.compute()
|
|
130
143
|
|
|
131
|
-
|
|
144
|
+
const {skipNull = true, dateFormat = 'string'} = options
|
|
145
|
+
|
|
146
|
+
validateArrayOptions(Object.keys(dateOutputFormaters), dateFormat, 'dateFormat', 'getData')
|
|
147
|
+
validateObject(options, 'options', 'getData')
|
|
148
|
+
|
|
149
|
+
return verticalToHorizontal({
|
|
150
|
+
main: this,
|
|
151
|
+
skipNull,
|
|
152
|
+
startIndex: 0,
|
|
153
|
+
dateFormat
|
|
154
|
+
})
|
|
132
155
|
}
|
|
133
156
|
|
|
134
157
|
|
|
135
|
-
getLastValues(){
|
|
158
|
+
getLastValues(options = {}){
|
|
136
159
|
|
|
137
160
|
this.compute()
|
|
138
161
|
|
|
139
|
-
|
|
162
|
+
const {dateFormat = 'string'} = options
|
|
163
|
+
validateArrayOptions(Object.keys(dateOutputFormaters), dateFormat, 'dateFormat', 'getData')
|
|
164
|
+
|
|
165
|
+
return verticalToHorizontal({
|
|
166
|
+
skipNull: false,
|
|
167
|
+
main: this,
|
|
168
|
+
startIndex: this.len - 1,
|
|
169
|
+
dateFormat
|
|
170
|
+
})[0]
|
|
140
171
|
}
|
|
141
172
|
|
|
142
173
|
compute() {
|
|
@@ -302,14 +333,15 @@ export default class OHLCV_INDICATORS {
|
|
|
302
333
|
validateNumber(stdDev, {min: 0.01, max: 50, allowDecimals: true}, 'stdDev', methodName)
|
|
303
334
|
validateObject(options, 'options', methodName)
|
|
304
335
|
|
|
305
|
-
const {target = 'close', height = false, range = [], lag = 0} = options
|
|
336
|
+
const {target = 'close', height = false, range = [], lag = 0, decimals = null} = options
|
|
306
337
|
|
|
307
338
|
|
|
308
339
|
validateArray(range, 'options.range', methodName)
|
|
309
340
|
validateNumber(lag, {min: 0, max: this.len, allowDecimals: false}, 'options.lag', methodName)
|
|
310
341
|
validateBoolean(height, 'options.height', methodName)
|
|
342
|
+
if(decimals !== null) validateNumber(decimals, {min: 1, max: 15, allowDecimals: false}, 'decimals', methodName)
|
|
311
343
|
|
|
312
|
-
this.inputParams.push({key: methodName, params: [size, stdDev, {target, height, range, lag}]});
|
|
344
|
+
this.inputParams.push({key: methodName, params: [size, stdDev, {target, height, range, lag, decimals}]});
|
|
313
345
|
|
|
314
346
|
return this;
|
|
315
347
|
}
|
|
@@ -342,13 +374,14 @@ export default class OHLCV_INDICATORS {
|
|
|
342
374
|
validateNumber(offset, {min: 0, max: this.len, allowDecimals: false}, 'offset', methodName)
|
|
343
375
|
|
|
344
376
|
validateObject(options, 'options', methodName)
|
|
345
|
-
const { height = false, range = [], lag = 0} = options;
|
|
377
|
+
const { height = false, range = [], lag = 0, decimals = null} = options;
|
|
346
378
|
|
|
347
379
|
validateArray(range, 'options.range', methodName)
|
|
348
380
|
validateNumber(lag, {min: 0, max: this.len, allowDecimals: false}, 'options.lag', methodName)
|
|
349
381
|
validateBoolean(height, 'options.height', methodName)
|
|
382
|
+
if(decimals !== null) validateNumber(decimals, {min: 1, max: 15, allowDecimals: false}, 'decimals', methodName)
|
|
350
383
|
|
|
351
|
-
this.inputParams.push({ key: methodName, params: [size, offset, { height, range, lag }] });
|
|
384
|
+
this.inputParams.push({ key: methodName, params: [size, offset, { height, range, lag, decimals}] });
|
|
352
385
|
|
|
353
386
|
return this;
|
|
354
387
|
}
|
|
@@ -401,17 +434,19 @@ export default class OHLCV_INDICATORS {
|
|
|
401
434
|
validateNumber(size, {min: 1, max: this.len, allowDecimals: false}, 'size', methodName)
|
|
402
435
|
validateArray(colKeys, 'colKeys', methodName)
|
|
403
436
|
|
|
404
|
-
const {group = false, range = [0, 1], lag = 0, type = 'minmax'} = options
|
|
437
|
+
const {group = false, range = [0, 1], lag = 0, type = 'minmax', decimals = null} = options
|
|
405
438
|
|
|
406
439
|
validateBoolean(group, 'options.group', methodName)
|
|
407
440
|
validateArrayOfRanges(range, 'options.range', methodName)
|
|
408
441
|
validateArrayOptions(['minmax', 'zscore'], type, 'options.type', methodName)
|
|
409
442
|
|
|
443
|
+
if(decimals !== null) validateNumber(decimals, {min: 1, max: 15, allowDecimals: false}, 'decimals', methodName)
|
|
444
|
+
|
|
410
445
|
const groupKey = (group) ? `${type}_${size}_group_${colKeys.join('_')}` : ''
|
|
411
446
|
const groupKeyLen = colKeys.length
|
|
412
447
|
const precomputed = {groupKey, groupKeyLen}
|
|
413
448
|
|
|
414
|
-
this.inputParams.push({key: methodName, params: [size, colKeys, {type, group, range, lag, precomputed}]})
|
|
449
|
+
this.inputParams.push({key: methodName, params: [size, colKeys, {type, group, range, lag, precomputed, decimals}]})
|
|
415
450
|
return this
|
|
416
451
|
}
|
|
417
452
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ohlcv-indicators",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.7",
|
|
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,8 +1,9 @@
|
|
|
1
1
|
import { FasterBollingerBands } from 'trading-signals'
|
|
2
|
+
import { roundDecimalPlaces } from '../utilities/numberUtilities.js';
|
|
2
3
|
|
|
3
4
|
const defaultTarget = 'close'
|
|
4
5
|
|
|
5
|
-
export const bollingerBands = (main, index, size, stdDev, { height, range = [], target, lag }) => {
|
|
6
|
+
export const bollingerBands = (main, index, size, stdDev, { height, range = [], target, lag, decimals }) => {
|
|
6
7
|
const { verticalOhlcv, instances } = main;
|
|
7
8
|
const suffix = target === defaultTarget ? '' : `_${target}`;
|
|
8
9
|
const indicatorKey = `${size}_${stdDev}${suffix}`;
|
|
@@ -111,7 +112,7 @@ export const bollingerBands = (main, index, size, stdDev, { height, range = [],
|
|
|
111
112
|
if (!Number.isNaN(lower) && !Number.isNaN(upper)) {
|
|
112
113
|
heightValue = ((upper - lower) / lower)
|
|
113
114
|
}
|
|
114
|
-
main.pushToMain({ index, key: `${subPrefix}_height`, value: heightValue });
|
|
115
|
+
main.pushToMain({ index, key: `${subPrefix}_height`, value: (decimals === null) ? heightValue : roundDecimalPlaces(heightValue, decimals) });
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
// Process each range property.
|
|
@@ -121,7 +122,7 @@ export const bollingerBands = (main, index, size, stdDev, { height, range = [],
|
|
|
121
122
|
if (!Number.isNaN(priceValue) && !Number.isNaN(lower) && !Number.isNaN(upper)) {
|
|
122
123
|
rangeValue = (priceValue - lower) / (upper - lower)
|
|
123
124
|
}
|
|
124
|
-
main.pushToMain({ index, key: `${subPrefix}_range_${rangeKey}`, value: rangeValue });
|
|
125
|
+
main.pushToMain({ index, key: `${subPrefix}_range_${rangeKey}`, value: (decimals === null) ? rangeValue : roundDecimalPlaces(rangeValue, decimals) });
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
return true;
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
|
|
2
|
+
import { roundDecimalPlaces } from "../utilities/numberUtilities.js";
|
|
3
|
+
|
|
2
4
|
export const donchianChannels = (main, index, size, offset, options) => {
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
len,
|
|
7
|
-
inputParams,
|
|
8
|
-
priceBased,
|
|
9
|
-
arrayTypes,
|
|
10
|
-
lag,
|
|
11
|
-
} = main;
|
|
12
|
-
const { height: includeHeight, range: rangeKeys } = options;
|
|
13
|
-
const indicatorKey = `${size}_${offset}`;
|
|
5
|
+
const {verticalOhlcv, instances, len, inputParams, priceBased, arrayTypes, lag} = main
|
|
6
|
+
const { height: includeHeight, range: rangeKeys, decimals } = options
|
|
7
|
+
const indicatorKey = `${size}_${offset}`
|
|
14
8
|
|
|
15
9
|
// ---- INIT (only at first bar) ----
|
|
16
10
|
if (index === 0) {
|
|
@@ -103,7 +97,7 @@ export const donchianChannels = (main, index, size, offset, options) => {
|
|
|
103
97
|
const heightVal = hasBounds && lower
|
|
104
98
|
? (upper - lower) / lower
|
|
105
99
|
: NaN;
|
|
106
|
-
main.pushToMain({ index, key: `${prefix}_height`, value: heightVal });
|
|
100
|
+
main.pushToMain({ index, key: `${prefix}_height`, value: (decimals === null) ? heightVal : roundDecimalPlaces(heightVal, decimals) });
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
// precompute spread once
|
|
@@ -118,7 +112,7 @@ export const donchianChannels = (main, index, size, offset, options) => {
|
|
|
118
112
|
const val = hasBounds && price === price && spread
|
|
119
113
|
? (price - lower) / spread
|
|
120
114
|
: NaN;
|
|
121
|
-
main.pushToMain({ index, key: rangeOut[i], value: val });
|
|
115
|
+
main.pushToMain({ index, key: rangeOut[i], value: (decimals === null) ? val : roundDecimalPlaces(val, decimals) });
|
|
122
116
|
}
|
|
123
117
|
|
|
124
118
|
return true;
|
package/src/studies/scaler.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { roundDecimalPlaces } from "../utilities/numberUtilities.js";
|
|
2
|
+
|
|
1
3
|
/* General scaler: supports "minmax" and "zscore" types */
|
|
2
4
|
|
|
5
|
+
|
|
6
|
+
|
|
3
7
|
const normalizeMinMax = (value, min, max, [validMin, validMax]) => {
|
|
4
8
|
const clamped = Math.min(Math.max(value, min), max);
|
|
5
9
|
return ((clamped - min) / (max - min)) * (validMax - validMin) + validMin;
|
|
@@ -9,7 +13,7 @@ const normalizeMinMax = (value, min, max, [validMin, validMax]) => {
|
|
|
9
13
|
return std === 0 ? 0 : (value - mean) / std;
|
|
10
14
|
};
|
|
11
15
|
|
|
12
|
-
export const scaler = (main, index, size, colKeys, {type, group, range, lag, precomputed}) => {
|
|
16
|
+
export const scaler = (main, index, size, colKeys, {type, group, range, lag, precomputed, decimals}) => {
|
|
13
17
|
const {groupKey, groupKeyLen} = precomputed
|
|
14
18
|
const { verticalOhlcv, instances, arrayTypes } = main;
|
|
15
19
|
const prefix = `${type}_${size}`;
|
|
@@ -93,7 +97,7 @@ export const scaler = (main, index, size, colKeys, {type, group, range, lag, pre
|
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
main.pushToMain({ index, key, value: scaled })
|
|
100
|
+
main.pushToMain({ index, key, value: (decimals === null) ? scaled : roundDecimalPlaces(scaled, decimals)})
|
|
97
101
|
}
|
|
98
102
|
};
|
|
99
103
|
|
|
@@ -68,3 +68,11 @@ export const classifyNum = (num, throwError = false) => {
|
|
|
68
68
|
|
|
69
69
|
return typeof num
|
|
70
70
|
};
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
export const roundDecimalPlaces = (value, decimals) => {
|
|
74
|
+
|
|
75
|
+
const factor = 10 ** decimals
|
|
76
|
+
// add a tiny epsilon to mitigate floating-point quirks around .5
|
|
77
|
+
return Math.round((value + Number.EPSILON) * factor) / factor
|
|
78
|
+
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
startIndex = 0
|
|
5
|
-
) => {
|
|
1
|
+
import { dateOutputFormaters } from "./dateUtilities.js"
|
|
2
|
+
|
|
3
|
+
export const verticalToHorizontal = ({main, skipNull = false, startIndex = 0, dateFormat}) => {
|
|
6
4
|
|
|
7
5
|
const {precisionMultiplier, priceBased, precision, verticalOhlcv, invalidValueIndex, len, verticalOhlcvKeyNames, verticalOhlcvTempCols} = main
|
|
8
6
|
|
|
@@ -19,9 +17,19 @@ export const verticalToHorizontal = (
|
|
|
19
17
|
|
|
20
18
|
for (let i = maxStartIndex; i < len; i++)
|
|
21
19
|
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
if(shouldApplyPrecision)
|
|
21
|
+
{
|
|
22
|
+
result[i - maxStartIndex][key] = arr[i] / precisionMultiplier
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
else if(key === 'date')
|
|
26
|
+
{
|
|
27
|
+
result[i - maxStartIndex][key] = dateOutputFormaters[dateFormat](arr[i])
|
|
28
|
+
}
|
|
29
|
+
else
|
|
30
|
+
{
|
|
31
|
+
result[i - maxStartIndex][key] = arr[i]
|
|
32
|
+
}
|
|
25
33
|
}
|
|
26
34
|
}
|
|
27
35
|
|