ohlcv-indicators 1.9.2 → 1.9.4

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,99 +1,73 @@
1
-
2
1
  import {FasterBollingerBands, FasterSMA} from 'trading-signals';
3
2
  import { classifySize } from '../utilities/classification.js';
4
3
 
5
- export const bollingerBands = (main, size, times, bollingerBandsStudies) => {
6
-
7
- const {verticalOhlcv} = main
8
- const {close} = verticalOhlcv
4
+ export const bollingerBands = (main, index, size, times, bollingerBandsStudies = false) => {
9
5
 
10
- const col = getBollingerBands(close, size, times, bollingerBandsStudies)
11
- return col
12
- }
6
+ const value = main.verticalOhlcv.close[index]
13
7
 
14
- export const getBollingerBands = (data, size = 20, times = 2, bollingerBandsStudies = false) => {
15
-
16
- const dataLength = data.length
17
- const bollinger_bands_upper = Array(dataLength).fill(null)
18
- const bollinger_bands_middle = Array(dataLength).fill(null)
19
- const bollinger_bands_lower = Array(dataLength).fill(null)
8
+ if (!main.instances.hasOwnProperty(`bollinger_bands`)) {
20
9
 
10
+ Object.assign(main.instances, {bollinger_bands: {
11
+ instance: new FasterBollingerBands(size, times),
12
+ heightInstance: bollingerBandsStudies ? new FasterSMA(size) : null
13
+ }})
21
14
 
22
- let bollinger_bands_range
23
- let bollinger_bands_height
24
- let heightInstance
25
- let range = null
26
- let height = null
27
15
 
28
- if(bollingerBandsStudies)
29
- {
30
- bollinger_bands_range = Array(dataLength).fill(null)
31
- bollinger_bands_height = Array(dataLength).fill(null)
32
- heightInstance = new FasterSMA(size)
33
- }
16
+ Object.assign(main.verticalOhlcv, {
17
+ bollinger_bands_upper: new Array(main.len).fill(null),
18
+ bollinger_bands_middle: new Array(main.len).fill(null),
19
+ bollinger_bands_lower: new Array(main.len).fill(null)
20
+ })
34
21
 
35
- let getRange = (value, upper, lower) => ({
36
- range: ((value - lower) / (upper - lower)),
37
- height: upper-lower
38
- })
22
+ if (bollingerBandsStudies) {
39
23
 
40
- let instance = new FasterBollingerBands(size, times)
41
-
42
-
43
- for (let x = 0; x < dataLength; x++) {
44
- let obj = {};
45
- instance.update(data[x])
46
- let hasNull = false
47
- let heightMean
24
+ Object.assign(main.verticalOhlcv, {
25
+ bollinger_bands_range: new Array(main.len).fill(null),
26
+ bollinger_bands_height: new Array(main.len).fill(null),
27
+ })
28
+ }
29
+ }
48
30
 
31
+ const { instance, heightInstance } = main.instances[`bollinger_bands`];
32
+ instance.update(value);
49
33
 
34
+ let result;
50
35
  try {
51
- obj = instance.getResult()
36
+ result = instance.getResult();
52
37
  } catch (err) {
53
- hasNull = true
54
- obj = { upper: null, middle: null, lower: null }
38
+ //do nothing
55
39
  }
56
40
 
57
- bollinger_bands_upper[x] = obj.upper;
58
- bollinger_bands_middle[x] = obj.middle;
59
- bollinger_bands_lower[x] = obj.lower;
60
-
61
- if(bollingerBandsStudies === false) continue
62
-
63
- if(hasNull)
64
- {
65
- bollinger_bands_range[x] = null
66
- bollinger_bands_height[x] = null
67
- }
68
- else
69
- {
70
- const extraProps = getRange(data[x], obj.upper, obj.lower)
71
- range = extraProps.range
72
- height = extraProps.height
41
+ if(!result) return true
73
42
 
74
- heightInstance.update(height)
43
+ const { upper, middle, lower } = result;
44
+ main.verticalOhlcv.bollinger_bands_upper[index] = upper;
45
+ main.verticalOhlcv.bollinger_bands_middle[index] = middle;
46
+ main.verticalOhlcv.bollinger_bands_lower[index] = lower;
75
47
 
76
- try{
77
- heightMean = heightInstance.getResult()
78
- }
79
- catch(err)
80
- {
81
- heightMean = null
82
- }
48
+ if (!bollingerBandsStudies) return true;
83
49
 
84
- }
50
+ let range = null;
51
+ let height = null;
52
+ let heightMean;
85
53
 
86
- bollinger_bands_range[x] = range
87
- bollinger_bands_height[x] = classifySize(height, heightMean, 1.5)
88
- }
54
+ range = (value - lower) / (upper - lower);
55
+ height = upper - lower;
89
56
 
90
- let output = { bollinger_bands_upper, bollinger_bands_middle, bollinger_bands_lower }
57
+ heightInstance.update(height);
91
58
 
92
- if(bollingerBandsStudies)
93
- {
94
- output = {...output, bollinger_bands_range, bollinger_bands_height}
95
- }
59
+ try {
60
+ heightMean = heightInstance.getResult();
61
+ } catch (err) {
62
+ //do nothing
63
+ }
96
64
 
97
- return output
98
- }
65
+ main.verticalOhlcv.bollinger_bands_range[index] = range;
99
66
 
67
+ if(heightMean)
68
+ {
69
+ main.verticalOhlcv.bollinger_bands_height[index] = classifySize(height, heightMean, 1.5);
70
+ }
71
+
72
+ return true;
73
+ };
@@ -1,59 +1,50 @@
1
- export const donchianChannels = (main, period, offset) => {
2
-
3
- const {verticalOhlcv, len} = main
4
- const {high, low} = verticalOhlcv
5
-
6
- return getDonchianChannels(high, low, period, offset, len)
7
- }
8
-
9
- export const getDonchianChannels = (high, low, period, offset, len) => {
10
- const donchian_channel_upper = new Array(len).fill(null)
11
- const donchian_channel_lower = new Array(len).fill(null)
12
- const donchian_channel_basis = new Array(len).fill(null)
13
-
14
- const maxQueue = []
15
- const minQueue = []
16
-
17
- const avg = ((h, l) => (h + l) / 2)
18
-
19
- for (let i = 0; i < len; i++) {
20
-
21
- while (maxQueue.length && maxQueue[0] <= i - period) {
22
- maxQueue.shift()
23
- }
24
- // Remove smaller values from the end
25
- while (maxQueue.length && high[maxQueue[maxQueue.length - 1]] <= high[i]) {
26
- maxQueue.pop()
27
- }
28
- maxQueue.push(i)
29
-
30
- while (minQueue.length && minQueue[0] <= i - period) {
31
- minQueue.shift()
32
- }
33
- while (minQueue.length && low[minQueue[minQueue.length - 1]] >= low[i]) {
34
- minQueue.pop()
35
- }
36
-
37
- minQueue.push(i)
38
-
39
- if (i >= period - 1) {
40
- const upperValue = high[maxQueue[0]]
41
- const lowerValue = low[minQueue[0]]
42
- const basisValue = avg(upperValue, lowerValue)
43
-
44
- const indexWithOffset = i + offset
45
-
46
- if (indexWithOffset >= 0 && indexWithOffset < len) {
47
- donchian_channel_upper[indexWithOffset] = upperValue
48
- donchian_channel_lower[indexWithOffset] = lowerValue
49
- donchian_channel_basis[indexWithOffset] = basisValue
50
- }
51
- }
1
+ const avg = (h, l) => (h + l) / 2;
2
+
3
+ export const donchianChannels = (main, index, size, offset) => {
4
+
5
+ const highs = main.verticalOhlcv.high;
6
+ const lows = main.verticalOhlcv.low;
7
+
8
+ // If we don't have enough data to fill one size ending at (index - offset), return
9
+ if ((index - offset) < (size - 1)) return true;
10
+
11
+ // Ensure that the required arrays exist
12
+ if (!main.instances.hasOwnProperty('donchian_channels')) {
13
+
14
+ main.instances['donchian_channels'] = {};
15
+
16
+ Object.assign(main.verticalOhlcv, {
17
+ donchian_channel_upper: new Array(main.len).fill(null),
18
+ donchian_channel_basis: new Array(main.len).fill(null),
19
+ donchian_channel_lower: new Array(main.len).fill(null),
20
+ })
52
21
  }
53
22
 
54
- return {
55
- donchian_channel_upper,
56
- donchian_channel_lower,
57
- donchian_channel_basis
23
+
24
+ // Compute the slice start and end to get exactly 'size' bars
25
+ const endIdx = (index - offset) + 1; // inclusive end of the slice
26
+ const startIdx = endIdx - size; // start index for slicing
27
+
28
+ // If any of these indices is out of bounds, return
29
+ if (startIdx < 0 || endIdx > main.len) return true;
30
+
31
+ // Extract the relevant chunks of data
32
+ const highChunk = highs.slice(startIdx, endIdx)
33
+ const lowChunk = lows.slice(startIdx, endIdx)
34
+
35
+ // Compute the Donchian channels
36
+ const upper = Math.max(...highChunk);
37
+ const lower = Math.min(...lowChunk);
38
+ const basis = avg(upper, lower);
39
+
40
+ // Place the result at index
41
+ const placementIndex = index;
42
+
43
+ if (placementIndex >= 0 && placementIndex < main.len) {
44
+ main.verticalOhlcv['donchian_channel_upper'][placementIndex] = upper;
45
+ main.verticalOhlcv['donchian_channel_basis'][placementIndex] = basis;
46
+ main.verticalOhlcv['donchian_channel_lower'][placementIndex] = lower;
58
47
  }
59
- }
48
+
49
+ return true;
50
+ };
@@ -1,54 +1,29 @@
1
1
 
2
- import {EMA, FasterEMA} from 'trading-signals'
2
+ import {FasterEMA} from 'trading-signals'
3
3
 
4
- export const ema = (main, size) => {
4
+ export const ema = (main, index, size) => {
5
5
 
6
- const {verticalOhlcv} = main
7
- const {close} = verticalOhlcv
6
+ const value = main.verticalOhlcv.close[index]
8
7
 
9
- const col = getEMA(close, size)
10
-
11
- return {
12
- [`ema_${size}`]: col
8
+ if(!main.instances.hasOwnProperty(`ema_${size}`))
9
+ {
10
+ main.instances[`ema_${size}`] = new FasterEMA(size)
11
+ main.verticalOhlcv[`ema_${size}`] = new Array(main.len).fill(null)
13
12
  }
14
- }
15
13
 
16
- export const getEMA = (data, size) => {
17
-
14
+ let currSma
15
+ main.instances[`ema_${size}`].update(value)
18
16
 
19
- if(typeof data === 'undefined' || typeof size === 'undefined')
17
+ try{
18
+ currSma = main.instances[`ema_${size}`].getResult()
19
+ } catch(err)
20
20
  {
21
- throw Error('undefined param in getEMA')
21
+ currSma = null
22
22
  }
23
23
 
24
- const dataLength = data.length
25
- const output = new Array(dataLength).fill(null)
26
- const instance = new FasterEMA(size)
27
-
28
- for(let x = 0; x < dataLength; x++)
24
+ if(currSma)
29
25
  {
30
-
31
- let value = null
32
-
33
- if(data[x] !== null)
34
- {
35
- instance.update(data[x])
36
-
37
- try
38
- {
39
- value = instance.getResult()
40
- }
41
- catch(err)
42
- {
43
- value = null
44
- }
45
- }
46
-
47
- output[x] = value
26
+ main.verticalOhlcv[`ema_${size}`][index] = currSma
48
27
  }
49
28
 
50
-
51
-
52
- return output
53
-
54
29
  }
@@ -1,50 +1,43 @@
1
- import { findCrosses } from "../studies/findCrosses.js";
2
- import {EMA, MACD, FasterEMA, FasterMACD} from 'trading-signals';
1
+ import {FasterEMA, FasterMACD} from 'trading-signals';
3
2
 
3
+ export const macd = (main, index, fastLine = 12, slowLine = 26, signalLine = 9) => {
4
4
 
5
- export const macd = (main, fastLine, slowLine, signalLine) => {
5
+ const value = main.verticalOhlcv.close[index]
6
6
 
7
- const {verticalOhlcv} = main
8
- const {close} = verticalOhlcv
9
- const col = getMACD(close, fastLine, slowLine, signalLine)
7
+ if (!main.instances.hasOwnProperty('macd')) {
10
8
 
11
- return col
12
- }
9
+ main.autoCrossPairsList.push({fast: 'macd_diff', slow: 'macd_dea'});
13
10
 
14
- export const getMACD = (data, fastLine = 12, slowLine = 26, signalLine = 9) => {
11
+ main.instances['macd'] = new FasterMACD(
12
+ new FasterEMA(fastLine),
13
+ new FasterEMA(slowLine),
14
+ new FasterEMA(signalLine)
15
+ );
15
16
 
16
- const dataLength = data.length
17
- const diff = new Array(dataLength).fill(null)
18
- const dea = new Array(dataLength).fill(null)
19
- const histogram = new Array(dataLength).fill(null)
17
+ Object.assign(main.verticalOhlcv, {
18
+ macd_diff: new Array(main.len).fill(null),
19
+ macd_dea: new Array(main.len).fill(null),
20
+ macd_histogram: new Array(main.len).fill(null),
21
+ })
22
+ }
20
23
 
21
- const instance = new FasterMACD(new FasterEMA(fastLine), new FasterEMA(slowLine), new FasterEMA(signalLine))
24
+ const macdInstance = main.instances[`macd`];
25
+ macdInstance.update(value);
22
26
 
23
- for(let x = 0; x < dataLength; x++)
24
- {
25
- let obj = {}
26
- instance.update(data[x])
27
-
28
- try
29
- {
30
- obj = instance.getResult()
31
- }
32
- catch(err)
33
- {
34
- obj = {macd: null, signal: null, histogram: null}
35
- }
27
+ let macdResult;
36
28
 
37
- diff[x] = obj.macd
38
- dea[x] = obj.signal
39
- histogram[x] = obj.histogram
29
+ try {
30
+ macdResult = macdInstance.getResult();
31
+ } catch (err) {
32
+ //do nothing
40
33
  }
41
34
 
42
- const x = findCrosses({fast: diff, slow: dea})
43
35
 
44
- return {
45
- macd_diff: diff,
46
- macd_dea: dea,
47
- macd_histogram: histogram,
48
- macd_diff_x_macd_dea: x
36
+ 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;
49
40
  }
50
- }
41
+
42
+ return true;
43
+ };
@@ -1,43 +1,35 @@
1
- import {FasterSMA} from 'trading-signals'
1
+ import {FasterSMA} from 'trading-signals';
2
2
 
3
- export const relativeVolume = (main, size = 10) => {
4
- const {verticalOhlcv} = main
5
- const {volume} = verticalOhlcv
6
- const col = getRelativeVolume(volume, size)
3
+ export const relativeVolume = (main, index, size = 10) => {
7
4
 
8
- return {
9
- [`relative_volume_${size}`]: col
5
+ const value = main.verticalOhlcv.volume[index]
6
+
7
+ if (!main.instances.hasOwnProperty(`relative_volume_${size}`)) {
8
+ main.instances[`relative_volume_${size}`] = new FasterSMA(size);
9
+
10
+ Object.assign(main.verticalOhlcv, {
11
+ [`relative_volume_${size}`]: new Array(main.len).fill(null),
12
+ [`relative_volume_sma_${size}`]: new Array(main.len).fill(null)
13
+ })
14
+ }
15
+
16
+ const smaInstance = main.instances[`relative_volume_${size}`]
17
+ smaInstance.update(value)
18
+
19
+ let smaValue;
20
+ try {
21
+ smaValue = smaInstance.getResult()
22
+ } catch (err) {
23
+ //do nothing
10
24
  }
11
- }
12
-
13
- export const getRelativeVolume = (volume, size) => {
14
-
15
- const instance = new FasterSMA(size)
16
- const sma = new Array(volume.length).fill(null)
17
- const output = new Array(volume.length).fill(null)
18
-
19
- for(let x = 0; x < volume.length; x++)
20
- {
21
- let value = null
22
-
23
- instance.update(volume[x])
24
-
25
- try
26
- {
27
- value = instance.getResult()
28
- }
29
- catch(err)
30
- {
31
- value = null
32
- }
33
-
34
- sma[x] = value
35
-
36
- if(typeof sma[x-1] === 'number')
37
- {
38
- output[x] = volume[x] / sma[x-1]
39
- }
25
+
26
+ main.verticalOhlcv[`relative_volume_sma_${size}`][index] = smaValue;
27
+
28
+ if (smaValue !== null && typeof main.verticalOhlcv[`relative_volume_sma_${size}`][index - 1] === 'number') {
29
+ main.verticalOhlcv[`relative_volume_${size}`][index] = value / main.verticalOhlcv[`relative_volume_sma_${size}`][index - 1];
30
+ } else {
31
+ main.verticalOhlcv[`relative_volume_${size}`][index] = null;
40
32
  }
41
-
42
- return output
43
- }
33
+
34
+ return true;
35
+ };
@@ -1,49 +1,29 @@
1
1
 
2
2
  import {FasterSMA} from 'trading-signals';
3
3
 
4
- export const sma = (main, size) => {
4
+ export const sma = (main, index, size) => {
5
5
 
6
- const {verticalOhlcv} = main
7
- const {close} = verticalOhlcv
6
+ const value = main.verticalOhlcv.close[index]
8
7
 
9
- const col = getSMA(close, size)
10
-
11
- return {
12
- [`sma_${size}`]: col
8
+ if(!main.instances.hasOwnProperty(`sma_${size}`))
9
+ {
10
+ main.instances[`sma_${size}`] = new FasterSMA(size)
11
+ main.verticalOhlcv[`sma_${size}`] = new Array(main.len).fill(null)
13
12
  }
14
- }
15
13
 
16
- export const getSMA = (data, size) => {
17
-
18
- if(typeof data === 'undefined' || typeof size === 'undefined')
14
+ let currSma
15
+ main.instances[`sma_${size}`].update(value)
16
+
17
+ try{
18
+ currSma = main.instances[`sma_${size}`].getResult()
19
+ } catch(err)
19
20
  {
20
- throw Error('undefined param in getSMA')
21
+ //do nothing
21
22
  }
22
23
 
23
- const dataLength = data.length
24
- const output = new Array(dataLength).fill(null)
25
- const instance = new FasterSMA(size)
26
-
27
- for(let x = 0; x < dataLength; x++)
24
+ if(currSma)
28
25
  {
29
- let value = null
30
-
31
- if(data[x] !== null)
32
- {
33
- instance.update(data[x])
34
-
35
- try
36
- {
37
- value = instance.getResult()
38
- }
39
- catch(err)
40
- {
41
- value = null
42
- }
43
- }
44
-
45
- output[x] = value
26
+ main.verticalOhlcv[`sma_${size}`][index] = currSma
46
27
  }
47
28
 
48
- return output
49
29
  }
@@ -1,68 +1,56 @@
1
- import { getSMA } from "../moving-averages/sma.js";
2
- import { getEMA } from "../moving-averages/ema.js";
3
- import { findCrosses } from "../studies/findCrosses.js";
4
1
  import {FasterRSI} from 'trading-signals';
2
+ import { FasterSMA } from 'trading-signals';
5
3
 
6
- const ma = {getSMA, getEMA}
7
4
 
8
- export const rsi = (main, period, movingAverage, movingAveragePeriod) => {
9
-
10
- const {verticalOhlcv} = main
11
- const {close} = verticalOhlcv
5
+ export const rsi = (main, index, size) => {
6
+
7
+ const value = main.verticalOhlcv.close[index]
12
8
 
13
- if(typeof period === 'number' && typeof movingAveragePeriod === 'undefined')
9
+ if(!main.instances.hasOwnProperty(`rsi_${size}`))
14
10
  {
15
- movingAveragePeriod = period
16
- }
17
-
18
- const col = getRSI(close, period, movingAverage, movingAveragePeriod)
11
+ main.autoCrossPairsList.push({fast: `rsi_${size}`, slow: `rsi_sma_${size}`})
19
12
 
20
- return col
21
- }
13
+ Object.assign(main.instances, {
14
+ [`rsi_${size}`]: new FasterRSI(size),
15
+ [`rsi_sma_${size}`]: new FasterSMA(size)
16
+ })
22
17
 
23
- export const getRSI = (data, period = 14, movingAverage = 'SMA', movingAveragePeriod = 14) => {
24
-
25
- const dataLength = data.length
26
-
27
- if (dataLength < period) {
28
- return [];
18
+ Object.assign(main.verticalOhlcv, {
19
+ [`rsi_${size}`]: new Array(main.len).fill(null),
20
+ [`rsi_sma_${size}`]: new Array(main.len).fill(null)
21
+ })
29
22
  }
23
+
24
+ let currentRsi
25
+ let smoothedRsi
30
26
 
31
- let rsi = new Array(dataLength).fill(null)
32
- const instance = new FasterRSI(period)
27
+ main.instances[`rsi_${size}`].update(value)
33
28
 
34
- for(let x = 0; x < dataLength; x++)
29
+ try
35
30
  {
36
- let value = null
37
-
38
- if(data[x] !== null)
39
- {
40
- instance.update(data[x])
41
-
42
- try
43
- {
44
- value = instance.getResult()
45
- }
46
- catch(err)
47
- {
48
- value = null
49
- }
50
- }
31
+ currentRsi = main.instances[`rsi_${size}`].getResult()
32
+ } catch(err) {
33
+ currentRsi = null
34
+ }
51
35
 
52
- rsi[x] = value
36
+ if(currentRsi)
37
+ {
38
+ main.verticalOhlcv[`rsi_${size}`][index] = currentRsi
39
+ main.instances[`rsi_sma_${size}`].update(currentRsi)
53
40
  }
54
41
 
55
- let output = {[`rsi_${period}`]: rsi}
42
+ try
43
+ {
44
+ smoothedRsi = main.instances[`rsi_sma_${size}`].getResult()
45
+ } catch(err)
46
+ {
47
+ smoothedRsi = null
48
+ }
56
49
 
57
- if(typeof movingAverage === 'string' && typeof movingAveragePeriod === 'number')
50
+ if(smoothedRsi)
58
51
  {
59
- if(ma.hasOwnProperty(`get${movingAverage}`))
60
- {
61
- const rsi_smoothed = ma[`get${movingAverage}`](rsi, movingAveragePeriod)
62
- output[`rsi_${movingAverage}_${movingAveragePeriod}`] = rsi_smoothed
63
- output[`rsi_${period}_x_rsi_${movingAverage}_${movingAveragePeriod}`] = findCrosses({fast: rsi, slow: rsi_smoothed})
64
- }
52
+ main.verticalOhlcv[`rsi_sma_${size}`][index] = smoothedRsi
65
53
  }
66
54
 
67
- return output
68
- }
55
+ return true
56
+ }