I think you got it pretty right, but when building a VAR model, I usually make sure I follow these steps:
1. Select the variables
This is the most important part of building your model. If you want to forecast the price of an asset, you need to include variables that are related with the mechanism of price formation. The best way to do this is through a theoretical model. Since you did not mention what is the asset and what are the other variables you included in your model I really cannot say much about this item, but you can find a summary of asset pricing models in here.
2. Check the data and make the proper adjustments
Once you select the variables, you can make some adjustments to the data that will improve the estimation and interpretation of the model. It is useful to use summary statistics and see a plot of the series to detect outliers, missing data and other strange behaviors. When working with price data, people usually take natural logs, which is a variance-stabilizing transformation and also has a good interpretation (price difference in logs become continuously compound returns). I'm not sure if you have taken logs before estimating the model, but it is a good idea to do so if you are working with asset prices.
3. Check if data contains non-stationary components
Now you can use unit root tests to check if your series are stationary. If you are only interested in forecasting, as noted by @JacobH, you can run VAR in levels even when your series are non-stationary, but then your standard errors cannot be trusted, meaning that you can't make inference about the value of the coefficients. You've tested stationary using the ADF test, which is very commonly used in these applications, but note that you should specify if you want to run the test with i) no constant and no trend; ii) a constant and no trend; and iii) a constant and a trend. Usually price series have stochastic trends, so a linear trend will not be accurate. In this case you may choose the specification ii. In your code you used the ndiffs
function of the forecast package. I am not sure which of those three alternatives this function implements in order to calculate the number of differences (I couldn't find it in the documentation). To check your result you may want to use the ur.df
function in the "urca" package:
adf <- ur.df(x[, "VAR1"], type = "drift", lags = 10, selectlags = "AIC")
Note that this command will run the ADF test with a constant and the lags selected by the AIC command, with maximum lag of 10. If you have problems interpreting the results just look at this question. If the series are I(1) just use the difference, which will be equal to the continuously compounded returns. If the test indicates that the series are I(2) and you are in doubt about that you can use other tests, e.g. Phillips-Perron test (PP.test
function in R). If all tests confirm that your series are I(2) (remember to use the log of the series before running the tests) then take the second difference, but note that your interpretation of the results will change, since now you are working with the difference of the continuously compounded returns. Prices of assets are usually I(1) since they are close to a random walk, which is a white noise when applying the first difference.
4. Select the order of the model
This can be done with commonly used criteria such as Akaike, Schwarz (BIC) and Hannan-Quinn. You've done that with the VARselect
function and that is right, but remember what is the criterion that you used to make your decision. Usually different criteria indicate different orders for the VAR.
5. Check if there are cointegrating relationships
If all your series are I(1) or I(2), before running a VAR model, it is usually a good idea to check if there is no cointegration relationships between the series, specially if you want to make impulse response analysis with the residuals. You can do that using the Johansenn test or the Engle-Granger (only for bivariate models). In R you can run the Johansen test with the ca.jo
function of the "urca" package. Note that this test also has different specifications. For price series I usually use the following code (where p
is the lag length of item 4, performed with the series in levels):
jo_eigen <- ca.jo(x, type = "eigen", ecdet = "const", K = p)
jo_trace <- ca.jo(x, type = "trace", ecdet = "const", K = p)
6. Estimate the model
If your series are not cointegrated, you can easily estimate the model with the VAR
command, as done in your code. In case the series are cointegrated you need to consider the long run relationship by estimating a Vector Error Correction model with the following code (where k
is the order of cointegration):
vecm <- cajorls(joeigen, r = k)
7. Run diagnostics tests
To test if your model is well specified you can run a test of serial correlation on the residuals. In your code you used a Portmanteau test with the serial.test
function. I've never used this function but I think it is OK. There is also a multivariate version of the Ljung-Box test implemented in the package MTS which you can run with the function mq
.
8. Make predictions
After you are sure your model is well specified you can use the predict
function as you did in your code. You can even plot impulse response functions to check how the variables respond to a particular shock using the irf
function.
9. Evaluate predictions
Once you made your predictions you must evaluate them and compare against other models. Some methods to evaluate accuracy of forecasts can be found here, but to do that it is crucial that you divide your series in a training and a test set, as explained in the link.