This question and related answers will be for educational or learning purpose only.
This question is much different from my other
Assuming today is 12th Jan 2021, below is the expected output:
------- ------------------- ------------ ------------ -------------- -------- ---------------
| Stock | Consecutive Count | Start Date | End Date | Latest Close | Volume | Pattern |
------- ------------------- ------------ ------------ -------------- -------- ---------------
| XYZ | 3 | 09-01-2021 | 12-01-2021 | 37.8 | 281461 | Piercing Line |
------- ------------------- ------------ ------------ -------------- -------- ---------------
Since the source table will have many other stocks, would like to show results on 12th Jan 2021 for other stocks as well if there is any pattern identified. I feel this is quite challenging and complex logic. Hence seeking help here. Thanks in advance.
Update: Thank you @JustinCave
Here's the formula for calculation:
For Bullish Engulfing:
O1 > C1 and C > O and C > H1 and O < L1
where,
O1 = Previous day Open price
C1 = Previous day Close price
C = Today's Close price
O = Today's Open price
H1 = Previous day High price
L1 = Previous day Low price
For Bearish Harami:
(O1 < C1) and (O > C) and (O < C1) and (C > O1) and (H < H1) and (L > L1)
where,
O1 = Previous day Open price
C1 = Previous day Close price
C = Today's Close price
O = Today's Open price
H1 = Previous day High price
L1 = Previous day Low price
H = Today's High price
L = Today's Low price
For Piercing Line:
(O < C) and (O1 > C1) and (C > (C1 O1)/2) and (O < C1) and (C < O1)
where,
O1 = Previous day Open price
C1 = Previous day Close price
C = Today's Close price
O = Today's Open price
CodePudding user response:
Patterns in MATCH_RECOGNIZE
work in a similar fashion to regular expressions; you want something like:
(Note: your PIERCING_LINE
formula does not give the expected output so I have assumed you want C > (C1 O1)/2
rather than C > C1 (O1/2)
.)
SELECT *
FROM raw_source
MATCH_RECOGNIZE (
PARTITION BY stock
ORDER BY Close_Date
MEASURES
CLASSIFIER() AS pttrn
ALL ROWS PER MATCH
PATTERN (
^initial_value
|
down (bullish_engulfing | piercing_line | $)
|
up (bearish_harami | $)
|
other
)
DEFINE
down AS
PREV(open) > open
AND PREV(close) > close
AND PREV(open) > PREV(close)
AND open > close,
up AS
PREV(open) < open
AND PREV(close) < close
AND PREV(open) < PREV(close)
AND open < close,
bullish_engulfing AS
-- O1 > C1 and C > O and C > H1 and O < L1
PREV(open) > PREV(close)
AND close > open
AND close > PREV(high)
AND open < PREV(low),
bearish_harami AS
-- O1 < C1 and O > C and O < C1 and C > O1 and H < H1 and L > L1
PREV(open) < PREV(close)
AND open > close
AND open < PREV(close)
AND close > PREV(open)
AND high < PREV(high)
AND low > PREV(low),
piercing_line AS
-- O < C and O1 > C1 and C > (C1 O1)/2 and O < C1 and C < O1
open < close
AND PREV(open) > PREV(close)
AND close > (PREV(close) PREV(open))/2
AND open < PREV(close)
AND close < PREV(open)
)
Which outputs:
STOCK CLOSE_DATE PTTRN OPEN HIGH LOW CLOSE VOLUME XYZ 01/01/2021 INITIAL_VALUE 40 40.5 38.5 38.8 83057 XYZ 02/01/2021 DOWN 39.2 39.2 37.2 37.8 181814 XYZ 03/01/2021 DOWN 38 38.5 36.5 37 117378 XYZ 04/01/2021 DOWN 36.5 36.6 35.6 35.7 93737 XYZ 05/01/2021 BULLISH_ENGULFING 35.35 36.8 35.1 36.7 169106 XYZ 06/01/2021 UP 36.5 38.5 36.5 38 123179 XYZ 07/01/2021 UP 37.5 39.5 37.3 39.4 282986 XYZ 08/01/2021 UP 39 40.5 38.5 40 117437 XYZ 09/01/2021 BEARISH_HARAMI 39.7 39.8 39.3 39.4 873009 XYZ 10/01/2021 DOWN 39.2 39.2 37.2 37.8 62522 XYZ 11/01/2021 DOWN 38 38.5 36.5 37 114826 XYZ 12/01/2021 PIERCING_LINE 36.5 37.9 36.3 37.8 281461 XYZ 13/01/2021 UP 37.5 39.5 37.3 39.4 77334 XYZ 14/01/2021 UP 39 40.5 38.5 40 321684
db<>fiddle here
CodePudding user response:
I've upvoted @MT0's answer and I would use match_recognize
for this sort of thing myself since this is squarely the sort of problem it is designed to deal with. However, match_recognize
is a pretty sophisticated construct and the patterns you're looking for are pretty simple. So as expressed, you could solve your problem with a simpler query that just uses a few lag
analytic functions. As the patterns you're looking for get more sophisticated, you'll find that it'll be easier to express them using match_recognize
and harder to handle them just with lag
but the current problem is relatively easy to express this way.
Note that I'm making the same change to the "Piercing Line" formula that @MT0 did
with data as (
select src.stock,
src.close_date,
src.open o,
src.close c,
src.high h,
src.low l,
lag(src.open) over (partition by src.stock order by src.close_date) o1,
lag(src.close) over (partition by src.stock order by src.close_date) c1,
lag(src.high) over (partition by src.stock order by src.close_date) h1,
lag(src.low) over (partition by src.stock order by src.close_date) l1
from raw_source src
)
select d.*,
case when o1 > c1 and c > o and c > h1 and o < l1
then 'Bullish Engulfing'
when (O1 < C1) and (O > C) and (O < C1) and (C > O1) and (H < H1) and (L > L1)
then 'Bearish Harami'
when (O < C) and (O1 > C1) and (C > (C1 O1)/2) and (O < C1) and (C < O1)
then 'Piercing Line'
end pattern
from data d
which produces the same results in the pattern
column in this dbfiddle. Since we can use the same syntax you're using to express the formulas, though, it may be easier to follow the logic in this query than to understand the match_recognize
syntax.