Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update r_gov_scale and r_gov_shift variables in macro_params.py #24

Merged
merged 9 commits into from
Jan 13, 2023

Conversation

SeaCelo
Copy link
Collaborator

@SeaCelo SeaCelo commented Dec 14, 2022

New calculation for r_gov_shift and r_gov_scale

Closes #22

New calculation for r_gov_shift and r_gov_scale
@SeaCelo SeaCelo added the enhancement New feature or request label Dec 14, 2022
@SeaCelo SeaCelo requested review from rickecon and sarvonz December 14, 2022 18:02
@SeaCelo SeaCelo self-assigned this Dec 14, 2022
@SeaCelo SeaCelo changed the title Update macro_params.py Update r_gov_scale and r_gov_shift variables in macro_params.py Dec 14, 2022
@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Dec 19, 2022

We can also hard-code the results instead of running the same OLS with the fixed results:
The results:
r_gov_shift = 0.24484764
r_gov_scale = 3.37662504

Note: the estimated values exceed the hard coded limits:

paramtools.exceptions.ValidationError: {
"errors": {
"r_gov_scale": [
"r_gov_scale 3.376625043803517 > max 2.0 "
],
"r_gov_shift": [
"r_gov_shift 0.24484763593657807 > max 0.2 "
]
}
}

@rickecon : Can we consider changing the limits? These look to be hard-coded into the OG-Core default parameters.

@sarvonz
Copy link
Contributor

sarvonz commented Dec 20, 2022

@SeaCelo @rickecon Hi Marcelo - I reviewed the code and it looks good to me in terms of achieving what you set out to do, which I thought is a good way to reverse-engineer the constant and the coefficient on corporate bond yield.

But a question I have for Rick is about how r_gov_scale and r_gov_shift feed into the model. Looking at the fiscal.py script in the OG-CORE model, there is this line of code r_gov = np.maximum(p.r_gov_scale * r - p.r_gov_shift, 0.00). Applying the estimates from Marcelo (i.e. r_gov_scale=3.37 and r_gov_shift=.24) to this equation, it would give r_gov that is consistently higher than r, except for close to zero r, which is odd. Could it be that the estimated constant (from the regression of government bond yield on corporate bond yield) be r_gov_shift, and r_gov_scale the estimated coefficient on corporate bond yield? In the current code, it is the other way around.

@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Dec 20, 2022

scale and shift must be switched around. I'll look to make sure everything is estimated correctly and assigned to the correct variable.

From existing calibration in macro_params.py, "shift" refers to the coefficient and "scale" is the constant term of the OLS. This may be wrong.

    macro_parameters["r_gov_shift"] = res.params["BAA Corp Bond Rates"]
    macro_parameters["r_gov_scale"] = res.params["constant"]

The formula seems to be the opposite (which is what Rick found weird at our last conversation):
r_gov = r_gov_scale * r - r_gov_shift

@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Dec 20, 2022

FYI, the documentation in OG-CORE uses a slightly different application of the scale parameter.

Equation 79:
r_gov = (1-r_gov_scale) * r - r_gov_shift

Fix the assignation of the shift and scale parameters
@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Jan 9, 2023

Unless there is a reason to switch the shift and scale parameters, this PR is ready to merge
@sarvonz @rickecon

@rickecon
Copy link
Collaborator

rickecon commented Jan 9, 2023

