Introduction

The financial account balance is one part of a country’s balance of payments. It reflects the net direct investment, net portfolio investments, the funding of assets, and errors for a country (Kenton). Some economists raise concerns about the United States (U.S.) financial account balance being negative. They believe that high levels of debt are unsustainable. I wanted to learn more about what actually impacts the financial account balance, in addition to questioning dominant strains of thinking in economics. This sort of thinking tells us that an important economic factor like the value of exports of the U.S. for example, will affect the financial account balance. This effect is assumed to be positive – the account balance will increase as a result of more money coming into the country (the U.S. will rely less on foreign capital too). I wanted to confirm the economic intuition behind this thinking, in addition to looking at other variables that may also impact the net lending status of the U.S. I came up with the research question: how do factors like trade (exports, imports) and investments affect the financial account balance of the U.S.?

I obtained my data from the Federal Reserve Bank of St. Louis (FRED). They have historical data on the U.S financial account for every quarter dating from 1946 up to the third quarter of 2024. There were missing data points pre-1960 so I decided to start in 1960 as the base year. And because we are not completely through 2024, I decided to use quarter 4 of 2023 be the last data point. This data was collected directly from the U.S. government.

The complete list of variables I examined were as follows:

FinanceData <- read.csv("FinanceData.csv")
names(FinanceData)
## [1] "Period"                      "Exports"                    
## [3] "Imports"                     "DirectInvestmentAssets"     
## [5] "PortfolioInvestmentAssets"   "ReserveAssets"              
## [7] "DirectInvestmentLiabilities" "DirectPortfolioLiabilities" 
## [9] "FinNetLending"


I have generated three example scatter plots, plotting ‘Exports’ vs. ‘FinNetLending’, ‘Imports’ vs. ‘FinNetLending’, and ‘DirectPortfolioLiabilities’ vs. ‘FinNetLending’ (These turn out to be the three variables in our model). These scatter plots show a large spread of data points and they also show very complex relationships between the explanatory variables and the response variable ‘FinNetLending’ (U.S. Financial Account Balance). These trends were very similar amongst all the other variables when compared to ‘FinNetLending’. The scatter plots reflect data that seems to be too complex to be represented by some sort of linear model. The scatter plots are below:

plot(FinNetLending~Exports, data=FinanceData, main='Exports vs. U.S. Fianancial Account Balance', pch=19, col='blue')

plot(FinNetLending~Imports, data=FinanceData, main='Imports vs. U.S. Financial Account Balance', pch=19, col='red')

plot(FinNetLending~DirectPortfolioLiabilities, data=FinanceData, main='Direct Portfolio Liabilities vs. U.S. Financial Account Balance', pch=19, col='orange')


Methodology

The data, as shown through two example scatter plots above, does not seem to be linear. There also appears to be complex relationships between all of the variables and the response variable ‘FinNetLending’. There also seems to be a very wide spread of data points in each of the scatter plots. It would be difficult for any sort of linear models to adequately capture the complexity of these relationships. For these reasons, a generalized additive model (GAM) is appropriate. This model is an extension of multiple linear regression, where now the coefficients for each term are non-linear smoothing spline functions. In order to pick variables that are the best predictors of ‘FinNetLending,’ and in order to choose the best model overall, we are splitting our data set into three subsets. The first subset will be a random sample of 60% of the data, and will be used for training – picking the best variables for the model. The second subset will consist of 20% of the data, and will be used to pick the best model through adjusting the tuning parameter k and calculating the highest adjusted R-squared value and lowest root mean squared error. The third subset will consist of the last 20% of the data and will be used for testing and making predictions to assess how good the model is at predicting the value of ‘FinNetLending’ for data previously unseen by the model. We split up the data into each of our subsets below:

