Mann-Kendall算法用于金融品种长周期趋势判断和变点检测,以及策略思路

之前在研究用机器学习库Sci-kit做计算指标(特征值)和金融产品趋势(分类)关系学习的时候,对于如何判断趋势,是直接使用当前之后5根k线close值做线性回归,如果拟合的P值可信的直线斜率向上则是上涨,斜率向下则是下跌。具体代码可以见之前我之前blog。


在vnpy有个网友讨论,为什么用这样方法判断趋势的时候;我做了些搜索,才发现判断一组时序队列的趋势并不是一个简单的事情,虽然人眼看很直接,但是数学分析并不简单,尤其考虑置信范围和变点存在。


  • 所谓置信范围一两句说不清,可以看看这个问答,我的理解95%置信区间就是在这个一个时序队列里面95%都是符合上涨趋势,但是存在5%可能不符合: https://www.zhihu.com/question/26419030


  • 突变点:变点理论是统计学中的一个经典分支,其基本定义是在一个序列或过程中,当某个统计特性(分布类型、分布参数)在某时间点受系统性因素而非偶然性因素影响发生变化,我们就称该时间点为变点。变点识别即利用统计量或统计方法将该变点位置估计出来。这里主要是用数学方法,过滤出偶尔出现的异常点,和真正改变规律的变点。



其实趋势检测和突变点检测是很数据挖掘很经典的话题,尤其在气象,水文,医药验证等,使用方法很多,从简单的均值,方差,到概率线性回归等。这里主要讲 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程序化,可以学习。

https://blog.csdn.net/u012111465/article/details/82016757


一,趋势校验,算法如下


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

二,突变点校验


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更加适合,用于长线的投资。

策略思路说下:

  1. 读取历史数据,载入close数据;分析过去一组数据中是否存在变异点

  2. 如果有变异点,分析从变异点到最近一个close的趋势,是否满足95%置信区间

  3. 如果满足,结合一些指标,比如布林线,唐安琦等买入或者卖出

  4. 持有后,继续监控趋势,如果低于90%置信区间,平仓。



来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22259926/viewspace-2651575/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/22259926/viewspace-2651575/

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值