R 抛物线 SAR 和前视偏差

R Parabolic SAR and Look-Ahead Bias

我正在 R 中使用 SAR() 函数进行测试 TTR 包由 Joshua Ulrich 实施。我不确定这是否是 Parabolic SAR 的标准行为。如果是,我需要一些帮助来实施 "future blind" SAR。

为了简单起见,我将使用短向量和整数值而不是实时序列数据。

L <- c(1:4, 5)
H <- c(2:5, 6)

ParSAR <- SAR(cbind(H, L))
cbind(L, H, ParSAR)

     L H   ParSAR
[1,] 1 2 1.000000
[2,] 2 3 1.000000
[3,] 3 4 1.080000
[4,] 4 5 1.255200
[5,] 5 6 1.554784

我只会在 last 间隔上更改一个值,现在 Low - High 范围是 5 - 7 , 而不是 5 - 6.

L <- c(1:4, 5)
H <- c(2:5, 7)

我们得到:

     L H    ParSAR
[1,] 1 2 0.5527864
[2,] 2 3 0.5817307
[3,] 3 4 0.6784614
[4,] 4 5 0.8777538
[5,] 5 7 1.2075335

Parabolic SAR 的所有历史都被显着修改是预期的行为吗?如果第 1 行到第 4 行上的 SAR 值被第 5 行上不同的 未来值 修改,则会对前面的行引入前瞻性偏差。

如果这是抛物线 SAR 的标准行为并且我需要它进行回测,我将不得不为每一行重新计算它,始终屏蔽所有未来数据(行)。

期望的结果是每一行都有抛物线 SAR 值,因为我可以在特定时刻及时见证它,不知道未来。


编辑2016-06-18

user3666197 的简化代码示例:

> SAR(cbind(c(2, 3, 4, 5, 6), c(1, 2, 3, 4, 5)), c(0.02, 0.2))
[1] 1.000000 1.000000 1.080000 1.255200 1.554784

> SAR(cbind(c(2, 3, 4, 5, 7), c(1, 2, 3, 4, 5)), c(0.02, 0.2))
[1] 0.5527864 0.5817307 0.6784614 0.8777538 1.2075335

pSAR 没有实现任何前瞻性窥视

稍加 code-review of Joshua ULRICH's pSAR implementation 就可以确认源代码中的零前瞻性窥视。

这些问题可能会从函数调用签名的第一眼看出,但 the R-wrapper 修复了这些问题。

#'@export
"SAR" <-
function(HL, accel=c(.02,.2)) {

  # Parabolic Stop-and-Reverse (SAR)
  # ----------------------------------------------
  #       HL = HL vector, matrix, or dataframe
  # accel[1] = acceleration factor
  # accel[2] = maximum acceleration factor
  ...

  # Gap for inital SAR
  initGap <- sd(drop(coredata(HL[,1] - HL[,2])), na.rm=TRUE)

  # Call C routine
  sar <- .Call("sar", HL[,1], HL[,2], accel, initGap, PACKAGE = "TTR")

  reclass( sar, HL )
}

SAR()实现使用sar():

的已发布调用接口

SEXP sar ( SEXP hi, /* HIGH[]-s */ SEXP lo, /* LOW[]-s */ SEXP xl, /* [initial AF value, max AF value] */ SEXP ig /* initial GAP */ )

在任何 for(){...} 扫描仪中都无法窥视未来(零前瞻)(所有扫描仪都纯粹是回顾)。


更新

两个给定数据集的测试输出:

|>>> sar( ( 2, 3, 4, 5, 6 ), ( 1, 2, 3, 4, 5 ), ( 0.02, 0.2 ) )
[1.0, 1, 1.08, 1.2552, 1.5547840000000002]
|
|>>> sar( ( 2, 3, 4, 5, 7 ), ( 1, 2, 3, 4, 5 ), ( 0.02, 0.2 ) )
[1.0, 1, 1.08, 1.2552, 1.5547840000000002]

在 Joshua ULRICH 的 pSAR 算法实施中观察到零前瞻性窥视

Q.E.D.



Ex-post

as noted from the very beginning, the sar() function was proved to be correctly implemented pSAR technical indicator. The R wrapper was the issue, as it decides on what parameters the underlying, correctly working, function sar() is being invoked. Upon a case the call-signature is loaded with parameters, that carry a forward looking bias, the function is not to be blamed for a such behaviour, but rather the user. Q.E.D.

