ohlcv-indicators 1.3.9 → 1.4.1

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,19 +1,22 @@
1
1
 
2
- import {BollingerBands, Big} from 'trading-signals';
2
+ import {BollingerBands, FasterBollingerBands, Big} from 'trading-signals';
3
3
 
4
4
 
5
- export const bollingerBands = (close, size, times) => {
5
+ export const bollingerBands = (main, size, times) => {
6
+
7
+ const {verticalOhlcv, precision} = main
8
+ const {close} = verticalOhlcv
6
9
 
7
10
  const sliceData = close.slice(-(size*3))
8
- const col = getBollingerBands(sliceData, size, times)
11
+ const col = getBollingerBands(sliceData, size, times, precision)
9
12
  return col
10
13
  }
11
14
 
12
- export const getBollingerBands = (data, size = 20, times = 2) => {
15
+ export const getBollingerBands = (data, size = 20, times = 2, precision) => {
13
16
 
14
17
  const dataLength = data.length
15
18
  const output = {bollinger_bands_upper: [], bollinger_bands_middle: [], bollinger_bands_lower: []}
16
- const instance = new BollingerBands(size, times)
19
+ const instance = (precision) ? new BollingerBands(size, times) : new FasterBollingerBands(size, times)
17
20
 
18
21
  for(let x = 0; x < dataLength; x++) {
19
22
  let obj = {}
@@ -35,25 +38,35 @@ export const getBollingerBands = (data, size = 20, times = 2) => {
35
38
  }
36
39
 
37
40
  const {bollinger_bands_upper, bollinger_bands_middle, bollinger_bands_lower} = output
38
- const bollinger_bands_range = bollingerBandsRange(data, {bollinger_bands_upper, bollinger_bands_lower})
41
+ const bollinger_bands_range = bollingerBandsRange(data, {bollinger_bands_upper, bollinger_bands_lower}, precision)
39
42
 
40
43
  return {bollinger_bands_upper, bollinger_bands_middle, bollinger_bands_lower, bollinger_bands_range}
41
44
  }
42
45
 
43
46
 
44
47
 
45
- const bollingerBandsRange = (data, bollingerBands) => {
48
+ const bollingerBandsRange = (data, bollingerBands, precision) => {
46
49
  const { bollinger_bands_upper, bollinger_bands_lower } = bollingerBands;
50
+
47
51
  const output = new Array(data.length);
48
52
 
49
53
  for (let i = 0; i < data.length; i++) {
50
54
  if (bollinger_bands_upper[i] != null && bollinger_bands_lower[i] != null && data[i] != null) {
51
- const upperBig = new Big(bollinger_bands_upper[i]);
52
- const lowerBig = new Big(bollinger_bands_lower[i]);
53
- const dataBig = new Big(data[i]);
54
55
 
55
- const range = upperBig.minus(lowerBig);
56
- output[i] = dataBig.minus(lowerBig).div(range).times(100)
56
+ if(precision)
57
+ {
58
+ const upperBig = new Big(bollinger_bands_upper[i])
59
+ const lowerBig = new Big(bollinger_bands_lower[i])
60
+ const dataBig = new Big(data[i])
61
+ const range = upperBig.minus(lowerBig);
62
+ output[i] = dataBig.minus(lowerBig).div(range).times(100)
63
+ }
64
+ else
65
+ {
66
+ const range = bollinger_bands_upper[i] - bollinger_bands_lower[i]
67
+ output[i] = ((data[i] - bollinger_bands_lower[i]) / range) * 100
68
+ }
69
+
57
70
  } else {
58
71
  output[i] = null;
59
72
  }
@@ -1,19 +1,28 @@
1
1
 
2
- import {EMA} from 'trading-signals'
2
+ import {EMA, FasterEMA} from 'trading-signals'
3
3
 
4
- export const ema = (close, size) => {
4
+ export const ema = (main, size) => {
5
5
 
6
- const col = getEMA(close, size)
6
+ const {verticalOhlcv, precision} = main
7
+ const {close} = verticalOhlcv
8
+
9
+ const col = getEMA(close, size, precision)
7
10
 
8
11
  return {
9
12
  [`ema_${size}`]: col
10
13
  }
11
14
  }
12
15
 
13
- export const getEMA = (data, size) => {
16
+ export const getEMA = (data, size, precision) => {
14
17
 
18
+
19
+ if(typeof precision === 'undefined' || typeof data === 'undefined' || typeof size === 'undefined')
20
+ {
21
+ throw Error('undefined param in getEMA')
22
+ }
23
+
15
24
  const output = []
16
- const instance = new EMA(size)
25
+ const instance = (precision) ? new EMA(size) : new FasterEMA(size)
17
26
  const dataLength = data.length
18
27
 
19
28
  for(let x = 0; x < dataLength; x++)
@@ -1,28 +1,30 @@
1
1
  import { findCrosses } from "../studies/findCrosses.js";
2
- import {EMA, MACD} from 'trading-signals';
2
+ import {EMA, MACD, FasterEMA, FasterMACD} from 'trading-signals';
3
3
 
4
4
 
5
- export const macd = (close, fastLine, slowLine, signalLine) => {
5
+ export const macd = (main, fastLine, slowLine, signalLine) => {
6
6
 
7
+ const {verticalOhlcv, precision} = main
8
+ const {close} = verticalOhlcv
7
9
  const maxSize = Math.max(fastLine, slowLine, signalLine)
8
10
  const sliceData = close.slice(-(maxSize*3))
9
- const col = getMACD(sliceData, fastLine, slowLine, signalLine)
11
+ const col = getMACD(sliceData, fastLine, slowLine, signalLine, precision)
10
12
 
11
13
  return col
12
14
  }
13
15
 
14
- export const getMACD = (data, fastLine = 12, slowLine = 26, signalLine = 9) => {
16
+ export const getMACD = (data, fastLine = 12, slowLine = 26, signalLine = 9, precision) => {
15
17
 
16
18
  const diff = []
17
19
  const dea = []
18
20
  const histogram = []
19
21
 
20
- const instance = new MACD({
22
+ const instance = (precision) ? new MACD({
21
23
  indicator: EMA,
22
24
  shortInterval: fastLine,
23
25
  longInterval: slowLine,
24
26
  signalInterval: signalLine
25
- })
27
+ }) : new FasterMACD(new FasterEMA(fastLine), new FasterEMA(slowLine), new FasterEMA(signalLine))
26
28
 
27
29
  const dataLength = data.length
28
30
 
@@ -45,7 +47,7 @@ export const getMACD = (data, fastLine = 12, slowLine = 26, signalLine = 9) => {
45
47
  histogram.push(obj.histogram)
46
48
  }
47
49
 
48
- const x = findCrosses(diff, dea)
50
+ const x = findCrosses(diff, dea, precision)
49
51
 
50
52
  return {
51
53
  macd_diff: diff,
@@ -1,8 +1,8 @@
1
1
  import { getSMA } from './sma.js'
2
2
 
3
3
  export const RelativeVolume = (main, size) => {
4
- const {ohlcv} = main
5
- const data = ohlcv['volume']
4
+ const {verticalOhlcv} = main
5
+ const data = verticalOhlcv['volume']
6
6
  const relVolume = getRelativeVolume(main.BigNumber, data, size)
7
7
  main.addColumn(`relative_volume_${size}`, relVolume)
8
8
  }
@@ -1,19 +1,27 @@
1
1
 
2
- import {SMA} from 'trading-signals';
2
+ import {SMA, FasterSMA} from 'trading-signals';
3
3
 
4
- export const sma = (close, size) => {
4
+ export const sma = (main, size) => {
5
5
 
6
- const col = getSMA(close, size)
6
+ const {verticalOhlcv, precision} = main
7
+ const {close} = verticalOhlcv
8
+
9
+ const col = getSMA(close, size, precision)
7
10
 
8
11
  return {
9
12
  [`sma_${size}`]: col
10
13
  }
11
14
  }
12
15
 
13
- export const getSMA = (data, size) => {
16
+ export const getSMA = (data, size, precision) => {
14
17
 
18
+ if(typeof precision === 'undefined' || typeof data === 'undefined' || typeof size === 'undefined')
19
+ {
20
+ throw Error('undefined param in getSMA')
21
+ }
22
+
15
23
  const output = []
16
- const instance = new SMA(size)
24
+ const instance = (precision) ? new SMA(size) : new FasterSMA(size)
17
25
  const dataLength = data.length
18
26
 
19
27
  for(let x = 0; x < dataLength; x++)
@@ -1,11 +1,14 @@
1
1
  import { getSMA } from "../moving-averages/sma.js";
2
2
  import { getEMA } from "../moving-averages/ema.js";
3
3
  import { findCrosses } from "../studies/findCrosses.js";
4
- import {RSI} from 'trading-signals';
4
+ import {RSI, FasterRSI} from 'trading-signals';
5
5
 
6
6
  const ma = {getSMA, getEMA}
7
7
 
8
- export const rsi = (close, period, movingAverage, movingAveragePeriod) => {
8
+ export const rsi = (main, period, movingAverage, movingAveragePeriod) => {
9
+
10
+ const {verticalOhlcv, precision} = main
11
+ const {close} = verticalOhlcv
9
12
 
10
13
  const sliceData = close.slice(-(period*3))
11
14
 
@@ -14,12 +17,12 @@ export const rsi = (close, period, movingAverage, movingAveragePeriod) => {
14
17
  movingAveragePeriod = period
15
18
  }
16
19
 
17
- const col = getRSI(sliceData, period, movingAverage, movingAveragePeriod)
20
+ const col = getRSI(sliceData, period, movingAverage, movingAveragePeriod, precision)
18
21
 
19
22
  return col
20
23
  }
21
24
 
22
- export const getRSI = (data, period = 14, movingAverage = 'SMA', movingAveragePeriod = 14) => {
25
+ export const getRSI = (data, period = 14, movingAverage = 'SMA', movingAveragePeriod = 14, precision) => {
23
26
 
24
27
 
25
28
  if (data.length < period) {
@@ -29,7 +32,7 @@ export const getRSI = (data, period = 14, movingAverage = 'SMA', movingAveragePe
29
32
  let rsi = []
30
33
  period = parseInt(period)
31
34
  movingAveragePeriod = parseInt(movingAveragePeriod)
32
- const instance = new RSI(period)
35
+ const instance = (precision) ? new RSI(period) : new FasterRSI(period)
33
36
  const dataLength = data.length
34
37
 
35
38
  for(let x = 0; x < dataLength; x++)
@@ -57,9 +60,9 @@ export const getRSI = (data, period = 14, movingAverage = 'SMA', movingAveragePe
57
60
  {
58
61
  if(ma.hasOwnProperty(`get${movingAverage}`))
59
62
  {
60
- const rsi_smoothed = ma[`get${movingAverage}`](rsi, movingAveragePeriod)
63
+ const rsi_smoothed = ma[`get${movingAverage}`](rsi, movingAveragePeriod, precision)
61
64
  output[`rsi_${movingAverage}_${movingAveragePeriod}`] = rsi_smoothed
62
- output[`rsi_${period}_x_rsi_${movingAverage}_${movingAveragePeriod}`] = findCrosses(rsi, rsi_smoothed)
65
+ output[`rsi_${period}_x_rsi_${movingAverage}_${movingAveragePeriod}`] = findCrosses(rsi, rsi_smoothed, precision)
63
66
  }
64
67
  }
65
68
 
@@ -1,171 +1,268 @@
1
- export const candles = ohlcv => {
1
+ export const candles = main => {
2
2
 
3
- const cols = getCandlestickPattern(ohlcv);
3
+ const {inputOhlcv} = main
4
+ const cols = getCandlestickPattern(inputOhlcv);
4
5
  return cols;
5
6
  }
6
7
 
7
- export const getCandlestickPattern = ohlcv => {
8
- const { open, high, low, close } = ohlcv;
9
- const length = open.length;
8
+ export const getCandlestickPattern = inputOhlcv => {
9
+ const size = 2; //remove slice for backtesting
10
+ inputOhlcv = inputOhlcv.slice(-size);
10
11
 
11
- // Ensure input arrays are valid and of equal length
12
- if (![open, high, low, close].every(o => Array.isArray(o) && o.length > 1 && o.length === length)) {
13
- return { pattern: Array(length).fill('Neutral'), name: Array(length).fill('No Pattern'), score: Array(length).fill(0) };
14
- }
12
+ const candle_pattern = [];
13
+ const candle_name = [];
14
+ const candle_score = [];
15
15
 
16
- // Helper function to check if two numbers are close
17
- const isCloseTo = (a, b, epsilon = 0.0001) => Math.abs(a - b) < epsilon;
18
- const isUp = o => o.close > o.open
19
- const isDown = o => o.close < o.open
20
- const isDouble = (large, small) => large > (small * 2)
21
-
22
- // Conditions for bullish and bearish patterns
23
- const conditions = {
24
- bullish: [
25
- {
26
- name: 'Marubozu',
27
- condition: (prev2, prev, curr) => isDown(prev2) && isDown(prev) && isUp(curr) && isDouble(curr, prev),
28
- score: 2
29
- },
30
- {
31
- name: 'Engulfing',
32
- condition: (prev, curr) => curr.open < prev.close && curr.close > prev.open && curr.low < prev.low && curr.high > prev.high,
33
- score: 2
34
- },
35
- {
36
- name: 'Kicker',
37
- condition: (prev, curr) => curr.open < prev.open && curr.close > curr.open && prev.close < prev.open,
38
- score: 2
39
- },
40
- {
41
- name: 'Morning Star',
42
- condition: (prev2, prev, curr) => prev2.close > prev2.open && prev.close < prev.open && curr.close > prev.open,
43
- score: 3
44
- },
45
- {
46
- name: 'Piercing Line',
47
- condition: (prev, curr) => curr.close > prev.close && curr.open < prev.open && curr.close > ((prev.open + prev.close) / 2),
48
- score: 1
49
- },
50
- {
51
- name: 'Belt Hold',
52
- condition: (prev, curr) => curr.open > prev.open && isCloseTo(curr.close, curr.high) && isCloseTo(prev.close, prev.low),
53
- score: 1
54
- },
55
- {
56
- name: 'Harami',
57
- condition: (prev, curr) => curr.open > prev.close && curr.close < prev.open && curr.open < prev.open && curr.close > prev.close,
58
- score: 1
59
- },
60
- {
61
- name: 'Doji',
62
- condition: (prev, curr) => isCloseTo(curr.close, curr.open) && (curr.high - curr.low) > Math.abs(curr.close - curr.open),
63
- score: 0
64
- }
65
- ],
66
- bearish: [
67
- {
68
- name: 'Marubozu',
69
- condition: (prev, curr) => isCloseTo(curr.open, curr.high) && isCloseTo(curr.close, curr.low),
70
- score: -2
71
- },
72
- {
73
- name: 'Engulfing',
74
- condition: (prev, curr) => curr.open > prev.close && curr.close < prev.open && curr.high > prev.high && curr.low < prev.low,
75
- score: -2
76
- },
77
- {
78
- name: 'Kicker',
79
- condition: (prev, curr) => curr.open > prev.open && curr.close < curr.open && prev.close > prev.open,
80
- score: -2
81
- },
82
- {
83
- name: 'Evening Star',
84
- condition: (prev2, prev, curr) => prev2.close < prev2.open && prev.close > prev.open && curr.close < prev.open,
85
- score: -3
86
- },
87
- {
88
- name: 'Dark Cloud Cover',
89
- condition: (prev, curr) => curr.close < prev.close && curr.open > prev.open && curr.close < ((prev.open + prev.close) / 2),
90
- score: -1
91
- },
92
- {
93
- name: 'Belt Hold',
94
- condition: (prev, curr) => curr.open < prev.open && isCloseTo(curr.close, curr.low) && isCloseTo(prev.close, prev.high),
95
- score: -1
96
- },
97
- {
98
- name: 'Harami',
99
- condition: (prev, curr) => curr.open < prev.close && curr.close > prev.open && curr.open > prev.open && curr.close < prev.close,
100
- score: -1
101
- },
102
- {
103
- name: 'Doji',
104
- condition: (prev, curr) => isCloseTo(curr.close, curr.open) && (curr.high - curr.low) > Math.abs(curr.close - curr.open),
105
- score: 0
106
- }
107
- ]
108
- };
109
-
110
- // Helper function to check priority of patterns
111
- const priorityCheck = (prev, curr, patterns, prev2 = null) => {
112
- for (const { name, condition, score } of patterns) {
113
- if (prev2) {
114
- if (condition(prev2, prev, curr)) {
115
- return { name, score };
16
+ for (let x = 1; x < size; x++) {
17
+ const curr = inputOhlcv[x];
18
+ const prev = inputOhlcv[x - 1];
19
+
20
+ let pattern = 'Neutral';
21
+ let name = 'None';
22
+ let score = 0;
23
+
24
+ for (const patternObj of candlePatterns) {
25
+ const { isSingleCandle, candle_name: patternName, candle_score: patternScore } = patternObj;
26
+ const isMatch = isSingleCandle
27
+ ? candleFunctions[patternName](curr)
28
+ : candleFunctions[patternName](prev, curr);
29
+
30
+ if (isMatch) {
31
+ if (score === 0) {
32
+ pattern = patternScore === 1 ? 'Bullish' : 'Bearish';
33
+ name = patternName;
34
+ score = patternScore;
35
+ } else if (score !== patternScore) {
36
+ pattern = 'Neutral';
37
+ name = 'None';
38
+ score = 0;
39
+ break;
40
+ } else {
41
+ name += `,${patternName}`;
116
42
  }
117
- } else if (condition(prev, curr)) {
118
- return { name, score };
119
43
  }
120
44
  }
121
- return null;
122
- };
123
-
124
- // Arrays to store pattern results
125
- const patternArray = ['Neutral'];
126
- const nameArray = ['No Pattern'];
127
- const scoreArray = [0];
128
-
129
- // Loop through each data point starting from the second one
130
- for (let i = 2; i < length; i++) {
131
- const prev = {
132
- open: open[i - 1],
133
- high: high[i - 1],
134
- low: low[i - 1],
135
- close: close[i - 1]
136
- };
137
-
138
- const curr = {
139
- open: open[i],
140
- high: high[i],
141
- low: low[i],
142
- close: close[i]
143
- };
144
-
145
- const prev2 = {
146
- open: open[i - 2],
147
- high: high[i - 2],
148
- low: low[i - 2],
149
- close: close[i - 2]
150
- }
151
45
 
152
- const result = prev2 ? priorityCheck(prev, curr, conditions.bullish, prev2) || priorityCheck(prev, curr, conditions.bearish, prev2) :
153
- priorityCheck(prev, curr, conditions.bullish) || priorityCheck(prev, curr, conditions.bearish);
154
-
155
- if (result) {
156
- patternArray.push(result.score > 0 ? 'Bullish' : 'Bearish');
157
- nameArray.push(result.name);
158
- scoreArray.push(result.score);
159
- } else {
160
- patternArray.push('Neutral');
161
- nameArray.push('No Pattern');
162
- scoreArray.push(0);
163
- }
46
+ candle_pattern.push(pattern);
47
+ candle_name.push(name);
48
+ candle_score.push(score);
164
49
  }
165
50
 
166
51
  return {
167
- candle_pattern: patternArray,
168
- candle_name: nameArray,
169
- candle_score: scoreArray
52
+ candle_pattern,
53
+ candle_name,
54
+ candle_score
170
55
  }
171
56
  }
57
+
58
+
59
+
60
+
61
+ const candlePatterns = [
62
+ {
63
+ candle_name: "isHammer",
64
+ candle_score: 1,
65
+ isSingleCandle: true
66
+ },
67
+ {
68
+ candle_name: "isInvertedHammer",
69
+ candle_score: 1,
70
+ isSingleCandle: true
71
+ },
72
+ {
73
+ candle_name: "isBullishHammer",
74
+ candle_score: 1,
75
+ isSingleCandle: true
76
+ },
77
+ {
78
+ candle_name: "isBearishHammer",
79
+ candle_score: -1,
80
+ isSingleCandle: true
81
+ },
82
+ {
83
+ candle_name: "isBullishInvertedHammer",
84
+ candle_score: 1,
85
+ isSingleCandle: true
86
+ },
87
+ {
88
+ candle_name: "isBearishInvertedHammer",
89
+ candle_score: -1,
90
+ isSingleCandle: true
91
+ },
92
+ {
93
+ candle_name: "isHangingMan",
94
+ candle_score: -1,
95
+ isSingleCandle: false
96
+ },
97
+ {
98
+ candle_name: "isShootingStar",
99
+ candle_score: -1,
100
+ isSingleCandle: false
101
+ },
102
+ {
103
+ candle_name: "isBullishEngulfing",
104
+ candle_score: 1,
105
+ isSingleCandle: false
106
+ },
107
+ {
108
+ candle_name: "isBearishEngulfing",
109
+ candle_score: -1,
110
+ isSingleCandle: false
111
+ },
112
+ {
113
+ candle_name: "isBullishHarami",
114
+ candle_score: 1,
115
+ isSingleCandle: false
116
+ },
117
+ {
118
+ candle_name: "isBearishHarami",
119
+ candle_score: -1
120
+ },
121
+ {
122
+ candle_name: "isBullishKicker",
123
+ candle_score: 1,
124
+ isSingleCandle: false
125
+ },
126
+ {
127
+ candle_name: "isBearishKicker",
128
+ candle_score: -1,
129
+ isSingleCandle: false
130
+ }
131
+ ]
132
+
133
+
134
+ const bodyLen = candlestick => Math.abs(candlestick.open - candlestick.close);
135
+
136
+ const wickLen = candlestick => candlestick.high - Math.max(candlestick.open, candlestick.close);
137
+
138
+ const tailLen = candlestick => Math.min(candlestick.open, candlestick.close) - candlestick.low;
139
+
140
+ const bodyEnds = candlestick => candlestick.open <= candlestick.close ?
141
+ { bottom: candlestick.open, top: candlestick.close } :
142
+ { bottom: candlestick.close, top: candlestick.open };
143
+
144
+ const isBullish = candlestick => candlestick.open < candlestick.close;
145
+
146
+ const isBearish = candlestick => candlestick.open > candlestick.close;
147
+
148
+ const isEngulfed = (previous, current) =>
149
+ bodyEnds(previous).top <= bodyEnds(current).top &&
150
+ bodyEnds(previous).bottom >= bodyEnds(current).bottom;
151
+
152
+ const hasGapUp = (previous, current) =>
153
+ bodyEnds(previous).top < bodyEnds(current).bottom;
154
+
155
+ const hasGapDown = (previous, current) =>
156
+ bodyEnds(previous).bottom > bodyEnds(current).top;
157
+
158
+ const isHammer = candlestick =>
159
+ tailLen(candlestick) > (bodyLen(candlestick) * 2) &&
160
+ wickLen(candlestick) < bodyLen(candlestick);
161
+
162
+ const isInvertedHammer = candlestick =>
163
+ wickLen(candlestick) > (bodyLen(candlestick) * 2) &&
164
+ tailLen(candlestick) < bodyLen(candlestick);
165
+
166
+ const isBullishHammer = candlestick =>
167
+ isBullish(candlestick) && isHammer(candlestick);
168
+
169
+ const isBearishHammer = candlestick =>
170
+ isBearish(candlestick) && isHammer(candlestick);
171
+
172
+ const isBullishInvertedHammer = candlestick =>
173
+ isBullish(candlestick) && isInvertedHammer(candlestick);
174
+
175
+ const isBearishInvertedHammer = candlestick =>
176
+ isBearish(candlestick) && isInvertedHammer(candlestick);
177
+
178
+ const isHangingMan = (previous, current) =>
179
+ isBullish(previous) && isBearishHammer(current) && hasGapUp(previous, current);
180
+
181
+ const isShootingStar = (previous, current) =>
182
+ isBullish(previous) && isBearishInvertedHammer(current) && hasGapUp(previous, current);
183
+
184
+ const isBullishEngulfing = (previous, current) =>
185
+ isBearish(previous) && isBullish(current) && isEngulfed(previous, current);
186
+
187
+ const isBearishEngulfing = (previous, current) =>
188
+ isBullish(previous) && isBearish(current) && isEngulfed(previous, current);
189
+
190
+ const isBullishHarami = (previous, current) =>
191
+ isBearish(previous) && isBullish(current) && isEngulfed(current, previous);
192
+
193
+ const isBearishHarami = (previous, current) =>
194
+ isBullish(previous) && isBearish(current) && isEngulfed(current, previous);
195
+
196
+ const isBullishKicker = (previous, current) =>
197
+ isBearish(previous) && isBullish(current) && hasGapUp(previous, current) &&
198
+ !(isHammer(current) || isInvertedHammer(current));
199
+
200
+ const isBearishKicker = (previous, current) =>
201
+ isBullish(previous) && isBearish(current) && hasGapDown(previous, current) &&
202
+ !(isHammer(current) || isInvertedHammer(current));
203
+
204
+ const findPattern = (dataArray, callback) => {
205
+ const paramCount = callback.length;
206
+ const upperBound = dataArray.length - paramCount;
207
+ const results = [];
208
+
209
+ for (let i = 0; i <= upperBound; i++) {
210
+ const values = [];
211
+
212
+ for (let j = 0; j < paramCount; j++) {
213
+ values.push(dataArray[i + j]);
214
+ }
215
+
216
+ if (callback(...values)) {
217
+ results.push(i);
218
+ }
219
+ }
220
+
221
+ return results;
222
+ }
223
+
224
+ const hammer = dataArray => findPattern(dataArray, isHammer);
225
+
226
+ const invertedHammer = dataArray => findPattern(dataArray, isInvertedHammer);
227
+
228
+ const bullishHammer = dataArray => findPattern(dataArray, isBullishHammer);
229
+
230
+ const bearishHammer = dataArray => findPattern(dataArray, isBearishHammer);
231
+
232
+ const bullishInvertedHammer = dataArray => findPattern(dataArray, isBullishInvertedHammer);
233
+
234
+ const bearishInvertedHammer = dataArray => findPattern(dataArray, isBearishInvertedHammer);
235
+
236
+ const hangingMan = dataArray => findPattern(dataArray, isHangingMan);
237
+
238
+ const shootingStar = dataArray => findPattern(dataArray, isShootingStar);
239
+
240
+ const bullishEngulfing = dataArray => findPattern(dataArray, isBullishEngulfing);
241
+
242
+ const bearishEngulfing = dataArray => findPattern(dataArray, isBearishEngulfing);
243
+
244
+ const bullishHarami = dataArray => findPattern(dataArray, isBullishHarami);
245
+
246
+ const bearishHarami = dataArray => findPattern(dataArray, isBearishHarami);
247
+
248
+ const bullishKicker = dataArray => findPattern(dataArray, isBullishKicker);
249
+
250
+ const bearishKicker = dataArray => findPattern(dataArray, isBearishKicker)
251
+
252
+
253
+ const candleFunctions = {
254
+ isHammer,
255
+ isInvertedHammer,
256
+ isBullishHammer,
257
+ isBearishHammer,
258
+ isBullishInvertedHammer,
259
+ isBearishInvertedHammer,
260
+ isHangingMan,
261
+ isShootingStar,
262
+ isBullishEngulfing,
263
+ isBearishEngulfing,
264
+ isBullishHarami,
265
+ isBearishHarami,
266
+ isBullishKicker,
267
+ isBearishKicker
268
+ }