ohlcv-indicators 1.3.8 → 1.4.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/dist/ohlcv-indicators.min.js +1 -1
- package/index.js +75 -91
- package/package.json +1 -1
- package/src/moving-averages/bollingerBands.js +26 -13
- package/src/moving-averages/ema.js +14 -5
- package/src/moving-averages/macd.js +9 -7
- package/src/moving-averages/relativeVolume.js +2 -2
- package/src/moving-averages/sma.js +13 -5
- package/src/oscillators/rsi.js +10 -7
- package/src/studies/candles.js +253 -156
- package/src/studies/findCrosses.js +27 -16
- package/src/studies/volumeProfile.js +4 -4
- package/src/studies/chart.js +0 -466
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import {Big} from 'trading-signals';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
// Function to find crosses between two arrays: fast and slow
|
|
5
|
-
export const findCrosses = (fast, slow) => {
|
|
4
|
+
export const findCrosses = (fast, slow, precision) => {
|
|
6
5
|
// Map states based on comparison of fast and slow arrays
|
|
7
6
|
|
|
8
|
-
fast = fast.filter(o => o instanceof Big)
|
|
9
|
-
slow = slow.filter(o => o instanceof Big)
|
|
7
|
+
fast = fast.filter(o => o instanceof Big || typeof o === 'number')
|
|
8
|
+
slow = slow.filter(o => o instanceof Big || typeof o === 'number')
|
|
9
|
+
|
|
10
10
|
const min = Math.min(fast.length, slow.length)
|
|
11
11
|
|
|
12
|
-
fast = fast.slice(-min)
|
|
13
|
-
slow = slow.slice(-min)
|
|
12
|
+
fast = fast.slice(-min)
|
|
13
|
+
slow = slow.slice(-min)
|
|
14
14
|
|
|
15
15
|
let state = fast.map((f, i) => {
|
|
16
|
-
if(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
if(precision)
|
|
17
|
+
{
|
|
18
|
+
if(f.eq(slow[i])) return 'neutral'
|
|
19
|
+
else if(f.gt(slow[i])) return 'up'
|
|
20
|
+
else if(f.lt(slow[i])) return 'down'
|
|
21
|
+
}
|
|
22
|
+
else
|
|
23
|
+
{
|
|
24
|
+
if(f === slow[i]) return 'neutral'
|
|
25
|
+
else if(f > slow[i]) return 'up'
|
|
26
|
+
else if(f < slow[i]) return 'down'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
throw Error('undefined error in findCrosses')
|
|
20
30
|
})
|
|
21
31
|
|
|
22
32
|
const groups = groupConsecutiveValues(state)
|
|
@@ -75,8 +85,9 @@ const groupConsecutiveValues = arr => {
|
|
|
75
85
|
|
|
76
86
|
|
|
77
87
|
|
|
78
|
-
export const crossPairs = (
|
|
88
|
+
export const crossPairs = (main, arr) => {
|
|
79
89
|
|
|
90
|
+
const {verticalOhlcv, precision} = main
|
|
80
91
|
const slowNumArrCache = {};
|
|
81
92
|
const output = {}
|
|
82
93
|
|
|
@@ -87,21 +98,21 @@ export const crossPairs = (ohlcv, arr) => {
|
|
|
87
98
|
// Prepare slowNumArr if 'slow' is a number
|
|
88
99
|
if (typeof slow === 'number' && !slowNumArrCache[slow]) {
|
|
89
100
|
|
|
90
|
-
slowNumArrCache[slow] = Array(
|
|
101
|
+
slowNumArrCache[slow] = Array(verticalOhlcv.close.length).fill(new Big(slow))
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
const keyName = `${fast}_x_${slow}`
|
|
94
105
|
|
|
95
106
|
// Find and add crosses
|
|
96
|
-
if (
|
|
107
|
+
if (verticalOhlcv[fast] && verticalOhlcv[slow]) {
|
|
97
108
|
|
|
98
|
-
const cross = findCrosses(
|
|
109
|
+
const cross = findCrosses(verticalOhlcv[fast], verticalOhlcv[slow], precision);
|
|
99
110
|
|
|
100
111
|
output[keyName] = cross
|
|
101
112
|
|
|
102
113
|
|
|
103
|
-
} else if (
|
|
104
|
-
const cross = findCrosses(
|
|
114
|
+
} else if (verticalOhlcv[fast] && slowNumArrCache[slow]) {
|
|
115
|
+
const cross = findCrosses(verticalOhlcv[fast], slowNumArrCache[slow], precision)
|
|
105
116
|
|
|
106
117
|
output[keyName] = cross
|
|
107
118
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export const volumeProfile = (
|
|
1
|
+
export const volumeProfile = (verticalOhlcv, numBins, daysBack = 1, targetDateKey) => {
|
|
2
2
|
|
|
3
|
-
const filteredOhlcv = filterLastDays(
|
|
3
|
+
const filteredOhlcv = filterLastDays(verticalOhlcv, daysBack, targetDateKey)
|
|
4
4
|
const vP = calculateBins(filteredOhlcv, numBins)
|
|
5
5
|
const vp_high = vP.nodes.high.price
|
|
6
6
|
const vp_low = vP.nodes.low.price
|
|
@@ -12,8 +12,8 @@ export const volumeProfile = (ohlcv, numBins, daysBack = 1, targetDateKey) => {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
export const calculateBins = (
|
|
16
|
-
const { open, high, low, close, volume } =
|
|
15
|
+
export const calculateBins = (verticalOhlcv, numBins = 5) => {
|
|
16
|
+
const { open, high, low, close, volume } = verticalOhlcv;
|
|
17
17
|
|
|
18
18
|
// Determine the range of prices
|
|
19
19
|
const lowPrice = Math.min(...low);
|
package/src/studies/chart.js
DELETED
|
@@ -1,466 +0,0 @@
|
|
|
1
|
-
export default class ChartPatterns {
|
|
2
|
-
|
|
3
|
-
constructor(ohlcv, period = 100) {
|
|
4
|
-
const validProps = ['open', 'high', 'low', 'close'];
|
|
5
|
-
this.ohlcv = {};
|
|
6
|
-
|
|
7
|
-
for (let key of Object.keys(ohlcv)) {
|
|
8
|
-
if (validProps.includes(key)) {
|
|
9
|
-
this.ohlcv[key] = ohlcv[key].slice(-period);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
init() {
|
|
15
|
-
const length = this.ohlcv.close.length;
|
|
16
|
-
if (length < 50) {
|
|
17
|
-
console.log('PatternRecognizer requires at least 50 datapoints')
|
|
18
|
-
return { chart_pattern: 'Neutral', chart_score: 0 };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const patterns = [
|
|
22
|
-
{ name: 'Bullish Flag', condition: this.isBullishFlag.bind(this), score: 2 },
|
|
23
|
-
{ name: 'Bearish Flag', condition: this.isBearishFlag.bind(this), score: -2 },
|
|
24
|
-
{ name: 'Bullish Pennant', condition: this.isBullishPennant.bind(this), score: 2 },
|
|
25
|
-
{ name: 'Bearish Pennant', condition: this.isBearishPennant.bind(this), score: -2 },
|
|
26
|
-
{ name: 'Bearish Double Top', condition: this.isDoubleTop.bind(this), score: -1 },
|
|
27
|
-
{ name: 'Bullish Double Bottom', condition: this.isDoubleBottom.bind(this), score: 1 },
|
|
28
|
-
{ name: 'Bearish Triple Top', condition: this.isTripleTop.bind(this), score: -1 },
|
|
29
|
-
{ name: 'Bullish Triple Bottom', condition: this.isTripleBottom.bind(this), score: 1 },
|
|
30
|
-
{ name: 'Bearish Head And Shoulders', condition: this.isHeadAndShoulders.bind(this), score: -1 },
|
|
31
|
-
{ name: 'Bullish Inverse Head And Shoulders', condition: this.isInverseHeadAndShoulders.bind(this), score: 1 },
|
|
32
|
-
{ name: 'Bearish Rising Wedge', condition: this.isRisingWedge.bind(this), score: -1 },
|
|
33
|
-
{ name: 'Bullish Falling Wedge', condition: this.isFallingWedge.bind(this), score: 1 },
|
|
34
|
-
{ name: 'Bullish Triangle', condition: this.isBullishTriangle.bind(this), score: 1 },
|
|
35
|
-
{ name: 'Bearish Triangle', condition: this.isBearishTriangle.bind(this), score: -1 },
|
|
36
|
-
{ name: 'Bullish Rectangle', condition: this.isBullishRectangle.bind(this), score: 1 },
|
|
37
|
-
{ name: 'Bearish Rectangle', condition: this.isBearishRectangle.bind(this), score: -1 },
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
for (const { name, condition, score } of patterns) {
|
|
41
|
-
if (condition()) {
|
|
42
|
-
return { chart_pattern: name, chart_score: score };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return { chart_pattern: 'Neutral', chart_score: 0 };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// Implementation of Bullish Flag
|
|
51
|
-
// https://www.tradingview.com/support/solutions/43000653209/
|
|
52
|
-
|
|
53
|
-
isBullishFlag() {
|
|
54
|
-
|
|
55
|
-
// A Bullish Flag is characterized by a sharp price rise followed by a period of consolidation that has a downward slant.
|
|
56
|
-
const length = this.ohlcv.close.length;
|
|
57
|
-
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
58
|
-
const consolidationLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
59
|
-
|
|
60
|
-
// Sharp price rise (flagpole)
|
|
61
|
-
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
62
|
-
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
63
|
-
const flagpoleGain = (flagpoleEnd - flagpoleStart) / flagpoleStart;
|
|
64
|
-
|
|
65
|
-
if (flagpoleGain < 0.15) { // A significant gain, at least 15%
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Consolidation period
|
|
70
|
-
const consolidationStart = this.ohlcv.close[length - flagpoleLength];
|
|
71
|
-
const consolidationEnd = this.ohlcv.close[length - 1];
|
|
72
|
-
const consolidationDrop = (consolidationStart - consolidationEnd) / consolidationStart;
|
|
73
|
-
|
|
74
|
-
if (consolidationDrop > 0.05) { // A downward slant, less than 5%
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Ensure that the consolidation period has lower highs and lower lows
|
|
79
|
-
for (let i = length - flagpoleLength; i < length - 1; i++) {
|
|
80
|
-
if (this.ohlcv.high[i] > this.ohlcv.high[i + 1] || this.ohlcv.low[i] > this.ohlcv.low[i + 1]) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Implementation of Bearish Flag
|
|
89
|
-
// https://www.tradingview.com/support/solutions/43000653209-chart-pattern-bullish-flag/
|
|
90
|
-
isBearishFlag() {
|
|
91
|
-
// A Bearish Flag is characterized by a sharp price decline followed by a period of consolidation that has an upward slant.
|
|
92
|
-
const length = this.ohlcv.close.length;
|
|
93
|
-
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
94
|
-
const consolidationLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
95
|
-
|
|
96
|
-
// Sharp price decline (flagpole)
|
|
97
|
-
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
98
|
-
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
99
|
-
const flagpoleDrop = (flagpoleStart - flagpoleEnd) / flagpoleStart;
|
|
100
|
-
|
|
101
|
-
if (flagpoleDrop < 0.15) { // A significant drop, at least 15%
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Consolidation period
|
|
106
|
-
const consolidationStart = this.ohlcv.close[length - flagpoleLength];
|
|
107
|
-
const consolidationEnd = this.ohlcv.close[length - 1];
|
|
108
|
-
const consolidationGain = (consolidationEnd - consolidationStart) / consolidationStart;
|
|
109
|
-
|
|
110
|
-
if (consolidationGain > 0.05) { // An upward slant, less than 5%
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Ensure that the consolidation period has higher lows and higher highs
|
|
115
|
-
for (let i = length - flagpoleLength; i < length - 1; i++) {
|
|
116
|
-
if (this.ohlcv.high[i] < this.ohlcv.high[i + 1] || this.ohlcv.low[i] < this.ohlcv.low[i + 1]) {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Implementation of Bullish Pennant
|
|
125
|
-
// https://www.tradingview.com/support/solutions/43000653215-chart-pattern-bullish-pennant/
|
|
126
|
-
isBullishPennant() {
|
|
127
|
-
// A Bullish Pennant is characterized by a sharp price rise followed by a small symmetrical triangle consolidation.
|
|
128
|
-
const length = this.ohlcv.close.length;
|
|
129
|
-
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
130
|
-
const pennantLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
131
|
-
|
|
132
|
-
// Sharp price rise (flagpole)
|
|
133
|
-
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
134
|
-
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
135
|
-
const flagpoleGain = (flagpoleEnd - flagpoleStart) / flagpoleStart;
|
|
136
|
-
|
|
137
|
-
if (flagpoleGain < 0.15) { // A significant gain, at least 15%
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Small symmetrical triangle consolidation
|
|
142
|
-
const pennantStart = this.ohlcv.close[length - flagpoleLength];
|
|
143
|
-
const pennantEnd = this.ohlcv.close[length - 1];
|
|
144
|
-
const pennantDrop = (pennantStart - pennantEnd) / pennantStart;
|
|
145
|
-
|
|
146
|
-
if (pennantDrop > 0.05) { // A downward slant, less than 5%
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Ensure the consolidation period forms a small symmetrical triangle
|
|
151
|
-
for (let i = length - pennantLength; i < length - 1; i++) {
|
|
152
|
-
if ((this.ohlcv.high[i] < this.ohlcv.high[i + 1] && this.ohlcv.low[i] < this.ohlcv.low[i + 1]) ||
|
|
153
|
-
(this.ohlcv.high[i] > this.ohlcv.high[i + 1] && this.ohlcv.low[i] > this.ohlcv.low[i + 1])) {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Implementation of Bearish Pennant
|
|
162
|
-
// https://www.tradingview.com/support/solutions/43000697937-chart-pattern-bearish-pennant/
|
|
163
|
-
isBearishPennant() {
|
|
164
|
-
const length = this.ohlcv.close.length;
|
|
165
|
-
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
166
|
-
const pennantLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
167
|
-
|
|
168
|
-
// Sharp price decline (flagpole)
|
|
169
|
-
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
170
|
-
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
171
|
-
const flagpoleDrop = (flagpoleStart - flagpoleEnd) / flagpoleStart;
|
|
172
|
-
|
|
173
|
-
if (flagpoleDrop < 0.15) { // A significant drop, at least 15%
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Small symmetrical triangle consolidation
|
|
178
|
-
const pennantStart = this.ohlcv.close[length - flagpoleLength];
|
|
179
|
-
const pennantEnd = this.ohlcv.close[length - 1];
|
|
180
|
-
const pennantGain = (pennantEnd - pennantStart) / pennantStart;
|
|
181
|
-
|
|
182
|
-
if (pennantGain > 0.05) { // An upward slant, less than 5%
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Ensure the consolidation period forms a small symmetrical triangle
|
|
187
|
-
for (let i = length - pennantLength; i < length - 1; i++) {
|
|
188
|
-
if ((this.ohlcv.high[i] > this.ohlcv.high[i + 1] && this.ohlcv.low[i] > this.ohlcv.low[i + 1]) ||
|
|
189
|
-
(this.ohlcv.high[i] < this.ohlcv.high[i + 1] && this.ohlcv.low[i] < this.ohlcv.low[i + 1])) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Implementation of Double Top
|
|
198
|
-
// https://www.tradingview.com/support/solutions/43000653211-chart-pattern-double-top/
|
|
199
|
-
isDoubleTop() {
|
|
200
|
-
const length = this.ohlcv.close.length;
|
|
201
|
-
const midpoint = Math.floor(length / 2);
|
|
202
|
-
|
|
203
|
-
const firstPeak = Math.max(...this.ohlcv.close.slice(0, midpoint));
|
|
204
|
-
const secondPeak = Math.max(...this.ohlcv.close.slice(midpoint));
|
|
205
|
-
|
|
206
|
-
if (firstPeak <= 0 || secondPeak <= 0) {
|
|
207
|
-
return false;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const firstValley = Math.min(...this.ohlcv.close.slice(0, midpoint));
|
|
211
|
-
const secondValley = Math.min(...this.ohlcv.close.slice(midpoint));
|
|
212
|
-
|
|
213
|
-
const dropFromFirstPeak = (firstPeak - firstValley) / firstPeak;
|
|
214
|
-
const dropFromSecondPeak = (secondPeak - secondValley) / secondPeak;
|
|
215
|
-
|
|
216
|
-
if (dropFromFirstPeak < 0.1 || dropFromSecondPeak < 0.1) {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return Math.abs(firstPeak - secondPeak) / firstPeak < 0.03;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Implementation of Double Bottom
|
|
224
|
-
// https://www.tradingview.com/support/solutions/43000690659-chart-pattern-double-bottom/
|
|
225
|
-
isDoubleBottom() {
|
|
226
|
-
const length = this.ohlcv.close.length;
|
|
227
|
-
const midpoint = Math.floor(length / 2);
|
|
228
|
-
|
|
229
|
-
const firstValley = Math.min(...this.ohlcv.close.slice(0, midpoint));
|
|
230
|
-
const secondValley = Math.min(...this.ohlcv.close.slice(midpoint));
|
|
231
|
-
|
|
232
|
-
if (firstValley <= 0 || secondValley <= 0) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const firstPeak = Math.max(...this.ohlcv.close.slice(0, midpoint));
|
|
237
|
-
const secondPeak = Math.max(...this.ohlcv.close.slice(midpoint));
|
|
238
|
-
|
|
239
|
-
const riseFromFirstValley = (firstPeak - firstValley) / firstValley;
|
|
240
|
-
const riseFromSecondValley = (secondPeak - secondValley) / secondValley;
|
|
241
|
-
|
|
242
|
-
if (riseFromFirstValley < 0.1 || riseFromSecondValley < 0.1) {
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return Math.abs(firstValley - secondValley) / firstValley < 0.03;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Implementation of Triple Top
|
|
250
|
-
// https://www.tradingview.com/support/solutions/43000653218-chart-pattern-triple-top/
|
|
251
|
-
isTripleTop() {
|
|
252
|
-
const length = this.ohlcv.close.length;
|
|
253
|
-
const third = Math.floor(length / 3);
|
|
254
|
-
|
|
255
|
-
const firstPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
256
|
-
const secondPeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
257
|
-
const thirdPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
258
|
-
|
|
259
|
-
if (firstPeak <= 0 || secondPeak <= 0 || thirdPeak <= 0) {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const dropFromFirstPeak = (firstPeak - Math.min(...this.ohlcv.close.slice(0, third))) / firstPeak;
|
|
264
|
-
const dropFromSecondPeak = (secondPeak - Math.min(...this.ohlcv.close.slice(third, third * 2))) / secondPeak;
|
|
265
|
-
const dropFromThirdPeak = (thirdPeak - Math.min(...this.ohlcv.close.slice(third * 2))) / thirdPeak;
|
|
266
|
-
|
|
267
|
-
if (dropFromFirstPeak < 0.1 || dropFromSecondPeak < 0.1 || dropFromThirdPeak < 0.1) {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return Math.abs(firstPeak - secondPeak) / firstPeak < 0.03 && Math.abs(firstPeak - thirdPeak) / firstPeak < 0.03;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Implementation of Triple Bottom
|
|
275
|
-
// https://www.tradingview.com/support/solutions/43000690660-chart-pattern-triple-bottom/
|
|
276
|
-
isTripleBottom() {
|
|
277
|
-
const length = this.ohlcv.close.length;
|
|
278
|
-
const third = Math.floor(length / 3);
|
|
279
|
-
|
|
280
|
-
const firstValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
281
|
-
const secondValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
282
|
-
const thirdValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
283
|
-
|
|
284
|
-
if (firstValley <= 0 || secondValley <= 0 || thirdValley <= 0) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const riseFromFirstValley = (Math.max(...this.ohlcv.close.slice(0, third)) - firstValley) / firstValley;
|
|
289
|
-
const riseFromSecondValley = (Math.max(...this.ohlcv.close.slice(third, third * 2)) - secondValley) / secondValley;
|
|
290
|
-
const riseFromThirdValley = (Math.max(...this.ohlcv.close.slice(third * 2)) - thirdValley) / thirdValley;
|
|
291
|
-
|
|
292
|
-
if (riseFromFirstValley < 0.1 || riseFromSecondValley < 0.1 || riseFromThirdValley < 0.1) {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return Math.abs(firstValley - secondValley) / firstValley < 0.03 && Math.abs(firstValley - thirdValley) / firstValley < 0.03;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Implementation of Head and Shoulders
|
|
300
|
-
// https://www.tradingview.com/support/solutions/43000653213-chart-pattern-head-and-shoulders/
|
|
301
|
-
isHeadAndShoulders() {
|
|
302
|
-
const length = this.ohlcv.close.length;
|
|
303
|
-
const third = Math.floor(length / 3);
|
|
304
|
-
|
|
305
|
-
const leftShoulder = Math.max(...this.ohlcv.close.slice(0, third));
|
|
306
|
-
const head = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
307
|
-
const rightShoulder = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
308
|
-
|
|
309
|
-
if (leftShoulder <= 0 || head <= 0 || rightShoulder <= 0) {
|
|
310
|
-
return false;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const leftValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
314
|
-
const middleValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
315
|
-
const rightValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
316
|
-
|
|
317
|
-
const dropFromHead = (head - middleValley) / head;
|
|
318
|
-
const riseFromValleys = (Math.max(leftValley, rightValley) - Math.min(leftValley, rightValley)) / Math.min(leftValley, rightValley);
|
|
319
|
-
|
|
320
|
-
return dropFromHead > 0.15 && riseFromValleys < 0.03;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Implementation of Inverse Head and Shoulders
|
|
324
|
-
// https://www.tradingview.com/support/solutions/43000690666-chart-pattern-inverse-head-and-shoulders/
|
|
325
|
-
isInverseHeadAndShoulders() {
|
|
326
|
-
const length = this.ohlcv.close.length;
|
|
327
|
-
const third = Math.floor(length / 3);
|
|
328
|
-
|
|
329
|
-
const leftShoulder = Math.min(...this.ohlcv.close.slice(0, third));
|
|
330
|
-
const head = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
331
|
-
const rightShoulder = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
332
|
-
|
|
333
|
-
if (leftShoulder <= 0 || head <= 0 || rightShoulder <= 0) {
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const leftPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
338
|
-
const middlePeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
339
|
-
const rightPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
340
|
-
|
|
341
|
-
const riseFromHead = (middlePeak - head) / head;
|
|
342
|
-
const dropFromPeaks = (Math.min(leftPeak, rightPeak) - Math.max(leftPeak, rightPeak)) / Math.max(leftPeak, rightPeak);
|
|
343
|
-
|
|
344
|
-
return riseFromHead > 0.15 && dropFromPeaks < 0.03;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Implementation of Rising Wedge
|
|
348
|
-
// https://www.tradingview.com/support/solutions/43000653219-chart-pattern-rising-wedge/
|
|
349
|
-
isRisingWedge() {
|
|
350
|
-
const length = this.ohlcv.close.length;
|
|
351
|
-
const third = Math.floor(length / 3);
|
|
352
|
-
|
|
353
|
-
const firstPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
354
|
-
const secondPeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
355
|
-
const thirdPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
356
|
-
|
|
357
|
-
const firstValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
358
|
-
const secondValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
359
|
-
const thirdValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
360
|
-
|
|
361
|
-
const risingPeaks = firstPeak < secondPeak && secondPeak < thirdPeak;
|
|
362
|
-
const risingValleys = firstValley < secondValley && secondValley < thirdValley;
|
|
363
|
-
|
|
364
|
-
return risingPeaks && risingValleys;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Implementation of Falling Wedge
|
|
368
|
-
// https://www.tradingview.com/support/solutions/43000697938-chart-pattern-falling-wedge/
|
|
369
|
-
isFallingWedge() {
|
|
370
|
-
const length = this.ohlcv.close.length;
|
|
371
|
-
const third = Math.floor(length / 3);
|
|
372
|
-
|
|
373
|
-
const firstPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
374
|
-
const secondPeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
375
|
-
const thirdPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
376
|
-
|
|
377
|
-
const firstValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
378
|
-
const secondValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
379
|
-
const thirdValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
380
|
-
|
|
381
|
-
const fallingPeaks = firstPeak > secondPeak && secondPeak > thirdPeak;
|
|
382
|
-
const fallingValleys = firstValley > secondValley && secondValley > thirdValley;
|
|
383
|
-
|
|
384
|
-
return fallingPeaks && fallingValleys;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// Implementation of Bullish Triangle
|
|
388
|
-
// https://www.tradingview.com/support/solutions/43000653217/
|
|
389
|
-
isBullishTriangle() {
|
|
390
|
-
const length = this.ohlcv.close.length;
|
|
391
|
-
const half = Math.floor(length / 2);
|
|
392
|
-
|
|
393
|
-
const firstHalfHigh = Math.max(...this.ohlcv.high.slice(0, half));
|
|
394
|
-
const secondHalfHigh = Math.max(...this.ohlcv.high.slice(half));
|
|
395
|
-
|
|
396
|
-
const firstHalfLow = Math.min(...this.ohlcv.low.slice(0, half));
|
|
397
|
-
const secondHalfLow = Math.min(...this.ohlcv.low.slice(half));
|
|
398
|
-
|
|
399
|
-
const contractingHighs = firstHalfHigh > secondHalfHigh;
|
|
400
|
-
const risingLows = firstHalfLow < secondHalfLow;
|
|
401
|
-
|
|
402
|
-
return contractingHighs && risingLows;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Implementation of Bearish Triangle
|
|
406
|
-
// https://www.tradingview.com/support/solutions/43000653217/
|
|
407
|
-
isBearishTriangle() {
|
|
408
|
-
const length = this.ohlcv.close.length;
|
|
409
|
-
const half = Math.floor(length / 2);
|
|
410
|
-
|
|
411
|
-
const firstHalfHigh = Math.max(...this.ohlcv.high.slice(0, half));
|
|
412
|
-
const secondHalfHigh = Math.max(...this.ohlcv.high.slice(half));
|
|
413
|
-
|
|
414
|
-
const firstHalfLow = Math.min(...this.ohlcv.low.slice(0, half));
|
|
415
|
-
const secondHalfLow = Math.min(...this.ohlcv.low.slice(half));
|
|
416
|
-
|
|
417
|
-
const contractingLows = firstHalfLow < secondHalfLow;
|
|
418
|
-
const fallingHighs = firstHalfHigh > secondHalfHigh;
|
|
419
|
-
|
|
420
|
-
return contractingLows && fallingHighs;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Implementation of Bullish Rectangle
|
|
424
|
-
// https://www.tradingview.com/support/solutions/43000653216/
|
|
425
|
-
isBullishRectangle() {
|
|
426
|
-
const length = this.ohlcv.close.length;
|
|
427
|
-
const third = Math.floor(length / 3);
|
|
428
|
-
|
|
429
|
-
const firstSectionHigh = Math.max(...this.ohlcv.high.slice(0, third));
|
|
430
|
-
const secondSectionHigh = Math.max(...this.ohlcv.high.slice(third, third * 2));
|
|
431
|
-
const thirdSectionHigh = Math.max(...this.ohlcv.high.slice(third * 2));
|
|
432
|
-
|
|
433
|
-
const firstSectionLow = Math.min(...this.ohlcv.low.slice(0, third));
|
|
434
|
-
const secondSectionLow = Math.min(...this.ohlcv.low.slice(third, third * 2));
|
|
435
|
-
const thirdSectionLow = Math.min(...this.ohlcv.low.slice(third * 2));
|
|
436
|
-
|
|
437
|
-
const stableHighs = Math.abs(firstSectionHigh - secondSectionHigh) / firstSectionHigh < 0.03 &&
|
|
438
|
-
Math.abs(secondSectionHigh - thirdSectionHigh) / secondSectionHigh < 0.03;
|
|
439
|
-
const stableLows = Math.abs(firstSectionLow - secondSectionLow) / firstSectionLow < 0.03 &&
|
|
440
|
-
Math.abs(secondSectionLow - thirdSectionLow) / secondSectionLow < 0.03;
|
|
441
|
-
|
|
442
|
-
return stableHighs && stableLows;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// Implementation of Bearish Rectangle
|
|
446
|
-
// https://www.tradingview.com/support/solutions/43000653216/
|
|
447
|
-
isBearishRectangle() {
|
|
448
|
-
const length = this.ohlcv.close.length;
|
|
449
|
-
const third = Math.floor(length / 3);
|
|
450
|
-
|
|
451
|
-
const firstSectionHigh = Math.max(...this.ohlcv.high.slice(0, third));
|
|
452
|
-
const secondSectionHigh = Math.max(...this.ohlcv.high.slice(third, third * 2));
|
|
453
|
-
const thirdSectionHigh = Math.max(...this.ohlcv.high.slice(third * 2));
|
|
454
|
-
|
|
455
|
-
const firstSectionLow = Math.min(...this.ohlcv.low.slice(0, third));
|
|
456
|
-
const secondSectionLow = Math.min(...this.ohlcv.low.slice(third, third * 2));
|
|
457
|
-
const thirdSectionLow = Math.min(...this.ohlcv.low.slice(third * 2));
|
|
458
|
-
|
|
459
|
-
const stableHighs = Math.abs(firstSectionHigh - secondSectionHigh) / firstSectionHigh < 0.03 &&
|
|
460
|
-
Math.abs(secondSectionHigh - thirdSectionHigh) / secondSectionHigh < 0.03;
|
|
461
|
-
const stableLows = Math.abs(firstSectionLow - secondSectionLow) / firstSectionLow < 0.03 &&
|
|
462
|
-
Math.abs(secondSectionLow - thirdSectionLow) / secondSectionLow < 0.03;
|
|
463
|
-
|
|
464
|
-
return stableHighs && stableLows;
|
|
465
|
-
}
|
|
466
|
-
}
|