郑志勇 ArisZheng
文本是使用Python实现Hurst指数计算,作者王玮珩,从事股票策略研发兼回测系统开发;
Hurst指数是分形技术在金融量化分析中的典型应用。分形是以非整数维形式充填空间的形态特征分形可以说是来自于一种思维上的理论存在1973年,曼德勃罗(B.B.Man-
delbrot) 在法兰西学院讲课时,首次提出了分维和分形几何的设想。分形(Fractal)一词,是曼 德勃罗创造出来的,其原意具有不规则、支离破碎等意义,分形几何学是一门以非规则几何形态为研究对象的几何学。由于不规则现象在自然界是普遍存在的,因此分形几何又称为描述 大自然的几何学。分形几何建立以后,很快就引起了许多学科的关注,这是由于它不仅在理论 上,而且在实用上都具有重要价值。
一、Hurst指数简介
基于重标极差(R/S)分析方法基础上的 Hurst(赫斯特)指数(H)研究是由英国水文专家 H.E.Hurst(1900—1978)在研究尼罗河水库水流量和贮存能力的关系时,发现用有偏的随机 游走(分形布朗运动)能够更好地描述水库的长期贮存能力,并在此基础上提出了用重标极差 (R/S)分析方法来建立 Hurst指数,作为判断时间序列数据遵从随机游走还是有偏的随机游 走过程的指标。
Hurst指数有三种形式:
① 如果 H=0.5,表明时间序列可以用随机游走来描述;
② 如果0.5
③ 如果0≤H<0.5,表明粉红噪声(反持续性),即均值回复过程。< span="">
也就是说,只要 H ≠0.5,就可以用有偏的布朗运动(分形布朗运动)来描述该时间序列
数据。
Mandelbrot在1972年首次将 R/S分析应用于美国证券市场,分析股票收益的变化,Pe-ters把这种方法作为其分形市场假说最重要的研究工具进行了详细的讨论和发展,并做了很
多实证研究。经典的金融理论一般认为股票市场是有效的,已有的信息已经充分在股价上得到了反映,无法帮助预测未来走势,下一时刻的变动独立于历史价格变动。因此股市变化没有 记忆。实际上中国股市并非完全有效,在一定程度上表现出长期记忆性(LongTermMemo-
ry)。中国股市的牛熊交替(2001—2017),伴随着对股市趋势的记忆的加强和减弱的轮换,分 形理论中的重标极差法导出的 Hurst指数可以反映股市的长期记忆性的强弱。用移动时间 区间的 Hurst指数来对照股指的变化,可以分析Hurst指数的高低与市场指数走势的关系。
赫斯特指数预测股票市值走势的三种形式:
① 如果 H=0.5,表明时间序列可以用随机游走来描述。股市未来方向(上涨或者下跌)
无法确定,市场处于震荡行情中。
有方向,若时间周期序列长度为120,当最近半年市场上涨(横盘、下跌),则市场很可能将继续 上涨(横盘、下跌),H 值越大市场保持原有趋势的惯性越大。
③ 如果0≤H<0.5,表明粉红噪声(反持续性),即均值回复过程。股市将改变原有方向, 若时间周期序列长度为120,当最近半年市场上涨(横盘、下跌),则市场很可能将继续下跌或="" 者横盘(上涨或下跌、横盘或上涨),h值越小市场改变原有趋势的可能性越大。<="" span="">
中国的证券市场随着金融产品丰富、监管效率的提高,未来的中国证券市场的有效性将越 来越高。
二、R/S方法计算 Hurst指数
具体参见《金融数量分析基于Matlab编程》第16章
三、 移动平均 Hurst指数计算程序
(1)时间序列分段
子区间长度n 是可变的,如果回归分析需要将时间序列进行分段,例如若时间序列长度为
240,则其可以分解成4段长度为60的等长子区间,或者6段长度为40的等长子区间……
时间序列分段函数(除因子2外,例如240分为2与120或者120与2,因数据段数太少或
者子区间长度太短将影响回归效果)语法如下:
FactorMatrix,FactorNum = HurstFactorization(x)
x:时间序列长度。
输出参数:
FactorMatrix:时间序列分段方案;
FactorNum:时间序列分段方案数量。
py文件 HurstFactorization.py如下:
# -*- coding: utf-8 -*-
import math
def HurstFactorization(x): # hurstFactorization
# codebyawang6254978@163.com
# 2017 09 20
# 因子分解,以4开始以X/4结束
# floor函数表示四舍五入
FactorMatrix = []
N = int(math.floor(x / 4))
# 方案数量初始为0
FactorNum = 0
for i in range(4, N + 1):
# i可以被x整除,即得到一组分解方案
if x % i == 0:
# 方案数量+1
FactorNum = FactorNum + 1
# 将可行方案存储到FactorMatrix中
FactorMatrix.append([i, x / i])
return FactorMatrix, FactorNum
函数测试240共有14个分段方案:
X=240
%调用HurstFactorization函数
﹥﹥[FactorMatrix,FactorNum]=HurstFactorization(x)
%分解方案序列
FactorMatrix=
4 60
……
60 4
FactorNum=
14
(2) Hurst指数计算
时间序列 Hurst指数计算函数语法如下:
HurstExponent=HurstCompute(Xtimes)
输入参数:
Xtimes:时间序列数据。
HurstExponent:为二元向量,第一元素为时间序列的 Hurst指数,第二元素为回归分 析常数项。
注:回归模型log((R/S)n)=log(K)+Hlog(n)。
PY文件 HurstCompute.py如下:
# -*- coding: utf-8 -*-
import numpy as np
from numpy.matlib import repmat
from HurstFactorization import HurstFactorization
def HurstCompute(Xtimes):
# HurstCompute
#codebyawang6254978@163.com
# 2017-09-20
# 输入参数为Xtimes
LengthX = len(Xtimes)
# 进行因式分解
FactorMatrix, FactorNum =HurstFactorization(LengthX)
# 定义LogRS
LogRS = []
# 定义LogN
#LogN=np.zeros([FactorNum, 1])
LogN = []
# 分组计算
for i in range(0,FactorNum):
# 根据因式分解方案,将数量进行分组
# 例如 FactorMatrix(i,:)=[8 30]
# 将240个元素的列向量,转换为8X30的矩阵
dataM = np.reshape(Xtimes,FactorMatrix[i])
# print dataM.shape
#dataM=reshape(Xtimes,FactorMatrix(i,:))
# 计算矩阵每列的均值
MeanM = np.mean(dataM, axis=0)
SubM = dataM - repmat(MeanM, FactorMatrix[i][0], 1)
RVector = np.zeros([FactorMatrix[i][1], 1])
SVector = np.zeros([FactorMatrix[i][1], 1])
# 计算(R/S)n的累加
for j in xrange(0, FactorMatrix[i][1]):
SubVector = np.cumsum(SubM[:, j])
RVector[j] = max(SubVector) - min(SubVector)
SVector[j] = np.std(dataM[:, j])
# 分别计算LogRS、LogN
LogRS.append(np.log(np.sum(RVector / SVector) / FactorMatrix[i][1]))
LogN.append(np.log(FactorMatrix[i][0]))
# 使用最小二乘法进行回归,计算赫斯特指数HurstExponent
HurstExponent = np.polyfit(LogN, LogRS, 1)
return HurstExponent
return HurstExponent函数测试的 PY 文件testHurstCompute.py如下测试方法生成一组布朗运动序列,计算布朗运动序列对数序列的 Hurst指数,共测试10次:
# -*- coding: utf-8-*-
from HurstCompute import HurstCompute
import matplotlib.pyplot as plt
testNum = 10
# 并将结果存储在result中
result = np.zeros([testNum, 2])
for i in xrange(0, testNum):
n = 120 *(i + 1)
dt = 1
# 生存长度不同的布朗运动序列
y =np.cumsum(dt ** 0.5 * np.random.random((1, n)))
# 计算每组序列的Hurst值
result[i,:] = HurstCompute(np.log(y))
#生成图表
plt.plot(range(len(result)), result[:, 0], '*')
#设置标题
plt.title("PyPlot First Example")
#显示图表
plt.show()
测试结果图像如图所示。
结果说明:图16.1横轴表示1~10共10次计算测试,纵轴表示每次测试计算出的 Hurst
指数值。
(3) 移动平均 Hurst指数计算
使用上证指数2000至2017年上证综指时间序列数据,计算其给定移动平均长度的 Hurst指数。编写 MoveHurst.m函数,其中cyclength为计算周期,用户可根据需求 进行修改。
例如计算120个交易日的 Husrt指数,使用的数据为[t-119,t]的价格数据,移动平均的意思为根据t的向前移动,计算指数的数据为[t-119,t]的价格数据,同时根据t进行移动。代码如下:
import xlrd
# MoveHurst
# codebyawwheng 2017 9 20
# 读取xlsx文件
workbook = xlrd.open_workbook("shindex.xlsx")
# 读取Sheet1工作簿
sheet1 = workbook.sheet_by_name('Sheet1')
# 获取行指针
rows = sheet1.nrows
Prices = []
dates = []
for i inxrange(rows): # 循环指针并读取价格与时间数据至Prices,dates Prices.append(sheet1.row_values(i)[0])
dates.append(int(sheet1.row_values(i)[1]))
# 数据长度
DataLength = len(Prices)
# 计算周期
cyclength = 120
# 数据长度是否大于计算周期,若只有100个数据
# 不可能计算出120计算周期的Hurst指数的
if cyclength> DataLength:
plt.plot(range(1, 100), range(1,100), "r*", range(1, 100), range(100, 1, -1), "ro")
else:
# 将价格数据转换为对数数据
logData = np.log(Prices)
# 计算价格的对数数据对应的每日收益率
IndexReturn=(np.array(logData[1:])-np.array(logData[:-1]).tolis())
# 生成Hurst指数并初始化为NaN
hurstE = np.array([np.nan] *DataLength)
# 计算移动的hurst指数
for i in xrange(0, DataLength -cyclength + 1):
HurstExponent =HurstCompute(IndexReturn[i:i + cyclength - 1])
hurstE[cyclength + i - 1] =HurstExponent[0]
# 创建图表
plt.figure(1)
# 在图表1中创建HurstExponent子图
ax1 = plt.subplot(211)
# 设置y轴标签
plt.ylabel("HurstExponent")
# 设置X轴刻度
ax.set_xticklabels(dates,rotation=1)
# 设置数据与数据宽度
plt.plot(hurstE, linewidth=0.5)
# 在图表2中创建logIndex子图2
ax2 = plt.subplot(212)
plt.ylabel("logIndex")
plt.plot(logData, linewidth=0.5)