Oracle SQL 或 PL/SQL:如何仅在上升趋势或下降趋势结束时识别烛台形态并在列中设置标志?
Oracle SQL or PL/SQL: How to identify candlestick pattern only in end of uptrend or downtrend and set a flag in column?
此问题及相关答案仅供教育或学习之用。
这个问题与我的另一个问题 大不相同,并且不重复。由于它造成了混乱,并且正如@MT0 所建议的那样,我将其作为一个新问题发布在这里。
我有下面table,我每天上传股票数据。
/* CREATE TABLE */
CREATE TABLE RAW_SOURCE(
Stock VARCHAR(100),
Close_Date DATE,
Open NUMBER,
High NUMBER,
Low NUMBER,
Close NUMBER,
Volume NUMBER
);
/* INSERT QUERY NO: 1 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '01/01/2021', 40, 40.5, 38.5, 38.8, 83057
);
/* INSERT QUERY NO: 2 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '02/01/2021', 39.2, 39.2, 37.2, 37.8, 181814
);
/* INSERT QUERY NO: 3 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '03/01/2021', 38, 38.5, 36.5, 37, 117378
);
/* INSERT QUERY NO: 4 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '04/01/2021', 36.5, 36.6, 35.6, 35.7, 93737
);
/* INSERT QUERY NO: 5 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '05/01/2021', 35.35, 36.8, 35.1, 36.7, 169106
);
/* INSERT QUERY NO: 6 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '06/01/2021', 36.5, 38.5, 36.5, 38, 123179
);
/* INSERT QUERY NO: 7 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '07/01/2021', 37.5, 39.5, 37.3, 39.4, 282986
);
/* INSERT QUERY NO: 8 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '08/01/2021', 39, 40.5, 38.5, 40, 117437
);
/* INSERT QUERY NO: 9 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '09/01/2021', 39.7, 39.8, 39.3, 39.4, 873009
);
/* INSERT QUERY NO: 10 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '10/01/2021', 39.2, 39.2, 37.2, 37.8, 62522
);
/* INSERT QUERY NO: 11 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '11/01/2021', 38, 38.5, 36.5, 37, 114826
);
/* INSERT QUERY NO: 12 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '12/01/2021', 36.5, 37.9, 36.3, 37.8, 281461
);
/* INSERT QUERY NO: 13 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '13/01/2021', 37.5, 39.5, 37.3, 39.4, 77334
);
/* INSERT QUERY NO: 14 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '14/01/2021', 39, 40.5, 38.5, 40, 321684
);
下面是一只股票“XYZ”的样本数据:
+-------+------------+-------+------+------+-------+--------+
| Stock | Close Date | Open | High | Low | Close | Volume |
+-------+------------+-------+------+------+-------+--------+
| XYZ | 01-01-2021 | 40 | 40.5 | 38.5 | 38.8 | 83057 |
| XYZ | 02-01-2021 | 39.2 | 39.2 | 37.2 | 37.8 | 181814 |
| XYZ | 03-01-2021 | 38 | 38.5 | 36.5 | 37 | 117378 |
| XYZ | 04-01-2021 | 36.5 | 36.6 | 35.6 | 35.7 | 93737 |
| XYZ | 05-01-2021 | 35.35 | 36.8 | 35.1 | 36.7 | 169106 |
| XYZ | 06-01-2021 | 36.5 | 38.5 | 36.5 | 38 | 123179 |
| XYZ | 07-01-2021 | 37.5 | 39.5 | 37.3 | 39.4 | 282986 |
| XYZ | 08-01-2021 | 39 | 40.5 | 38.5 | 40 | 117437 |
| XYZ | 09-01-2021 | 39.7 | 39.8 | 39.3 | 39.4 | 873009 |
| XYZ | 10-01-2021 | 39.2 | 39.2 | 37.2 | 37.8 | 62522 |
| XYZ | 11-01-2021 | 38 | 38.5 | 36.5 | 37 | 114826 |
| XYZ | 12-01-2021 | 36.5 | 37.9 | 36.3 | 37.8 | 281461 |
| XYZ | 13-01-2021 | 37.5 | 39.5 | 37.3 | 39.4 | 77334 |
| XYZ | 14-01-2021 | 39 | 40.5 | 38.5 | 40 | 321684 |
+-------+------------+-------+------+------+-------+--------+
随着时间的推移,每个股票代码将有超过数千条记录,我只想在 upmove/uptrend 的顶部或 [=58= 的底部识别烛台模式] 但不是在横向(因为这将是误报)。以下是示例屏幕截图:
假设今天是 2021 年 1 月 12 日,下面是预期输出:
+-------+-------------------+------------+------------+--------------+--------+---------------+
| Stock | Consecutive Count | Start Date | End Date | Latest Close | Volume | Pattern |
+-------+-------------------+------------+------------+--------------+--------+---------------+
| XYZ | 3 | 09-01-2021 | 12-01-2021 | 37.8 | 281461 | Piercing Line |
+-------+-------------------+------------+------------+--------------+--------+---------------+
由于来源 table 将有许多其他股票,如果发现任何模式,我想在 2021 年 1 月 12 日显示其他股票的结果。
我觉得这是一个相当具有挑战性和复杂的逻辑。因此在这里寻求帮助。提前致谢。
更新: 谢谢@JustinCave
下面是计算公式:
看涨吞没:
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
对于看跌孕线:
(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
对于穿线:
(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
MATCH_RECOGNIZE
中的模式与正则表达式的工作方式类似;你想要这样的东西:
(注意:您的 PIERCING_LINE
公式没有给出预期的输出,所以我假设您想要 C > (C1 + O1)/2
而不是 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)
)
输出:
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
我对@MT0 的回答投了赞成票,我自己会使用 match_recognize
来处理这类事情,因为这正是它旨在处理的问题。但是,match_recognize
是一个非常复杂的构造,您正在寻找的模式非常简单。因此,正如所表达的那样,您可以使用仅使用几个 lag
分析函数的更简单的查询来解决您的问题。随着您正在寻找的模式变得越来越复杂,您会发现使用 match_recognize
更容易表达它们,而仅使用 lag
更难处理它们,但当前的问题相对容易以这种方式表达。
请注意,我正在对@MT0 所做的“穿刺线”公式进行相同的更改
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
在 this dbfiddle 的 pattern
列中产生相同的结果。但是,由于我们可以使用您用于表达公式的相同语法,因此遵循此查询中的逻辑可能比理解 match_recognize
语法更容易。
此问题及相关答案仅供教育或学习之用。
这个问题与我的另一个问题
我有下面table,我每天上传股票数据。
/* CREATE TABLE */
CREATE TABLE RAW_SOURCE(
Stock VARCHAR(100),
Close_Date DATE,
Open NUMBER,
High NUMBER,
Low NUMBER,
Close NUMBER,
Volume NUMBER
);
/* INSERT QUERY NO: 1 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '01/01/2021', 40, 40.5, 38.5, 38.8, 83057
);
/* INSERT QUERY NO: 2 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '02/01/2021', 39.2, 39.2, 37.2, 37.8, 181814
);
/* INSERT QUERY NO: 3 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '03/01/2021', 38, 38.5, 36.5, 37, 117378
);
/* INSERT QUERY NO: 4 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '04/01/2021', 36.5, 36.6, 35.6, 35.7, 93737
);
/* INSERT QUERY NO: 5 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '05/01/2021', 35.35, 36.8, 35.1, 36.7, 169106
);
/* INSERT QUERY NO: 6 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '06/01/2021', 36.5, 38.5, 36.5, 38, 123179
);
/* INSERT QUERY NO: 7 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '07/01/2021', 37.5, 39.5, 37.3, 39.4, 282986
);
/* INSERT QUERY NO: 8 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '08/01/2021', 39, 40.5, 38.5, 40, 117437
);
/* INSERT QUERY NO: 9 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '09/01/2021', 39.7, 39.8, 39.3, 39.4, 873009
);
/* INSERT QUERY NO: 10 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '10/01/2021', 39.2, 39.2, 37.2, 37.8, 62522
);
/* INSERT QUERY NO: 11 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '11/01/2021', 38, 38.5, 36.5, 37, 114826
);
/* INSERT QUERY NO: 12 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '12/01/2021', 36.5, 37.9, 36.3, 37.8, 281461
);
/* INSERT QUERY NO: 13 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '13/01/2021', 37.5, 39.5, 37.3, 39.4, 77334
);
/* INSERT QUERY NO: 14 */
INSERT INTO RAW_SOURCE(Stock, Close_Date, Open, High, Low, Close, Volume)
VALUES
(
'XYZ', '14/01/2021', 39, 40.5, 38.5, 40, 321684
);
下面是一只股票“XYZ”的样本数据:
+-------+------------+-------+------+------+-------+--------+
| Stock | Close Date | Open | High | Low | Close | Volume |
+-------+------------+-------+------+------+-------+--------+
| XYZ | 01-01-2021 | 40 | 40.5 | 38.5 | 38.8 | 83057 |
| XYZ | 02-01-2021 | 39.2 | 39.2 | 37.2 | 37.8 | 181814 |
| XYZ | 03-01-2021 | 38 | 38.5 | 36.5 | 37 | 117378 |
| XYZ | 04-01-2021 | 36.5 | 36.6 | 35.6 | 35.7 | 93737 |
| XYZ | 05-01-2021 | 35.35 | 36.8 | 35.1 | 36.7 | 169106 |
| XYZ | 06-01-2021 | 36.5 | 38.5 | 36.5 | 38 | 123179 |
| XYZ | 07-01-2021 | 37.5 | 39.5 | 37.3 | 39.4 | 282986 |
| XYZ | 08-01-2021 | 39 | 40.5 | 38.5 | 40 | 117437 |
| XYZ | 09-01-2021 | 39.7 | 39.8 | 39.3 | 39.4 | 873009 |
| XYZ | 10-01-2021 | 39.2 | 39.2 | 37.2 | 37.8 | 62522 |
| XYZ | 11-01-2021 | 38 | 38.5 | 36.5 | 37 | 114826 |
| XYZ | 12-01-2021 | 36.5 | 37.9 | 36.3 | 37.8 | 281461 |
| XYZ | 13-01-2021 | 37.5 | 39.5 | 37.3 | 39.4 | 77334 |
| XYZ | 14-01-2021 | 39 | 40.5 | 38.5 | 40 | 321684 |
+-------+------------+-------+------+------+-------+--------+
随着时间的推移,每个股票代码将有超过数千条记录,我只想在 upmove/uptrend 的顶部或 [=58= 的底部识别烛台模式] 但不是在横向(因为这将是误报)。以下是示例屏幕截图:
假设今天是 2021 年 1 月 12 日,下面是预期输出:
+-------+-------------------+------------+------------+--------------+--------+---------------+
| Stock | Consecutive Count | Start Date | End Date | Latest Close | Volume | Pattern |
+-------+-------------------+------------+------------+--------------+--------+---------------+
| XYZ | 3 | 09-01-2021 | 12-01-2021 | 37.8 | 281461 | Piercing Line |
+-------+-------------------+------------+------------+--------------+--------+---------------+
由于来源 table 将有许多其他股票,如果发现任何模式,我想在 2021 年 1 月 12 日显示其他股票的结果。 我觉得这是一个相当具有挑战性和复杂的逻辑。因此在这里寻求帮助。提前致谢。
更新: 谢谢@JustinCave
下面是计算公式:
看涨吞没:
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
对于看跌孕线:
(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
对于穿线:
(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
MATCH_RECOGNIZE
中的模式与正则表达式的工作方式类似;你想要这样的东西:
(注意:您的 PIERCING_LINE
公式没有给出预期的输出,所以我假设您想要 C > (C1 + O1)/2
而不是 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)
)
输出:
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
我对@MT0 的回答投了赞成票,我自己会使用 match_recognize
来处理这类事情,因为这正是它旨在处理的问题。但是,match_recognize
是一个非常复杂的构造,您正在寻找的模式非常简单。因此,正如所表达的那样,您可以使用仅使用几个 lag
分析函数的更简单的查询来解决您的问题。随着您正在寻找的模式变得越来越复杂,您会发现使用 match_recognize
更容易表达它们,而仅使用 lag
更难处理它们,但当前的问题相对容易以这种方式表达。
请注意,我正在对@MT0 所做的“穿刺线”公式进行相同的更改
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
在 this dbfiddle 的 pattern
列中产生相同的结果。但是,由于我们可以使用您用于表达公式的相同语法,因此遵循此查询中的逻辑可能比理解 match_recognize
语法更容易。