ohlcv-indicators 1.8.6 → 1.8.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ohlcv-indicators",
3
- "version": "1.8.6",
3
+ "version": "1.8.8",
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",
@@ -0,0 +1,40 @@
1
+
2
+
3
+ export const vwap = (main) => {
4
+ const { verticalOhlcv } = main;
5
+
6
+ const vwapValues = calculateVWAP(verticalOhlcv);
7
+
8
+ return {
9
+ [`vwap`]: vwapValues,
10
+ };
11
+ };
12
+
13
+ const calculateVWAP = data => {
14
+ const { high, low, close, volume } = data;
15
+ const output = new Array(close.length).fill(null)
16
+
17
+ // Cumulative sums for VWAP calculation
18
+ let cumulativePriceVolume = 0;
19
+ let cumulativeVolume = 0;
20
+
21
+ for (let x = 0; x < close.length; x++) {
22
+
23
+ const typicalPrice = (high[x] + low[x] + close[x]) / 3;
24
+
25
+ // Calculate Price * Volume for this interval
26
+ const priceVolume = typicalPrice * volume[x];
27
+
28
+ // Update cumulative sums
29
+ cumulativePriceVolume += priceVolume;
30
+ cumulativeVolume += volume[x];
31
+
32
+ // Calculate VWAP for this interval
33
+ const vwap = cumulativePriceVolume / cumulativeVolume;
34
+
35
+ // Push the VWAP value into the array
36
+ output[x] = vwap
37
+ }
38
+
39
+ return output
40
+ }
@@ -1,5 +1,5 @@
1
1
  import {FasterSMA} from 'trading-signals'
2
- import { classifyChange, classifySize } from '../utilities/classification.js'
2
+ import { classifySize } from '../utilities/classification.js'
3
3
 