set.seed(123)
trainIndices <- sample(1:nrow(FinanceData), size = 0.6 * nrow(FinanceData)) # Taking sample of 60% of data for training
trainData <- FinanceData[trainIndices, ]
remainingIndices <- setdiff(1:nrow(FinanceData), trainIndices)
validationIndices <- sample(remainingIndices, size = 0.5 * length(remainingIndices)) # 20% sample for validation 
validationData <- FinanceData[validationIndices, ]
testIndices <- setdiff(remainingIndices, validationIndices) # 20% sample for testing
testData <- FinanceData[testIndices, ]


Fitting a GAM with all of the variables as smooth terms to predict ‘FinNetLending’, I found that the significant smooth terms were ‘Exports’, ‘Imports’, ‘DirectInvestmentAssets’, and ‘DirectPortfolioLiabilities’ – which all yielded p-values that were statistically significant at a 95% confidence level. From this reduced model I narrowed down the significant smooth terms to include only ‘Exports’, ‘Imports’, and ‘DirectPortfolioLiabilities’ – as their p-values were all significant again at an \(\alpha=0.05\). The summary of this model is shown below:

suppressPackageStartupMessages(library(mgcv))
suppressWarnings(suppressPackageStartupMessages(library(mgcv)))
library(mgcv)
fullGam <- gam(FinNetLending ~ s(Exports) + s(Imports) + s(DirectPortfolioLiabilities) + s(Period) + s(DirectInvestmentLiabilities) + s(DirectInvestmentLiabilities) + s(ReserveAssets) + s(DirectInvestmentAssets), data=trainData)
reducedGam1 <- gam(FinNetLending ~ s(Exports) + s(Imports) + s(DirectInvestmentAssets) + s(DirectPortfolioLiabilities), data=trainData)
finalReducedGam<- gam(FinNetLending ~ s(Exports) + s(Imports) + s(DirectPortfolioLiabilities), data=trainData)
summary(finalReducedGam)
## 
## Family: gaussian 
## Link function: identity 
## 
## Formula:
## FinNetLending ~ s(Exports) + s(Imports) + s(DirectPortfolioLiabilities)
## 
## Parametric coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   -63024       3111  -20.25   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Approximate significance of smooth terms:
##                                 edf Ref.df     F p-value    
## s(Exports)                    2.811  3.442 17.57  <2e-16 ***
## s(Imports)                    1.000  1.000 72.39  <2e-16 ***
## s(DirectPortfolioLiabilities) 2.167  2.768  3.37   0.024 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## R-sq.(adj) =  0.793   Deviance explained = 80.1%
## GCV = 1.552e+09  Scale est. = 1.4812e+09  n = 153

We can see that the estimated degrees of freedom that are being used for the smooth term associated with ‘Exports’ are 2.811, which indicates a somewhat complex relationship with the response variable of ‘FinNetLending’. The smooth term for ‘Imports’ is only using an estimated 1 degree of freedom which indicates a linear relationship between ‘Imports’ and the response. We will adjust the tuning parameter (k) later to see if more complexity may be present or captured. The smooth term for ‘DirectPortfolioLiabilities’ is using 2.167 estimated degrees of freedom which indicates a somewhat complex non-linear relationship with the U.S. financial account balance. We will point out here that direct portfolio liabilities represent the financial obligations that the U.S. has to foreign investors who hold its securities (often bonds like U.S. Treasury bonds).


Model:

The general form of the GAM will be: \(y_i=\beta_0+\sum_{j=1}^{p}f_j(x_{ij})+\epsilon_i\). The specific model with our three predictor variables turns out to be: \[FinNetLending_i=\beta_0+f_1(Exports_i)+f_2(Imports_i)+f_3(DirectPortfolioLiabilities_i)+\epsilon_i\] where \(f_i(x_{i})\) represents the ith smooth function. Each smooth function is made up of a certain number of basis functions. The number of basis functions is specified by the “k” parameter in R. It is important to pick values of k carefully to ensure that we are capturing the complex relationships between our variables fully. However, we will need to make sure that the k-values are not too high so that overfitting does not occur.