@SeaCelo. Will you please update this branch with the most recent PR's so I can test it properly? To do so, do the following steps:

  • Go to your main branch on your local machine
  • Update your main branch with the new PRs
    • git fetch upstream
    • git merge upstream/main
    • git push origin main
  • Change to your yield-wedge branch: git checkout yield-wedge
  • Merge the changes to your main branch into your yield-wedge branch: `git merge origin/yield-wedge
    • This should bring up a merge message page. That you just save and push up to your yield-wedge branch
    • If you have merge conflicts, you'll have to go into each of the conflicted files and choose whether to go with your change or the change that came in from the new PRs.
  • Once you push those changes up to your origin remote yield-wedge branch, those changes are automatically incorporated into this PR. Then I can download this branch and test it properly.

@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Jan 9, 2023

@rickecon I think the branch is updated now

@rickecon
Copy link
Collaborator

@SeaCelo. This doesn't work. The value for r_gov_shift is above the maximum value allowed in OG-Core. This is what I get when I run run_og_zaf.py.

Traceback (most recent call last):
  File "/Users/richardevans/Docs/Economics/OSE/OG-ZAF/./examples/run_og_zaf.py", line 122, in <module>
    main()
  File "/Users/richardevans/Docs/Economics/OSE/OG-ZAF/./examples/run_og_zaf.py", line 54, in main
    p.update_specifications(updated_params)
  File "/Users/richardevans/opt/anaconda3/envs/ogzaf-dev/lib/python3.9/site-packages/ogcore/parameters.py", line 622, in update_specifications
    self.adjust(revision, raise_errors=raise_errors)
  File "/Users/richardevans/opt/anaconda3/envs/ogzaf-dev/lib/python3.9/site-packages/paramtools/parameters.py", line 257, in adjust
    return self._adjust(
  File "/Users/richardevans/opt/anaconda3/envs/ogzaf-dev/lib/python3.9/site-packages/paramtools/parameters.py", line 375, in _adjust
    raise self.validation_error
paramtools.exceptions.ValidationError: {
    "errors": {
        "r_gov_shift": [
            "r_gov_shift 3.376625043803517 > max 0.3 "
        ]
    }
}

@jdebacker and I had this discussion/debate in OG-Core Issue #841 about what the bounds of r_gov_scale and r_gov_shift should be. I am not sure what the answer is, and I would love your thoughts on this. For this PR, I think the following two points are true.

  1. In this PR, you are setting r_gov_scale and r_gov_shift to the correct regression coefficients. However, given that the specification for r_gov in fiscal.get_r_gov() is r_gov = np.maximum(p.r_gov_scale * r - p.r_gov_shift, 0.00), then the correct specification in your macro_params.py line 219 should be macro_parameters["r_gov_shift"] = -res.params[0]. This will still fail the default_parameters.json boundaries being below the minimum value.
  2. We should look at a scatterplot of the two regression variables with sov_y on the y-axis and corp_yhat on the x-axis. Let's see if those coefficients make sense. If they do, then we need to decide what we want to do with the boundaries in default_parameters.json for r_gov_scale and r_gov_shift.

@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Jan 10, 2023

And here is the full code to estimate the coefficients

# defining the variables
sov_y = (np.arange(20, 120) / 10)
corp_yhat = 8.199 - (2.975*sov_y) + (0.478*sov_y**2)
 
# adding the constant term
corp_yhat = sm.add_constant(corp_yhat)
 
# performing the regression
mod = sm.OLS(
    sov_y,
    corp_yhat,
)
res = mod.fit()
p = mod.fit().params
 
# See results
print(res.summary())
print(res.params)  # first term is the constant. Second is the coefficient
#macro_parameters["r_gov_shift"] = res.params[1]  #coefficient
#macro_parameters["r_gov_scale"] = res.params[0]  #constant

Changed sign of the coefficient to match the specification
@rickecon
Copy link
Collaborator

@SeaCelo. Three questions.

  1. How can the blue line be data? It is too clean. Data on government borrowing rates by year (or quarter, month, or day) and corresponding private borrowing rates shouldn't look that clean.
  2. I think the units are wrong. A 4% interest rate in the model is represented by 0.04. It looks like we need to divide those interest rates by 100.
  3. What are the black lines?

@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Jan 10, 2023

@rickecon
The chart was my bad ability to make charts in Python. I fixed it above.

Remember that we don't actually have data. We have the estimated model from the paper referenced in this post.

We are taking a fitted quadratic model and then estimating a linear model to fit the specification in OG-CORE.

This line creates the fitted data since we only have the coefficients from the paper:
corp_yhat = 8.199 - (2.975*sov_y) + (0.478*sov_y**2)

@rickecon
Copy link
Collaborator

@SeaCelo. I see. This makes the transformation more difficult. Here are the steps I would do.

  1. Make sure the paper from which the coefficients are taken has the interest rates in percentage form (4.5% is 4.5) and not fraction form (this is how the OG models are specified, where 4.5% is 0.045).
  2. Simulate only the values of the government borrowing rate sov_y that are seen in the data over the last specified period of time
  3. Simulate the private borrowing rate corp_yhat using the appropriate equation.
    • If the paper uses interest rates in fraction form (4.5% is 0.045), then use the exact coefficients from the paper.
    • If the paper uses interest rates in percentage form (4.5% is 4.5) then use the following adjusted equation that results from dividing both sides by 100, and multiplying and dividing the squared term by an extra 100. This is just changing the units of a nonlinear equation. Notice that all the variables are in terms of (4.5% is 0.045).
corp_yhat/100 = (8.199/100) - (2.975*(sov_y/100)) + ((100*0.478)*(sov_y/100)**2)
  1. Now estimate the linear equation on the appropriate data.

@rickecon
Copy link
Collaborator

@SeaCelo. Maybe it is easier to do steps (1) and (2) above, skip step (3), do step (4) and estimate the linear model. Then just divide its constant coefficient by 100 in the end.

Fix unit and sign of the constant
@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Jan 10, 2023

@rickecon I think we agree on the procedure. The units needed to be fixed as you pointed out, but that just requires dividing the constant by 100. Regardless, I retraced the steps:

  1. The paper uses the "4.5%" form, not the decimal form.
  2. The range simulated in the paper is from 2-12. This is the range that I use.
  3. I recreate the private borrowing rate corp_yhat using their estimated coefficients. This is the same as their figure 3.
  4. With this data I estimate the linear equation, using govt_rate as the dependent variable.

With the corrected units we should be fine now.

macro_parameters["r_gov_shift"] = (
        -res.params[0] / 100
    )  # constant = 0.0337662504
    macro_parameters["r_gov_scale"] = res.params[1]  # coefficient = 0.24484764

I updated the PR with this change.

@rickecon
Copy link
Collaborator

rickecon commented Jan 12, 2023

@SeaCelo. Was your last commit merging the new changes from PR #14 into this branch? It looks like it was.

@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Jan 12, 2023

@rickecon After I merged PR #14 into main I did synchronize this branch. Is that not correct?

@SeaCelo SeaCelo marked this pull request as draft January 12, 2023 20:53
@rickecon
Copy link
Collaborator

@SeaCelo. That is correct. I'll try and get this merged in the next hour.

@rickecon
Copy link
Collaborator

@SeaCelo. If this is ready for my review, which I think it is, will you please click the "Ready for review" button right under "All checks have passed". This will remove the "Draft" status and allow me to merge it once I finish my review.

Hardcoding the estimated parameters for r_gov_shift and r_gov_scale
@SeaCelo SeaCelo marked this pull request as ready for review January 12, 2023 21:15
@SeaCelo
Copy link
Collaborator Author

SeaCelo commented Jan 12, 2023

I changed the code a bit to hard code the estimates but keep the model under comment as a reference.

@rickecon
Copy link
Collaborator

@SeaCelo. The new update in OG-Core that allows for a negative r_gov_shift has not been uploaded to the PyPI ogcore package yet, which is the package that is loaded by the ogzaf-dev conda environment. So I need to upload that OG-Core package. Then this PR should be ready to go.

@rickecon
Copy link
Collaborator

rickecon commented Jan 13, 2023

@SeaCelo. Thanks for this PR. This is ready to merge as soon as you merge the small PR I submitted to your branch. With the publishing of OG-Core version 0.10.2, the new minimum value of r_gov_shift allows this calibration to go forward. I deleted my old ogzaf-dev conda environment and re-created it, which installed the ogcore package v0.10.2. I ran this on my machine and got the following results. Because the baseline steady state took at least two guesses to find the SS, I recommend that we update the initial_guess_r_SS=0.04 (actual rss=0.039983762484688004), initial_guess_TR_SS=0.042 (actual TR_ss=0.042351285854548566), and initial_guess_factor_SS=71707.0 (actual factor_ss=71707.13582692057) in ogzaf_default_parameters.json so the initial steady-state solves quicker. I submitted a PR to this branch with these default parameter changes.

Baseline steady state equilibrium computation output

GE loop errors =  [-2.3779589408690072e-14, -2.6749435999562365e-14, 5.213607323639735e-13, 0.0, 2.9660718325885682e-12, -2.433470092100265e-14, -5.046171813738454e-12, -3.4840186291518194e-14, -2.0816681711721685e-14, -2.5142041226722256e-12, -5.032550765005084e-12, -4.6091602756703764e-15, 1.186412079690058e-13, -8.808231921619836e-14]
Iteration: 01  Distance:  6.322518307504174e-11
SS debt =  1.0587821463637141 0.002894061979909914
IO:  (1, 1) , C:  (1,)
Foreign debt holdings =  0.24883569478937936
Foreign capital holdings =  -0.015158573202765936
resource constraint:  [1.70592707e-14]
Checking constraints on capital, labor, and consumption.
	There were no violations of the constraints on labor  supply.
	There were no violations of the constraints on  consumption.
Maximum error in labor FOC =  7.416289804496046e-14
Maximum error in savings FOC =  5.1514348342607263e-14
JUST SAVED SS output to  /Users/richardevans/Docs/Economics/OSE/OG-ZAF/examples/OG-ZAF-Example/OUTPUT_BASELINE/SS/SS_vars.pkl

Baseline transition path equilibrium computation output (21 min, 0 sec)

Maximum debt ratio:  5.004100174218012
w diff:  1.1929702339319448e-06 -3.3621953665630144e-07
r diff:  2.0221364388506302e-08 -6.763265426867893e-08
r_p diff:  1.3768578006889687e-08 -5.9209164279816484e-08
p_m diff:  0.0 0.0
BQ diff:  3.2837736430035847e-07 -1.855537620776282e-08
TR diff:  6.677956358724924e-08 -1.9242348071879523e-07
Iteration: 24
	Distance: 6.700440474222973e-06
Max absolute value resource constraint error: 2.222274267779656e-05
Checking time path for violations of constraints.
Max Euler error, savings:  9.233336317748808e-12
Max Euler error labor supply:  3.1734614935885475e-12
Time path iteration complete.
It took 1267.7601969242096 seconds to get that part done.
run time =  1267.7611808776855

Reform steady state equilibrium computation output

GE loop errors =  [-2.0816681711721685e-17, -2.0816681711721685e-17, 4.440892098500626e-16, 0.0, 2.220446049250313e-16, -1.3877787807814457e-17, -2.0816681711721685e-17, 0.0, -6.938893903907228e-18, -1.3877787807814457e-17, -6.938893903907228e-18, 3.469446951953614e-18, 6.938893903907228e-18]
Iteration: 01  Distance:  1.3029594003443846e-15
SS debt =  1.2656834802827899 0.003459603518501506
IO:  (1, 1) , C:  (1,)
Foreign debt holdings =  0.2974617859597122
Foreign capital holdings =  0.10254780984016268
resource constraint:  [-3.96904731e-15]
Checking constraints on capital, labor, and consumption.
	There were no violations of the constraints on labor  supply.
	There were no violations of the constraints on  consumption.
Maximum error in labor FOC =  8.08242361927114e-14
Maximum error in savings FOC =  4.796163466380676e-14
JUST SAVED SS output to  /Users/richardevans/Docs/Economics/OSE/OG-ZAF/examples/OG-ZAF-Example/OUTPUT_REFORM/SS/SS_vars.pkl

Reform transition path equilibrium computation output (22 min, 43 sec)

Maximum debt ratio:  4.97631014743914
w diff:  1.2274024514535853e-06 -3.308339033836205e-07
r diff:  1.9912302390290293e-08 -6.977240300104492e-08
r_p diff:  1.3390019683312548e-08 -5.963321363100516e-08
p_m diff:  0.0 0.0
BQ diff:  3.3460752954517226e-07 -1.917074315960221e-08
TR diff:  6.812615294810032e-08 -1.9435479579887893e-07
Iteration: 24
	Distance: 6.839261890053496e-06
Max absolute value resource constraint error: 2.2167051384920644e-05
Checking time path for violations of constraints.
Max Euler error, savings:  9.249545573908335e-12
Max Euler error labor supply:  3.1739055827983975e-12
Time path iteration complete.
It took 1363.174157857895 seconds to get that part done.
run time =  1363.1757566928864
Percentage changes in aggregates: Year                    Variable  2021  2022  2023  ...  2029  2030  2021-2030    SS
0                    GDP ($Y_t$) -0.17 -0.18 -0.18  ... -0.21 -0.20      -0.19 -0.38
1            Consumption ($C_t$) -0.06  0.03 -0.39  ... -0.11 -0.12      -0.13 -0.11
2          Capital Stock ($K_t$) -0.39 -0.40 -0.41  ... -0.43 -0.42      -0.41 -0.78
3                  Labor ($L_t$)  0.01  0.01  0.00  ... -0.03 -0.03      -0.01 -0.07
4     Real interest rate ($r_t$) -0.05 -0.06 -0.05  ... -0.07 -0.07      -0.06  0.32
5                      Wage rate -0.18 -0.18 -0.18  ... -0.18 -0.18      -0.18 -0.32

[6 rows x 13 columns]

@rickecon
Copy link
Collaborator

@SeaCelo. Great. I just made sure that the steady-state solved with its first initial guess with the new parameters in ogzaf_default_parameters.json. Merging.

@rickecon rickecon merged commit 374a502 into EAPD-DRB:main Jan 13, 2023
@SeaCelo SeaCelo deleted the yield-wedge branch January 13, 2023 04:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New source for r_gov_shift and r_gov_scale
3 participants