ohlcv-indicators 2.0.4 → 2.0.6

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,82 +1,132 @@
1
- import {FasterBollingerBands, FasterSMA} from 'trading-signals';
1
+ import { FasterBollingerBands, FasterSMA } from 'trading-signals';
2
2
  import { classifySize } from '../utilities/classification.js';
3
3
 
4
- let defaultTarget = 'close'
5
-
6
- export const bollingerBands = (main, index, size, times, options) => {
7
-
8
- const {height, range, target} = options
9
- let suffix = (target === defaultTarget) ? '' : `_${target}`
10
-
11
- if (index === 0) {
12
-
13
- if(!main.verticalOhlcv.hasOwnProperty(target))
14
- {
15
- throw new Error(`bollingerBands could not find target "${target}"`)
16
- }
17
-
18
- Object.assign(main.instances, {
19
- [`bollinger_bands${suffix}`]: {
20
- instance: new FasterBollingerBands(size, times),
21
- heightInstance: height ? new FasterSMA(size) : null
22
- }
23
- })
24
-
25
- Object.assign(main.verticalOhlcv, {
26
- [`bollinger_bands_upper${suffix}`]: [...main.nullArray],
27
- [`bollinger_bands_middle${suffix}`]: [...main.nullArray],
28
- [`bollinger_bands_lower${suffix}`]: [...main.nullArray],
29
- ...(height && {
30
- [`bollinger_bands_height${suffix}`]: [...main.nullArray]
31
- }),
32
- ...(range && {
33
- [`bollinger_bands_range${suffix}`]: [...main.nullArray],
34
- })
35
- })
36
- }
4
+ const defaultTarget = 'close';
37
5
 
38
-
39
- const { instance, heightInstance } = main.instances[`bollinger_bands${suffix}`]
40
- const value = main.verticalOhlcv[target][index]
41
- instance.update(value, main.lastIndexReplace)
6
+ export const bollingerBands = (main, index, size, stdDev, options) => {
7
+ // Destructure options; ensure range and zScore default to empty arrays if not provided.
8
+ const { height, range = [], zScore = [], target } = options;
9
+ const suffix = target === defaultTarget ? '' : `_${target}`;
10
+ const indicatorKey = `${size}_${stdDev}${suffix}`;
11
+ let prefix; // Will be computed during initialization
42
12
 
43
- let result;
44
- try {
45
- result = instance.getResult();
46
- } catch (err) {
47
- //do nothing
13
+ // Initialize indicator instances and output arrays on the first call.
14
+ if (index === 0) {
15
+ if (!(target in main.verticalOhlcv)) {
16
+ throw new Error(`bollingerBands could not find target "${target}"`);
48
17
  }
49
18
 
50
- if(!result) return true
19
+ const numberOfIndicators = main.inputParams.filter(o => o.key === 'bollingerBands').length;
20
+ // Choose a prefix based on the number of indicators.
21
+ prefix = numberOfIndicators > 1
22
+ ? `bollinger_bands_${indicatorKey}`
23
+ : `bollinger_bands${suffix}`;
24
+
25
+ // Ensure the container exists.
26
+ if (!main.instances.bollinger_bands) {
27
+ main.instances.bollinger_bands = {
28
+ numberOfIndicators,
29
+ settings: {}
30
+ };
31
+ }
51
32
 
52
- const { upper, middle, lower } = result;
53
- main.verticalOhlcv[`bollinger_bands_upper${suffix}`][index] = upper;
54
- main.verticalOhlcv[`bollinger_bands_middle${suffix}`][index] = middle;
55
- main.verticalOhlcv[`bollinger_bands_lower${suffix}`][index] = lower;
33
+ // Create the Bollinger Bands (and optional height) indicator instance.
34
+ main.instances.bollinger_bands.settings[indicatorKey] = {
35
+ instance: new FasterBollingerBands(size, stdDev),
36
+ heightInstance: height >= size ? new FasterSMA(height) : null
37
+ };
56
38
 
57
- if (!height && !range) return true;
39
+ // Build the base output arrays.
40
+ const ohlcvSetup = {
41
+ [`${prefix}_upper`]: [...main.nullArray],
42
+ [`${prefix}_middle`]: [...main.nullArray],
43
+ [`${prefix}_lower`]: [...main.nullArray],
44
+ ...(height >= size && { [`${prefix}_height`]: [...main.nullArray] })
45
+ };
58
46
 
59
- let rangeValue = null;
60
- let heightValue = null;
61
- let heightMean;
62
47
 
63
- rangeValue = (value - lower) / (upper - lower);
64
- heightValue = upper - lower;
65
48
 
66
- heightInstance.update(heightValue, main.lastIndexReplace);
67
49
 
68
- try {
69
- heightMean = heightInstance.getResult();
70
- } catch (err) {
71
- //do nothing
50
+ // Set up additional arrays for each range property.
51
+ for (const rangeKey of range) {
52
+ if (!(rangeKey in main.verticalOhlcv) || !main.priceBased.includes(rangeKey)) {
53
+ throw new Error(`Invalid range item value "${rangeKey}" property for bollingerBands. Only price based key names are accepted:\n${JSON.stringify(main.priceBased)}`);
54
+ }
55
+ ohlcvSetup[`${prefix}_range_${rangeKey}`] = [...main.nullArray];
72
56
  }
73
57
 
74
- main.verticalOhlcv[`bollinger_bands_range${suffix}`][index] = rangeValue;
58
+ // Set up additional arrays for each zScore property.
59
+ for (const zScoreKey of zScore) {
60
+ if (!(zScoreKey in main.verticalOhlcv) || !main.priceBased.includes(zScoreKey)) {
61
+ throw new Error(`Invalid zScore item value "${zScoreKey}" for bollingerBands. Only price based key names are accepted:\n${JSON.stringify(main.priceBased)}`);
62
+ }
63
+ ohlcvSetup[`${prefix}_zscore_${zScoreKey}`] = [...main.nullArray];
64
+ }
75
65
 
76
- if(heightMean)
77
- {
78
- main.verticalOhlcv[`bollinger_bands_height${suffix}`][index] = classifySize(heightValue, heightMean, 1.5);
66
+ // Merge the new arrays into verticalOhlcv.
67
+ Object.assign(main.verticalOhlcv, ohlcvSetup);
68
+ }
69
+
70
+ // For subsequent calls, if prefix wasn’t computed (i.e. index > 0), derive it.
71
+ if (!prefix) {
72
+ const num = main.instances.bollinger_bands.numberOfIndicators;
73
+ prefix = num > 1 ? `bollinger_bands_${indicatorKey}` : `bollinger_bands${suffix}`;
74
+ }
75
+ // Use the same prefix for output keys.
76
+ const subPrefix = prefix;
77
+
78
+ // Retrieve the indicator instance(s) and update with the current value.
79
+ const { instance, heightInstance } = main.instances.bollinger_bands.settings[indicatorKey];
80
+ const value = main.verticalOhlcv[target][index];
81
+ instance.update(value, main.lastIndexReplace);
82
+
83
+ let result;
84
+ try {
85
+ result = instance.getResult();
86
+ } catch (err) {
87
+ // If the result is not available yet, simply exit.
88
+ }
89
+ if (!result) return true;
90
+
91
+ const { upper, middle, lower } = result;
92
+ main.pushToMain({index, key: `${subPrefix}_upper`, value: upper})
93
+ main.pushToMain({index, key: `${subPrefix}_middle`, value: middle})
94
+ main.pushToMain({index, key: `${subPrefix}_lower`, value: lower})
95
+
96
+ // Exit early if neither height nor range are requested.
97
+ if (!height && !range) return true;
98
+
99
+ // Process height if a height instance exists.
100
+ if (heightInstance) {
101
+ const heightValue = upper - lower;
102
+ heightInstance.update(heightValue, main.lastIndexReplace);
103
+ let heightMean;
104
+ try {
105
+ heightMean = heightInstance.getResult();
106
+ } catch (err) {
107
+ // Swallow error if the height result is not ready.
108
+ }
109
+ if (heightMean) {
110
+ main.pushToMain({index, key: `${subPrefix}_height`, value: classifySize(heightValue, heightMean, 0.5, 7)})
79
111
  }
80
-
81
- return true;
112
+ }
113
+
114
+ // Process each range property.
115
+ for (const rangeKey of range) {
116
+ const rangeValue = (main.verticalOhlcv[rangeKey][index] - lower) / (upper - lower);
117
+ main.pushToMain({index, key: `${subPrefix}_range_${rangeKey}`, value: rangeValue})
118
+ }
119
+
120
+ // Process each zScore property.
121
+ for (const zScoreKey of zScore) {
122
+ const denominator = upper - lower;
123
+ const zScoreValue = denominator !== 0
124
+ ? (2 * stdDev * (main.verticalOhlcv[zScoreKey][index] - middle)) / denominator
125
+ : 0;
126
+
127
+
128
+ main.pushToMain({index, key: `${subPrefix}_zscore_${zScoreKey}`, value: zScoreValue})
129
+ }
130
+
131
+ return true;
82
132
  };
@@ -1,43 +1,112 @@
1
- export const donchianChannels = (main, index, size, offset) => {
1
+ import { FasterSMA } from 'trading-signals';
2
+ import { classifySize } from '../utilities/classification.js';
2
3
 
3
- const highs = main.verticalOhlcv.high;
4
- const lows = main.verticalOhlcv.low;
4
+ export const donchianChannels = (main, index, size, offset, options) => {
5
+ const { height, range } = options;
6
+ const indicatorKey = `${size}_${offset}`;
5
7
 
6
- // Ensure that the required arrays exist
7
- if (index === 0) {
8
+ // Initialization: create output arrays and indicator instance on the first call.
9
+ if (index === 0) {
10
+ const numberOfIndicators = main.inputParams.filter(o => o.key === 'donchianChannels').length;
11
+ const prefix = numberOfIndicators > 1 ? `donchian_channel_${indicatorKey}` : 'donchian_channel';
8
12
 
9
- Object.assign(main.verticalOhlcv, {
10
- donchian_channel_upper: [...main.nullArray],
11
- donchian_channel_basis: [...main.nullArray],
12
- donchian_channel_lower: [...main.nullArray],
13
- })
13
+ Object.assign(main.verticalOhlcv, {
14
+ [`${prefix}_upper`]: [...main.nullArray],
15
+ [`${prefix}_basis`]: [...main.nullArray],
16
+ [`${prefix}_lower`]: [...main.nullArray],
17
+ ...(height && { [`${prefix}_height`]: [...main.nullArray] }),
18
+ ...(range && { [`${prefix}_range`]: [...main.nullArray] })
19
+ });
20
+
21
+ if (!main.instances.hasOwnProperty('donchian_channel')) {
22
+ main.instances.donchian_channel = { numberOfIndicators, settings: {} };
14
23
  }
15
24
 
25
+ // In addition to your heightInstance, also initialize deques for highs and lows.
26
+ main.instances.donchian_channel.settings[indicatorKey] = {
27
+ heightInstance: height
28
+ ? new FasterSMA(typeof height === 'number' && height > 0 ? height : size)
29
+ : null,
30
+ maxDeque: [], // will hold indices for highs in descending order
31
+ minDeque: [] // will hold indices for lows in ascending order
32
+ };
33
+ }
34
+
35
+ const numberOfIndicators = main.instances.donchian_channel.numberOfIndicators;
36
+ const subPrefix = numberOfIndicators > 1 ? `donchian_channel_${indicatorKey}` : 'donchian_channel';
37
+ const state = main.instances.donchian_channel.settings[indicatorKey];
38
+ const { heightInstance, maxDeque, minDeque } = state;
39
+
40
+ // Compute the “current bar index” for the window.
41
+ // Note: We use index - offset so that the window is built on the proper part of the array.
42
+ const currentBarIdx = index - offset;
43
+ const endIdx = currentBarIdx + 1; // currentBarIdx is inclusive
44
+ const startIdx = endIdx - size; // window: [startIdx, endIdx)
45
+
46
+ // If the window is not fully available, exit early.
47
+ if (startIdx < 0 || endIdx > main.len) return true;
16
48
 
17
- // Compute the slice start and end to get exactly 'size' bars
18
- const endIdx = (index - offset) + 1; // inclusive end of the slice
19
- const startIdx = endIdx - size; // start index for slicing
49
+ const highs = main.verticalOhlcv.high;
50
+ const lows = main.verticalOhlcv.low;
20
51
 
21
- // If any of these indices is out of bounds, return
22
- if (startIdx < 0 || endIdx > main.len) return true;
52
+ // **Update the maximum deque:**
53
+ // Remove indices that are out of the current window.
54
+ while (maxDeque.length && maxDeque[0] < startIdx) {
55
+ maxDeque.shift();
56
+ }
57
+ // Remove indices whose corresponding high value is less than or equal to the current high.
58
+ while (maxDeque.length && highs[maxDeque[maxDeque.length - 1]] <= highs[currentBarIdx]) {
59
+ maxDeque.pop();
60
+ }
61
+ // Add the current index.
62
+ maxDeque.push(currentBarIdx);
23
63
 
24
- // Extract the relevant chunks of data
25
- const highChunk = highs.slice(startIdx, endIdx)
26
- const lowChunk = lows.slice(startIdx, endIdx)
64
+ // **Update the minimum deque:**
65
+ // Remove indices that are out of the current window.
66
+ while (minDeque.length && minDeque[0] < startIdx) {
67
+ minDeque.shift();
68
+ }
69
+ // Remove indices whose corresponding low value is greater than or equal to the current low.
70
+ while (minDeque.length && lows[minDeque[minDeque.length - 1]] >= lows[currentBarIdx]) {
71
+ minDeque.pop();
72
+ }
73
+ // Add the current index.
74
+ minDeque.push(currentBarIdx);
27
75
 
28
- // Compute the Donchian channels
29
- const upper = Math.max(...highChunk);
30
- const lower = Math.min(...lowChunk);
31
- const basis = (upper + lower) / 2;
76
+ // Now the maximum high is at the front of maxDeque and the minimum low is at the front of minDeque.
77
+ const upper = highs[maxDeque[0]];
78
+ const lower = lows[minDeque[0]];
79
+ const basis = (upper + lower) / 2;
80
+ const close = main.verticalOhlcv.close[index];
81
+ const rangeValue = (close - lower) / (upper - lower);
82
+ const heightValue = upper - lower;
32
83
 
33
- // Place the result at index
34
- const placementIndex = index;
84
+ // Update the height indicator if requested.
85
+ if (height && heightInstance) {
86
+ heightInstance.update(heightValue, main.lastIndexReplace);
87
+ }
88
+
89
+ // Update the computed values in the output arrays.
90
+
91
+ main.pushToMain({index, key: `${subPrefix}_upper`, value: upper})
92
+ main.pushToMain({index, key: `${subPrefix}_basis`, value: basis})
93
+ main.pushToMain({index, key: `${subPrefix}_lower`, value: lower})
94
+
95
+ if (range) {
96
+ main.pushToMain({index, key: `${subPrefix}_range`, value: rangeValue})
97
+ }
98
+ if (height && heightInstance) {
99
+ let heightMean;
100
+ try {
101
+ heightMean = heightInstance.getResult();
102
+ } catch (err) {
103
+ // Ignore errors if the result isn't ready.
104
+ }
105
+ if (heightMean) {
35
106
 
36
- if (placementIndex >= 0 && placementIndex < main.len) {
37
- main.verticalOhlcv['donchian_channel_upper'][placementIndex] = upper;
38
- main.verticalOhlcv['donchian_channel_basis'][placementIndex] = basis;
39
- main.verticalOhlcv['donchian_channel_lower'][placementIndex] = lower;
107
+ main.pushToMain({index, key: `${subPrefix}_height`, value: classifySize(heightValue, heightMean, 1.5)})
40
108
  }
109
+ }
41
110
 
42
- return true;
111
+ return true;
43
112
  };
@@ -26,7 +26,7 @@ export const ema = (main, index, size, target) => {
26
26
 
27
27
  if(currEma)
28
28
  {
29
- main.verticalOhlcv[keyName][index] = currEma
29
+ main.pushToMain({index, key: keyName, value: currEma})
30
30
  }
31
31
 
32
32
  }
@@ -1,27 +1,56 @@
1
1
  import {FasterEMA, FasterMACD} from 'trading-signals';
2
2
 
3
- export const macd = (main, index, fast, slow, signal) => {
3
+ const defaultTarget = 'close'
4
4
 
5
- const value = main.verticalOhlcv.close[index]
5
+ export const macd = (main, index, fast, slow, signal, options) => {
6
+
7
+ const {target} = options
8
+ const suffix = target === defaultTarget ? '' : `_${target}`;
9
+ const indicatorKey = `${fast}_${slow}_${signal}${suffix}`;
6
10
 
7
11
  if (index === 0) {
8
12
 
9
- main.crossPairsList.push({fast: 'macd_diff', slow: 'macd_dea', isDefault: true});
13
+ if(!main.verticalOhlcv.hasOwnProperty(target))
14
+ {
15
+ throw new Error(`Target property ${target} not found in verticalOhlcv for macd.`)
16
+ }
17
+
18
+ const numberOfIndicators = main.inputParams.filter(o => o.key === 'macd').length;
19
+ const prefix =
20
+ numberOfIndicators > 1
21
+ ? `macd_${indicatorKey}`
22
+ : `macd${suffix}`;
23
+
24
+ main.crossPairsList.push({fast: `${prefix}_diff`, slow: `${prefix}_dea`, isDefault: true});
25
+
26
+ if(!main.instances.hasOwnProperty('macd'))
27
+ {
28
+ main.instances.macd = {
29
+ numberOfIndicators,
30
+ settings: {}
31
+ }
32
+ }
10
33
 
11
- main.instances['macd'] = new FasterMACD(
34
+ main.instances.macd.settings[indicatorKey] = new FasterMACD(
12
35
  new FasterEMA(fast),
13
36
  new FasterEMA(slow),
14
37
  new FasterEMA(signal)
15
38
  );
16
39
 
17
40
  Object.assign(main.verticalOhlcv, {
18
- macd_diff: [...main.nullArray],
19
- macd_dea: [...main.nullArray],
20
- macd_histogram: [...main.nullArray],
41
+ [`${prefix}_diff`]: [...main.nullArray],
42
+ [`${prefix}_dea`]: [...main.nullArray],
43
+ [`${prefix}_histogram`]: [...main.nullArray],
21
44
  })
22
45
  }
23
46
 
24
- const macdInstance = main.instances[`macd`];
47
+
48
+ const subPrefix = main.instances.macd.numberOfIndicators > 1
49
+ ? `macd_${indicatorKey}`
50
+ : `macd${suffix}`;
51
+
52
+ const macdInstance = main.instances.macd.settings[indicatorKey];
53
+ const value = main.verticalOhlcv[target][index]
25
54
  macdInstance.update(value, main.lastIndexReplace);
26
55
 
27
56
  let macdResult;
@@ -34,9 +63,10 @@ export const macd = (main, index, fast, slow, signal) => {
34
63
 
35
64
 
36
65
  if (macdResult) {
37
- main.verticalOhlcv['macd_diff'][index] = macdResult.macd;
38
- main.verticalOhlcv['macd_dea'][index] = macdResult.signal;
39
- main.verticalOhlcv['macd_histogram'][index] = macdResult.histogram;
66
+
67
+ main.pushToMain({index, key: `${subPrefix}_diff`, value: macdResult.macd})
68
+ main.pushToMain({index, key: `${subPrefix}_dea`, value: macdResult.signal})
69
+ main.pushToMain({index, key: `${subPrefix}_histogram`, value: macdResult.histogram})
40
70
  }
41
71
 
42
72
  return true;
@@ -2,39 +2,43 @@ import {FasterSMA} from 'trading-signals';
2
2
 
3
3
  export const relativeVolume = (main, index, size = 10) => {
4
4
 
5
- const value = main.verticalOhlcv.volume[index]
5
+ const key = `relative_volume_${size}`
6
6
 
7
7
  if (index === 0) {
8
- main.instances[`relative_volume_${size}`] = {
8
+ main.instances[key] = {
9
9
  instance: new FasterSMA(size),
10
10
  prevRelativeVolumeSma: null
11
11
  }
12
12
 
13
13
  Object.assign(main.verticalOhlcv, {
14
- [`relative_volume_${size}`]: [...main.nullArray],
14
+ [key]: [...main.nullArray],
15
15
  })
16
16
  }
17
17
 
18
- const smaInstance = main.instances[`relative_volume_${size}`].instance
18
+
19
+ const value = main.verticalOhlcv.volume[index]
20
+
21
+ const smaInstance = main.instances[key].instance
19
22
  smaInstance.update(value, main.lastIndexReplace)
20
23
 
21
24
  let smaValue;
22
25
  try {
23
26
  smaValue = smaInstance.getResult()
27
+
28
+
24
29
  } catch (err) {
25
30
  //do nothing
26
31
  }
27
32
 
28
- const {prevRelativeVolumeSma} = main.instances[`relative_volume_${size}`]
29
-
30
- if (smaValue !== null && prevRelativeVolumeSma !== null) {
31
- main.verticalOhlcv[`relative_volume_${size}`][index] = value / prevRelativeVolumeSma;
32
- } else {
33
- main.verticalOhlcv[`relative_volume_${size}`][index] = null;
34
- }
33
+ const {prevRelativeVolumeSma} = main.instances[key]
35
34
 
35
+ main.pushToMain({
36
+ index,
37
+ key,
38
+ value: (smaValue !== null && prevRelativeVolumeSma !== null) ? value / prevRelativeVolumeSma : null
39
+ })
36
40
 
37
- main.instances[`relative_volume_${size}`].prevRelativeVolumeSma = smaValue
41
+ main.instances[key].prevRelativeVolumeSma = smaValue
38
42
 
39
43
  return true;
40
44
  };
@@ -27,7 +27,7 @@ export const sma = (main, index, size, target) => {
27
27
 
28
28
  if(currSma)
29
29
  {
30
- main.verticalOhlcv[keyName][index] = currSma
30
+ main.pushToMain({index, key: keyName, value: currSma})
31
31
  }
32
32
 
33
33
  }
@@ -35,7 +35,7 @@ export const rsi = (main, index, size) => {
35
35
 
36
36
  if(currentRsi)
37
37
  {
38
- main.verticalOhlcv[`rsi_${size}`][index] = currentRsi
38
+ main.pushToMain({index, key: `rsi_${size}`, value: currentRsi})
39
39
  main.instances[`rsi_sma_${size}`].update(currentRsi, main.lastIndexReplace)
40
40
  }
41
41
 
@@ -49,7 +49,7 @@ export const rsi = (main, index, size) => {
49
49
 
50
50
  if(smoothedRsi)
51
51
  {
52
- main.verticalOhlcv[`rsi_sma_${size}`][index] = smoothedRsi
52
+ main.pushToMain({index, key: `rsi_sma_${size}`, value: smoothedRsi})
53
53
  }
54
54
 
55
55
  return true
@@ -3,6 +3,7 @@ import { FasterEMA } from 'trading-signals';
3
3
  export const volumeOscillator = (main, index, fast, slow) => {
4
4
 
5
5
  const value = main.verticalOhlcv.volume[index]
6
+ const key = 'volume_oscillator'
6
7
 
7
8
  if (index === 0) {
8
9
 
@@ -13,11 +14,11 @@ export const volumeOscillator = (main, index, fast, slow) => {
13
14
  }
14
15
  })
15
16
 
16
- main.verticalOhlcv[`volume_oscillator`] = [...main.nullArray];
17
- main.crossPairsList.push({ fast: `volume_oscillator`, slow: 0, isDefault: true });
17
+ main.verticalOhlcv[key] = [...main.nullArray];
18
+ main.crossPairsList.push({ fast: key, slow: 0, isDefault: true });
18
19
  }
19
20
 
20
- const { fastEMA, slowEMA } = main.instances[`volume_oscillator`];
21
+ const { fastEMA, slowEMA } = main.instances[key];
21
22
 
22
23
  fastEMA.update(value, main.lastIndexReplace);
23
24
  slowEMA.update(value, main.lastIndexReplace);
@@ -38,9 +39,10 @@ export const volumeOscillator = (main, index, fast, slow) => {
38
39
  }
39
40
 
40
41
  if (typeof fastValue === 'number' && typeof slowValue === 'number' && slowValue !== 0) {
41
- main.verticalOhlcv[`volume_oscillator`][index] = 100 * (fastValue - slowValue) / slowValue
42
+
43
+ main.pushToMain({index, key, value: 100 * (fastValue - slowValue) / slowValue})
42
44
  } else {
43
- main.verticalOhlcv[`volume_oscillator`][index] = null;
45
+ main.pushToMain({index, key, value: null})
44
46
  }
45
47
 
46
48
  return true;
@@ -112,45 +112,54 @@ export const candleStudies = (main, index, size, classify = true, classification
112
112
  // If there's not enough data, means remain null
113
113
  }
114
114
 
115
- main.verticalOhlcv.candle_body_size[index] = isUp
116
- ? classifySize(candleBodySize, bodySizeMean, 2, changeLevel)
117
- : -Math.abs(classifySize(candleBodySize, bodySizeMean, 2, changeLevel)) || 0;
115
+ main.pushToMain({
116
+ index,
117
+ key: 'candle_body_size',
118
+ value: isUp
119
+ ? classifySize(candleBodySize, bodySizeMean, 2, changeLevel)
120
+ : -Math.abs(classifySize(candleBodySize, bodySizeMean, 2, changeLevel)) || 0
121
+ })
122
+
123
+
118
124
 
119
- main.verticalOhlcv.candle_gap_size[index] = isUp
125
+ main.pushToMain({index, key: 'candle_gap_size', value: isUp
120
126
  ? classifySize(gapSize, gapMean, 2, changeLevel)
121
- : -Math.abs(classifySize(gapSize, gapMean, 2, changeLevel)) || 0;
127
+ : -Math.abs(classifySize(gapSize, gapMean, 2, changeLevel)) || 0})
128
+
122
129
 
123
- main.verticalOhlcv.candle_close_direction[index] = isUp
130
+ main.pushToMain({index, key: 'candle_close_direction', value: isUp
124
131
  ? classifySize(closeDirection, closeDirectionMean, 2, changeLevel)
125
- : -Math.abs(classifySize(closeDirection, closeDirectionMean, 2, changeLevel)) || 0;
132
+ : -Math.abs(classifySize(closeDirection, closeDirectionMean, 2, changeLevel)) || 0})
126
133
 
127
- main.verticalOhlcv.candle_high_direction[index] = isUp
134
+
135
+ main.pushToMain({index, key: 'candle_high_direction', value: isUp
128
136
  ? classifySize(highDirection, highDirectionMean, 2, changeLevel)
129
- : -Math.abs(classifySize(highDirection, highDirectionMean, 2, changeLevel)) || 0;
137
+ : -Math.abs(classifySize(highDirection, highDirectionMean, 2, changeLevel)) || 0})
130
138
 
131
- main.verticalOhlcv.candle_low_direction[index] = isUp
139
+ main.pushToMain({index, key: 'candle_low_direction', value: isUp
132
140
  ? classifySize(lowDirection, lowDirectionMean, 2, changeLevel)
133
- : -Math.abs(classifySize(lowDirection, lowDirectionMean, 2, changeLevel)) || 0;
141
+ : -Math.abs(classifySize(lowDirection, lowDirectionMean, 2, changeLevel)) || 0})
134
142
 
135
- main.verticalOhlcv.candle_open_direction[index] = isUp
143
+ main.pushToMain({index, key: 'candle_open_direction', value: isUp
136
144
  ? classifySize(openDirection, openDirectionMean, 2, changeLevel)
137
- : -Math.abs(classifySize(openDirection, openDirectionMean, 2, changeLevel)) || 0;
145
+ : -Math.abs(classifySize(openDirection, openDirectionMean, 2, changeLevel)) || 0})
146
+
147
+ main.pushToMain({index, key: 'candle_top_size', value: classifySize(topSize, topSizeMean, 0.5, sizeLevel)})
148
+ main.pushToMain({index, key: 'candle_bottom_size', value: classifySize(bottomSize, bottomSizeMean, 0.5, sizeLevel)})
149
+ main.pushToMain({index, key: 'candle_shadow_size', value: classifySize(shadowSize, shadowSizeMean, 0.5, sizeLevel)})
138
150
 
139
- main.verticalOhlcv.candle_top_size[index] = classifySize(topSize, topSizeMean, 0.5, sizeLevel);
140
- main.verticalOhlcv.candle_bottom_size[index] = classifySize(bottomSize, bottomSizeMean, 0.5, sizeLevel);
141
- main.verticalOhlcv.candle_shadow_size[index] = classifySize(shadowSize, shadowSizeMean, 0.5, sizeLevel);
142
151
  } else {
143
152
  // Without classification, just store raw values
144
- main.verticalOhlcv.candle_body_size[index] = isUp ? candleBodySize : -candleBodySize;
145
- main.verticalOhlcv.candle_gap_size[index] = isUp ? gapSize : -gapSize;
146
- main.verticalOhlcv.candle_close_direction[index] = isUp ? closeDirection : -closeDirection;
147
- main.verticalOhlcv.candle_high_direction[index] = isUp ? highDirection : -highDirection;
148
- main.verticalOhlcv.candle_low_direction[index] = isUp ? lowDirection : -lowDirection;
149
- main.verticalOhlcv.candle_open_direction[index] = isUp ? openDirection : -openDirection;
150
-
151
- main.verticalOhlcv.candle_top_size[index] = topSize;
152
- main.verticalOhlcv.candle_bottom_size[index] = bottomSize;
153
- main.verticalOhlcv.candle_shadow_size[index] = shadowSize;
153
+
154
+ main.pushToMain({index, key: 'candle_body_size', value: isUp ? candleBodySize : -candleBodySize})
155
+ main.pushToMain({index, key: 'candle_gap_size', value: isUp ? gapSize : -gapSize})
156
+ main.pushToMain({index, key: 'candle_close_direction', value: isUp ? closeDirection : -closeDirection})
157
+ main.pushToMain({index, key: 'candle_high_direction', value: isUp ? highDirection : -highDirection})
158
+ main.pushToMain({index, key: 'candle_low_direction', value: isUp ? lowDirection : -lowDirection})
159
+ main.pushToMain({index, key: 'candle_open_direction', value: isUp ? openDirection : -openDirection})
160
+ main.pushToMain({index, key: 'candle_top_size', value: topSize})
161
+ main.pushToMain({index, key: 'candle_bottom_size', value: bottomSize})
162
+ main.pushToMain({index, key: 'candle_shadow_size', value: shadowSize})
154
163
  }
155
164
 
156
165
  return true;
@@ -48,15 +48,14 @@ export const dateTime = (main, index) => {
48
48
  main.instances.dateTime.sessionIntradayIndexCount = 0
49
49
  }
50
50
 
51
-
52
- main.verticalOhlcv.session_daily_index[index] = main.instances.dateTime.sessionDailyIndexCount
53
- main.verticalOhlcv.session_intraday_index[index] = main.instances.dateTime.sessionIntradayIndexCount
54
- main.verticalOhlcv.day_of_the_week[index] = day_of_the_week
55
- main.verticalOhlcv.day_of_the_month[index] = day_of_the_month
56
- main.verticalOhlcv.week_of_the_month[index] = week_of_the_month
57
- main.verticalOhlcv.month[index] = month
58
- main.verticalOhlcv.year[index] = year
59
- main.verticalOhlcv.hour[index] = hour
51
+ main.pushToMain({index, key: 'session_daily_index', value: main.instances.dateTime.sessionDailyIndexCount})
52
+ main.pushToMain({index, key: 'session_intraday_index', value: main.instances.dateTime.sessionIntradayIndexCount})
53
+ main.pushToMain({index, key: 'day_of_the_week', value: day_of_the_week})
54
+ main.pushToMain({index, key: 'day_of_the_month', value: day_of_the_month})
55
+ main.pushToMain({index, key: 'week_of_the_month', value: week_of_the_month})
56
+ main.pushToMain({index, key: 'month', value: month})
57
+ main.pushToMain({index, key: 'year', value: year})
58
+ main.pushToMain({index, key: 'hour', value: hour})
60
59
 
61
60
  }
62
61