代码实现 BTC vs 美股(SPY)对比收益率自相关性
对比四件事:
- |rₜ| 自相关(波动聚集)
- rₜ² 的 ARCH / GARCH 结构
- Realized Volatility 的长记忆
- 低频收益(周 / 月)的趋势性
特点
- 只依赖
yfinance + numpy + pandas + statsmodels + arch - 不做花哨回测,只做统计证据
- BTC vs 美股(SPY)对照
一、环境依赖
pip install yfinance numpy pandas statsmodels arch scipy
二、数据获取(BTC vs SPY)
import yfinance as yf
import numpy as np
import pandas as pd
def get_returns(ticker, start="2018-01-01"):
df = yf.download(ticker, start=start, progress=False)
px = df["Adj Close"].dropna()
ret = np.log(px).diff().dropna()
return ret
btc_ret = get_returns("BTC-USD")
spy_ret = get_returns("SPY")
三、1️⃣ |rₜ| 的自相关(波动聚集)
from statsmodels.tsa.stattools import acf
def acf_summary(series, nlags=50):
return acf(series, nlags=nlags, fft=True)
btc_abs_acf = acf_summary(np.abs(btc_ret))
spy_abs_acf = acf_summary(np.abs(spy_ret))
print("BTC |r_t| ACF (first 10 lags):", btc_abs_acf[:10])
print("SPY |r_t| ACF (first 10 lags):", spy_abs_acf[:10])
你会看到:
- BTC:缓慢衰减,10–20 lag 仍明显 > 0
- SPY:5–10 lag 内迅速贴近 0
👉 这是你表中 “非常强 | 波动率聚集” 的第一条证据。
四、2️⃣ rₜ² 的 ARCH / GARCH 结构
1. Ljung–Box(检验是否白噪声)
from statsmodels.stats.diagnostic import acorr_ljungbox
lb_btc = acorr_ljungbox(btc_ret**2, lags=[10, 20], return_df=True)
lb_spy = acorr_ljungbox(spy_ret**2, lags=[10, 20], return_df=True)
print("BTC r^2 Ljung-Box:\n", lb_btc)
print("SPY r^2 Ljung-Box:\n", lb_spy)
BTC 的 p-value 通常 接近 0,SPY 明显更弱。
2. GARCH 参数对比
from arch import arch_model
def fit_garch(ret):
model = arch_model(ret * 100, vol="Garch", p=1, q=1, dist="normal")
res = model.fit(disp="off")
return res
btc_garch = fit_garch(btc_ret)
spy_garch = fit_garch(spy_ret)
print("BTC GARCH params:\n", btc_garch.params)
print("SPY GARCH params:\n", spy_garch.params)
重点看:
alpha_beta_btc = btc_garch.params["alpha[1]"] + btc_garch.params["beta[1]"]
alpha_beta_spy = spy_garch.params["alpha[1]"] + spy_garch.params["beta[1]"]
print("BTC α+β =", alpha_beta_btc)
print("SPY α+β =", alpha_beta_spy)
典型结果:
- BTC:α + β ≈ 0.95 – 1.0
- SPY:α + β ≈ 0.85 – 0.9
👉 这就是 “BTC 接近 IGARCH” 的实证体现。
五、3️⃣ Realized Volatility 的长记忆(Hurst)
yfinance 没有分钟数据,但我们可以用 日内平方收益近似 做一个简化版本。
1. 构造 RV(滚动)
def realized_volatility(ret, window=5):
return (ret**2).rolling(window).sum().dropna()
btc_rv = realized_volatility(btc_ret, window=5)
spy_rv = realized_volatility(spy_ret, window=5)
2. Hurst 指数估计(R/S)
from scipy.stats import linregress
def hurst_exponent(ts):
lags = range(2, 50)
tau = [np.std(ts.diff(lag).dropna()) for lag in lags]
slope, _, _, _, _ = linregress(np.log(lags), np.log(tau))
return slope
print("BTC RV Hurst:", hurst_exponent(btc_rv))
print("SPY RV Hurst:", hurst_exponent(spy_rv))
经验结果:
- BTC:H ≈ 0.7–0.85
- SPY:H ≈ 0.55–0.65
👉 对应你表里的 “Realized volatility | 长记忆”。
六、4️⃣ 低频收益(周 / 月)趋势性
1. 聚合收益
btc_weekly = btc_ret.resample("W").sum()
spy_weekly = spy_ret.resample("W").sum()
btc_monthly = btc_ret.resample("M").sum()
spy_monthly = spy_ret.resample("M").sum()
2. 一阶自相关
def lag1_corr(series):
return series.autocorr(lag=1)
print("BTC weekly autocorr:", lag1_corr(btc_weekly))
print("SPY weekly autocorr:", lag1_corr(spy_weekly))
print("BTC monthly autocorr:", lag1_corr(btc_monthly))
print("SPY monthly autocorr:", lag1_corr(spy_monthly))
常见现象:
- BTC:显著正相关
- SPY:弱正或接近 0
3. 最简单的动量 t-stat
def momentum_tstat(series):
mean = series.mean()
std = series.std()
n = len(series)
return mean / (std / np.sqrt(n))
print("BTC monthly momentum t:", momentum_tstat(btc_monthly))
print("SPY monthly momentum t:", momentum_tstat(spy_monthly))
👉 你会看到 BTC 在低频上的 t-stat 明显更高。
七、把“实证结果”映射回你那张表
| 序列 | 实证证据 |
|---|---|
| |rₜ| | ACF 缓慢衰减 |
| rₜ² | Ljung–Box 拒绝 + α+β≈1 |
| RV | Hurst > 0.7 |
| 周/月收益 | 正自相关 + 动量 t-stat |
八、专业提醒(很重要)
- 不要用 rₜ 的 ACF 否定 BTC 的可预测性
- 所有可利用信号都在“状态变量”而非“方向变量”
- 这套框架是:
- 研究级验证
- 不是直接盈利策略