概述
) K' e5 Q( b6 P" z! z众多外汇和加密货币交易者都希望从短期走势当中获益,但缺乏可以帮助他们奋斗的基本面信息,因而备受困扰。 而这恰是标准时间序列技术可以提供帮助的地方。 George Box 和 Gwilym Jenkins 开发出可以说是最受尊崇的时间序列预测方法。 尽管已经取得了许多大幅进步,改进了原始方法,但其基本原则在今天依旧适用。
; k/ [5 y4 x# l1 F( l/ f' \1 v0 I他们方法的衍生物之一是自回归综合移动平均线(ARIMA),其已成为时间序列预测的流行方法。 它是一类模型,用于捕获数据序列中的时间依赖关系,并提供了针对非稳态时间序列进行建模的框架。 在本文中,我们将采用函数最小化 Powells 方法作为基础创建 ARIMA 训练算法,并利用 mql5 编程语言实现。/ W/ K& d; Z" \" U a! `, c
ARIMA 概览
- p$ K Z6 a1 |: u9 G: ]3 }Box 和 Jenkins 表示,大多数时间序列可以由两个框架中之一个或两个来建模。 其一是自回归(AR),这意味着序列的值可以由与其先前的值相关性来解释,而当中的恒定偏移量和微小的差异,通常称为创新或噪声。 请注意,在本文中,我们将噪声或误差部分称为创新。 创新解释了无法解释的随机变化。
9 y+ c# `% E" Z+ Y) E; }% qARIMA 模型的第二个框架是移动平均线(MA)。该模型指出,序列的值是特定数量的前期创新项、当前创新、和恒定偏移量的比例和。 还有许多其它统计条件可以定义这些模型,但我们不会深入研究细节。 网上有许多资源可以提供更多信息。我们对它们的应用更感兴趣。1 {1 Y* n' b2 S e; u1 E/ [: b
我们不会受限于纯 MA 和 AR 模型,我们可以将它们组合在一起,生成称为自回归移动平均模型(ARMA)的混合模型。 在 ARMA 模型当中,除了恒定偏移量和当前创新项外,我们还指定了有限数量的滞后序列和噪声项。* ^; Y6 x k" g0 s( u7 x
影响所有这些框架应用的基本要求之一是,被建模的序列必须是稳态的。 取决于您对稳态定义的严格程度,到目前为止所描述的模型在技术上都不适合应用于金融时间序列。 这就是 ARIMA 的用武之地。 数学积分是微分的逆向。 当非稳态时间序列相差一次或更多次时,成果序列通常具有更好的稳态。 首先对序列进行微分,可以将这些模型应用于成果序列。ARIMA 中的 “I” 是指逆向(积分)所应用的差分的要求,以便将建模的序列返回到其原始域。5 y1 n! @/ o9 i: g" g( j# I
自回归模型标注法' q0 Z' C# K! a9 {4 o( H5 e2 W
有一个标准标注法来管控模型的描述。 AR 项(不包括常数项)的个数通常称为 p。 MA 项表示为 q,且 d 表示原始序列差异的次数。 使用这些术语,ARIMA 模型被指定为 ARIMA(p,d,q)。 纯过程可以描述为 MA(q) 和 AR(p)。 没有差分的混合模型写为 ARMA(p,q)。 此标注法假定这些术语是连续的。 例如,ARMA(4,2) 表示序列可以用 4 个连续的 AR 项,和两个连续的创新项来描述。 采用 ARIMA,我们可以通过将 p、q 或 d 指定为零值来描绘纯过程。 例如,ARIMA(1,0,0) 简化为纯 AR(1) 模型。
/ \6 `9 @; D! j" `大多数自回归模型指定各自的项是连续的,分别是 AR 项从滞后 1 到滞后 p,及 MA 项滞后 q。 将要演示的算法将允许指定 MA 和/或 AR 项的非连续滞后。 该算法将引入的另一个灵活性是能够指定模型是否带有恒定偏移量。
1 \$ z ~/ W' `$ s# f例如,可以构建由以下函数定义的模型:
' [! S; T( k0 G4 t. l6 w$ V% l% Gy(t) = AR1* y(t-4) + AR2*y(t-6) + E(t) (1)
; q: g5 q J+ `! y5 i上面的函数描述了一个纯 AR(2) 过程,该过程没有恒偏移量,当前值由前期第 4 和第 6 时隙的序列值定义。 标准标注法没有提供指定这种模型的方法,但我们不必被这些限制所束缚。
; u3 L7 |" O2 T$ a计算模型系数和恒定偏移量3 y6 x5 p6 x. \2 H
模型可以具有必须经计算的 p+q 系数。 为此,我们使用模型的规范对已知序列值进行预测,然后将预测值与已知值进行比较,并计算误差的平方和。 最优系数将是产生最小误差平方和的系数。
2 q$ ?2 ~ A3 ?在进行预测时必须小心,无限延伸的数据并不可用,因此会施加限制。 如果模型规范有任何 AR 项,我们只能跳过与所有 AR 项的最大滞后值对应的数值个数之后,再开始进行预测。
$ z e7 y1 B: r使用上面(1)指定的示例,我们只能从时隙 7 开始进行预测。 因为任何超前的预测都会在序列开始之前引用未知值。5 U, V1 W* n: l) C
应该注意的是,如果(1)有任何 MA 项,此时该模型将被视为纯自回归,因为我们还没有创新序列。 随着预测的推进,一系列的创新数值就会不断积累。 回到这个示例,第 7 处时隙的第一个预测将利用人工初始 AR 系数进行计算。
6 e% K: x5 s P# D2 W1 v+ a) B计算出的预测值与第 7 处时隙的已知值之间的差值就是该时隙的创新值。 如果指定了任何 MA 项,则当相应的创新滞后值已知时,在计算预测时将包含它们在内。 否则,MA 项将清零。 在纯 MA 模型的情况下,遵循类似的过程,除了这次,如果应包含恒定偏移量,则将其初始化为序列的均值。
0 u3 C2 U+ Y) T7 l+ q$ h刚才讲述的方法只有一个明显的局限性。 已知序列需要包含与其所应用模型按顺序等量的数值。 更多的项和/或滞后越大,我们需要的值就越多,才能有效地拟合模型。 然后,通过应用相应的全局最小化算法来优化系数,从而完善训练过程。 我们将采用的最小化预测误差的算法是 Powells 方法 。 该实现于此应用的详情记录在文章利用指数平滑进行时间序列预测之中。0 s; X1 `' B$ {, F
CArima 类
* v7 Q& Y1 \) ~+ Q3 H5 qARIMA 训练算法将被包含在 Arima.mqh 文件定义的 CArima 类当中。 该类有两个构造函数,每个构造函数初始化一个自回归模型。 默认构造函数创建一个具有恒定偏移量的纯 AR(1) 模型。/ W0 \/ `4 l4 n' p7 [# H( c- _
CArima::CArima(void)( I( U& r& q4 S, P+ p o, b1 J# P
{* q }. i7 G; S) F/ S
m_ar_order=1;
" c" v* z% Z3 _9 t# S//--- {7 a# ~% Y- C8 ~ h
ArrayResize(m_arlags,m_ar_order);
/ `/ C5 w- |8 x+ S: C: e; b4 Q$ ~for(uint i=0; i<m_ar_order; i++)
1 z# g3 z# }1 y- Km_arlags=i+1;5 } Q9 _' V4 y& `
//---% a( I% ?9 m! E
m_ma_order=m_diff_order=0;" Y; S8 m8 x5 ` `2 R. L7 Q1 c1 l
m_istrained=false;4 c) R/ ?0 D4 K) [2 G: o
m_const=true;
7 i) G, \7 J3 x! ^ArrayResize(m_model,m_ar_order+m_ma_order+m_const);1 M3 G& V" F4 ~" ]4 g1 h0 ?9 h
ArrayInitialize(m_model,0);
$ Z9 T& m. `0 j) f9 T* ~, LCArima::CArima(const uint p,const uint d,const uint q,bool use_const_term=true)% }9 r5 \" i, ]/ {
{
( Q# w' R- S% r4 R. k! _4 g" Mm_ar_order=m_ma_order=m_diff_order=0;
+ ^. L$ p2 ?' t& U- Lif(d)
7 A, }# E4 H [8 \0 u$ ~( {m_diff_order=d;0 {, t" w' X. @( c6 U5 X
if(p)$ \9 q) d. @% K- ]" Z; G) b
{
3 r: w, t/ L% qm_ar_order=p;
/ G$ q* L' l$ h: B" tArrayResize(m_arlags,p);
1 T# C- P1 l p* V3 Z' Ifor(uint i=0; i<m_ar_order; i++)
" P9 l, t) V/ Im_arlags=i+1;
# b' `$ L+ u! q3 h+ x) o* d}
0 ^0 P3 c; X3 l' W2 D4 Kif(q)
$ `# ?7 [3 B- Q9 }, a6 D# \3 L( ~; F- ~{5 z& y( F9 K, [( g
m_ma_order=q;
3 r+ s! o) k' u2 @ArrayResize(m_malags,q);, v- V% A* K5 c! s% p( i% [* z# F
for(uint i=0; i<m_ma_order; i++)
2 g5 Y# F2 }0 }4 N% l/ \m_malags=i+1;
# {+ d" z- m5 P6 `}+ K* Z% J# B+ B5 q
m_istrained=false;
5 q2 _/ `8 l& f5 c8 Y) j% B) |m_const=use_const_term;
/ u: K; c& a# {3 Q& ^$ v* P2 SArrayResize(m_model,m_ar_order+m_ma_order+m_const);
) v0 s. {7 R" r+ v7 t5 ZArrayInitialize(m_model,0);
" H5 l- i1 [, Q" n" U/ l: d}3 P j2 }5 I: l/ `. _, e6 S+ C
除了提供的两个构造函数外,还可以使用重载的 Fit() 方法之一来指定模型。 这两种方法都把建模的数据序列作为其第一个参数。 第一个 Fit() 方法只有一个参数,而第二个方法需要更多的四个参数,所有这些参数都与上表中所记录的参数相同。
0 R+ Q, w; v+ A/ [# I3 [9 xbool CArima::Fit(double &input_series[])
- x: s7 G" T& x" E{
j; e3 u7 Q5 t3 J8 M K# f7 U( zuint input_size=ArraySize(input_series);: o1 v: t& ~; C1 u7 O/ a
uint in = m_ar_order+ (m_ma_order*2);7 g* X" E2 x% f4 c) Q
if(input_size<=0 || input_size<in)
8 Z/ w6 p5 W/ Freturn false;# v4 G7 l1 `% H; k& N! P
if(m_diff_order)7 i7 W Q* `3 w1 v+ i
difference(m_diff_order,input_series,m_differenced,m_leads);
5 r" i# n5 _, t7 I- X% Yelse
8 c1 b* C# j7 g/ T) JArrayCopy(m_differenced,input_series);
- R+ X# P" P4 ]. o6 F* aArrayResize(m_innovation,ArraySize(m_differenced));
1 o K) V2 ?1 I- x7 |! ^1 idouble parameters[];
! x9 K& V* U: i q0 d6 c& OArrayResize(parameters,(m_const)?m_ar_order+m_ma_order+1:m_ar_order+m_ma_order);8 H4 o L. ]- b. W- M5 g" C5 a
ArrayInitialize(parameters,0.0);
1 Q) t, |. q( N( |2 j' Gint iterations = Optimize(parameters);
# p/ Q# s( ?/ q: [7 W% dif(iterations>0)3 Q! e4 v# Y# R% g6 q( q
m_istrained=true;
' v" Q; r& m# p; s0 P4 s. ^) Nelse4 I; l/ ~6 O6 a' v( B
return false;
3 @( ?" U/ }$ S" N( Y' q$ Dm_sse=PowellsMethod::GetFret();) O5 j7 A, K/ I3 k# ~
ArrayCopy(m_model,parameters);3 h, `' f6 j4 A( P$ ]. w# ~# I
return true;% I0 u c. Q- D: d( `( z k- ~. K, t
}
" u9 n2 W# ]% @& K$ y调用更多参数的方法会覆盖以前指定的任何模型,并且还假定每一项的滞后是彼此相邻的。 两者都假定第一个参数指定的数据序列并无差别。 因此,如果由模型参数指定,则会应用差别。 这两种方法都返回一个布尔值,表示模型训练过程的成功或失败。 |