ohlcv-indicators 1.1.9 → 1.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.
package/index.js CHANGED
@@ -5,6 +5,7 @@ import {bollingerBands} from './src/moving-averages/bollingerBands.js'
5
5
  import { rsi } from './src/oscillators/rsi.js'
6
6
  import { VolumeProfile } from './src/studies/volumeProfile.js'
7
7
  import {findCrosses} from './src/utilities.js'
8
+ import { candles } from './src/studies/candles.js'
8
9
 
9
10
  export default class OHLCV_INDICATORS {
10
11
  constructor() {
@@ -137,4 +138,9 @@ export default class OHLCV_INDICATORS {
137
138
  rsi(this, period, movingAverage, movingAveragePeriod)
138
139
  return this
139
140
  }
141
+ candles()
142
+ {
143
+ candles(this)
144
+ return this
145
+ }
140
146
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ohlcv-indicators",
3
- "version": "1.1.9",
3
+ "version": "1.2.0",
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",
@@ -11,8 +11,7 @@
11
11
  "author": "https://jaimelias.com/",
12
12
  "license": "ISC",
13
13
  "dependencies": {
14
- "@debut/indicators": "^1.3.20",
15
- "bignumber.js": "^9.1.2"
14
+ "@debut/indicators": "^1.3.20"
16
15
  },
17
16
  "devDependencies": {
18
17
  "dotenv": "^16.4.5",
@@ -0,0 +1,165 @@
1
+ export const candles = main => {
2
+
3
+ const {ohlcv} = main
4
+
5
+ const cols = getCandlestickPattern(ohlcv)
6
+
7
+ for(let k in cols)
8
+ {
9
+ main.addColumn(`candle_${k}`.toLowerCase(), cols[k])
10
+ }
11
+
12
+ }
13
+
14
+
15
+ export const getCandlestickPattern = ohlcv => {
16
+ const { open, high, low, close } = ohlcv;
17
+ const length = open.length;
18
+
19
+ // Ensure input arrays are valid and of equal length
20
+ if (![open, high, low, close].every(o => Array.isArray(o) && o.length > 1 && o.length === length)) {
21
+ return { pattern: [], name: [], score: [] };
22
+ }
23
+
24
+ // Helper function to check if two numbers are close
25
+ const isCloseTo = (a, b, epsilon = 0.0001) => Math.abs(a - b) < epsilon;
26
+
27
+ // Conditions for bullish and bearish patterns
28
+ const conditions = {
29
+ bullish: [
30
+ {
31
+ name: 'Marubozu',
32
+ condition: (prev, curr) => isCloseTo(curr.open, curr.low) && isCloseTo(curr.close, curr.high),
33
+ score: 3
34
+ },
35
+ {
36
+ name: 'Engulfing',
37
+ condition: (prev, curr) => curr.open < prev.close && curr.close > prev.open && curr.low < prev.low && curr.high > prev.high,
38
+ score: 2
39
+ },
40
+ {
41
+ name: 'Kicker',
42
+ condition: (prev, curr) => curr.open < prev.open && curr.close > curr.open && prev.close < prev.open,
43
+ score: 2
44
+ },
45
+ {
46
+ name: 'Morning Star',
47
+ condition: (prev, curr) => curr.close > prev.close && curr.open < prev.open && prev.close < prev.open,
48
+ score: 2
49
+ },
50
+ {
51
+ name: 'Piercing Line',
52
+ condition: (prev, curr) => curr.close > prev.close && curr.open < prev.open && curr.close > ((prev.open + prev.close) / 2),
53
+ score: 1
54
+ },
55
+ {
56
+ name: 'Belt Hold',
57
+ condition: (prev, curr) => curr.open > prev.open && isCloseTo(curr.close, curr.high) && isCloseTo(prev.close, prev.low),
58
+ score: 1
59
+ },
60
+ {
61
+ name: 'Harami',
62
+ condition: (prev, curr) => curr.open > prev.close && curr.close < prev.open && curr.open < prev.open && curr.close > prev.close,
63
+ score: 1
64
+ },
65
+ {
66
+ name: 'Doji',
67
+ condition: (prev, curr) => isCloseTo(curr.close, curr.open) && (curr.high - curr.low) > Math.abs(curr.close - curr.open),
68
+ score: 0
69
+ }
70
+ ],
71
+ bearish: [
72
+ {
73
+ name: 'Marubozu',
74
+ condition: (prev, curr) => isCloseTo(curr.open, curr.high) && isCloseTo(curr.close, curr.low),
75
+ score: -3
76
+ },
77
+ {
78
+ name: 'Engulfing',
79
+ condition: (prev, curr) => curr.open > prev.close && curr.close < prev.open && curr.high > prev.high && curr.low < prev.low,
80
+ score: -2
81
+ },
82
+ {
83
+ name: 'Kicker',
84
+ condition: (prev, curr) => curr.open > prev.open && curr.close < curr.open && prev.close > prev.open,
85
+ score: -2
86
+ },
87
+ {
88
+ name: 'Evening Star',
89
+ condition: (prev, curr) => curr.close < prev.close && curr.open > prev.open && prev.close < prev.open,
90
+ score: -2
91
+ },
92
+ {
93
+ name: 'Dark Cloud Cover',
94
+ condition: (prev, curr) => curr.close < prev.close && curr.open > prev.open && curr.close < ((prev.open + prev.close) / 2),
95
+ score: -1
96
+ },
97
+ {
98
+ name: 'Belt Hold',
99
+ condition: (prev, curr) => curr.open < prev.open && isCloseTo(curr.close, curr.low) && isCloseTo(prev.close, prev.high),
100
+ score: -1
101
+ },
102
+ {
103
+ name: 'Harami',
104
+ condition: (prev, curr) => curr.open < prev.close && curr.close > prev.open && curr.open > prev.open && curr.close < prev.close,
105
+ score: -1
106
+ },
107
+ {
108
+ name: 'Doji',
109
+ condition: (prev, curr) => isCloseTo(curr.close, curr.open) && (curr.high - curr.low) > Math.abs(curr.close - curr.open),
110
+ score: 0
111
+ }
112
+ ]
113
+ };
114
+
115
+ // Helper function to check priority of patterns
116
+ const priorityCheck = (prev, curr, patterns) => {
117
+ for (const { name, condition, score } of patterns) {
118
+ if (condition(prev, curr)) {
119
+ return { name, score };
120
+ }
121
+ }
122
+ return null;
123
+ };
124
+
125
+ // Arrays to store pattern results
126
+ const patternArray = [];
127
+ const nameArray = [];
128
+ const scoreArray = [];
129
+
130
+ // Loop through each data point starting from the second one
131
+ for (let i = 1; i < length; i++) {
132
+ const prev = {
133
+ open: open[i - 1],
134
+ high: high[i - 1],
135
+ low: low[i - 1],
136
+ close: close[i - 1]
137
+ };
138
+
139
+ const curr = {
140
+ open: open[i],
141
+ high: high[i],
142
+ low: low[i],
143
+ close: close[i]
144
+ };
145
+
146
+ const result = priorityCheck(prev, curr, conditions.bullish) || priorityCheck(prev, curr, conditions.bearish);
147
+
148
+ if (result) {
149
+ patternArray.push(result.score > 0 ? 'Bullish' : 'Bearish');
150
+ nameArray.push(result.name);
151
+ scoreArray.push(result.score);
152
+ } else {
153
+ patternArray.push('');
154
+ nameArray.push('');
155
+ scoreArray.push(0);
156
+ }
157
+ }
158
+
159
+ return {
160
+ pattern: patternArray,
161
+ name: nameArray,
162
+ score: scoreArray
163
+ };
164
+ };
165
+