In our model we assume that residuals are independent from each other, and are normally distributed, with a mean of zero. We also assume that residuals have the same variance: \(\epsilon_i\)~\(NI(0,\sigma^2_i)\)


Using the validation subset now, we will adjust our tuning parameter k to find the model with the highest adjusted R-squared value and the lowest root mean Squared Error (RMSE).

library(Metrics)
validationGam <- gam(FinNetLending ~ s(Exports, k=6) + s(Imports, k=9) + s(DirectPortfolioLiabilities, k=4), data=validationData)
summary(validationGam)
## 
## Family: gaussian 
## Link function: identity 
## 
## Formula:
## FinNetLending ~ s(Exports, k = 6) + s(Imports, k = 9) + s(DirectPortfolioLiabilities, 
##     k = 4)
## 
## Parametric coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   -48318       4207  -11.48 2.48e-14 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Approximate significance of smooth terms:
##                                 edf Ref.df      F  p-value    
## s(Exports)                    1.295  1.476 22.474 6.39e-05 ***
## s(Imports)                    7.090  7.704  6.397 2.81e-05 ***
## s(DirectPortfolioLiabilities) 1.000  1.000  0.276    0.602    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## R-sq.(adj) =  0.782   Deviance explained = 82.3%
## GCV = 1.1337e+09  Scale est. = 9.0281e+08  n = 51
validationPrediction <- predict(validationGam, newdata=validationData)
rmse(validationData$FinNetLending, validationPrediction)
## [1] 26813.53


Through a process of adjusting the tuning parameter k we have achieved an adjusted \(R^2\) value of 0.782. We have done this while ensuring k-values are not too large to prevent overfitting in our model. This model also achieves a RMSE of 26,813.53 This means that the model predictions differ from the actual value of ‘FinNetLending’ by around 26,814 millions of dollars (26.8 billion). This is somewhat high, but because the units of ‘FinNetLending’ are in the high tens and low hundreds of billions of dollars, it indicates a relatively good model fit. Also, through continuous testing we have determined that these values of k result in the highest adjusted \(R^2\) value when we use the model for the test data. This testing process is shown below, in the Results section.


Results

testGam <- gam(FinNetLending ~ s(Exports, k=6) + s(Imports, k=9) + s(DirectPortfolioLiabilities, k=4), data=testData)
summary(testGam)
## 
## Family: gaussian 
## Link function: identity 
## 
## Formula:
## FinNetLending ~ s(Exports, k = 6) + s(Imports, k = 9) + s(DirectPortfolioLiabilities, 
##     k = 4)
## 
## Parametric coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   -50106       2628  -19.07   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Approximate significance of smooth terms:
##                                 edf Ref.df      F  p-value    
## s(Exports)                    1.492  1.862  0.634 0.507472    
## s(Imports)                    7.850  7.980  5.472 0.000112 ***
## s(DirectPortfolioLiabilities) 2.700  2.933 43.403  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## R-sq.(adj) =  0.932   Deviance explained = 94.8%
## GCV = 4.7934e+08  Scale est. = 3.5911e+08  n = 52
testPrediction <- predict(testGam, newdata=testData)
rmse(testData$FinNetLending, testPrediction)
## [1] 16402.3


The model that we came up with using the validation subset generalizes very well to the test data. We observe a high adjusted R-squared value of 0.932. This means that roughly 93% of the variation in the U.S. Financial Account Balance is explained by the smooth predictor terms in our model. We should be conscious of the possibility of overfitting however, because this adjusted \(R^2\) value is larger than the adjusted \(R^2\) of 0.782 we observed for the validation subset. We also observe an RMSE of 16,402.3 which is lower than what we observed with our validation subset. This tells us that the model predictions differ from the actual value of the account balance by approximately 16,402 millions of dollars (16.4 billion). It is also important to note the estimated degrees of freedom that are being used for each term. For ‘Exports’, we observe 1.492 edf which means there is a slight non-linear relationship between ‘Exports’ and ‘FinNetLending’. However, the p-value associated with the smooth term for ‘Exports’ is 0.507472, and is not significant at an \(\alpha=0.05\). This means that when we apply this model to the test data, this term is now not a significant predictor of ‘FinNetLending.’


