Saturday, November 5, 2016

Financial products with capital protection barrier - part 3

Structural Changes

Abstract

In this post, I will start over the exploratory analysis with the investigation of structural changes presence in our time series. The analysis of structural changes is particular important in order to determine if the observation history under analysis has homogeneous properties.

Analysis

I am going to introduce each structural test, outlining basic concepts and results.

a. EFP (Empirical Fluctuation Process) CUSUM Tests

The generalized fluctuation tests fit a model to the given data and derive an empirical process, that captures the fluctuation either in residuals or in estimates. For these empirical processes the limiting processes are known, so that boundaries can be computed, whose crossing probability under the null hypothesis is \(\alpha\). If the empirical process path crosses these boundaries, the fluctuation is improbably large and hence the null hypothesis should be rejected (at significance level \(\alpha\)).

The EFP CUSUM tests are one kind of EFP tests, which contain cumulative sums of standardized residuals. Under the null hypothesis the limiting process for the empirical fluctuation process Wn(t) is the Standard Brownian Motion.

However Zeileis (see ref. [3]) examined the properties of the alternative boundaries and showed that the resulting OLS-based CUSUM test has better power for structural changes early and late in the sample period. That is why I am going to check against alternative boundaries too.

Here below I am going to test our time series against recursive CUSUM test, with standard linear boundaries and alternative ones.

load(file="structured-product-1.RData")
invisible(lapply(ts.package, function(x) {
  suppressPackageStartupMessages(library(x, character.only=TRUE)) }))

par(mfrow=(c(1,2)))

GSPC_log_returns.efp <- efp(GSPC_log_returns ~ 1, type = "Rec-CUSUM")

plot(GSPC_log_returns.efp, alpha = 0.05, alt.boundary = FALSE)
plot(GSPC_log_returns.efp, alpha = 0.05, alt.boundary = TRUE)

sctest(GSPC_log_returns.efp)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Recursive CUSUM test
## 
## Data:                            GSPC_log_returns.efp
## 
## Test Statistic:                  S = 0.902762
## 
## P-value:                         0.06946896

Above plots do not show any boundary crossing, hence we cannot reject the null-hypothesis of no structural changes.

The Ordinary Least Square CUSUM residual test is then carried on.

par(mfrow=(c(1,2)))

GSPC_log_returns.efp <- efp(GSPC_log_returns ~ 1, type = "OLS-CUSUM")

plot(GSPC_log_returns.efp, alpha = 0.05, alt.boundary = FALSE)
plot(GSPC_log_returns.efp, alpha = 0.05, alt.boundary = TRUE)

Plots above shows boundary crossing border line scenarios occurring within the time normalized interval [0, 0.2]. In this case, alternative boundary plot would allow us to reject the null hypothesis. Anyway, I am going with verifications about that in next tests.

b. Chow Test

So far I have shown structural change tests oriented to fluctuation tests. In the following, I am going to show structural change tests based on F-stats, such as Chow test and F-stats one.

Chow test is carried on by first separating the original time series into two sub-intervals as determined by a pre-determined split point and comparing the two corresponding regression structures. If significative differences are found, based on F statistics, a structural breakpoint is determined (as equal to the input split point). Ref. 4 points out that Chow test demands homoschedasticity, otherwise Wald test is prescribed. At the purpose I run a McLeod-Li test to verify that.

McLeod_Li_test <- McLeod.Li.test(y=GSPC_log_returns, plot=TRUE)

McLeod_Li_test
## $p.values
##  [1] 0.08807727 0.09029326 0.06467083 0.08836652 0.13772037 0.18384129
##  [7] 0.25016812 0.22415456 0.28220262 0.32856674 0.30837092 0.35665455
## [13] 0.43443415 0.34993440 0.41776972 0.49009200 0.55807636 0.46362755
## [19] 0.43384248 0.35053726 0.40223383 0.41422189 0.43098867 0.46357864
## [25] 0.51992212 0.41560913 0.46771651 0.48311545

As McLeod_Li_test resulting p-value is greater than 0.05, we cannot reject the null-hypothesis of homoscedasticity.

Since I do not know in advance where the potential breakpoint may be, I am going to run chow test for arbitrary split points chosen from the normalized time domain [0, 1] at fixed intervals of 0.05 length. I then collect their resulting Chow test p-value and F-statistics.

chow_test_compute <- function(tseries, points) {
  l <- length(tseries)
  chow_test_results <- lapply(points, function(x) {
      sct <- sctest(tseries ~ 1, type='Chow', from = 0.05, to = 0.95, point = x); 
      c("point" = x, "observation" = floor(x*l), "p.value" = sct$p.value, "F.stats" = sct$statistic)})
  chow_test_results_df <- data.frame(t(sapply(chow_test_results, rbind)))
  colnames(chow_test_results_df) <- c("point", "observation", "p.value", "F.stats")
  chow_test_results_df
}

GSPC_log_returns <- coredata(GSPC_log_returns)
chow_test_results_df <- chow_test_compute(GSPC_log_returns, 
                                          seq(from = 0.05, to = 0.95, length = 19))