#----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        # CRAN - R-Project TTR lib: indicators::                        # Joshua ULRICH: >>> https://github.com/joshuaulrich/TTR/tree/master/src + https://cran.r-project.org/web/packages/TTR/TTR.pdf
        def sar( Hi, Lo, acceleration_factor = ( 0.02, 0.2 ), initGap = 0. ):
            """                                                         __doc__
            USAGE:      calculate parabolic SAR on given inputs
                        sar( Hi,
                             Lo,
                             acceleration_factor = ( 0.02, 0.2 ),
                             initGap = 0.
                             )
            PARAMS:     Hi:                     High[]s in []-alike representation
                        Lo:                     Low[]-s in []-alike representation
                        acceleration_factor:    [ afSTEP, afMAX ], ref. pSAR rules
                        initGap:                initial gap under first valid Low[]
            RETURNS:    pSAR[]
            THROWS:     n/a
            EXAMPLE:    |>>> QuantFX.sar( (2,3,4,5,6), (1,2,3,4,5) )
                        [1.0, 1, 1.08, 1.2552, 1.5547840000000002]
                        |
                        |>>> QuantFX.sar( (2,3,4,5,7), (1,2,3,4,5) )
                        [1.0, 1, 1.08, 1.2552, 1.5547840000000002]
            """
            """
            #___________________________________________________________/* Initalize loop and PROTECT counters */
            int i, P=0;
            #___________________________________________________________/* Ensure all arguments are double */
            if(TYPEOF(hi) != REALSXP) {
              PROTECT(hi   = coerceVector(hi, REALSXP)); P++;
            }
            if(TYPEOF(lo) != REALSXP) {
              PROTECT(lo   = coerceVector(lo, REALSXP)); P++;
            }
            if(TYPEOF(xl) != REALSXP) {
              PROTECT(xl   = coerceVector(xl, REALSXP)); P++;
            }
            double initGap = asReal( ig );                              ### ------------------------ extern ( ig )
            #___________________________________________________________/* Pointers to function arguments */
            double *d_hi   = REAL(hi);
            double *d_lo   = REAL(lo);
            double *d_xl   = REAL(xl);
            """
            #___________________________________________________________/* Input object length */
            #int nr        = nrows(hi);
            nRows          = len(  Hi )
            #___________________________________________________________/* Initalize result R object */
            #SEXP sar; PROTECT(sar = allocVector(REALSXP,nr)); P++;
            #double *d_sar = REAL(sar);
            sar            = [None] * nRows
            #___________________________________________________________/* Find first non-NA value */
            #int beg       = 1;
            begFrom        = 1
            #for(i=0; i < nr; i++) {
            for i in xrange( nRows ):
              if (  np.isnan( Hi[i] )
                 or np.isnan( Lo[i] )
                 ):
                 sar[i]    = None                                       # NA_REAL; /* skip-it */
                 begFrom  += 1
              else:
                 break                                                  #          /* break   */
              pass
            pass
            #___________________________________________________________/* Initialize values needed by the routine */
            #int sig0 = 1, sig1 = 0;
            sig0           = 1
            sig1           = 0

            xpt0           = Hi[begFrom-1]
            xpt1           = 0

            afStp          = acceleration_factor[0]
            afMAX          = acceleration_factor[1]
            af0            = afStp
            af1            = 0

            sar[begFrom-1] = Lo[begFrom-1] - initGap                    # /* SUB initGap from 1st Lo[] to begin from */

            for i in xrange( begFrom, nRows ):
              #_________________________________________________________/* Increment signal, extreme point, and acceleration factor */
              sig1         = sig0
              xpt1         = xpt0
              af1          = af0
              #_________________________________________________________/* Local extrema */
              lmin         = min( Lo[i-1], Lo[i] )                                      #?? pSAR_RULE_Exc 2 ?? 2 last bars checked
              lmax         = max( Hi[i-1], Hi[i] )
              #_________________________________________________________/* Create signal and extreme price vectors */
              if ( sig1   == 1 ):                                                         #/* Previous buy signal */
                   #ig0    = ( Lo[i] > d_sar[i-1]) ?  1 : -1                              #/* New signal */
                   sig0    =                          1 if ( Lo[i] > sar[i-1] ) else -1   #/* New signal */
                   xpt0    = max( lmax, xpt1 )                                            #/* New extreme price */
              else:                                                                       #/* Previous sell signal */
                   #ig0    = ( Hi[i] < d_sar[i-1]) ? -1 : 1                               #/* New signal */
                   sig0    =                         -1 if ( Hi[i] < sar[i-1] ) else 1    #/* New signal */
                   xpt0    = min( lmin, xpt1 )                                            #/* New extreme price */
              pass
              """
              /*
               * Calculate acceleration factor (af)
               * and stop-and-reverse (sar) vector
               */
              """
              #_________________________________________________________/* No signal change */
              if ( sig0   == sig1 ):
                #_______________________________________________________/* Initial calculations */
                sar[i]     =     sar[i-1] + ( xpt1 - sar[i-1] ) * af1
                #f0        = ( af1 == afMAX ) ? afMAX : ( afStp + af1 )
                af0        =                    afMAX if ( af1 == afMAX ) else ( afStp + af1 )
                #_______________________________________________________/* Current buy signal */
                if ( sig0 == 1 ):
                     #f0   = (xpt0 > xpt1) ? af0 : af1                                  #/* Update acceleration factor */
                     af0   =                 af0 if (xpt0 > xpt1) else af1              #/* Update acceleration factor */
                     sar[i]= min( sar[i], lmin )                                        #/* Determine sar value */
                #_______________________________________________________/* Current sell signal */
                else:
                     #f0   = (xpt0 < xpt1) ? af0 : af1                                  #/* Update acceleration factor */
                     af0   =                 af0 if (xpt0 < xpt1) else af1              #/* Update acceleration factor */
                     sar[i]= max( sar[i], lmax )                                        #/* Determine sar value */
              #_________________________________________________________/* New signal */
              else:
                af0        = afStp                                                      #/* reset acceleration factor */
                sar[i]     = xpt0                                                       #/* set sar value */
              pass
            pass
            #___________________________________________________________/* UNPROTECT R objects and return result */
            #UNPROTECT(P);
            #return(sar);
            return  sar

抛物线 SAR 的 R 实现带有前瞻偏差。

initGap 值是所有时间 HL 数据的标准偏差:

initGap <- sd(drop(coredata(HL[, 1] - HL[, 2])), na.rm = TRUE)

参考文献:https://github.com/joshuaulrich/TTR/issues/23

对我的原始示例的巨大影响是由短数据样本和使用的极值造成的。

@user3666197 :

您的测试对两个简短示例给出了相同的结果,因为在这两种情况下都使用了默认值 initGap = 0.。如上所述,R 包装函数不是这种情况:

  # Gap for inital SAR
  initGap <- sd(drop(coredata(HL[,1] - HL[,2])), na.rm=TRUE)