The edf associated with the smooth term for ‘Imports’ is 7.850 which indicates a complex non-linear relationship between ‘Imports’ and the account balance. We observe a p-value of 0.000112 which is small and significant at an \(\alpha=0.05\). This indicates that ‘Imports’ is a statistically significant predictor of ‘FinNetLending’.

The edf for the ‘DirectPortfolioLiabilities’ smooth term is 2.7, which means there is a somewhat complex and non-linear relationship between the variable and our response ‘FinNetLending’. This smooth term also yields a p-value of \(2x10^{-16}\) which at the 95% significance level means that ‘DirectPortfolioLiabilities’ is a significant predictor of the U.S. Financial Account Balance with the test data.


We will now plot each of our predictor variables to see the effect they have on ‘FinNetLending’, holding all other variables constant. This will show the effect that the smooth terms have on the response, when the model is applied to the testing data. The plot for ‘Exports’ is shown below:

library(ggplot2)
exportsGam <- gam(FinNetLending ~ s(Exports, k=6), data=testData)
exportSeq <- data.frame(Exports = seq(min(testData$Exports), max(testData$Exports), length.out = 100)) # Creates range of values from min to max of Exports to use to predict values of 'FinNetLending' 
exportSeq$FinNetLending <- predict(exportsGam, newdata = exportSeq, type = "response")
predictions <- predict(exportsGam, newdata = exportSeq, type = "response", se.fit = TRUE) # calculate standard errors
exportSeq$fit <- predictions$fit
exportSeq$lower <- predictions$fit - 1.96 * predictions$se.fit # Making 95% confidence interval
exportSeq$upper <- predictions$fit + 1.96 * predictions$se.fit
plot1 <- ggplot(testData, aes(x = Exports, y = FinNetLending)) + 
  geom_point(color = "blue", alpha = 0.7, size = 2) +  
  geom_line(data = exportSeq, aes(x = Exports, y = fit), color = "maroon", linewidth = 0.7) + 
  geom_ribbon(data = exportSeq, aes(x = Exports, ymin = lower, ymax = upper), fill = "maroon", alpha = 0.2) + 
  labs(title = "Exports vs. Financial Account Balance", 
        x = "Exports", 
        y = "Financial Account Balance")
plot1


It appears as though from a level of around 10 million dollars in exports up until 450 billion dollars in exports, the U.S. Financial Account Balance is decreasing as exports are increasing. After exports hit approximately 450 billion, the account balance starts to climb back up as exports increase. The 95% confidence interval seems to capture some of the variability in ‘FinNetLending’. However, we should point out that in this model the smooth term for ‘Exports’ was not statistically significant and may not be able to powerfully predict ‘FinNetLending’ well.


Now looking at the effect that imports have on the account balance:

importsGam <- gam(FinNetLending ~ s(Imports, k=9), data=testData)
exportSeq <- data.frame(Imports = seq(min(testData$Imports), max(testData$Imports), length.out = 100))
exportSeq$FinNetLending <- predict(importsGam,, newdata = exportSeq)
predictions <- predict(importsGam, newdata = exportSeq, type = "response", se.fit = TRUE)
exportSeq$fit <- predictions$fit
exportSeq$lower <- predictions$fit - 1.96 * predictions$se.fit # Making 95% confidence interval
exportSeq$upper <- predictions$fit + 1.96 * predictions$se.fit
plot2 <- ggplot(testData, aes(x = Imports, y = FinNetLending)) + 
  geom_point(color = "red", alpha = 0.7, size = 2) +  
  geom_line(data = exportSeq, aes(x = Imports, y = fit), color = "black", linewidth = 0.7) + 
  geom_ribbon(data = exportSeq, aes(x = Imports, ymin = lower, ymax = upper), fill = "black", alpha = 0.2) + 
  labs(title = "Imports vs. Financial Account Balance", 
        x = "Imports", 
        y = "Financial Account Balance")
