猜涨跌预测

支付宝会员里的猜大盘涨跌一直是一个获取支付宝积分的有效途径。其玩法也非常简单,只需要在股市交易日 13:00 前作出预测——当日的上证指数是涨还是跌,并选择投入的支付宝会员积分即可(目前有20,50,100,200积分四档)。

作为一个羊毛党,试想如果每次都能正确预测出上证指数的涨跌,岂不是可以迅速获取大量支付宝会员积分,兑换大量心水的礼物,想想都觉得很刺激 233。

对上证指数建模

我们采用课本上必学的 Geometric Brownian Motion(几何布朗运动)对上证指数进行建模。简单来说,就是认为上证指数是一个随机过程 StS_t,满足

dSt=μStdt+σStdWtdS_t = \mu S_t dt + \sigma S_t dW_t

这里 WtW_tBrownian Motion(标准布朗运动),μ\muσ\sigma 是常数,称为收益率和波动率。

简单计算(逃……)可知,给定中午休盘的上证指数 S0S_0,交易日结束时的上证指数 StS_t 可以通过如下公式计算

(1)St=S0exp((μσ22)t+σWt)S_t = S_0 \exp\left ( (\mu-\frac{\sigma^2}{2})t + \sigma W_t\right) \tag{1}

这个公式保证了我们只要准确估计出 μ\muσ\sigma,就可以在截止竞猜前准确预估交易日结束时的上证指数相比开盘时上涨的概率,从而指导我们到底应该预测上涨还是下跌了。

估计收益率和波动率

我们用上证指数昨天的历史记录来估计收益率 μ\mu 和波动率 σ\sigma

(1)(1)log(StS0)=(μσ22)t+σWt\log(\frac{S_t}{S_0}) = (\mu-\frac{\sigma^2}{2})t + \sigma W_t 做差分,可以得到

log(St+ΔtS0)log(StS0)=(μσ22)Δt+σ(Wt+ΔtWt)\log(\frac{S_{t+\Delta t}}{S_0}) - \log(\frac{S_t}{S_0}) = (\mu-\frac{\sigma^2}{2})\Delta t + \sigma (W_{t+\Delta t} - W_{t})

也就是

log(St+ΔtSt)=(μσ22)Δt+σ(Wt+ΔtWt)\log(\frac{S_{t+\Delta t}}{S_t}) = (\mu-\frac{\sigma^2}{2})\Delta t + \sigma(W_{t+\Delta t} - W_{t})

Δt=1min\Delta t = 1\min,则 log(St+1St)=(μσ22)+σ(Wt+1Wt)\log(\frac{S_{t+1}}{S_t}) = (\mu-\frac{\sigma^2}{2}) + \sigma(W_{t+1} - W_{t}),并注意到 W1W0,W2W1,...,Wt+1Wti.i.dN(0,1)W_{1} - W_{0}, W_{2} - W_{1},...,W_{t+1} - W_{t} \overset{i.i.d}{\sim} N(0,1)

于是

σ^=std({log(S1S0),log(S2S1),...,log(St+1St),...})μ^=mean({log(S1S0),log(S2S1),...,log(St+1St),...})+σ^22\begin{array}{lll} \hat{\sigma} & = & \text{std}(\{\log(\frac{S_{1}}{S_0}), \log(\frac{S_{2}}{S_1}) , ...,\log(\frac{S_{t+1}}{S_t}),... \}) \\ \hat{\mu} & = & \text{mean}(\{\log(\frac{S_{1}}{S_0}), \log(\frac{S_{2}}{S_1}) , ...,\log(\frac{S_{t+1}}{S_t}),... \}) + \frac{\hat{\sigma}^2}{2} \end{array}

计算指数上涨的概率

假设上一个交易日上证指数收盘为 S1S_{-1},则我们需要计算

P(St>S1)=P(S0exp((μσ22)t+σWt)>S1)=P(Wt>1σ(log(S1S0)(μσ22)t))\begin{array}{lll} P(S_t > S_{-1}) & = & P \left( S_0 \exp((\mu-\frac{\sigma^2}{2})t + \sigma W_t) > S_{-1}\right) \\ & = & P \left( W_t > \frac{1}{\sigma}( \log(\frac{S_{-1}}{S_0}) - (\mu-\frac{\sigma^2}{2})t)\right) \end{array}

注意到 WtN(0,t)W_t \sim N(0, t),于是

(2)P(St>S1)=1Φ(1tσ(log(S1S0)(μσ22)t))P(S_t > S_{-1}) = 1 - \Phi \left( \frac{1}{\sqrt{t}\sigma}( \log(\frac{S_{-1}}{S_0}) - (\mu-\frac{\sigma^2}{2})t)\right) \tag{2}

利用 Python 量化计算

准备数据

拉取昨天和今天9:30AM到12:00AM的上证指数的历史记录

stock-2day

估计收益率和波动率

估计昨天上证指数的收益率和波动率 μ^0\hat{\mu}_0σ^0\hat{\sigma}_0 与今天上午上证指数的收益率和波动率 μ^1\hat{\mu}_1σ^1\hat{\sigma}_1

1
2
3
4
5
6
7
8
9
10
import numpy as np
# sh_yest, sh_tday分别是01-31和02-01上证指数数值(一天和半天)
sh_yest = np.array(sh_yest)
sh_tday = np.array(sh_tday)
# 计算sigma0, sigma1
sig0 = np.std(np.diff(np.log(sh_yest)))
sig1 = np.std(np.diff(np.log(sh_tday)))
# 计算u0, u1
u0 = np.mean(np.diff(np.log(sh_yest))) + sig0 ** 2 / 2
u1 = np.mean(np.diff(np.log(sh_tday))) + sig1 ** 2 / 2

使用今天上午和昨天的平均值作为收益率和波动率的估计

σ^=12(σ^0+σ^1)μ^=12(μ^0+μ^1)\begin{array}{lll} \hat{\sigma} & = & \frac{1}{2}(\hat{\sigma}_0+\hat{\sigma}_1) \\ \hat{\mu} & = & \frac{1}{2}(\hat{\mu}_0+\hat{\mu}_1) \end{array}

1
2
3
# 计算u, sigma
u = 0.5 * (u0 + u1)
sig = 0.5 * (sig0 + sig1)

得到 μ^=1.392×105,σ^=4.326×104\hat{\mu} = 1.392\times 10^{-5}, \hat{\sigma}=4.326\times 10^{-4}

计算今日上涨概率

已知开盘 S1=2597.78S_{-1} = 2597.78,中午休市时 S0=2605.32S_0 = 2605.32,根据公式(2)(2)计算今天交易结束时的上证指数相比开盘时上涨的概率

1
2
3
4
5
from scipy.stats import norm
sp = 2597.78
s0 = 2605.32
t = 120
p = 1.0 - norm.cdf(1.0 / np.sqrt(t) / sig * (np.log(sp / s0) - (u - sig ** 2 / 2) * t))

计算得到 p=0.8318p = 0.8318

决策

所以当预测赔率大于 1p=1.2\frac{1}{p} = 1.2 的时候,就大胆预测今日上证指数会上涨吧,这样就能够薅到支付宝积分的羊毛了(配合使用翻倍卡效果更佳)。

补充数据

如果仅仅只用昨天和今天的历史数据来做决策,可能会错误的估计当前的收益率和波动率,推荐使用根据三年历史数据计算得到的收益率 u=1.3×106u=1.3\times 10^{-6}