Investigating the Dynamics between Price-to-Rent Ratio and Market Fundamentals: A Vector Error Correction Model (VECM) Analysis in R
Introduction
The real estate market plays a vital role in the economic landscape of any country, acting as both a key indicator of economic health and a crucial component of household wealth. Among the numerous metrics used to gauge the state of the real estate market, the Price-to-Rent Ratio stands out as a valuable and widely recognized measure. It serves as a critical indicator of the affordability and investment attractiveness of residential properties, thus capturing the essence of the housing market dynamics.
In recent years, the global economy has experienced significant fluctuations, marked by economic crises, recessions, and periods of growth. The real estate sector, being highly sensitive to economic changes, has often been at the forefront of these movements. Understanding the factors that influence the Price-to-Rent Ratio is, therefore, of paramount importance for policymakers, investors, and market analysts seeking to make informed decisions in an ever-changing economic environment.
The primary objective of this study is to investigate the relationships and dynamics between the Price-to-Rent Ratio and a set of key macroeconomic variables. These variables include the Unemployment Rate, Stock Index, Debt-to-Income Ratio, Disposable Income, and Population. By employing the Vector Error Correction Model (VECM) framework, we aim to establish both short-term and long-term interactions among these variables, providing valuable insights into the factors shaping the Price-to-Rent Ratio.
Research Objectives:
To examine the short-term and long-term relationships between the Price-to-Rent Ratio and the selected macroeconomic variables
Methodology
To achieve our research objectives, we will utilize the Vector Error Correction Model (VECM) methodology. The VECM framework allows us to analyze both short-term deviations from equilibrium relationships and long-term trends, capturing the dynamic adjustments among the Price-to-Rent Ratio and the macroeconomic variables over time.
#loading the required packages
library(tsDyn)
library(vars)
library(urca)
library(readxl)
library(tidyverse)
library(tseries)
Loading the Data
maindat<-read_excel('vecmdata.xlsx')
glimpse(maindat)
## Rows: 84
## Columns: 10
## $ Date <dttm> 2002-01-01, 2002-04-01, 2002-07-…
## $ `Houseprice index` <dbl> NA, NA, NA, NA, 100.00000, 96.596…
## $ `Rental index` <dbl> NA, NA, NA, NA, 100.0000, 110.209…
## $ `Unemployment rate` <dbl> 3.533333, 3.766667, NA, 4.200000,…
## $ `Real interest Rate Fisher Equation` <dbl> NA, NA, NA, NA, NA, 0.06500000, 0…
## $ Population <dbl> 512589, 514541, 515425, 516467, 5…
## $ `Household debt` <dbl> 894141.7, 919077.3, 942992.3, 966…
## $ `Disp income` <dbl> 161130, 172009, 174446, 175389, 1…
## $ `stock index` <dbl> 179.060, 148.450, 110.620, 115.21…
## $ Expectation <dbl> 19.54262, 19.13242, 10.92876, 2.1…
Focusing on data between 2004 and 2022
maindat<-maindat[maindat$Date >= "2004-01-01" &
maindat$Date <= "2022-10-01", ]
Data Preparation
## Renaming the variables
maindat<-rename(maindat,house_price_index=`Houseprice index`, rental_index=`Rental index`, unemployment_rate=`Unemployment rate`, house_debt= `Household debt`, disp_income=`Disp income`, stock_index=`stock index`)
## Obtaining the Price to rent ratio using House price and rental index
maindat1<-maindat%>%mutate(price_to_rent=house_price_index/rental_index)
#Checking missing values0
colSums(is.na(maindat1))
## Date house_price_index
## 0 0
## rental_index unemployment_rate
## 0 0
## Real interest Rate Fisher Equation Population
## 0 0
## house_debt disp_income
## 0 0
## stock_index Expectation
## 0 0
## price_to_rent
## 0
No missing values in the data set
Testing for Stationarity using ADF Test
adf.test(diff(maindat1$house_price_index))
## Warning in adf.test(diff(maindat1$house_price_index)): p-value smaller than
## printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: diff(maindat1$house_price_index)
## Dickey-Fuller = -4.8143, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
adf.test(diff(maindat1$unemployment_rate))
##
## Augmented Dickey-Fuller Test
##
## data: diff(maindat1$unemployment_rate)
## Dickey-Fuller = -3.805, Lag order = 4, p-value = 0.02332
## alternative hypothesis: stationary
adf.test(diff(maindat1$stock_index))
##
## Augmented Dickey-Fuller Test
##
## data: diff(maindat1$stock_index)
## Dickey-Fuller = -3.6379, Lag order = 4, p-value = 0.03617
## alternative hypothesis: stationary
adf.test(diff(maindat1$Population))
##
## Augmented Dickey-Fuller Test
##
## data: diff(maindat1$Population)
## Dickey-Fuller = -3.6871, Lag order = 4, p-value = 0.03194
## alternative hypothesis: stationary
adf.test(diff(maindat1$disp_income))
## Warning in adf.test(diff(maindat1$disp_income)): p-value smaller than printed
## p-value
##
## Augmented Dickey-Fuller Test
##
## data: diff(maindat1$disp_income)
## Dickey-Fuller = -5.1509, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
At 5% level of significance, all the variables are statistically significant at the first difference. To run the Johansen Co-integration test, we need to find the appropriate lag. Let’s run the lag selection criteria.
maindat2<-maindat1%>%select(house_price_index, unemployment_rate, disp_income, stock_index, Population)
lagselection<- VARselect(maindat2, lag.max = 5, type = "const")
lagselection$selection
## AIC(n) HQ(n) SC(n) FPE(n)
## 4 3 3 4
Using the lag order selection criterion, The AIC and FPE statistics indicates 4 lags. We weil be using 4 lags for the Johansen Cointegration Test.
Johansen Co-integration Test
jtest<-ca.jo(maindat2, type = "trace", ecdet = "const", K = 4)
summary(jtest)
##
## ######################
## # Johansen-Procedure #
## ######################
##
## Test type: trace statistic , without linear trend and constant in cointegration
##
## Eigenvalues (lambda):
## [1] 5.562366e-01 3.559108e-01 2.396547e-01 1.275879e-01 8.823309e-02
## [6] 4.521574e-16
##
## Values of teststatistic and critical values of test:
##
## test 10pct 5pct 1pct
## r <= 4 | 6.56 7.52 9.24 12.97
## r <= 3 | 16.25 17.85 19.96 24.60
## r <= 2 | 35.70 32.00 34.91 41.07
## r <= 1 | 66.94 49.65 53.12 60.16
## r = 0 | 124.62 71.86 76.07 84.45
##
## Eigenvectors, normalised to first column:
## (These are the cointegration relations)
##
## house_price_index.l4 unemployment_rate.l4 disp_income.l4
## house_price_index.l4 1.000000000 1.000000e+00 1.000000e+00
## unemployment_rate.l4 -11.006446080 1.100535e+01 -1.468749e+01
## disp_income.l4 0.001807349 -4.380915e-04 -7.834441e-04
## stock_index.l4 -0.085321885 -1.537148e-01 -1.668333e-01
## Population.l4 -0.002939197 -7.576155e-05 -2.535996e-04
## constant 967.699674445 -2.390015e+01 3.365177e+02
## stock_index.l4 Population.l4 constant
## house_price_index.l4 1.000000e+00 1.000000e+00 1.000000e+00
## unemployment_rate.l4 5.215113e+01 -1.286784e+01 -8.884744e+00
## disp_income.l4 -9.953815e-03 -1.320551e-03 3.158971e-03
## stock_index.l4 8.325769e-01 -8.366555e-02 -8.143422e-02
## Population.l4 7.627003e-03 8.250524e-04 -4.844966e-03
## constant -2.705255e+03 -2.275530e+02 1.921081e+03
##
## Weights W:
## (This is the loading matrix)
##
## house_price_index.l4 unemployment_rate.l4 disp_income.l4
## house_price_index.d -5.018237e-02 0.012981589 -0.045067342
## unemployment_rate.d 6.412331e-03 -0.004402782 -0.002814955
## disp_income.d -1.022313e+02 -19.569791287 -82.308859820
## stock_index.d -1.090375e+00 1.594152991 0.292996773
## Population.d -6.067787e+00 -38.835015426 5.554261826
## stock_index.l4 Population.l4 constant
## house_price_index.d -0.011233613 -0.037179521 4.826062e-15
## unemployment_rate.d -0.001984202 0.004909443 -5.660411e-15
## disp_income.d 28.825908626 77.439408104 1.223346e-10
## stock_index.d -0.048826350 0.017932925 5.506764e-13
## Population.d -1.134438807 -0.495769414 2.236135e-12
Based on the test statistics above, the test statistics are greater than the critical values from rank 0 down to rank 2 at 5% level of significance. At rank 3, the test statistics is less than the critical value at 5%, hence we can not reject the null hypothesis and conclude that there are 3 cointegrating relationships.
Let’s implement the vector error correction model using the 3 cointegrating relationships.
Vector Error Correction Model
vecm_model<- VECM(maindat2, lag = 4, r =3, estim = "ML")
summary(vecm_model)
## #############
## ###Model VECM
## #############
## Full sample size: 75 End sample size: 70
## Number of variables: 5 Number of estimated slope parameters 120
## AIC 2980.128 BIC 3263.438 SSR 5363493003
## Cointegrating vector (estimated by ML):
## house_price_index unemployment_rate disp_income stock_index
## r1 1.000000e+00 0 -4.065758e-20 -0.131176692
## r2 3.469447e-18 1 1.355253e-20 -0.002155525
## r3 -2.842171e-14 0 1.000000e+00 -15.704630857
## Population
## r1 -0.0007440166
## r2 0.0000172500
## r3 -0.9876070419
##
##
## ECT1 ECT2
## Equation house_price_index -0.1928(0.0829)* 1.5655(1.0191)
## Equation unemployment_rate 0.0095(0.0107) -0.3510(0.1319)*
## Equation disp_income -124.3107(194.7610) 1344.2890(2393.5420)
## Equation stock_index 0.4347(0.7611) 30.3146(9.3541)**
## Equation Population -32.5666(14.6560)* -498.0438(180.1171)**
## ECT3 Intercept
## Equation house_price_index 7.9e-05(0.0001) -47.3468(46.1710)
## Equation unemployment_rate 4.3e-05(1.4e-05)** 19.0203(5.9762)**
## Equation disp_income -0.1703(0.2539) -93977.3307(108439.7957)
## Equation stock_index -0.0031(0.0010)** -1090.1788(423.7876)*
## Equation Population 0.0073(0.0191) -64.5007(8160.2336)
## house_price_index -1 unemployment_rate -1
## Equation house_price_index 0.8095(0.1425)*** -2.9172(1.3525)*
## Equation unemployment_rate -0.0084(0.0184) 0.4659(0.1751)*
## Equation disp_income 166.3330(334.7641) 58.9107(3176.4600)
## Equation stock_index 2.7900(1.3083)* -29.8030(12.4137)*
## Equation Population 24.4709(25.1914) 115.3074(239.0327)
## disp_income -1 stock_index -1
## Equation house_price_index -5.6e-05(0.0001) -0.0213(0.0192)
## Equation unemployment_rate -3.5e-05(1.4e-05)* 0.0029(0.0025)
## Equation disp_income -0.5990(0.2607)* -41.4424(45.0234)
## Equation stock_index 0.0031(0.0010)** -0.6080(0.1760)**
## Equation Population -0.0037(0.0196) -1.9782(3.3881)
## Population -1 house_price_index -2
## Equation house_price_index 0.0016(0.0010) -0.3302(0.1942).
## Equation unemployment_rate 0.0003(0.0001)* -0.0273(0.0251)
## Equation disp_income -1.5502(2.3304) 22.6129(456.0237)
## Equation stock_index -0.0212(0.0091)* -2.6848(1.7822)
## Equation Population -0.1215(0.1754) -4.4252(34.3164)
## unemployment_rate -2 disp_income -2
## Equation house_price_index 0.7177(1.3813) -0.0002(0.0001)*
## Equation unemployment_rate -0.1105(0.1788) -3.6e-05(1.5e-05)*
## Equation disp_income -3325.2422(3244.1765) -0.3448(0.2690)
## Equation stock_index -5.2625(12.6784) 0.0015(0.0011)
## Equation Population 144.4379(244.1284) 0.0201(0.0202)
## stock_index -2 Population -2
## Equation house_price_index -0.0490(0.0195)* -0.0024(0.0010)*
## Equation unemployment_rate 0.0076(0.0025)** 0.0001(0.0001)
## Equation disp_income -24.0556(45.7904) -1.1799(2.2869)
## Equation stock_index -0.4074(0.1790)* -0.0323(0.0089)***
## Equation Population 0.2739(3.4458) 0.4159(0.1721)*
## house_price_index -3 unemployment_rate -3
## Equation house_price_index 0.0391(0.1843) -0.8537(1.2135)
## Equation unemployment_rate 0.0095(0.0239) 0.4459(0.1571)**
## Equation disp_income 145.9643(432.9081) 1666.2445(2850.1076)
## Equation stock_index -0.2048(1.6918) -17.4037(11.1383)
## Equation Population 37.8971(32.5769) 396.6538(214.4743).
## disp_income -3 stock_index -3
## Equation house_price_index -0.0002(0.0001) -0.0163(0.0200)
## Equation unemployment_rate -1.8e-05(1.5e-05) 0.0019(0.0026)
## Equation disp_income -0.4449(0.2650). -12.4770(46.9112)
## Equation stock_index 0.0003(0.0010) -0.1114(0.1833)
## Equation Population 0.0217(0.0199) -0.6225(3.5301)
## Population -3 house_price_index -4
## Equation house_price_index -0.0017(0.0011) 0.2004(0.1556)
## Equation unemployment_rate 0.0004(0.0001)** -0.0008(0.0201)
## Equation disp_income -1.0152(2.5742) 171.2797(365.4477)
## Equation stock_index -0.0181(0.0101). 0.2208(1.4282)
## Equation Population -0.0702(0.1937) -19.6083(27.5004)
## unemployment_rate -4 disp_income -4
## Equation house_price_index -0.6598(1.0958) -8.9e-05(8.7e-05)
## Equation unemployment_rate 0.1683(0.1418) 7.4e-06(1.1e-05)
## Equation disp_income -324.2258(2573.5963) 0.2145(0.2045)
## Equation stock_index -0.0973(10.0577) -0.0004(0.0008)
## Equation Population 42.7762(193.6664) 0.0006(0.0154)
## stock_index -4 Population -4
## Equation house_price_index -0.0305(0.0156). 0.0011(0.0011)
## Equation unemployment_rate 0.0038(0.0020). 0.0002(0.0001)
## Equation disp_income 32.0569(36.5970) -0.8567(2.4860)
## Equation stock_index -0.2955(0.1430)* 0.0045(0.0097)
## Equation Population 1.2572(2.7540) 0.1242(0.1871)
According to the ECTs, The Vector Error Correction Model results shows that there is a significant negative long term relationship between Price-to-Rent Ratio and unemployment_rate. Also there is a significant negative relationship between Price-to-Rent Ratio and stock index.
Model Diagnostic
Normality Test for the Residuals
modv<-vec2var(jtest, r=3)
res<-normality.test(modv, multivariate.only = T)
res
## $JB
##
## JB-Test (multivariate)
##
## data: Residuals of VAR object modv
## Chi-squared = 266.79, df = 10, p-value < 2.2e-16
##
##
## $Skewness
##
## Skewness only (multivariate)
##
## data: Residuals of VAR object modv
## Chi-squared = 44.961, df = 5, p-value = 1.478e-08
##
##
## $Kurtosis
##
## Kurtosis only (multivariate)
##
## data: Residuals of VAR object modv
## Chi-squared = 221.83, df = 5, p-value < 2.2e-16
The residuals of the model are not normally distributed.