plot2


We observe that as imports increase up until approximately 600 billion dollars, the account balance seems to decrease. As exports increase from around 600 billion to 725 billion dollars, the account balance trends upwards, and then declines again after this point. This plot suggests a complex non-linear relationship between ‘Imports’ and ‘FinNetLending’ as is evidenced by the variability, or ‘wiggliness’, of the model curve. The 95% confidence interval seems to capture many of the data points well also. The smooth term for ‘Imports’ also yielded a p-value that was significant at an \(\alpha=0.05\), meaning that ‘Imports’ is a statistically significant predictor of ‘FinNetLending’. If the value of imports were to increase beyond $800 billion, the model predicts that the account balance would likely continue decreasing into negative territory.
Now taking a look at how direct portfolio liabilities affect the account balance:

portfolioGam <- gam(FinNetLending ~ s(DirectPortfolioLiabilities, k=4), data = FinanceData)
exportSeq <- data.frame(DirectPortfolioLiabilities = seq(min(testData$DirectPortfolioLiabilities), 
                                                        max(testData$DirectPortfolioLiabilities), length.out = 100))
exportSeq$FinNetLending <- predict(portfolioGam, newdata = exportSeq, type = "response")
predictions <- predict(portfolioGam, newdata = exportSeq, type = "response", se.fit = TRUE)
exportSeq$fit <- predictions$fit
exportSeq$lower <- predictions$fit - 1.96 * predictions$se.fit # Making 95% confidence interval
exportSeq$upper <- predictions$fit + 1.96 * predictions$se.fit
plot3 <- ggplot(testData, aes(x = DirectPortfolioLiabilities, y = FinNetLending)) + 
  geom_point(color = "orange", alpha = 0.7, size = 2) +  
  geom_line(data = exportSeq, aes(x = DirectPortfolioLiabilities, y = fit), color = "green", linewidth = 0.7) + 
  geom_ribbon(data = exportSeq, aes(x = DirectPortfolioLiabilities, ymin = lower, ymax = upper), fill = "green", alpha = 0.2) + 
  labs(title = "Direct Portfolio Liabilities vs. Financial Account Balance", 
        x = "Direct Portfolio Liabilities", 
        y = "Financial Account Balance")
plot3


The model curve appears to have a slight cubic shape with a general downward trend until we reach around 300 billion dollars in direct portfolio liabilities. Past this point the account balance increases very slightly along with direct portfolio liabilities. Before 300 billion dollars, as direct portfolio liabilities increase, the account balance shows a downward trend. The 95% confidence interval seems to capture some of the data points, but misses some especially for very low and very high values of liabilities. The smooth term for direct portfolio liabilities was significant at the 95% confidence level. If direct portfolio liabilities continue to increase above 400 billion, it seems that the financial account balance will be predicted to rise moderately.


Finally, we will compare the values of ‘FinNetLending’ that the overall additive test model predicts, and compare them to the actual values from our ‘FinanceData’. This process and plot is shown below:

testPrediction <- predict(testGam, newdata = FinanceData)
comparisonData <- data.frame(Actual = FinanceData$FinNetLending, Predicted = testPrediction)
finalPlot <- ggplot(comparisonData, aes(x = Actual, y = Predicted)) +
  geom_point(color = "red", alpha = 0.7, size = 2) +  
  geom_abline(slope = 1, intercept = 0, color = "black", linetype = "dashed") + 
  labs(title = "Actual vs. Predicted Financial Account Balance",
        x = "Actual Financial Account Balance",
        y = "Predicted Financial Account Balance") 
