很多做数据分析的朋友第一次接触GARCH模型时,都会先被它那一堆数学符号劝退。但如果你真正面对过股票、汇率或商品价格的日收益率序列,就会发现一个特别明显的事实:价格不是一直在温和波动,而是隔一段时间就剧烈震荡一阵,过后又恢复平静。这种"波动聚集"现象,恰恰是GARCH模型最擅长刻画的东西。这篇文章我就以R语言为工具,完整走一遍GARCH建模的实战流程,从数据准备、ARCH效应检验,到模型拟合、诊断、预测和风险度量,把每一步该做什么、为什么这么做、有哪些坑,一次性讲清楚。内容不算难,适合有基本统计基础、想用真实数据上手时序建模的朋友。
1. 波动率的秘密:GARCH模型到底在解决什么问题
1.1 从"方差恒定"到"方差会变"的思维转变
我们在学校学回归分析的时候,默认假设几乎都一样:误差项的方差是一个常数,也就是同方差性。但在真实的金融时间序列里,这个假设基本站不住脚。拿一段日收益率数据来看,你会发现明显的大波动区段和小波动区段交替出现,方差明显随着时间在变化,这就是"异方差性"。如果无视这个特点,仍然用普通回归或者简单ARMA模型去拟合,参数估计本身可能还算一致,但标准误、置信区间、预测区间都会失真,更不用说在风险管理场景下,方差被低估就意味着风险被严重低估。
上世纪八十年代初,经济学家Engle提出了ARCH模型,也就是自回归条件异方差模型,核心想法是把当前的方差表示为过去若干期"新息"(也就是残差)平方的线性组合。这个方向很快就火了,因为收益率序列里最显著的特征——波动率聚集——终于有了一个可估计、可检验的数学框架。但ARCH模型有个实际痛点:为了捕捉波动的持续效应,往往需要很多阶滞后项,参数一多,估计就困难,拟合也不稳定。
所以Bollerslev在几年后做了推广,提出了GARCH模型。它比ARCH高明的地方在于,方差方程里不仅包含过去的残差平方项(ARCH项),还包含了过去的条件方差项(GARCH项)。用GARCH(1,1)这个最经典的设定来说,方差方程写作:
sigma_t^2 = omega + alpha * epsilon_{t-1}^2 + beta * sigma_{t-1}^2
其中alpha就是ARCH项的系数,反映的是"当期新信息对波动率的冲击";beta是GARCH项的系数,反映的是"上一期波动率对当期波动率的延续"。alpha加beta如果接近1,说明波动率的冲击衰减非常慢,也就是的高波动状态会持续较长时间。类似于天气系统:今天的暴雨不仅由昨天的天气决定,昨天的天气状况本身也会延续下来影响今天,GARCH就是把这个"惯性"用数学方式表达出来了。
1.2 GARCH在金融场景里的典型用途
GARCH模型在金融领域的应用范围非常广,凡是需要度量不确定性的地方,它几乎都能派上用场。最直接的应用是波动率预测:在期权定价里,隐含波动率是市场交易出来的,但想做独立的风险评估,就需要用GARCH模型预测未来的波动水平。更常见的场景是风险价值(VaR)和条件风险价值(CVaR)计算,银行和券商做内部风险管控时,经常用GARCH类模型估计组合收益的方差,再结合分布假设计算出分位数。
另一个重要场景是资产配置。投资组合理论里的均值-方差优化,核心输入就是收益率的协方差矩阵。直接用历史样本协方差,往往估计噪音很大,尤其是市场剧烈震荡时参数更新不及时。如果用GARCH族模型分别估计各资产的时变方差,再配合动态相关结构,就能得到一套更贴合当前市场状态的协方差估计。策略研究里,GARCH还常被用来做波动率择时,比如当预测波动率上升到某个阈值时降低仓位,这类逻辑在量化交易里其实非常常见。
但这里要提个醒:GARCH模型本身做的是"条件方差的建模",它的均值方程如果只有常数项,预测的是波动率,而不是收益率的涨跌方向。很多人误以为用GARCH能预测明天股价涨跌,那是对模型的误解。它真正擅长的是回答"明天涨跌我不确定,但波动的剧烈程度大概率会处于什么水平"这个问题。
2. 工具准备:R语言做GARCH分析的完整选型
2.1 需要的R包清单与安装方法
R语言做GARCH建模,生态其实非常成熟。我通常习惯用这几个包配合完成:
rugarch:建模和预测的主力包,支持GARCH、EGARCH、GJR-GARCH等多种变体,也能灵活设定均值方程、分布假设、样本外滚动预测。功能很全,是我最常用的一个。FinTS:提供了方便的ARCH效应检验函数,用来判断数据是否存在条件异方差。tseries:提供ACF、PACF、ADF平稳性检验等基础工具,前期数据探索时会用到。zoo和xts:用来管理时间序列对象,尤其是处理日期对齐、缺失值、滞后项时非常方便。ggplot2:画收益序列图、波动率图和诊断图,出图效果好,方便给非技术同事解释结果。
安装这些包特别简单,直接执行下面的命令就行,注意rugarch依赖的包比较多,首次安装时耐心等一下:
install.packages("rugarch") install.packages("FinTS") install.packages("tseries") install.packages("zoo") install.packages("xts") install.packages("ggplot2")装好之后,加载的时候有个细节:rugarch和tseries里面都可能有同名函数,所以我一般先单独加载rugarch,等做完ARCH检验、需要其他包的功能时再一个个加载,尽量避免两个包同名函数互相遮蔽导致报错。
2.2 数据获取与预处理要点
数据是建模的地基。有的朋友手上有本地Excel导出的行情文件,有的则通过公开的金融数据接口直接拉取数据,不管来源是哪,落到R里后一定要先把它整理成标准的时间序列对象。
假设你的数据是一张有三列的表格:日期、收盘价、成交量,用read.csv读进来之后,第一步就是处理日期。很多行情导出的日期格式是字符串,比如"20230102"或者"2023-01-02",R里解析的时候很容易出问题。我习惯用as.Date配合format参数统一转成标准日期:
data$date <- as.Date(data$date, format = "%Y-%m-%d")然后按日期排序,再把它转成xts对象方便后续处理和画图:
library(xts) price_xts <- xts(data$close, order.by = data$date)价格序列本身一般不平稳,直接建模会出很多问题,所以我们要用对数收益率,而不是简单收益率。对数收益率的计算非常简单,但要注意别把顺序弄反:
log_ret <- diff(log(price_xts)) log_ret <- na.omit(log_ret)为什么要用对数收益率而不是普通百分比收益率?因为对数收益率在时间上具有可加性,两天的连续复利收益率可以直接相加,而且对数变换能在一定程度上压缩极值,让序列更接近正态分布。实操中有个经验:把对数收益率乘以100处理,这样数值的量级在0.1到几个之间,模型系数不会太小,输出结果可读性也更好。
数据清洗这里有一个我踩过的坑:有些接口拉下来的数据里,偶尔会混入价格等于0或空值的行。这样的数据在做对数差分会直接产生Inf或者NA,后面建模时整个模型都会崩溃。所以提前加一步过滤很重要:
data <- data[data$close > 0, ] log_ret <- na.omit(diff(log(price_xts)))预处理完,先画一张收益率序列图看看形态,这一步很直观,能让你对数据的基本特征有个印象:有没有趋势、波动是否聚集、有没有特别极端的单日涨跌。
3. 用数据说话:识别ARCH效应与模型定阶
3.1 收益率序列的特征观察与平稳性检验
拿到收益率序列后,先不要急着建模。我通常会按三个步骤做初步探索。
第一,画收益率的时序图。这一步能直接看到是否存在波动率聚集。以我处理过的一段日频数据为例,2000多个交易日里,明显能看出几个剧烈震荡的区间和几个平缓的区间交替出现,这就是GARCH模型存在的意义。如果时间序列图看不出任何波动聚集特征,建模的动力就要大打折扣。
第二,看收益率的分布特征。金融收益率普遍具有"尖峰厚尾"的特征,也就是均值附近的数据比正态分布更多,同时极端值出现的概率也更高。可以用hist或者density函数画分布图,再用偏度和峰度指标量化一下。R里可以用moments包或者直接自己写个函数算:
library(moments) skewness(log_ret) kurtosis(log_ret)如果峰度明显大于3,说明尾部比正态分布厚,后面设定分布假设时就不能直接用正态分布,要考虑std(Student-t分布)或者sstd(偏斜t分布)。
第三,做平稳性检验。虽然GARCH模型本身不要求收益率序列必须平稳的假设那么苛刻,但均值方程如果是ARMA形式,平稳性就很重要。最常用的是ADF检验:
library(tseries) adf.test(as.numeric(log_ret))p值小于0.05就拒绝单位根原假设,说明序列平稳。对绝大多数股票、指数、汇率日收益率来说,这一步基本都能过,如果没通过,多半是数据预处理环节出了问题。
3.2 ARCH效应检验:Ljung-Box与LM检验
在拟合GARCH模型之前,有一个步骤不能跳过:检验数据中是否真的存在ARCH效应。如果没有条件异方差,强行建模相当于多此一举,还会引入不必要的参数。
最直观的方法是看平方收益率的自相关函数(ACF)。因为条件异方差意味着方差不恒定,而方差又可以看作"收益率的平方",所以如果原始收益率没有明显的自相关,但平方收益率存在显著的自相关结构,就说明波动率存在某种可预测的模式。
acf(as.numeric(log_ret)^2, lag.max = 20, main = "平方收益率ACF图")如果图中多个滞后期都超出蓝色置信带,基本上可以初步判定存在ARCH效应。
正式的统计检验有两个常用方法。第一个是Ljung-Box检验,它检验的是平方收益率序列在若干滞后阶上是否存在自相关:
Box.test(as.numeric(log_ret)^2, type = "Ljung-Box", lag = 10)p值如果小于0.05,拒绝"平方收益率序列不存在自相关"的原假设,意味着条件异方差存在。第二个是FinTS包里的ArchTest函数,它做的是拉格朗日乘子(LM)检验,原理是用收益率平方对滞后的收益率平方做辅助回归,检验回归系数的联合显著性:
library(FinTS) ArchTest(as.numeric(log_ret), lags = 10)注意这里的lags可以多试几个值,比如5、10、15。如果结果在多个滞后阶数下都非常显著,说明数据里蕴含的ARCH效应是稳健的。这两个检验在实操中可以同时做,相互印证。
3.3 GARCH阶数选择的经验法则
确认了ARCH效应的存在,下一步就是确定GARCH模型的阶数,也就是p和q的取值。有些朋友一上来就想着用AIC/BIC在很宽的阶数空间里搜索,但实际操作中要慎重,因为GARCH阶数搜索的计算量不小,而且很容易过拟合。
其实大多数金融序列用GARCH(1,1)就够了。这不是偷懒,而是有理论依据的:GARCH(1,1)虽然只含有一阶滞后项,但它通过迭代可以等价于一个无限阶的ARCH模型,也就是说,两个参数就能捕捉相当长周期的波动率持续性。很多实证研究都表明,GARCH(1,1)在样本外的预测表现并不输给更高阶的模型,这就是所谓的"参数节俭原则"。
当然,如果GARCH(1,1)的残差诊断没通过,比如标准化残差的平方还有显著自相关,那就需要扩展阶数。比较靠谱的做法是在GARCH(1,1)、GARCH(1,2)、GARCH(2,1)之间做几个候选模型的比较,用AIC或BIC选择最优,但候选模型控制在个位数以内,别让它变成一个大网格搜索。
另外,如果数据存在明显的非对称效应,也就是利空消息和利好消息对波动率的冲击不一样,那普通GARCH模型就不太够用了,需要换成GJR-GARCH或EGARCH。判断非对称效应的方法很简单:先把收益率按正负分组,看看负收益期的波动是不是显著更大。很多股票数据都存在这种"杠杆效应",这时候在rugarch里把模型类型设置为"gjrGARCH"就能处理。
4. 模型拟合与诊断:让GARCH参数落地
4.1 用rugarch拟合GARCH(1,1)模型
rugarch包的使用逻辑和大多数计量软件不一样,它把整个模型设定拆成了规范和估计两步。第一步用ugarchspec设定模型结构,第二步用ugarchfit完成参数估计。
规范的设定看起来是这样的:
spec_garch11 <- ugarchspec( variance.model = list(model = "sGARCH", garchOrder = c(1, 1)), mean.model = list(armaOrder = c(0, 0), include.mean = TRUE), distribution.model = "std" )这里简单解释一下各部分的意思。variance.model里model = "sGARCH"表示标准GARCH模型,garchOrder = c(1,1)说明方差方程里含一阶ARCH项和一阶GARCH项。mean.model里armaOrder = c(0,0)表示均值方程不含ARMA项,只有常数项,这是最标准、也最常用的一种GARCH设定。收益率的均值本身极难预测,单纯为收益序列配一个很高的ARMA阶数往往只会增加过拟合风险,所以均值方程用常数就很合理。
我说一下为什么把均值方程设成常数:金融理论中,有效市场假说认为历史价格无法预测未来的涨跌方向,日收益率序列的自相关性通常非常微弱。均值方程设ARMA结构对样本内的拟合提升极小,却增加了参数数目,还容易导致估计不稳定。所以除非有明显的自相关证据,比如某些流动性较差的资产或低频数据出现显著自相关,否则均值方程保持简单永远是更稳的选择。
然后调用ugarchfit进行拟合:
fit_garch11 <- ugarchfit(spec = spec_garch11, data = log_ret) fit_garch11拟合结果的输出里,重点关注几个数字:omega、alpha1、beta1,以及shape。omega是长期方差水平的截距项,alpha1和beta1加总如果接近1,说明波动冲击衰减很慢、波动率的持续性高。shape是t分布的自由度参数,自由度越低,尾部越厚,说明数据里极端值越常见,t分布的设定比正态分布更契合数据特征。
4.2 用残差诊断判断模型是否合格
拟合完成后,最关键的环节是模型诊断,也就是检查模型的假设是否成立。GARCH模型的适用性主要看标准化残差是否满足两个条件:第一,没有自相关性;第二,平方标准化残差没有额外的ARCH结构。
所谓标准化残差,就是原始残差除以模型估计出的条件标准差。如果模型设定正确,这部分序列应该近似独立同分布,不应该再包含可预测的信息。在rugarch里提取很方便:
std_resid <- residuals(fit_garch11, standardize = TRUE)然后对标准化残差做Ljung-Box检验,滞后阶选10或15都可以:
Box.test(std_resid, type = "Ljung-Box", lag = 10) Box.test(std_resid^2, type = "Ljung-Box", lag = 10)第一个检验的原假设是标准化残差没有自相关,p值大于0.05就是好事,说明均值方程设定基本合理。第二个检验的原假设是标准化残差平方没有自相关,p值大于0.05说明GARCH部分已经充分捕捉了条件异方差,这是模型有效性最有力的证据。
如果第二个检验的p值很小,说明残差里还残留着可预测的波动率结构,这时候要考虑调整阶数或者换模型形式。比如先试GARCH(2,1),再试GJR-GARCH,看看哪个能让诊断通过。
还有一张图值得仔细看:标准化残差平方的ACF图。图形上如果只有少数几个点略微超出置信带,大概率是随机波动;但如果多个滞后项持续超出,说明模型仍然欠拟合。诊断这个环节不能只看检验p值,图的样子也很重要,两份证据相互补充才可靠。
4.3 分布假设:正态、t分布还是偏斜t分布
GARCH模型的参数估计用的通常是极大似然方法,而似然函数的形式取决于你对残差分布做了什么样的假设。最常见的三种选择是正态分布、标准t分布、偏斜t分布。
rugarch里对应参数是:
distribution.model = "norm" # 正态分布 distribution.model = "std" # t分布 distribution.model = "sstd" # 偏斜t分布正态分布假设计算最简便,但金融数据很少有真正的正态分布。t分布因为有额外的自由度参数能刻画厚尾,是更实用的选择。偏斜t分布在t分布的基础上又多了一个偏度参数,适合那些正负收益率分布不对称的资产。
实际操作中,我建议至少把正态和t分布各拟合一遍,用AIC和BIC做比较。AIC和BIC都是越小越好,如果t分布的AIC比正态分布的AIC低不少,基本可以确定厚尾假设更有必要。要注意的是,AIC和BIC在rugarch的拟合结果输出中都有直接给出,也可以像这样提取:
infocriteria(fit_garch11)这里特别提醒下:很多新手在做GARCH建模时,会先看正态分布的拟合结果,发现不理想后直接上偏斜t分布,但完全没关注参数估计的稳定性。实际上只要样本量不太小,带更多参数的分布假设在样本内总能获得更大的似然值,但样本外未必更好。判断的标准应该是"诊断是否通过、参数是否经济、AIC是否真的下降",而不是一味追求复杂的分布设定。
5. 让模型干活:波动率预测与VaR度量
5.1 未来波动率预测与方差回复特性
GARCH模型的一大优势就是可以进行波动率预测。用最新的数据拟合出参数之后,未来的条件方差就可以被逐步递推出来。
rugarch里用ugarchforecast函数做预测,我们来预测未来10个交易日的波动率:
garch_fc <- ugarchforecast(fit_garch11, n.ahead = 10) garch_fc # 查看预测的标准差(即波动率) sigma(garch_fc)输出的结果是一个按时间排开的波动率序列。你大概率会看到一个现象:预测的波动率会从当前水平开始,逐渐向长期平均波动率靠拢。这就是GARCH模型的均值回复特性。在当前波动率偏高时,预测未来短期内波动会缓慢下降;在当前波动率偏低时,预测未来波动会缓慢上升。这个特性特别符合直觉:市场不可能永远处于高波动或者低波动状态。
有一个细节需要注意:多步预测的波动率回复速度取决于alpha1 + beta1的和。这个和越接近1,回复越慢,意味着高波动状态延续的时间越长,此时预测结果的路径也会更平缓。很多研究把这个和作为"波动率持续性"的度量指标,在金融实践中它对应的就是市场对冲击的记忆长度。
5.2 基于GARCH的VaR计算
GARCH预测出的条件标准差,正好可以用来计算风险价值(VaR)。VaR的含义很简单:在给定的置信水平下,某一资产在持有期内可能遭受的最大损失。最常用的是95%和99%置信水平。
用参数法计算VaR的思路是:假设收益率服从某种分布,用预测出的条件均值和条件标准差构造分位数,再根据分位数算出损失边界。公式形式是:
VaR(95%) = -(mu + quantile_5% * sigma_t)
其中mu是条件均值,sigma_t是预测的条件标准差,quantile_5%是分布假设下5%的分位数。对于正态分布,5%的分位数大概是-1.645;对于t分布,要根据自由度算具体分位数。
在R里可以这样实现:
# 提取预测的均值项和标准差项 mu_fc <- fitted(garch_fc) sigma_fc <- sigma(garch_fc) # 以t分布为例,提取自由度参数 shape_param <- coef(fit_garch11)["shape"] # 计算5%分位数 q5 <- qt(0.05, df = shape_param) # 计算95% VaR(取正值表示损失) var_95 <- -(mu_fc + q5 * sigma_fc)如果用的是std分布,注意qt函数里的自由度是模型估计出的shape参数。这个细节很容易被忽略,如果直接用qnorm(0.05),在厚尾数据下会低估VaR,也就是低估风险。
对比一下你会看到,t分布假设下的VaR通常比正态分布假设下的VaR更大,这就是厚尾效应在风险管理中的具体体现。表面上只是一个分布假设的差异,但在真正的风控场景里,差异意味着真金白银的保证金规模。
5.3 滚动预测与样本外回测
单次预测只能得到一条波动率路径,但要评估一个模型的预测能力是否靠谱,一定要做样本外回测。基本思路是这样的:将数据分为样本内(用于估计参数)和样本外(用于验证预测),从某个时间点开始,用历史数据预测下一期的波动率,然后跟真实实现的波动率进行比较,再往前滚动一格,重复这个过程。
rugarch里封装了滚动预测函数ugarchroll,调用方式如下:
garch_roll <- ugarchroll( spec_garch11, data = log_ret, n.start = 800, refit.every = 25, forecast.length = 500 )n.start表示起始的样本内长度,比如800个观测;refit.every表示每隔多少个观测重新估计一次参数;forecast.length表示要预测多少个样本外观测。参数重估的频率很重要:如果每天重估,计算量大但参数最及时;如果每隔太长才重估,市场结构可能已经变了。一般日频数据里,20到25个交易重估一次是比较平衡的选择。
回测结果可以导出成数据框,用来计算实际收益是否落在预测的范围内:
roll_df <- as.data.frame(garch_roll)对于VaR的验证,核心指标是"失败率",也就是实际损失超过VaR的次数占比。如果置信水平是95%,理论上失败率应该在5%左右。如果实际失败率远高于5%,说明模型低估了风险;如果远低于5%,说明模型过于保守。利用VaR列和真实收益率做比较,这个检查非常直观。
6. 实战中容易踩的坑与排查方法
6.1 模型估计不收敛怎么办
GARCH模型的参数估计过程本质上是非线性优化,最常见的报错就是"非收敛"或"收敛失败"。遇到这种情况,第一个要检查的是数据本身:是否有缺失值、是否有异常极端值。极端值过大时,条件方差方程会被一个观测拉得很高,对数似然函数的表面变得很不光滑,优化算法就找不到最优解。
处理办法有几个思路。第一,可以把数据标准化,比如把收益率乘以100,让数值量级处在更舒服的范围。第二,给ugarchfit传更多的优化控制参数:
fit_garch11 <- ugarchfit( spec = spec_garch11, data = log_ret, solver = "hybrid" )solver = "hybrid"表示让包自动尝试多个求解器,很多情况下能解决收敛问题。第三,如果依然不收敛,可以考虑简化模型设定,比如去掉均值方程里的常数项,或者把t分布换成正态分布。分布假设越复杂,似然面越复杂,收敛就越困难。
6.2 均值方程要不要加ARMA项
不少朋友在建模时习惯性地给均值方程加一个ARMA结构,理由是"这样更严谨"。但实际运用中,日频收益率序列的均值自相关往往非常微弱,ARMA项不仅几乎不提升预测效果,还会导致参数之间的干扰。尤其在某些异常交易日,均值方程里ARMA项的系数会发生跳跃,反过来影响残差序列,进而污染方差方程的估计。我的习惯做法是:先用ACF/PACF判断一下收益率本身的自相关,如果滞后几阶都不显著,均值方程就用常数;如果确实存在显著自相关,再摸索ARMA阶数,但每加一个参数都要做一轮残差诊断验证。
6.3 样本长度和数据频率的权衡
GARCH模型的参数估计对样本量是有要求的。数据量太少时,参数估计的方差会很大,特别是t分布的自由度参数非常不稳定。我曾经用200个数据点拟合GARCH(1,1),结果AIC和系数每次滚动重估都大起大落,这样的模型根本没法用来做历史回测。
笼统地说,日频数据至少要有一千个左右的观测值,也就是大概四年的交易数据,参数估计才算稳定。如果只有几百个观测,可以考虑用周频数据,虽然样本个数更少,但每个观测包含的信息更稳定,有时候模型表现反而更好。数据频率和建模目的必须匹配:如果是做日内的风险监控,当然用日频甚至高频数据;如果是做中长期波动率配置,周频数据往往噪音更少。
注意:GARCH模型估计的是条件方差,对数据频率非常敏感。换算波动率时,日频波动率换算成年度波动率一般要乘以sqrt(252),也就是一年的交易日数。这个细节经常有人弄错,导致预测的波动率数值看起来严重偏差。
还有一个容易忽略的点:交易日和自然日的差异。节假日会导致收益率序列中某些日期间的间隔不是一天,但对于日频建模来说,大部分实践都直接按等间隔处理,这是行业的通用近似做法。如果做的是跨周预测,可以考虑在预测时适当调整时间尺度,但没必要把一个日频模型复杂化到逐日校准节假日。
7. 个人实操中的延伸体会
有关GARCH模型的实操技巧,最后再分享几点积累的经验。第一,模型拟合完不是终点,一定要把预测的波动率序列画出来看。很多时候模型输出几个参数觉得很完美,但画出来的波动率曲线明显不符合常识,比如某些时段的剧烈波动被严重平滑掉,这时要回头检查模型的分布假设和阶数选择。第二,GARCH模型的预测结果应当始终作为"参考分布"来使用,而不是当作确定性的结论。在真实的资金管理场景里,它给出的是一整套风险情境的概率描述,需要结合压力测试、情景分析一起使用,而不是孤零零看一组数字。第三,多模型对比永远比单模型可靠,我常把GARCH(1,1)、GJR-GARCH(1,1)、EGARCH(1,1)同时跑一遍,看它们的波动率预测路径是否互相印证。市场结构在演变,模型组合比单个模型更能反映不确定性。
我自己的习惯是在每个季度末把数据区间滚动更新一遍,重新估计参数,然后对比新旧参数的差异幅度。如果差异明显偏大,往往意味着这段时间市场的波动机制发生了变化,这时候模型的持续性和均值回复特征都要重新审视。这个过程虽然比"拟合一次模型就完事"要繁琐,但它才是量化分析真正落到实处的关键一步。