之前在研究用机器学习库Sci-kit做计算指标(特征值)和金融产品趋势(分类)关系学习的时候,对于如何判断趋势,是直接使用当前之后5根k线close值做线性回归,如果拟合的P值可信的直线斜率向上则是上涨,斜率向下则是下跌。具体代码可以见之前我之前blog。
在vnpy有个网友讨论,为什么用这样方法判断趋势的时候;我做了些搜索,才发现判断一组时序队列的趋势并不是一个简单的事情,虽然人眼看很直接,但是数学分析并不简单,尤其考虑置信范围和变点存在。
所谓置信范围一两句说不清,可以看看这个问答,我的理解95%置信区间就是在这个一个时序队列里面95%都是符合上涨趋势,但是存在5%可能不符合:
突变点:变点理论是统计学中的一个经典分支,其基本定义是在一个序列或过程中,当某个统计特性(分布类型、分布参数)在某时间点受系统性因素而非偶然性因素影响发生变化,我们就称该时间点为变点。变点识别即利用统计量或统计方法将该变点位置估计出来。这里主要是用数学方法,过滤出偶尔出现的异常点,和真正改变规律的变点。
其实趋势检测和突变点检测是很数据挖掘很经典的话题,尤其在气象,水文,医药验证等,使用方法很多,从简单的均值,方差,到概率线性回归等。这里主要讲 Mann-Kendall检验法 。
其他的,网上搜到的好多:
1。均值突变的检测方法有:(1)低通滤波法;(2)t-检验法;(3)Cramer法;(4)滑动t-检验法;(5)Yamaoto法;(6)M-K法;(7)最小二乘法;(8)连续滑动t-检验法;(9)Pttitt法;(10)Lepage法;(11)局部比较法。等等。在均值突变分析中,除了突变点、突变个数的估计外,一般还要分析跃变度等。
2。方差突变的检测方法有:(1)F-检验法;(2)滑动F-检验法;(3)连续滑动F-检验法。等等。
3。线性回归突变(也称趋势突变)的检测方法有:(1)最小二乘法;(2)局部比较法;滑动参数法等等。
4。概率突变的检测方法有:(1)极大似然法;(2)累计次数法;(3)Bayes法;等等。
曼-肯德尔法又称Mann—Kenddall 检验法,是一种气候诊断与预测技术,应用Mann-Kendall检验法可以判断气候序列中是否存在气候突变,如果存在,可确定出突变发生的时间。Mann-Kendall检验法也经常用于气候变化影响下的降水、干旱频次趋势检测。Mann—Kenddall的检验方法是非参数方法。非参数检验方法亦称无分布检验,其优点是不需要样本遵从一定的分布,也不受少数异常值的干扰,更适用于类型变量和顺序变量,计算也比较简便。
具体算法推导不讲了,主要有两种用法,一个是计算这个时序队列的趋势;还有一个是算这个时序队列是否有变点,如果有,是队列中几个点。
代码之前自己写了一些,后来在这个链接发现一个非常全的,修改引用了。他还有其他几个突变点算法的python程序化,可以学习。
一,趋势校验,算法如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
def Mann_Kenddall_Trend_desc(inputdata): # 计算总趋势秩次和 inputdata = np.array(inputdata) n = inputdata.shape[ 0 ] sum_sgn = 0 for i in np.arange(n): if i < = (n - 1 ): for j in np.arange(i + 1 ,n): if inputdata[j] > inputdata[i]: sum_sgn = sum_sgn + 1 elif inputdata[j] < inputdata[i]: sum_sgn = sum_sgn - 1 else : sum_sgn = sum_sgn # 计算Z统计值 if n < = 10 : Z_value = sum_sgn / (n * (n - 1 ) / 2 ) else : if sum_sgn > 0 : Z_value = (sum_sgn - 1 ) / np.sqrt(n * (n - 1 ) * ( 2 * n + 5 ) / 18 ) elif sum_sgn = = 0 : Z_value = 0 else : Z_value = (sum_sgn + 1 ) / np.sqrt(n * (n - 1 ) * ( 2 * n + 5 ) / 18 ) # 趋势描述 # 99% ——> +—2.576 # 95% ——> +—1.96 # 90% ——> +—1.645 if np. abs (Z_value) > 1.96 and np. abs (Z_value) < = 2.576 : if Z_value > 0 : result_desc = u "95% up" else : result_desc = u "95% down" elif np. abs (Z_value) > 2.576 : if Z_value > 0 : result_desc = u "99% up" else : result_desc = u "99% down" else : result_desc = u "not trendency" return result_desc |
二,突变点校验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
def Kendall_change_point_detection(inputdata): inputdata = np.array(inputdata) n = inputdata.shape[ 0 ] # 正序列计算--------------------------------- # 定义累计量序列Sk,初始值=0 Sk = [ 0 ] # 定义统计量UFk,初始值 =0 UFk = [ 0 ] # 定义Sk序列元素s,初始值 =0 s = 0 Exp_value = [ 0 ] Var_value = [ 0 ] # i从1开始,因为根据统计量UFk公式,i=0时,Sk(0)、E(0)、Var(0)均为0 # 此时UFk无意义,因此公式中,令UFk(0)=0 for i in range ( 1 ,n): for j in range (i): if inputdata[i] > inputdata[j]: s = s + 1 else : s = s + 0 Sk.append(s) Exp_value.append((i + 1 ) * (i + 2 ) / 4 ) # Sk[i]的均值 Var_value.append((i + 1 ) * i * ( 2 * (i + 1 ) + 5 ) / 72 ) # Sk[i]的方差 UFk.append((Sk[i] - Exp_value[i]) / np.sqrt(Var_value[i])) # ------------------------------正序列计算 # 逆序列计算--------------------------------- # 定义逆序累计量序列Sk2,长度与inputdata一致,初始值=0 Sk2 = [ 0 ] # 定义逆序统计量UBk,长度与inputdata一致,初始值=0 UBk = [ 0 ] UBk2 = [ 0 ] # s归0 s2 = 0 Exp_value2 = [ 0 ] Var_value2 = [ 0 ] # 按时间序列逆转样本y inputdataT = list ( reversed (inputdata)) # i从2开始,因为根据统计量UBk公式,i=1时,Sk2(1)、E(1)、Var(1)均为0 # 此时UBk无意义,因此公式中,令UBk(1)=0 for i in range ( 1 ,n): for j in range (i): if inputdataT[i] > inputdataT[j]: s2 = s2 + 1 else : s2 = s2 + 0 Sk2.append(s2) Exp_value2.append((i + 1 ) * (i + 2 ) / 4 ) # Sk[i]的均值 Var_value2.append((i + 1 ) * i * ( 2 * (i + 1 ) + 5 ) / 72 ) # Sk[i]的方差 UBk.append((Sk2[i] - Exp_value2[i]) / np.sqrt(Var_value2[i])) UBk2.append( - UBk[i]) # 由于对逆序序列的累计量Sk2的构建中,依然用的是累加法,即后者大于前者时s加1, # 则s的大小表征了一种上升的趋势的大小,而序列逆序以后,应当表现出与原序列相反 # 的趋势表现,因此,用累加法统计Sk2序列,统计量公式(S(i)-E(i))/sqrt(Var(i)) #也不应改变,但统计量UBk应取相反数以表征正确的逆序序列的趋势 # UBk(i)=0-(Sk2(i)-E)/sqrt(Var) # ------------------------------逆序列计算 # 此时上一步的到UBk表现的是逆序列在逆序时间上的趋势统计量 # 与UFk做图寻找突变点时,2条曲线应具有同样的时间轴,因此 # 再按时间序列逆转结果统计量UBk,得到时间正序的UBkT, UBkT = list ( reversed (UBk2)) diff = np.array(UFk) - np.array(UBkT) K = list () # 找出交叉点 for k in range ( 1 ,n): if diff[k - 1 ] * diff[k]< 0 and (UFk[k] > 1.96 or UFk[k] < - 1.96 ) : K.append(k) # 做突变检测图时,使用UFk和UBkT return K |
最后,我尝试着用M-K做了期货策略;长周期来看回测效果还不错,但是太长了,往往就超过一个品种期间,存在跨期的风险。感觉不是和做期货。
对于股票的大蓝筹和etf更加适合,用于长线的投资。
策略思路说下:
读取历史数据,载入close数据;分析过去一组数据中是否存在变异点
如果有变异点,分析从变异点到最近一个close的趋势,是否满足95%置信区间
如果满足,结合一些指标,比如布林线,唐安琦等买入或者卖出
持有后,继续监控趋势,如果低于90%置信区间,平仓。
Mann-Kendall算法用于金融品种长周期趋势判断和变点检测,以及策略思路
原文:https://www.cnblogs.com/chenguopa/p/15240080.html