finalPlot

We can see that when the account balance is closer to zero, the model seems to predict values of ‘FinNetLending’ very accurately. As the account balance becomes larger and larger in the negative, the model predictions deviate further from the actual account balance values. This implies that for more recent data points (where account balance is a larger negative) our final test model doesn’t perform as well. But for older data points, the model does seem to predict the value of ‘FinNetLending’ with some precision. Let us finally assess the conditions of this model.


Model Conditions:

qqnorm(resid(testGam))
qqline(resid(testGam))


The Normal Q-Q Plot looks concerning because most points don’t fall along the theoretical line. It appears as though the condition of normality of residuals is not fulfilled in our model.

plot(fitted(testGam), resid(testGam), main="Residuals vs. Fitted", xlab="Fitted Values", ylab="Residuals")
abline(h=0)


The Residuals vs. Fitted plot also raises some concerns. Points look to be spread evenly above and below zero so we can say that the condition of the residuals being centered at zero is met. However, there appears to be some clustering of residuals and we can reasonably conclude that the condition of equal variance among residuals is not fulfilled. This clustering also makes us have concerns about overfitting in our model. Because of this, and because our data is not coming from a random sample, we also can conclude that the assumption of independent residuals is not adequately met. Because our model conditions are not met, this will make our statistical inference less reliable for this model.


Discussion

Overall it is clear that exports, imports, and direct portfolio liabilities all have complex non-linear relationships with our response variable – the U.S. Financial Account Balance. One strength of this model is it was able to achieve a very high adjusted R-squared value when fit with the testing subset data (\(R^2\)=0.932). We were also able to achieve a relatively low RMSE of 16831 also. Our economic intuition was not completely confirmed by our results. For exports, the financial account balance seemed to decrease as exports increased, which contradicted our economic thinking. This only happened until around 450 billion dollars in exports though, and then the account balance seemed to go back up as exports went up. ‘Exports’ was not a significant predictor in our final model however. For imports, there was an overall decline in the account balance as exports increased to roughly 600 billion. This aligns with our economic intuition because more imports means more money flowing out of the country and a lower account balance. Outside of the range of around 600 to 725 billion dollars in imports, the account balance trended downwards as imports went up. Besides this small interval, the relationship we observed between ‘Imports’ and the financial account balance aligned with what the economics would predict. For direct portfolio liabilities, we observed an overall decline in the account balance as liabilities increased – until 300 billion when the account balance then started to trend upwards. This upward trend (which has been happening recently) aligns with financial thinking that says that when liabilities increase, more money will be flowing into the country which will increase the overall account balance.

One weakness of this model is its inability to fully satisfy the model conditions, mainly those of normality and homoscedasticity of residuals. This, coupled with the difference in adjusted r-squared values (~0.78 vs. 0.93) between the validation and test subset models, may be an indication of overfitting. Our final model may be taking to much noise into account, and our values of k may be too high, which makes it more difficult to generalize our model. This also may be represented by our final scatter plots which shows that our model may fit the cluster of points that are closer to an even account balance, and it misses predictions of larger account balance values. To make improvements, we could reduce values of k to try and address this issue. We could also consider removing data points from 1980 or 1990 and earlier for example, so we can generalize our model better to the present day. It would also be important to include interactions that may be significant – as we left all interactions out of this model. Another interesting approach could be to use a time series model, like an ARIMA model, to try and forecast the financial account balance into the future.



References:

“Financial Account Definition, With Components and Assets” Investopedia, 8 Sept. 2023, www.investopedia.com/terms/f/financial-account.asp. Accessed 2 December 2024.

Board of Governors of the Federal Reserve System (US), Federal Government; Net Lending (+) or Borrowing (-) (Financial Account), Transactions [FGLBAFQ027S], retrieved from FRED, Federal Reserve Bank of St. Louis; https://fred.stlouisfed.org/series/FGLBAFQ027S, December 15, 2024.