kable(chow_test_results_df, align='c')
point observation p.value F.stats
0.05 37 0.0845024 2.9839685
0.10 75 0.0073750 7.2183721
0.15 113 0.0005690 11.9767346
0.20 151 0.0243902 5.0871099
0.25 189 0.1100567 2.5594350
0.30 226 0.2524300 1.3118134
0.35 264 0.4712536 0.5195583
0.40 302 0.4000935 0.7088478
0.45 340 0.2239445 1.4813479
0.50 377 0.1461003 2.1168686
0.55 415 0.4191067 0.6535348
0.60 453 0.8282240 0.0471130
0.65 491 0.5283907 0.3978541
0.70 529 0.6626097 0.1905193
0.75 567 0.5163208 0.4216335
0.80 604 0.9970313 0.0000139
0.85 642 0.8722609 0.0258701
0.90 680 0.7789888 0.0788135
0.95 718 0.5077663 0.4390862

Above Chow test table results shows p-value < 0.05 for normalized observation points up to 0.20 included. However, the highest F-statistics value is reached at 0.15. Refining our computations in the interval [0.15, 0.20] yields to a more precise breakpoint value.

chow_test_results_df <- chow_test_compute(GSPC_log_returns, 
                                          seq(from = 0.15, to = 0.20, length = 6))
kable(chow_test_results_df, align='c')
point observation p.value F.stats
0.15 113 0.0005690 11.976735
0.16 120 0.0002824 13.308587
0.17 128 0.0046333 8.065448
0.18 136 0.0189828 5.526906
0.19 143 0.0275417 4.875442
0.20 151 0.0243902 5.087110

Further refinement in the interval [0.15, 0.16] follows.

chow_test_results_df <- chow_test_compute(GSPC_log_returns, 
                                          seq(from = 0.15, to = 0.16, length = 11))
kable(chow_test_results_df, align='c')
point observation p.value F.stats
0.150 113 0.0005690 11.97673
0.151 114 0.0007118 11.55344
0.152 114 0.0007118 11.55344
0.153 115 0.0006553 11.70971
0.154 116 0.0005847 11.92538
0.155 117 0.0001809 14.16037
0.156 117 0.0001809 14.16037
0.157 118 0.0001900 14.06650
0.158 119 0.0004128 12.58560
0.159 120 0.0002824 13.30859
0.160 120 0.0002824 13.30859
(breakpoint <- chow_test_results_df[which.max(chow_test_results_df$F.stats), "observation"])
## [1] 117

The breakpoint is determined by the highest F-statistics among those results having p < 0.05. Hence observation #117 is the breakpoint as determined by our Chow Test procedure based on iteractive dichotomic search.

In the following paragraph, I will show how to quickly determine the breakpoint by taking advantage of the Fstats test as provided by the \(strucchange\) package as well. Since the Fstats() function provides the Chow Test optimal point search similar to what I showed before, I will not include the present step as necessary for our analysis, anyway it is interesting a comparison between it and FStats analysis of the following sub-paragraph.

c. Fstats Test

The Fstats test extends the basic idea of the Chow Test when the breakpoint is not known in advance. Basically the steps needed for such kind of analysis are the following:

  • run Fstats() against the observation data specifying the timeline percentage range of interest; such interval cannot exceed [0.05, 0.95] as left and right boundaries

  • run the significance test sctest() on the Fstats result and evaluate F and p values

  • if significant, plot the Fstats results specifying the \(\alpha\) value to determine the intercept on the y-axis associated to the horizontal line determining the boundary of structural change (breakpoint); if no cross-boundary is observed, we cannot refuse the null hypothesis of no structural change

  • show found breakpoint on the time axis

GSPC_log_returns.efp.Fstats <- Fstats(GSPC_log_returns ~ 1,  from=0.05, to=0.95)
sctest(GSPC_log_returns.efp.Fstats, type="supF")
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       supF test
## 
## Data:                            GSPC_log_returns.efp.Fstats
## 
## Test Statistic:                  sup.F = 14.16037
## 
## P-value:                         0.005896987
(break_point <- breakpoints(GSPC_log_returns.efp.Fstats))
## 
##   Optimal 2-segment partition: 
## 
## Call:
## breakpoints.Fstats(obj = GSPC_log_returns.efp.Fstats)
## 
## Breakpoints at observation number:
## 117 
## 
## Corresponding to breakdates:
## 0.1534392
break_t <- break_point$breakpoints

par(mfrow=c(3,1))

plot(GSPC_log_returns.efp.Fstats, alpha = 0.05)

plot(GSPC_log_returns, type='l', main = "GSPC Log-Returns")
abline(v = break_t, lty = 'dotted', col = 'red')

plot(coredata(GSPC_AdjClose), type='l', main = "GSPC Adjusted Close Price")
abline(v = break_t, lty = 'dotted', col = 'red')

The structural change occured on 2013-12-13.

After having cut-off the observations preceeding the structural change, I verify that now there are not any further structural breaks.

GSPC_log_returns <- GSPC_log_returns[break_t:length(GSPC_log_returns)]
GSPC_log_returns.efp.Fstats <- Fstats(GSPC_log_returns ~ 1)

plot(GSPC_log_returns.efp.Fstats, alpha=0.05)

sctest(GSPC_log_returns.efp.Fstats, type="supF")
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       supF test
## 
## Data:                            GSPC_log_returns.efp.Fstats
## 
## Test Statistic:                  sup.F = 4.367217
## 
## P-value:                         0.3223131

The p-value aboveshown confirms such result.

Saving environmental data and specifically the log returns observations history beyond the instant of time the structural breakpoint occurred.

save(ts.package, GSPC_log_returns, GSPC_AdjClose, file="structured-product-2.RData")

Conclusions

The time series structural analysis has allowed to determine the subset of more recent observations with homogeneous properties. That observations subset is what I am going to further analyze on next posts.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.