白噪声是非常简单的一种建模时间序列的模型。
对于时间序列 { w t } \{w_t\} {wt},若满足下面三个条件,该序列为一个离散的白噪声(white noise):
前两个条件并没有规定 w t w_t wt一定是正态分布。如果是正态分布,那么这个时间序列又叫高斯白噪声(Gaussian white noise)。
回顾上一篇笔记中的平稳性要求,显然一个白噪声序列是符合弱平稳性的(其均值和自相关系数均为固定值,比弱平稳性更加严格一些)。
上一篇笔记中的日收益率序列,不严格地说,其实是一个差分序列。也就是每一个时间点的价格减去前一个时间点的价格(当然,还除以了前一时间点的价格)。
现在我们利用对数收益率处理成纯的差分序列,即每一个时间点价格的对数减去前一个时间点价格的对数。
对于价格的时间序列 { p t } \{p_t\} {pt},其对数收益率序列用下面的公式得到:
α t = ln p t − ln p t − 1 \alpha_t = \ln{p_t}-\ln{p_{t-1}} αt=lnpt−lnpt−1
如果价格序列 { p t } \{p_t\} {pt}体现出足够的自相关性(今天的价格和昨天强相关),那么对数收益率序列应该没有显著的自相关性了(自己减掉自己了)。也就是说对数收益率序列应该近似为一个白噪声。
我们将上一篇笔记的日收益率序列处理成对数收益率序列(即沪深300自2018年1月1日至2019年12月13日的对数收益率序列),如下:
import pandas as pd
import math
prices = get_price('000300.XSHG', start_date='2018-01-01', end_date='2019-12-13', frequency='daily', fields='close')
returns = {'return':{}}
for i in range(len(prices)):
current_price = prices.iloc[i,0]
if i == 0:
current_return = 0
else:
last_price = prices.iloc[i-1,0]
current_return = math.log(current_price)-math.log(last_price)
date = list(prices.index)[i]
returns['return'][date] = current_return
return_df = pd.DataFrame(returns, columns=['return'], index=list(prices.index))
fig = plt.figure(figsize=(10, 6))
ax = fig.add_axes([0.2, 0.2, 1.2, 1.2])
ax.plot(return_df, color="blue", linewidth=1.5, linestyle="-", label=r'hs300-daily-log-returns')
plt.legend(loc='upper right', frameon=False)
return_df.mean()
return_df.std()
它的均值和标准差分别是:-0.000062,0.01315。
然后看看其时间间隔在50以下的相关图(相关图是啥,见上一篇笔记)。
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf
fig = plt.figure(figsize=(10, 6))
ax = fig.add_axes([0.2, 0.2, 1.2, 1.2])
plot_acf(return_df, ax, lags=50)
plt.show()
可以看到,上述收益率序列的均值-0.000062,非常接近于0;样本方差不能代表时间序列的方差,所以方差这一项依据我们暂时放在一边。看看自相关性,对于间隔为3的自相关系数超过了95%的置信区间,但其它都在区间内。
不管怎样,我们说上述对数收益率序列近似为一个白噪声。
随机游走 random walk是对白噪声的简单延伸。
对于时间序列 { x t } \{x_t\} {xt},如果满足如下条件,该时间序列是一个随机游走:
x t = w t + w t − 1 + . . . + w 0 x_t=w_t+w_{t-1}+...+w_0 xt=wt+wt−1+...+w0
其中, w t w_t wt是一个均值为0,方差为 σ 2 \sigma^2 σ2的白噪声。
所以随机游走是白噪声的一个累积。比如,非严格地说,如果把股价看成随机游走,它其实就是每日收益率(如果看成白噪声)的不断累积。
根据均值和方差的可加性可以求得随机游走的的均值和方差:
μ x t = 0 ; V a r ( x t ) = t σ 2 \mu_{x_t}=0; Var(x_t)=t\sigma^2 μxt=0;Var(xt)=tσ2
进一步,随机游走的自协方差也可以计算出来:
C o v ( x t , x t + k ) = C o v ( x t , x t + w t + 1 + . . . + w k ) Cov(x_t,x_{t+k})=Cov(x_t,x_t+w_{t+1}+...+w_k) Cov(xt,xt+k)=Cov(xt,xt+wt+1+...+wk)
= C o v ( x t , x t ) + ∑ i = t + 1 k C o v ( x t , w i ) =Cov(x_t,x_t)+\sum^k_{i=t+1}Cov(x_t,w_i) =Cov(xt,xt)+i=t+1∑kCov(xt,wi)
= C o v ( x t , x t ) + 0 = t σ 2 =Cov(x_t,x_t)+0=t\sigma^2 =Cov(xt,xt)+0=tσ2
有了自协方差,自相关系数也可以算出来:
ρ k ( t ) = C o v ( x t , x t + k ) V a r ( x t ) V a r ( x t + k ) \rho_k(t)=\frac{Cov(x_t,x_{t+k})}{\sqrt{Var(x_t)}\sqrt{Var(x_{t+k})}} ρk(t)=Var(xt)Var(xt+k)Cov(xt,xt+k)
= t σ 2 t σ 2 ( t + k ) σ 2 =\frac{t\sigma^2}{\sqrt{t\sigma^2}\sqrt{(t+k)\sigma^2}} =tσ2(t+k)σ2tσ2
= 1 1 + k t =\frac{1}{\sqrt{1+\frac{k}{t}}} =1+tk1
显然,上面的自相关系数和时间间隔有关,所以不具有平稳性。
另外,当k很小时,自相关系数接近于1。如果把股价走势看成随机游走,那么它的当日价格和昨日价格的相关性理论上非常高。
很多人把上述结论看成是一个重要的工具,于是以今日价格作为次日价格的预测值(因为相关性很高嘛)。看似很有道理,但是策略的期望收益大概率为0。
这里要注意的是,当k很小时,自相关系数接近于1,但不是1!
下面我们用随机游走来生成一些序列看看。就用第二节中的均值(-0.000062)和标准差(0.01315)构建一个高斯白噪声。
设定初始值为3000(昨天,上证第44次突破3000点),然后,我们生成8条随机游走曲线如下:
import numpy as np
import pandas as pd
import math
mu = 0
sigma = 0.01315
num = 500
offsets = [i for i in range(500)]
fig = plt.figure(figsize=(10, 6))
ax = fig.add_axes([0.2, 0.2, 1.2, 1.2])
colors = ['grey', 'brown', 'red', 'sienna', 'olive', 'green', 'blue', 'purple']
for i in range(0, 8):
rand_returns = np.random.normal(mu, sigma, num)
prices = []
for j in range(500):
if j == 0:
current_price = 3000
else:
last_price = prices[j-1]
current_return = rand_returns[j]
current_price = math.pow(math.e, math.log(last_price)+current_return)
prices.append(current_price)
ax.plot(offsets, prices, color=colors[i], linewidth=1.5, linestyle="-", label=r'random walk %d' % i)
plt.legend(loc='upper left', frameon=False)
可以看到,这些数值走势毫无相关性和规律性,在时间推进过程中,波动由于单点白噪声的累积在远端越来越大,但是没有明显的方向性。