Home > Software engineering >  Oracle SQL or PL/SQL: How to identify candlestick pattern only in end of uptrend or downtrend and se
Oracle SQL or PL/SQL: How to identify candlestick pattern only in end of uptrend or downtrend and se

Time:10-05

This question and related answers will be for educational or learning purpose only.

This question is much different from my other enter image description here

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.

  • Related