The variable list was used from the NY Fed Nowcast method (https://www.newyorkfed.org/research/policy/nowcast) and augmented with several additional variables, specifically:
10-year Treasury rates DGS10
2-10 year Treasury rate spread T10Y2Y
weekly unemployment claims ICSA
Federal Reserve total assets WALCL
library(NNS) # NNS v0.9.4 on CRAN
library(rmarkdown)
library(nowcasting)
NYFED$legend[,-4]
NNS.nowcast objectThis preliminary step will create an interpolated/extrapolated
data.frame of all of the economic variables such that frequencies are
aligned to monthly values. We achieve this via the
NNS.nowcast function which has all variables predefined.
Setting h=0 returns just the data to the current month.
nns_estimates = NNS.nowcast(h = 0)
# View the last year's values
tail(nns_estimates, 12)
NNS.causNNS causality tries to determine the conditional
probability of two events by first normalizing past innovations of
itself for a given \(\tau\) (per the
Granger insight) such that:
$$x^* = f(x_{t-1}, x_{t-2},…,x_{t-\tau})$$
$$y^* = f(y_{t-1}, y_{t-2},…,y_{t-\tau})$$
and then normalizing each of these new variables to a shared rangespace by:
$$ x^{**} = f(x^*, y^*)$$
$$ y^{**} = g(x^*, y^*)$$
Once \(x^{**}\) and \(y^{**}\) are on the shared rangespace, the conditional probability can be ascertained and then the correlation applied to determine causation. \[C_{x\rightarrow{y}} = P(y^{**}|x^{**}) * \rho_{x^{**}y^{**}}\]
NNS.caus returns a matrix where directional causation is
returned as [column variable] ---> [row variable].
nns_econ_causes = NNS.caus(nns_estimates)
colnames(nns_econ_causes) = colnames(nns_estimates)
dim(nns_econ_causes)
## [1] 29 29
Large 29x29 matrix output, so we will just call the
WALCL column (note the 1 for the final entry which would be
the lower right diagonal entry).
nns_econ_causes[, ncol(nns_econ_causes)]
## PAYEMS JTSJOL CPIAUCSL DGORDER
## 0.659826699 0.429510557 0.205719438 0.419194364
## RSAFS UNRATE HOUST INDPRO
## 0.081722966 0.000000000 0.002056343 0.621722421
## DSPIC96 BOPTEXP BOPTIMP TTLCONS
## 0.004049306 0.343193396 0.244118243 0.278626686
## IR CPILFESL PCEPILFE PCEPI
## 0.564019839 0.094859761 0.141432154 0.165069001
## PERMIT TCU BUSINV ULCNFB
## 0.000000000 0.000000000 0.433602113 0.395638075
## IQ GACDISA066MSFRBNY GACDFSA066MSFRBPHI PCEC96
## 0.395719798 0.000000000 0.071892695 0.145776228
## GDPC1 ICSA DGS10 T10Y2Y
## 0.250547691 0.008500394 0.304207853 0.244174295
## WALCL
## 1.000000000
All positive or 0 causal directions to the other economic variables. Surely this can’t be, let’s try to add some noise terms to see if those are caused by the Federal Reserve’s asset levels too…
We will add some noise terms to see if WALCL expresses
causal inference on those variables as well. NOISE is \(N(0,1)\) while NOISE_2 is
\(N(10,20)\).
# View the last year's values with both noise terms
data.frame(tail(econ_variables_with_noise, 12))
Same NNS.nowcast procedure with the new
econ_variables_with_noise which utilizes the following
NNS.VAR call:
nns_estimates_with_noise = NNS.VAR(econ_variables_with_noise, h = 0, tau = 12, nowcast = TRUE)
Then use nns_estimates_with_noise in
NNS.caus.
nns_econ_causes_with_noise = NNS.caus(nns_estimates_with_noise)
nns_econ_causes_with_noise[, 29:31]
## WALCL NOISE NOISE_2
## PAYEMS 0.659826688 0.09856778 0.0000000000
## JTSJOL 0.429510904 0.06808786 0.0000000000
## CPIAUCSL 0.205705476 0.08698442 0.0000000000
## DGORDER 0.419190516 0.08793995 0.0000000000
## RSAFS 0.081711194 0.09226950 0.0000000000
## UNRATE 0.000000000 0.05121020 0.0953364223
## HOUST 0.002055175 0.06112331 0.0010841936
## INDPRO 0.621722574 0.10295232 0.0400328086
## DSPIC96 0.004050983 0.09506633 0.0000000000
## BOPTEXP 0.352358901 0.07351663 0.0000000000
## BOPTIMP 0.242951914 0.09865277 0.0000000000
## TTLCONS 0.278626931 0.00000000 0.0000000000
## IR 0.564040215 0.09224655 0.0458487296
## CPILFESL 0.094841592 0.08657842 0.0000000000
## PCEPILFE 0.141416551 0.09280547 0.0000000000
## PCEPI 0.165053156 0.09367095 0.0001504519
## PERMIT 0.000000000 0.04650272 0.0036113237
## TCU 0.000000000 0.10505892 0.0919810910
## BUSINV 0.433632640 0.08018879 0.0000000000
## ULCNFB 0.388491973 0.09636205 0.0000000000
## IQ 0.395723389 0.00000000 0.0096782079
## GACDISA066MSFRBNY 0.000000000 0.02332553 -0.0477040828
## GACDFSA066MSFRBPHI 0.071698602 -0.08785480 -0.0325825676
## PCEC96 0.145760542 0.09567023 0.0000000000
## GDPC1 0.250543113 0.09532958 0.0000000000
## ICSA 0.008515602 0.01369432 0.0000000000
## DGS10 0.306391014 0.00859394 0.0613115325
## T10Y2Y 0.243275602 0.04459461 0.0815768202
## WALCL 1.000000000 0.06857393 0.0000000000
## NOISE -0.068573926 1.00000000 0.0291295109
## NOISE_2 0.000000000 -0.02912951 1.0000000000
No positive causal inference for the noise term and no causal inference for the expanded noise term.
We can run random permutations of NNS.caus for the
NOISE and NOISE_2 variables and then determine
strength of causal inference [0,1] for WALCL on the other
economic variables of interest.
results = list()
n = nrow(nns_estimates_with_noise)
cl = parallel::makeCluster(detectCores()-1)
doParallel::registerDoParallel(cl)
results = foreach(i = 1:100, .packages = "NNS")%dopar%{
set.seed(123*i)
nns_estimates_with_noise$NOISE = rnorm(n, 0, 1)
nns_estimates_with_noise$NOISE_2 = rnorm(n, 10, 20)
NNS.caus(nns_estimates_with_noise)
}
parallel::stopCluster(cl)
registerDoSEQ()
noise_permutations = do.call(cbind, lapply(results, function(x) x[,30]))
noise_2_permutations = do.call(cbind, lapply(results, function(x) x[,31]))
Next we will determine the 95% quantile level for each of the
NOISE variables’ NNS.caus values, and see if
WALCL eclipses that value. We are using the maximum
quantile value between both NOISE values for each economic
variable.
sig_values = lapply(1:29, function(x) list(quantile(noise_permutations[x,], .95),
quantile(noise_2_permutations[x,], .95)))
noise_sig_values = unlist(lapply(sig_values,`[[`,1))
noise_2_sig_values = unlist(lapply(sig_values,`[[`,2))
final_comp = cbind.data.frame(nns_econ_causes[, ncol(nns_econ_causes)],
noise_sig_values,
noise_2_sig_values)
Significant = as.vector(final_comp[,1] > pmax(final_comp[,2], final_comp[,3]))
final_comp = cbind(final_comp, Significant)
colnames(final_comp)[1:3] = c("WALCL", "NOISE 95% Sig Value", "NOISE_2 95% Sig Value")
final_comp
WALCL implies causal inference via NNS.caus
onto the following macroeconomic variables in the NY Fed nowcast
model:
positive_results = which(final_comp$Significant[1:28]>0)
effects = cbind.data.frame("Macroeconomic Variable" = colnames(econ_variables)[positive_results],
"Strength of Causal Inference of Fed Assets" =
as.vector(final_comp[positive_results,1] - pmax(final_comp[positive_results,2],
final_comp[positive_results,3])))
effects
Viole, Fred, Multivariate Time Series Forecasting: Nonparametric Vector Autoregression Using NNS (November 18, 2019). Available at SSRN: https://ssrn.com/abstract=3489550
Viole, Fred and Nawrocki, David N., Causation (June 1, 2013). Available at SSRN: https://ssrn.com/abstract=2273756