|
我的做法:
第一步:先找出所有尽可能长的连续上升线段,这一步用match_recognize很容易做到。
第一条:1,3,3,5,7,10
第二条:6,8,9
第三条:4,6,8,9,11
第四条:2,5,7
所有的子线段都不是最 佳时机,比如第一条线中的子线段 (3,5)或(3,7)就应该抛弃,最 佳买入点只存在于这些线段的低点,卖出点则在高点中选择。
第二步:
每条线段的低点和其他后续线段的高点也可能组成最 佳时机,比如第一条线和第三条线组成(1,11)。但是这仅限于比前面高点更高的高点,比如第一条和第二条的组合(1,9)就应该抛弃,还不如前面的(1,10); 第一条和第四条的组合(1,7)也应该抛弃,因为前面已经出现了(1,11)这种更佳的。
同理,第二条和第三条也有**组合(6,11),而第二条和第四条组成的(6,7)则应抛弃。
这一步的结果是(1,10)(1,11)(6,9)(6,11)(4,11)(2,7)
看起来很像笛卡尔积,我想办法用match_recognize找了出来。
所以match_recognize进行了预处理优化,第一个找出尽可能长的连续上升段,第二个则找出高点呈上升趋势
第三步就是老生常谈,在第二步结果中找出1-k对组合让其利润最大化,用递归WITH实现,要注意下次交易必须在上次结束之后。
with d1 as (
-- 第一次匹配:求出所有尽可能长的连续上升段, 每个段输出一行
select *
from stock
match_recognize (
order by dt
measures min(dt) as dt1
,max(dt) as dt2
,min(price) as price1
,max(price) as price2
one row per match
pattern(start_point a+)
define a as price>=prev(price)
)
)
,d2 as (
-- 第二次匹配:用每个上升段的起点,去配对后面的其他上升段的高点,这些构成了可能的最 佳买入卖出时机。
-- 利用after match skip to next row避免了笛卡尔积,每个段都向后匹配,最终只输出高点呈上升趋势的那些段,下降的没有意义
select *
from d1
match_recognize (
order by dt1
measures --match_number() as grp_id
--,classifier() as flag
start_point.dt1 as start_dt
,start_point.price1 as start_price
all rows per match
after match skip to next row
pattern(start_point ( {- a -}| b)*) ---- 把a从输出中去除
define a as price2<max(price2) --- 这些不是上升的,可以从输出中去除
,b as price2=max(price2) --- 这些是需要留下的高点上升趋势
)
)
,t(end_dt,path,amount,cnt) as ( ---- 递归尝试从d2结果中取 1-K 个,看看哪个组合盈利最多
select dt2,'('||start_dt||':'||start_price||'->'||dt2||':'||price2||')',price2-start_price,1
from d2
union all
select d2.dt2,t.path||'('||d2.start_dt||':'||d2.start_price||'->'||d2.dt2||':'||d2.price2||')'
,t.amount+d2.price2-d2.start_price
,t.cnt+1
from t,d2
where t.end_dt<d2.start_dt
and t.cnt<:k
)
select * from t
order by amount desc
fetch first 1 rows with ties; |
|