4
4
  export const candlesStudies = (main, period, classify, classificationLevels) => {
5
5
 
@@ -19,8 +19,10 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
19
19
  let candle_bottom_size = new Array(len).fill(null) //scaled bottom size(0, 0.5 and 1)
20
20
  let candle_gap_size = new Array(len).fill(null) //scaled gap between the current open and previous close (-1 to 1)
21
21
  let candle_shadow_size = new Array(len).fill(null) //scaled shadow size high - slow
22
- let candle_position = new Array(len).fill(null) //scaled shadow size curr.close - prev.close
23
-
22
+ let candle_close_position = new Array(len).fill(null) //scaled shadow size curr.close - prev.close
23
+ let candle_high_position = new Array(len).fill(null) //scaled shadow size curr.high - prev.high
24
+ let candle_low_position = new Array(len).fill(null) //scaled shadow size curr.low - prev.low
25
+ let candle_open_position = new Array(len).fill(null) //scaled shadow size curr.open - prev.open
24
26
 
25
27
  //instances
26
28
  let topInstance
@@ -28,7 +30,10 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
28
30
  let gapInstance
29
31
  let bodySizeInstance
30
32
  let shadowSizeInstance
31
- let positionInstance
33
+ let closePositionInstance
34
+ let highPositionInstance
35
+ let lowPositionInstance
36
+ let openPositionInstance
32
37
 
33
38
  if(classify)
34
39
  {
@@ -37,7 +42,10 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
37
42
  gapInstance = new FasterSMA(period)
38
43
  bodySizeInstance = new FasterSMA(period)
39
44
  shadowSizeInstance = new FasterSMA(period)
40
- positionInstance = new FasterSMA(period)
45
+ closePositionInstance = new FasterSMA(period)
46
+ highPositionInstance = new FasterSMA(period)
47
+ lowPositionInstance = new FasterSMA(period)
48
+ openPositionInstance = new FasterSMA(period)
41
49
  }
42
50
 
43
51
  for(let x = 0; x < len; x++)
@@ -45,10 +53,7 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
45
53
  const curr = inputOhlcv[x]
46
54
  const prev = inputOhlcv[x-1]
47
55
 
48
- if(typeof prev === 'undefined')
49
- {
50
- continue
51
- }
56
+ if(typeof prev === 'undefined') continue
52
57
 
53
58
  const {open, high, low, close} = curr
54
59
 
@@ -59,17 +64,24 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
59
64
  let topSizeMean = null
60
65
  let bodySizeMean = null
61
66
  let shadowSizeMean = null
62
- let positionMean = null
67
+ let closePositionMean = null
68
+ let highPositionMean = null
69
+ let lowPositionMean = null
70
+ let openPositionMean = null
63
71
 
64
72
  //directions
65
- const candleBodySize = close - open // 1 for bullish and 0 for bearish
66
- const shadowSize = curr.high - curr.low
73
+ const isUp = close > open
74
+ const candleBodySize = Math.abs(close - open)
75
+ const shadowSize = Math.abs(curr.high - curr.low)
67
76
 
68
77
  //sizes
69
78
  const topSize = high - Math.max(open, close)
70
79
  const bottomSize = Math.min(open, close) - low
71
- const gapSize = prev.close - curr.open
72
- const position = curr.close - prev.close
80
+ const gapSize = Math.abs(prev.close - curr.open)
81
+ const closePosition = Math.abs(curr.close - prev.close)
82
+ const highPosition = Math.abs(curr.high - prev.high)
83
+ const lowPosition = Math.abs(curr.low - prev.low)
84
+ const openPosition = Math.abs(curr.open - prev.open)
73
85
 
74
86
  if(classify)
75
87
  {
@@ -80,8 +92,10 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
80
92
 
81
93
  gapInstance.update(gapSize)
82
94
  bodySizeInstance.update(candleBodySize)
83
- positionInstance.update(position)
84
-
95
+ closePositionInstance.update(closePosition)
96
+ highPositionInstance.update(highPosition)
97
+ lowPositionInstance.update(lowPosition)
98
+ openPositionInstance.update(openPosition)
85
99
 
86
100
  try
87
101
  {
@@ -90,7 +104,10 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
90
104
  gapMean = gapInstance.getResult()
91
105
  bodySizeMean = bodySizeInstance.getResult()
92
106
  shadowSizeMean = shadowSizeInstance.getResult()
93
- positionMean = positionInstance.getResult()
107
+ closePositionMean = closePositionInstance.getResult()
108
+ highPositionMean = highPositionInstance.getResult()
109
+ lowPositionMean = lowPositionInstance.getResult()
110
+ openPositionMean = openPositionInstance.getResult()
94
111
  }
95
112
  catch(err)
96
113
  {
@@ -99,14 +116,39 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
99
116
  topSizeMean = null
100
117
  bottomSizeMean = null
101
118
  shadowSizeMean = null
102
- positionMean = null
119
+ closePositionMean = null
120
+ highPositionMean = null
121
+ lowPositionMean = null
122
+ openPositionMean = null
103
123
  }
104
124
 
105
125
  //negatives and positives
106
- candle_body_size[x] = classifyChange(candleBodySize, bodySizeMean, 0.5, changeLevel)
107
- candle_gap_size[x] = classifyChange(gapSize, gapMean, 0.5, changeLevel)
108
- candle_position[x] = classifyChange(position, positionMean, 0.5, changeLevel)
126
+ candle_body_size[x] = (isUp)
127
+ ? classifySize(candleBodySize, bodySizeMean, 2, changeLevel)
128
+ : -Math.abs(classifySize(candleBodySize, bodySizeMean, 2, changeLevel)) || 0;
129
+
130
+ candle_gap_size[x] = (isUp)
131
+ ? classifySize(gapSize, gapMean, 2, changeLevel)
132
+ : -Math.abs(classifySize(gapSize, gapMean, 2, changeLevel)) || 0;
133
+
134
+ candle_close_position[x] = (isUp)
135
+ ? classifySize(closePosition, closePositionMean, 2, changeLevel)
136
+ : -Math.abs(classifySize(closePosition, closePositionMean, 2, changeLevel)) || 0;
109
137
 
138
+ candle_high_position[x] = (isUp)
139
+ ? classifySize(highPosition, highPositionMean, 2, changeLevel)
140
+ : -Math.abs(classifySize(highPosition, highPositionMean, 2, changeLevel)) || 0;
141
+
142
+
143
+ candle_low_position[x] = (isUp)
144
+ ? classifySize(lowPosition, lowPositionMean, 2, changeLevel)
145
+ : -Math.abs(classifySize(lowPosition, lowPositionMean, 2, changeLevel)) || 0;
146
+
147
+ candle_open_position[x] = (isUp)
148
+ ? classifySize(openPosition, openPositionMean, 2, changeLevel)
149
+ : -Math.abs(classifySize(openPosition, openPositionMean, 2, changeLevel)) || 0;
150
+
151
+
110
152
  //positives only
111
153
  candle_top_size[x] = classifySize(topSize, topSizeMean, 0.5, sizeLevel)
112
154
  candle_bottom_size[x] = classifySize(bottomSize, bottomSizeMean, 0.5, sizeLevel)
@@ -116,7 +158,9 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
116
158
  //negatives and positives
117
159
  candle_body_size[x] = candleBodySize
118
160
  candle_gap_size[x] = gapSize
119
- candle_position[x] = position
161
+ candle_close_position[x] = closePosition
162
+ candle_high_position[x] = highPosition
163
+ candle_low_position[x] = lowPosition
120
164
 
121
165
  //positives only
122
166
  candle_top_size[x] = topSize
@@ -132,6 +176,9 @@ const getCandlesStudies = (inputOhlcv, period = 20, len, classify = true, classi
132
176
  candle_top_size,
133
177
  candle_bottom_size,
134
178
  candle_shadow_size,
135
- candle_position
179
+ candle_close_position,
180
+ candle_high_position,
181
+ candle_low_position,
182
+ candle_open_position
136
183
  }
137
184
  }
@@ -18,32 +18,4 @@ export const classifySize = (value, mean, standardDeviation = 1.5, numLevels = 5
18
18
  }
19
19
 
20
20
  return 0
21
- }
22
-
23
-
24
- export const classifyChange = (value, mean, standardDeviation = 0.5, numLevels = 7) => {
25
- if (value === null || mean === null || standardDeviation === null) return null;
26
- if (numLevels < 2) throw new Error("numLevels must be at least 2");
27
-
28
- // Handle numLevels == 2 explicitly
29
- if (numLevels === 2) {
30
- return value >= mean ? 1 : -1;
31
- }
32
-
33
- // Calculate the range for each level
34
- const step = (4 * standardDeviation) / (numLevels - 1);
35
- const thresholds = [];
36
-
37
- for (let i = 0; i < numLevels - 1; i++) {
38
- thresholds.push(mean - (2 * standardDeviation) + (i * step));
39
- }
40
-
41
- // Classify the value based on calculated thresholds
42
- for (let i = thresholds.length - 1; i >= 0; i--) {
43
- if (value > thresholds[i]) {
44
- return (i - Math.floor((numLevels - 1) / 2)) / Math.floor((numLevels - 1) / 2);
45
- }
46
- }
47
-
48
- return -1;
49
- };
21
+ }
@@ -0,0 +1,64 @@
1
+ //change between current and prev
2
+ export const arrayChange = data => {
3
+
4
+ if(!Array.isArray(data))
5
+ {
6
+ throw Error('data param in arrayGt function must be array')
7
+ }
8
+
9
+ const output = Array(data.length).fill(0)
10
+
11
+ for (let x = 1; x < output.length; x++) {
12
+
13
+ if(data[x] === null || data[x - 1] === null)
14
+ {
15
+ output[x] === null
16
+ }
17
+ else
18
+ {
19
+ const curr = data[x]
20
+ const prev = data[x - 1]
21
+ output[x] = ((curr - prev) / prev) * 100
22
+ }
23
+ }
24
+
25
+ return output
26
+ }
27
+
28
+ //tells if array a is greater than array b
29
+
30
+ export const arrayGt = (a, b) => {
31
+
32
+ if(!Array.isArray(a) || !Array.isArray(b))
33
+ {
34
+ throw Error('a and b params in arrayGt function must be arrays')
35
+ }
36
+ if(a.length !== b.length)
37
+ {
38
+ throw Error('array a and b must be the same length in arrayGt function')
39
+ }
40
+ if(a.length < 2)
41
+ {
42
+ throw Error('arrays in arrayGt function must have at least 2 numeric items')
43
+ }
44
+
45
+ const output = Array(a.length).fill(0.5)
46
+
47
+ for (let x = 1; x < output.length; x++) {
48
+
49
+ if(a[x] === null || b[x] === null)
50
+ {
51
+ output[x] = null
52
+ }
53
+ if(a[x] > b[x])
54
+ {
55
+ output[x] = 1
56
+ }
57
+ else if(a[x] < b[x])
58
+ {
59
+ output[x] = 0
60
+ }
61
+ }
62
+
63
+ return output
64
+ }