在量化交易领域,我们经常遇到这样的困惑:为什么基于简单移动平均线或RSI的策略在某些市场环境下表现优异,而在另一些时期却频频失手?答案在于金融时间序列的复杂性——它们不仅具有自相关性,还存在时变的波动率特征。
今天要分析的这个策略,巧妙地结合了AR(2)自回归模型和GARCH(1,1)条件异方差模型,试图从统计学角度解决这个问题。这不是简单的技术指标叠加,而是对金融时间序列本质特征的深度挖掘。
策略的核心在于AR(2)自回归模型的应用。什么是自回归?简单来说,就是用过去的自己来预测未来的自己。AR(2)模型假设当前收益率可以由前两期的收益率线性表示:
r_t = φ₁ × r_{t-1} + φ₂ × r_{t-2} + ε_t
代码中通过Yule-Walker方程求解系数φ₁和φ₂:
c0 = calcAutoCovariance(returns, 0, lengthReg) // 滞后0期自协方差
c1 = calcAutoCovariance(returns, 1, lengthReg) // 滞后1期自协方差
c2 = calcAutoCovariance(returns, 2, lengthReg) // 滞后2期自协方差
phi1 = (c1 * c0 - c2 * c1) / denominator // 第一个自回归系数
phi2 = (c2 * c0 - c1 * c1) / denominator // 第二个自回归系数
这种方法的优势在于:它不依赖主观判断,而是让数据自己”说话”,发现价格序列中隐含的规律性。
仅有AR模型还不够,因为金融市场的波动率并非恒定。我们都知道”波动率聚集”现象——大幅波动往往伴随着大幅波动,平静期往往持续较长时间。
GARCH(1,1)模型正是为了刻画这种特征:
σ²_t = ω + α × ε²_{t-1} + β × σ²_{t-1}
代码中的实现逻辑清晰地体现了这一点:
omega = (1 - adjustedAlpha - adjustedBeta) * longTermVar
garchVariance := omega + adjustedAlpha * math.pow(arResidual[1], 2) + adjustedBeta * garchVariance[1]
这里的关键洞察是:当前的条件方差不仅依赖于上期的残差平方(短期冲击),还依赖于上期的条件方差(长期持续性)。参数α控制短期冲击的影响,β控制波动率的持续性。
有了AR预测和GARCH波动率估计,策略构建了动态的置信区间:
upperReturnBand = arReturnPredict + stdevFactor * garchStd
lowerReturnBand = arReturnPredict - stdevFactor * garchStd
交易信号的生成逻辑体现了均值回归的思想: - 当价格跌破下轨时做多(longSignal = rawPrice < lowerPriceBand) - 当价格突破上轨时做空(shortSignal = rawPrice > upperPriceBand)
这种设计的巧妙之处在于:置信区间的宽度会根据市场波动率动态调整。在高波动期,区间变宽,减少交易频率;在低波动期,区间收窄,增加交易机会。
1. 模型稳定性检验 代码中包含了重要的稳定性检查:
if stabilityCheck >= 0.99 or math.abs(phi2) >= 0.99
scaleFactor = 0.95 / math.max(stabilityCheck, math.abs(phi2) + 0.01)
这确保了AR模型的平稳性,避免了发散的预测结果。
2. 参数收敛性约束 GARCH模型要求α + β < 1以保证长期方差的存在:
if sumParam >= 0.999
scale = 0.99 / sumParam
3. 过滤机制的必要性 策略提供了RSI过滤选项,这在实际应用中很重要。纯统计模型可能忽略市场的趋势性特征,技术指标的加入能够提供额外的确认信号。
尽管这个策略在理论上很优雅,但实际应用中仍需考虑:
数据频率的选择:AR-GARCH模型在不同周期下的表现差异很大。高频数据能提供更多信息,但也引入更多噪音。
参数的时变性:当前实现假设AR和GARCH参数在估计窗口内恒定,但实际市场结构可能发生变化。
交易成本的影响:统计套利策略通常需要较高的交易频率,手续费和滑点成本不容忽视。
这个AR-GARCH策略展示了现代统计学在金融建模中的强大威力。它不是简单的技术指标组合,而是对金融时间序列统计特性的深度挖掘。
对于量化交易者而言,理解这类策略的价值不仅在于直接应用,更在于培养用统计思维分析市场的能力。在AI和机器学习大行其道的今天,这些经典的统计模型依然是我们理解市场、构建策略的重要基石。
/*backtest
start: 2024-09-10 09:00:00
end: 2025-09-09 15:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","balance":10000}]
args: [["ContractType","MA601",360008]]
*/
//@version=5
strategy("AR(2)-GARCH Strategy", overlay=true, default_qty_value=5)
//策略参数设置:配置AR模型、GARCH模型和交易信号的各项参数
lengthReg = input.int(50, "AR估计窗口", minval=50, maxval=200);//AR模型回归窗口长度
//GARCH波动率模型参数:控制条件方差的计算
useGarch = input.bool(true, "启用GARCH波动率");//是否启用GARCH波动率建模
garchAlpha = input.float(0.1, "GARCH Alpha", minval=0.01, maxval=0.3, step=0.01);//GARCH模型alpha参数
garchBeta = input.float(0.85, "GARCH Beta", minval=0.5, maxval=0.95, step=0.01);//GARCH模型beta参数
//交易信号生成参数:控制买卖信号的敏感度
stdevFactor = input.float(2.0, "标准差倍数", minval=1.0, maxval=3.0, step=0.1);//交易波段的标准差倍数
//风险控制参数:设置止损止盈水平
stopLossPerc = input.float(2.0, "止损 (%)", minval=0.5, maxval=5.0, step=0.1);//止损百分比
takeProfitPerc = input.float(4.0, "止盈 (%)", minval=1.0, maxval=10.0, step=0.1);//止盈百分比
//RSI过滤器参数:添加技术指标过滤条件
useRsiFilter = input.bool(false, "启用RSI过滤");//是否启用RSI过滤器
rsiLen = input.int(14, "RSI周期", minval=7, maxval=21);//RSI指标计算周期
rsiOB = input.float(70, "RSI超买线", minval=60, maxval=80);//RSI超买阈值
rsiOS = input.float(30, "RSI超卖线", minval=20, maxval=40);//RSI超卖阈值
//数据预处理:计算收益率序列
rawPrice = close;//原始收盘价
returns = math.log(rawPrice / rawPrice[1]);//对数收益率序列
//获取滞后收益率数据:AR(2)模型需要前两期的收益率数据
returns1 = returns[1];//滞后1期的收益率
returns2 = returns[2];//滞后2期的收益率
//计算收益率序列的移动平均值:作为AR模型的均值项
returnsMean = ta.sma(returns, lengthReg);//收益率的简单移动平均
//AR(2)模型系数计算:使用Yule-Walker方程求解自回归系数
//自协方差函数计算:计算不同滞后期的自协方差
calcAutoCovariance(data, lag, length) =>
mean = ta.sma(data, length);//计算数据的均值
sum = 0.0;//协方差累计值
count = 0;//有效数据点计数
for i = lag to length - 1
if not na(data[i]) and not na(data[i-lag])
sum := sum + (data[i] - mean) * (data[i-lag] - mean);//计算协方差分子
count := count + 1;//累计有效数据点
count > 0 ? sum / count : 0.0;//返回协方差值
//计算AR(2)模型所需的自协方差:用于Yule-Walker方程
c0 = calcAutoCovariance(returns, 0, lengthReg);//滞后0期的自协方差(即方差)
c1 = calcAutoCovariance(returns, 1, lengthReg);//滞后1期的自协方差
c2 = calcAutoCovariance(returns, 2, lengthReg);//滞后2期的自协方差
//Yule-Walker方程求解:计算AR(2)模型的两个自回归系数
// φ₁ = (c₁c₀ - c₂c₁) / (c₀² - c₁²)
// φ₂ = (c₂c₀ - c₁²) / (c₀² - c₁²)
denominator = c0 * c0 - c1 * c1;//分母计算
phi1 = denominator != 0 ? (c1 * c0 - c2 * c1) / denominator : 0.0;//第一个自回归系数
phi2 = denominator != 0 ? (c2 * c0 - c1 * c1) / denominator : 0.0;//第二个自回归系数
//AR(2)稳定性检验:确保模型稳定性条件 |φ₁| + |φ₂| < 1 且 |φ₂| < 1
stabilityCheck = math.abs(phi1) + math.abs(phi2);//计算系数绝对值之和
if stabilityCheck >= 0.99 or math.abs(phi2) >= 0.99
scaleFactor = 0.95 / math.max(stabilityCheck, math.abs(phi2) + 0.01);//计算缩放因子
phi1 := phi1 * scaleFactor;//调整第一个系数
phi2 := phi2 * scaleFactor;//调整第二个系数
//AR(2)收益率预测:根据历史收益率和AR系数预测下一期收益率
arReturnPredict = returnsMean + phi1 * (returns1 - returnsMean) + phi2 * (returns2 - returnsMean);//AR(2)预测公式
//计算AR模型的预测残差:用于GARCH建模
arResidual = returns - arReturnPredict;//AR模型的预测残差
//GARCH(1,1)波动率建模:对AR残差进行条件方差建模
var float garchVariance = na;//GARCH方差变量
var float longTermVar = na;//长期方差变量
//长期方差初始化:使用历史残差计算初始方差值
if na(longTermVar) and bar_index > lengthReg
longTermVar := ta.variance(arResidual, lengthReg);//计算长期方差
//GARCH参数调整:确保参数满足收敛条件
adjustedAlpha = garchAlpha;//调整后的alpha参数
adjustedBeta = garchBeta;//调整后的beta参数
sumParam = garchAlpha + garchBeta;//参数和
if sumParam >= 0.999
scale = 0.99 / sumParam;//计算参数缩放比例
adjustedAlpha := garchAlpha * scale;//调整alpha参数
adjustedBeta := garchBeta * scale;//调整beta参数
//GARCH(1,1)递归更新:根据GARCH公式更新条件方差
if useGarch and not na(longTermVar) and not na(arResidual)
if na(garchVariance)
garchVariance := longTermVar;//初始化GARCH方差
else
omega = (1 - adjustedAlpha - adjustedBeta) * longTermVar;//GARCH常数项
garchVariance := omega + adjustedAlpha * math.pow(arResidual[1], 2) + adjustedBeta * garchVariance[1];//GARCH递归公式
//条件标准差计算:从条件方差计算标准差
garchStd = useGarch and not na(garchVariance) ? math.sqrt(math.max(garchVariance, 0.0001)) : ta.stdev(arResidual, 20);//启用GARCH时使用条件标准差,否则使用历史标准差
//收益率空间的置信区间构建:基于AR预测和GARCH波动率
upperReturnBand = arReturnPredict + stdevFactor * garchStd;//上轨:预测收益率加上标准差倍数
lowerReturnBand = arReturnPredict - stdevFactor * garchStd;//下轨:预测收益率减去标准差倍数
//将置信区间转换为价格空间:用于实际交易信号生成
//基于预测收益率计算预测价格
predictedPrice = rawPrice[1] * math.exp(arReturnPredict);//根据预测收益率计算预测价格
upperPriceBand = rawPrice[1] * math.exp(upperReturnBand);//上轨价格
lowerPriceBand = rawPrice[1] * math.exp(lowerReturnBand);//下轨价格
//交易信号生成:基于当前价格相对于置信区间的位置
longSignal = rawPrice < lowerPriceBand;//做多信号:当前价格低于下轨
shortSignal = rawPrice > upperPriceBand;//做空信号:当前价格高于上轨
//RSI过滤器:使用RSI指标过滤交易信号
if useRsiFilter
rsi = ta.rsi(rawPrice, rsiLen);//计算RSI指标
longSignal := longSignal and rsi < rsiOS;//做多信号需要RSI超卖确认
shortSignal := shortSignal and rsi > rsiOB;//做空信号需要RSI超买确认
//策略执行:根据交易信号开仓和平仓
//开仓操作:根据信号建立多头或空头仓位
if longSignal
strategy.entry("Long", strategy.long);//开多仓
if shortSignal
strategy.entry("Short", strategy.short);//开空仓
//风险控制:设置止损止盈条件
if strategy.position_size > 0
strategy.exit("Long Exit", "Long",
stop=strategy.position_avg_price * (1 - stopLossPerc/100),
limit=strategy.position_avg_price * (1 + takeProfitPerc/100));//多仓止损止盈
if strategy.position_size < 0
strategy.exit("Short Exit", "Short",
stop=strategy.position_avg_price * (1 + stopLossPerc/100),
limit=strategy.position_avg_price * (1 - takeProfitPerc/100));//空仓止损止盈
//图表显示:在图表上绘制价格、预测线和交易信号
//主要价格线和预测线:显示实际价格和基于收益率预测的价格
plot(rawPrice, color=color.white, linewidth=1, title="价格");//绘制实际价格线
plot(predictedPrice, color=color.blue, linewidth=2, title="预测价格");//绘制预测价格线
plot(upperPriceBand, color=color.red, linewidth=1, title="上轨");//绘制上轨线
plot(lowerPriceBand, color=color.green, linewidth=1, title="下轨");//绘制下轨线
//交易信号标记:在图表上标记买卖信号点
plotshape(longSignal, style=shape.triangleup, location=location.belowbar,
color=color.green, size=size.small, title="买入");//标记买入信号
plotshape(shortSignal, style=shape.triangledown, location=location.abovebar,
color=color.red, size=size.small, title="卖出");//标记卖出信号
//波段区域填充:填充上下轨之间的区域以便观察
fill(plot(upperPriceBand, display=display.none), plot(lowerPriceBand, display=display.none),
color=color.new(color.blue, 90));//填充交易波段区域