HMM、信号、时序、降噪(附代码)
1 前言
我所处理的大多数信号都是有噪声的,反映了潜在价格、成交量、成交额等的噪声。许多基于这些指标的传统策略可能是:
1、利用信号开仓买卖。
2、考虑信号的特定等级来表示一个状态,例如:long {+1},short {-1},neutral {0}
下图是一个检测测下行动量信号的策略。我们的目标是当动量向下时信号为1,当动量向不下时信号为0。一种简单的方法可能是设置一个阈值,在阈值之上将原始信号映射为1,在阈值之下将原始信号映射为0。
在上述情况下,没有阈值水平可以避免0和1状态之间的不必要振荡。例如,在将阈值设置为0.75的情况下,有2次入侵低于阈值(将被映射到状态0)。尝试其他阈值(例如0.5)可以避免在动量期间产生噪音,但此后会遇到噪音。
去噪的信号(如图中的绿线所示)使用隐藏的马尔可夫模型(HMM)。
2 一种解决方案
在上述应用中,我们感兴趣的是配置状态+1和0,以消除信号中的噪声。让我们考虑一种常见的情况,我们想要将{Short,Neutral,Long}状态分配给一个有噪声的信号。
为此,可以构建一个三态系统并分配转换概率,例如从Long到Short,从Neutral到Long,保持在相同状态的转移概率等。
可以将相同的状态概率视为定义给定状态的“粘性”,以及对噪声的抵抗力,否则噪声可能导致我们转移到另一种状态。例如,如果我们给Pshort→short分配一个较高的概率,给脱离那个状态的转移分配一个相应的较低的概率,我们将能够在不转移到另一个状态的情况下承受更多的噪音。
上面的状态系统为我们提供了一个转换矩阵:
请注意,每行的概率总和必须为1,即对于转移矩阵M:∑jMi,j=1 。如果要根据对相同状态的“粘性”来定义降噪模型,则可以将三态转移矩阵的概率确定为:
对于二态矩阵,则为:
3 观测分布
接下来,我们需要考虑如何将(噪声)信号映射到这些状态。HMM采取的方法是引入观测分布p(y|x),其中 y 是我们的观测值(在这种情况下为原始信号),x 是特定的“隐藏状态”。
我们的下一步是为每个状态设计一个观测分布,提供分离以使p(y|x=si)对比p(y|x=sj)的概率对于应该映射到状态si与sj的信号值来说有显著的不同。在下面的示例中,我们使用正态分布将一个有噪声的信号映射到两种状态(long,short):
- Long状态: p(y|x=long)=N(+0.65,σ)或者
- Short状态: p(y|x=short)=N(−0.65,σ)
4 与HMM结合
观测分布为我们提供了 p(y|x=s),但我们正在寻找的是 p(x=s|yn,yn−1,..y0),即在给定观测序列(我们的噪声信号)的情况下处于“ s”状态的概率,yn,yn−1,..y0
HMM模型将转移概率矩阵M联系起来,我们的观测概率分布p(y|x=s)和状态概率先验πs=short,πs=neutral,πs=long进入一个模型,该模型确定我们沿着观测序列进行时最可能的状态。(先验通常被确定为每个状态的频率,例如1 / 3、1 / 3、1 / 3)。
在序列中的每个时间步上,我们都会计算处于xt=s状态的概率如下:
αt(xt)=p(yt|xt)∑xt−1p(xt|xt−1)αt−1(xt−1)
其中p(xt|xt−1) 是我们在所有可能状态组合中的转移概率,由M 和 p(yt|xt) 是我们在给定xt状态下的观测分布 。对于t = 0, αt(xt)根据每个状态的先验分布定义为 p(y0|x0=s)πs
以上内容被分解为动态编程问题。伪代码中的算法如下:
# initialize time step 0 using state priors and observation dist p(y | x = s)
for si in states:
alpha[t = 0, state = si] = pi[si] * p(y[0] | x = si)
# determine alpha for t = 1 .. n
for t in 1 .. n:
for sj in states:
alpha[t,sj] = max([alpha[t-1,si] * M[si,sj] for si in states]) * p(y[t] | x = sj)
# determine current state at time t
return argmax(alpha[t,si] over si)
请注意,以上内容将在对数似然空间中重申,以避免下溢和避免必须计算分布CDF。
5 过滤
总之,映射Long/Short信号或可选状态配置的方法是:
- 以分离信号域中状态的方式定义观测分布
- 定义控制“粘性”(状态转换噪声的数量)的转移概率矩阵
- 定义先验(通常对每个状态的预期频率)
- 使用正向维特比模型确定状态序列 xt:0作为观测到的原始信号序列 yt:0的函数
这是一个示例(我们并未尝试对其进行优化):
from tseries_patterns.ml.hmm import HMM2State
from tseries_patterns.data import YahooData
from talib import ADX
# get price bars
aapl = YahooData.getOHLC("AAPL", Tstart='2019-1-1')
# compute our raw signal (not a very good one, FYI)
rawsignal = ADX(aapl.high, aapl.low, aapl.close, timeperiod=20)
# denoise signal
hmm = HMM2State (means = [10, 40], ss_prob = 0.9999)
## predict 0 and 1 states, rescaling to 10, 40 to align with scale of ADX
denoised = 10 + hmm.predict(rawsignal.dropna()) * 30
# plot
...
上面的HMM2State类显式定义:
- 转移概率矩阵:
- i=j→0.9999和
- i≠j→1−0.9999
- 观测分布为:
- S0=N(μ=10,σdefault)和
- S1=N(μ=40,σdefault)
- 先验概率为πi=1/2
然后使用前向维特比方法确定hmm.predict()调用中的状态。HMM2State 是定义模型的底层scikit hmmlearn实现的简单包装,它绕过了fit() 阶段,定义了模型。
6 替代方案(效果不佳)
HMM的典型方法涉及使用前向—后向算法自动确定:
- 转移概率
- 观测分布
- 先验
例如:
from hmmlearn.hmm import GaussianHMM
rawsignal = ...
model = GaussianHMM(n_components=3)
model.fit (rawsignal)
states = model.decode(rawsignal)
尽管这将找到三种状态,但不太可能不会达到所需的过滤效果:
- 原始信号中的偏差可能会使3个观测值分布产生偏斜
- 转移概率不太可能代表所需的“粘性”,因此也不太可能表示期望的去噪
一般来说,通过自己定义观测分布和转移概率矩阵将会获得更好的结果。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- BigData--Zookeeper介绍和使用
- 一天一大 leet(通配符匹配)难度:困难-Day20200705
- 日志框架,选择Logback Or Log4j2?
- django-rest-framework配置json web token进行接口的认证
- spring中的SpEL表达式
- 京喜小程序首页无障碍优化实践
- 几种排序算法
- 一天一大 leet(转变数组后最接近目标值的数组和)难度:中等 DAY-14
- 推荐一个生成后端模拟数据的懒人工具:lazy-mock
- django-rest-framework框架学习
- 弄懂这 5 个问题,拿下 Python 迭代器!
- 一天一大 leet(跳水板)难度:简单-Day20200708
- 百度一二三面!喜提提起批offer!别问,问就是牛逼!
- 一天一大 leet(计算右侧小于当前元素的个数)难度:困难-Day20200711
- Spring 下,关于动态数据源的事务问题的探讨