SPL 量化系列实践:K 线形态
头肩顶
1. 形态整体上有 3 次撞顶的过程,出现 3 座顶峰,其中第一座和第三座的顶部位置较为接近,第二座顶峰的高点比其他两座更高。
2. 形态包括第一次撞顶的“左肩”、第二次撞顶的“头部”、第三次撞顶的“右肩”以及左肩和右肩底点的连线构成的“颈线”。
3. 一般来说,头肩顶的左肩成交量最大,头部成交量略小,右肩成交量最小。
4. 一般见于中线或长线的见顶反转。
圆顶
1. 整体形态呈上凸状,筑顶的过程较为漫长和缓慢。
2. 形态包括左边的“上涨”、中间的“顶部”、右边的“下跌”以及上涨和下跌关键位的连线构成“颈线”。但颈线位置不明显,也不易确定。
3. 圆顶的成交量呈由放量到缩量的过程,跌破颈线的时候有可能放量。
4. 在上升趋势中出现,大级别的下跌趋势中出现中级反弹,较容易出现圆顶。鲜见于大级别的顶部。
5. 一般构成中线或长线的见顶下跌。
上升三角形
1. 整体形态呈直角在左上方的直角三角形。
2. K 线多次冲击同一水平线的高点,但均回落形成逐步抬高的低点,高点之间的连线是“上边线”,低点之间的连线是“下边线”,两条线最终会交汇于一点。突破上边线时形态成立,突破点不要求在上边线与下边线的交汇点。有时会有突破上边线的“回抽”。
3. 一般见于上升趋势中的短期调整,经调整后继续上行。
4. 每波下跌时成交量下降,上行时成交量上涨,突破阶段成交量有效放大。
SPL 代码
A |
B |
|
1 |
=file("daily/"/stock).import@tc() |
|
2 |
=A1.select(trade_date>20230801&&trade_date<=20240131) |
|
3 |
=A2.derive(if(#>1, close/ pre_close *factor[-1], close/pre_close):factor) |
|
4 |
=hfq_fst=A3(1),A3.new(ts_code,trade_date,(fcls=factor/hfq_fst.factor*hfq_fst.close,c=fcls/close,round(c*open,2)): hfq_open,round(c*high,2): hfq_high,round(c*low,2): hfq_low,round(fcls,2): hfq_close,vol,amount) |
|
5 |
=A4.(hfq_close) |
|
6 |
=thd=0 |
|
7 |
=shp=null |
|
8 |
=lth=0 |
|
9 |
if shape=="head_shoulder" |
8 |
10 |
=k1=0.6/B9 |
|
11 |
=k2=1/B9 |
|
12 |
=shp=6.((if(#>2&&#<5,if(#%2==1,(k=k2,b=0),(k=-k2,b=1)),if(#%2==1,(k=k1,b=0),(k=-k1,b=0.6))),B9.(k*#+b))).conj().insert(1,0) |
|
13 |
=lth=B9*6 |
|
14 |
=thd=0.025 |
|
15 |
if shape=="circle" |
60 |
16 |
=a=2/B15,shp=(B15+1).((v=(a*(#-1)-1),sqrt(1-v*v))) |
|
17 |
=lth=B15 |
|
18 |
=thd=0.025 |
|
19 |
if shape=="u_triangle" |
15 |
20 |
[0,0.4,0.6] |
|
21 |
=B19**B20 |
|
22 |
=(1--B20)**B19 |
|
23 |
=1/B19 |
|
24 |
=shp=(2*B20.len()-1).((if(#%2==1,(a=B23,b=B20((#+2)\2)),(a=-B23,b=1)),n=B22((#+2)\2),n.(a*~+b))).conj().insert(1,0) |
|
25 |
=lth=B19*3 |
|
26 |
=thd=0.02 |
|
27 |
=A5.(if(#<lth.len()+1,,dis(max_min(~[-lth:0]),shp)/lth)) |
|
28 |
=A27.pselect@a(~&&~<thd) |
|
29 |
=A28.group@o(#-~).m(-1).~ |
|
30 |
=A27.run(~=if(!~,0,~)) |
|
31 |
=if(A29,to(max(A29-lth,1),A29)) |
A4:对股价进行后复权,包括开、高、低、收。
我们要找的 K 线形态都有标准形态,只要拿 K 线和标准形态对比,看哪段“长的像”就可以把该段作为想要找的形态了,怎么衡量长的像的程度呢?
下面以头肩顶为例进行介绍:
1. 画出 K 线的标准形态。
B12 生成头肩顶曲线,形态如下:
标准形态最小值为 0,最大值为 1,每个上升段和下降段的长度都是 N(本例中是 8),一共有 6 段,在加上起点,总长度是 6*N+1。这个长度可以根据要观察的 K 线时间长度进行设置,比如要看 97 根 K 线是否形成头肩顶,设置每个上升或下降段的长度为 16(B9 中的参数)即可。
2. 把观察天数(本例是 6*8+1=49)作为移动窗口,对窗口内的后复权股价(本例是收盘价)进行最大最小值归一化,即令最大值等于 1,最小值等于 0,其他按比例缩放,对应 A27 中的 max_min() 方法。
3. 计算标准形态和窗口数据的距离,这里用的是欧式距离,对应 A27 中的 dis() 方法。通常来讲,观察天数越多,与标准形态的距离越远,为了去除观察天数的影响,用距离除以观察天数来衡量与标准形态长的像的程度,我们把它叫做相似距离,相似距离越小,两者越像。
4. 设定一个阈值,相似距离小于阈值(本例中的头肩顶阈值是 0.025)时,认为该移动窗口内的数据是头肩顶形态,否则不是。
圆顶、上升三角形甚至其他形态都可以用类似的方法计算移动窗口内的数据与标准形态的距离相似度,从而找到相似的形态。
下面是这种方法找到的结果:
头肩顶
标准形态:
股票代码:603689
寻找时段:2023 年 8 月 1 日到 2024 年 1 月 31 日
观察天数:49
相似距离阈值:0.025
K 线图:
上半部分是 K 线图,下半部分是成交量柱状图,虚线部分是找到的 K 线形态。
该段收盘价与标准形态的对比图:
左纵轴是复权收盘价,右纵轴是归一化后的值,横轴是该段的序号。
圆顶
标准形态:
股票代码:300701
寻找时段:2023 年 8 月 1 日到 2024 年 1 月 31 日
观察天数:61
相似距离阈值:0.025
K 线图:
与标准形态对比图:
上升三角形
标准形态:
股票代码:300701
寻找时段:2023 年 8 月 1 日到 2024 年 1 月 31 日
观察天数:46
相似距离阈值:0.02
K 线图:
与标准形态对比图:
当阈值设的合适时,该方法能找到形态很像的 K 线形态的。但当阈值过大时,找到的结果可能不太像,阈值过小时,又可能漏掉一些相对较像的,所以需要反复尝试才能找到合适的参数。
还有一个办法,把阈值设置的相对宽松一些,再配合一些其他具体的指标(比如特殊点的位置、大小、交易量等等)把不太像或者不符合要求的 K 线段过滤掉。
类似这种需要反复调试的情况,用 SPL 再合适不过了,它代码写起来灵活,而且能实时查看结果,能节省大量的调试时间。