ohlcv-indicators 2.1.9 → 2.2.0

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.
@@ -4,102 +4,106 @@ import { classifyBoll } from '../utilities/classification.js'
4
4
 
5
5
  const indicatorClasses = {ema: FasterEMA, sma: FasterSMA}
6
6
 
7
- export const movingAverages = (main, index, indicatorName, size, {target, diff}) => {
8
-
9
- const {verticalOhlcv, instances, priceBased, lastIndexReplace} = main
10
- let suffix = (typeof target === 'string' && verticalOhlcv.hasOwnProperty(target) && target !== 'close') ? `_${target}` : ''
11
- const keyName = `${indicatorName}_${size}${suffix}`
12
- const diffKeyName = `${indicatorName}_${size}_diff${suffix}`
13
-
14
- if(index === 0)
15
- {
16
- const {nullArray} = main
17
-
18
- if(!verticalOhlcv.hasOwnProperty(target))
19
- {
20
- throw new Error(`Target property ${target} not found in verticalOhlcv for ${indicatorName}.`)
21
- }
7
+ export const movingAverages = (main, index, indicatorName, size, { target, diff }) => {
8
+ const { verticalOhlcv, instances, priceBased, lastIndexReplace } = main;
9
+ let suffix =
10
+ typeof target === 'string' &&
11
+ verticalOhlcv.hasOwnProperty(target) &&
12
+ target !== 'close'
13
+ ? `_${target}`
14
+ : '';
15
+ const keyName = `${indicatorName}_${size}${suffix}`;
16
+ const diffKeyName = `${indicatorName}_${size}_diff${suffix}`;
17
+
18
+ if (index === 0) {
19
+ const { nullArray } = main;
20
+
21
+ if (!verticalOhlcv.hasOwnProperty(target)) {
22
+ throw new Error(
23
+ `Target property ${target} not found in verticalOhlcv for ${indicatorName}.`
24
+ );
25
+ }
22
26
 
23
- instances[keyName] = {
24
- maInstance: new indicatorClasses[indicatorName](size)
25
- }
27
+ // Create the main moving average instance.
28
+ instances[keyName] = {
29
+ maInstance: new indicatorClasses[indicatorName](size)
30
+ };
26
31
 
27
- verticalOhlcv[keyName] = [...nullArray]
32
+ verticalOhlcv[keyName] = [...nullArray];
28
33
 
29
- if(diff !== null)
30
- {
31
- instances[keyName].diffInstance = new FasterBollingerBands(diff.size, diff.stdDev)
34
+ // If diff configuration is provided, create the diff indicator.
35
+ if (diff !== null) {
36
+ instances[keyName].diffInstance = new FasterBollingerBands(
37
+ diff.size,
38
+ diff.stdDev
39
+ );
32
40
 
33
- const lagDiffArr = []
41
+ const lagDiffArr = [];
34
42
 
35
- for(const targetKey of diff.targets)
36
- {
37
- verticalOhlcv[`${diffKeyName}_${targetKey}`] = [...nullArray]
43
+ for (const targetKey of diff.targets) {
44
+ verticalOhlcv[`${diffKeyName}_${targetKey}`] = [...nullArray];
38
45
 
39
- if(diff.lag > 0)
40
- {
41
- lagDiffArr.push(`${diffKeyName}_${targetKey}`)
42
- }
46
+ if (diff.lag > 0) {
47
+ lagDiffArr.push(`${diffKeyName}_${targetKey}`);
43
48
  }
49
+ }
44
50
 
45
- if(diff.lag > 0)
46
- {
47
- console.log(lagDiffArr, diff.lag)
48
- main.lag(lagDiffArr, diff.lag)
49
- }
51
+ if (diff.lag > 0) {
52
+ main.lag(lagDiffArr, diff.lag);
50
53
  }
54
+ }
51
55
 
52
- priceBased.push(keyName)
56
+ priceBased.push(keyName);
53
57
  }
54
58
 
55
- const value = verticalOhlcv[target][index]
56
- const {maInstance, diffInstance} = instances[keyName]
57
- maInstance.update(value, lastIndexReplace)
58
-
59
- let currMa
60
-
61
- try{
62
- currMa = maInstance.getResult()
63
- } catch(err)
64
- {
65
- //do nothing
59
+ // Retrieve the current price value.
60
+ const value = verticalOhlcv[target][index];
61
+ const { maInstance, diffInstance } = instances[keyName];
62
+
63
+ // Update the moving average instance.
64
+ maInstance.update(value, lastIndexReplace);
65
+ let currMa = null;
66
+ try {
67
+ currMa = maInstance.getResult();
68
+ } catch (err) {
69
+ currMa = null;
66
70
  }
67
71
 
68
- if(currMa)
69
- {
70
- main.pushToMain({index, key: keyName, value: currMa})
71
-
72
- if(diff === null)
73
- {
74
- return true
75
- }
72
+ // Always push the MA value (even if null).
73
+ main.pushToMain({ index, key: keyName, value: currMa });
76
74
 
77
- for(const targetKey of diff.targets)
78
- {
79
-
80
- const diffValue = (target === targetKey) ? value - currMa : verticalOhlcv[targetKey][index]
81
-
82
- diffInstance.update(Math.abs(diffValue), lastIndexReplace)
75
+ // Process the diff values if a diff is requested.
76
+ if (diff !== null) {
77
+ for (const targetKey of diff.targets) {
78
+ // Compute diffValue only if we have a valid MA value.
79
+ let diffValue = null;
80
+ if (currMa !== null && typeof currMa === 'number') {
81
+ diffValue = target === targetKey ? value - currMa : verticalOhlcv[targetKey][index];
82
+ }
83
83
 
84
- let diffBoll
84
+ // Update the diff indicator only if diffValue is a valid number.
85
+ if (diffValue !== null && typeof diffValue === 'number') {
86
+ diffInstance.update(Math.abs(diffValue), lastIndexReplace);
87
+ }
85
88
 
89
+ let diffBoll = null;
86
90
  try {
87
- diffBoll = diffInstance.getResult()
88
- } catch(err)
89
- {
90
- diffBoll = null
91
+ diffBoll = diffInstance.getResult();
92
+ } catch (err) {
93
+ diffBoll = null;
91
94
  }
92
95
 
93
- main.pushToMain({index, key: `${diffKeyName}_${targetKey}`, value: classifyBoll(diffValue, diffBoll, diff.scale)})
94
-
96
+ const classified = classifyBoll(diffValue, diffBoll, diff.scale);
97
+ main.pushToMain({
98
+ index,
99
+ key: `${diffKeyName}_${targetKey}`,
100
+ value: classified
101
+ });
95
102
  }
96
-
97
-
98
-
99
103
  }
100
104
 
101
- }
102
-
105
+ return true;
106
+ };
103
107
 
104
108
 
105
109
  export const getMovingAveragesParams = (indicatorName, size, options, validMagnitudeValues) => {
@@ -1,61 +1,43 @@
1
- import {FasterSMA} from 'trading-signals';
1
+ import { FasterSMA } from 'trading-signals';
2
2
  import { calcMagnitude } from '../utilities/numberUtilities.js';
3
3
 
4
- export const relativeVolume = (main, index, size = 10, {scale}) => {
5
-
6
- const key = `relative_volume_${size}`
7
- const {instances, verticalOhlcv, lastIndexReplace} = main
8
-
9
- if (index === 0) {
10
-
11
- const {nullArray} = main
12
-
13
- instances[key] = {
14
- instance: new FasterSMA(size),
15
- prevRelativeVolumeSma: null
16
- }
17
-
18
- Object.assign(verticalOhlcv, {
19
- [key]: [...nullArray],
20
- })
21
- }
22
-
23
-
24
- const value = verticalOhlcv.volume[index]
25
-
26
- const smaInstance = instances[key].instance
27
- smaInstance.update(value, lastIndexReplace)
28
-
29
- let smaValue;
30
- try {
31
- smaValue = smaInstance.getResult()
32
-
33
-
34
- } catch (err) {
35
- //do nothing
36
- }
37
-
38
- const {prevRelativeVolumeSma} = instances[key]
39
-
40
- let currRelativeVolume = null
41
-
42
- if(smaValue !== null && prevRelativeVolumeSma !== null && typeof smaValue !== 'undefined' && prevRelativeVolumeSma !== 'undefined')
43
- {
44
- currRelativeVolume = value / prevRelativeVolumeSma
45
-
46
- if(scale)
47
- {
48
- currRelativeVolume = calcMagnitude(currRelativeVolume, scale)
49
- }
4
+ export const relativeVolume = (main, index, size = 10, { scale }) => {
5
+ const key = `relative_volume_${size}`;
6
+ const { instances, verticalOhlcv, lastIndexReplace } = main;
7
+
8
+ if (index === 0) {
9
+ const { nullArray } = main;
10
+ instances[key] = {
11
+ instance: new FasterSMA(size),
12
+ prevRelativeVolumeSma: null
13
+ };
14
+ verticalOhlcv[key] = [...nullArray];
15
+ }
16
+
17
+ const value = verticalOhlcv.volume[index];
18
+ const smaInstance = instances[key].instance;
19
+ smaInstance.update(value, lastIndexReplace);
20
+
21
+ let smaValue = null;
22
+ try {
23
+ smaValue = smaInstance.getResult();
24
+ } catch (err) {
25
+ smaValue = null;
26
+ }
27
+
28
+ const prevSma = instances[key].prevRelativeVolumeSma;
29
+ let currRelativeVolume = null;
30
+
31
+ // Only calculate relative volume if both current SMA and previous SMA are valid numbers and prevSma is not zero.
32
+ if (typeof smaValue === 'number' && typeof prevSma === 'number' && prevSma !== 0) {
33
+ currRelativeVolume = value / prevSma;
34
+ if (scale) {
35
+ currRelativeVolume = calcMagnitude(currRelativeVolume, scale);
50
36
  }
37
+ }
51
38
 
52
- main.pushToMain({
53
- index,
54
- key,
55
- value: currRelativeVolume
56
- })
57
-
58
- instances[key].prevRelativeVolumeSma = smaValue
39
+ main.pushToMain({ index, key, value: currRelativeVolume });
40
+ instances[key].prevRelativeVolumeSma = smaValue;
59
41
 
60
- return true;
42
+ return true;
61
43
  };
@@ -1,77 +1,71 @@
1
- import {FasterRSI} from 'trading-signals';
1
+ import { FasterRSI } from 'trading-signals';
2
2
  import { FasterSMA } from 'trading-signals';
3
3
  import { calcMagnitude } from '../utilities/numberUtilities.js';
4
4
 
5
- const defaultTarget = 'close'
5
+ const defaultTarget = 'close';
6
6
 
7
- export const rsi = (main, index, size, {scale, target}) => {
8
-
9
- const {verticalOhlcv, instances, lastIndexReplace} = main
10
- const suffix = (target === defaultTarget) ? '' : `_${target}`
11
- const rsiKey = `rsi_${size}${suffix}`
12
- const rsiSmaKey = `rsi_sma_${size}${suffix}`
7
+ export const rsi = (main, index, size, { scale, target }) => {
8
+ const { verticalOhlcv, instances, lastIndexReplace } = main;
9
+ const suffix = target === defaultTarget ? '' : `_${target}`;
10
+ const rsiKey = `rsi_${size}${suffix}`;
11
+ const rsiSmaKey = `rsi_sma_${size}${suffix}`;
13
12
 
14
- if(index === 0)
15
- {
16
- const {crossPairsList, nullArray} = main
13
+ // Initialization on the first index.
14
+ if (index === 0) {
15
+ const { crossPairsList, nullArray } = main;
17
16
 
18
- if(!verticalOhlcv.hasOwnProperty(target))
19
- {
20
- throw new Error(`Target property ${target} not found in verticalOhlcv for rsi.`)
21
- }
17
+ if (!verticalOhlcv.hasOwnProperty(target)) {
18
+ throw new Error(`Target property ${target} not found in verticalOhlcv for rsi.`);
19
+ }
22
20
 
23
- crossPairsList.push({fast: rsiKey, slow: rsiSmaKey, isDefault: true})
21
+ crossPairsList.push({ fast: rsiKey, slow: rsiSmaKey, isDefault: true });
24
22
 
25
- Object.assign(instances, {
26
- [rsiKey]: new FasterRSI(size),
27
- [rsiSmaKey]: new FasterSMA(size)
28
- })
23
+ Object.assign(instances, {
24
+ [rsiKey]: new FasterRSI(size),
25
+ [rsiSmaKey]: new FasterSMA(size)
26
+ });
29
27
 
30
- Object.assign(verticalOhlcv, {
31
- [rsiKey]: [...nullArray],
32
- [rsiSmaKey]: [...nullArray],
33
- })
34
- }
28
+ Object.assign(verticalOhlcv, {
29
+ [rsiKey]: [...nullArray],
30
+ [rsiSmaKey]: [...nullArray],
31
+ });
32
+ }
35
33
 
36
- const value = verticalOhlcv[target][index]
37
- let currentRsi
38
- let smoothedRsi
34
+ const value = verticalOhlcv[target][index];
35
+ let currentRsi = null;
36
+ let smoothedRsi = null;
39
37
 
40
- instances[rsiKey].update(value, lastIndexReplace)
38
+ // Update the RSI indicator.
39
+ instances[rsiKey].update(value, lastIndexReplace);
41
40
 
42
- try
43
- {
44
- currentRsi = instances[rsiKey].getResult()
45
- } catch(err) {
46
- currentRsi = null
47
- }
48
-
49
- if(currentRsi)
50
- {
51
- if(scale)
52
- {
53
- currentRsi = calcMagnitude(currentRsi, scale)
54
- }
55
-
56
- main.pushToMain({index, key: rsiKey, value: currentRsi})
57
- instances[rsiSmaKey].update(currentRsi, lastIndexReplace)
58
- }
41
+ try {
42
+ currentRsi = instances[rsiKey].getResult();
43
+ } catch (err) {
44
+ currentRsi = null;
45
+ }
59
46
 
60
- try
61
- {
62
- smoothedRsi = instances[rsiSmaKey].getResult()
63
- } catch(err)
64
- {
65
- smoothedRsi = null
66
- }
47
+ if (currentRsi !== null && typeof currentRsi === 'number' && scale) {
48
+ currentRsi = calcMagnitude(currentRsi, scale);
49
+ }
67
50
 
68
- if(smoothedRsi)
69
- {
70
- if(scale)
71
- {
72
- smoothedRsi = calcMagnitude(smoothedRsi, scale)
73
- }
51
+ // Always push the RSI value, using null as a fallback.
52
+ main.pushToMain({ index, key: rsiKey, value: currentRsi });
74
53
 
75
- main.pushToMain({index, key: rsiSmaKey, value: smoothedRsi})
76
- }
77
- }
54
+ // Update the SMA indicator only if a valid RSI value is available.
55
+ if (currentRsi !== null && typeof currentRsi === 'number') {
56
+ instances[rsiSmaKey].update(currentRsi, lastIndexReplace);
57
+ }
58
+
59
+ try {
60
+ smoothedRsi = instances[rsiSmaKey].getResult();
61
+ } catch (err) {
62
+ smoothedRsi = null;
63
+ }
64
+
65
+ if (smoothedRsi !== null && typeof smoothedRsi === 'number' && scale) {
66
+ smoothedRsi = calcMagnitude(smoothedRsi, scale);
67
+ }
68
+
69
+ // Always push the smoothed RSI value.
70
+ main.pushToMain({ index, key: rsiSmaKey, value: smoothedRsi });
71
+ };
@@ -49,9 +49,11 @@ export const lag = (main, index) => {
49
49
  const key = `${colKey}_lag_${lag}`;
50
50
  const laggedIndex = index - lag;
51
51
 
52
- if(laggedIndex <= 0) break
52
+ const value = (laggedIndex <= 0 || typeof currentColumn[laggedIndex] === 'undefined')
53
+ ? null
54
+ : currentColumn[laggedIndex]
53
55
 
54
- main.pushToMain({index, key, value: currentColumn[laggedIndex]})
56
+ main.pushToMain({index, key, value})
55
57
  }
56
58
  }
57
59
  }
@@ -14,6 +14,8 @@ export const verticalToHorizontal = (
14
14
  const len = endIndex - startIndex;
15
15
 
16
16
  const result = new Array(len);
17
+
18
+ console.log({skipNull, invalidValueIndex, len})
17
19
 
18
20
  for (let i = startIndex; i < endIndex; i++) {
19
21
  const row = {};
@@ -21,7 +23,7 @@ export const verticalToHorizontal = (
21
23
  const key = keys[j];
22
24
  const value = obj[key][i];
23
25
 
24
- if(value === null || value === NaN || typeof value === 'undefined')
26
+ if(value === null || typeof value === 'undefined')
25
27
  {
26
28
  row[key] = null
27
29
  }