-
-
Notifications
You must be signed in to change notification settings - Fork 204
[WIP] Add stable points for PortfolioConsumerType #1259
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
base: main
Are you sure you want to change the base?
Changes from all commits
2488132
7cd382f
d2cfc15
72e0018
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,6 +9,7 @@ | |||||||||||||||||||
|
|
||||||||||||||||||||
| from HARK import AgentType, NullFunc, make_one_period_oo_solver | ||||||||||||||||||||
| from HARK.ConsumptionSaving.ConsIndShockModel import ( | ||||||||||||||||||||
| ConsIndShockSolver, | ||||||||||||||||||||
| IndShockConsumerType, | ||||||||||||||||||||
| init_idiosyncratic_shocks, | ||||||||||||||||||||
| utility, | ||||||||||||||||||||
|
|
@@ -238,6 +239,11 @@ def update_solution_terminal(self): | |||||||||||||||||||
| dvdsFuncFxd=dvdsFuncFxd_terminal, | ||||||||||||||||||||
| ) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| self.solution_terminal.mNrmMin = 0.0 | ||||||||||||||||||||
| self.solution_terminal.hNrm = 0.0 | ||||||||||||||||||||
| self.solution_terminal.MPCmin = 1.0 | ||||||||||||||||||||
| self.solution_terminal.MPCmax = 1.0 | ||||||||||||||||||||
|
|
||||||||||||||||||||
| def initialize_sim(self): | ||||||||||||||||||||
| """ | ||||||||||||||||||||
| Initialize the state of simulation attributes. Simply calls the same method | ||||||||||||||||||||
|
|
@@ -330,7 +336,7 @@ def __init__(self, verbose=False, quiet=False, **kwds): | |||||||||||||||||||
| self.solve_one_period = make_one_period_oo_solver(ConsSequentialPortfolioSolver) | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| class ConsPortfolioSolver(MetricObject): | ||||||||||||||||||||
| class ConsPortfolioSolver(ConsIndShockSolver): | ||||||||||||||||||||
| """ | ||||||||||||||||||||
| Define an object-oriented one period solver. | ||||||||||||||||||||
| Solve the one period problem for a portfolio-choice consumer. | ||||||||||||||||||||
|
|
@@ -433,6 +439,8 @@ def __init__( | |||||||||||||||||||
| self.ShareLimit = ShareLimit | ||||||||||||||||||||
| self.IndepDstnBool = IndepDstnBool | ||||||||||||||||||||
|
|
||||||||||||||||||||
| self.CubicBool = False # This solver doesn't use cubic interpolation | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Make sure the individual is liquidity constrained. Allowing a consumer to | ||||||||||||||||||||
| # borrow *and* invest in an asset with unbounded (negative) returns is a bad mix. | ||||||||||||||||||||
| if BoroCnstArt != 0.0: | ||||||||||||||||||||
|
|
@@ -447,6 +455,9 @@ def __init__( | |||||||||||||||||||
|
|
||||||||||||||||||||
| self.def_utility_funcs() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| self.solution_next.vFunc = self.solution_next.vFuncAdj # this is a hack | ||||||||||||||||||||
| self.solution_next.vPfunc = self.solution_next.vPfuncAdj # this is a hack | ||||||||||||||||||||
|
Comment on lines
+458
to
+459
|
||||||||||||||||||||
| self.solution_next.vFunc = self.solution_next.vFuncAdj # this is a hack | |
| self.solution_next.vPfunc = self.solution_next.vPfuncAdj # this is a hack | |
| self.solution_next.vFunc = self.solution_next.vFuncAdj # Map portfolio-adjusted value function to generic vFunc name expected by the parent class's set_and_update_values method. | |
| self.solution_next.vPfunc = self.solution_next.vPfuncAdj # Map portfolio-adjusted marginal value function to generic vPfunc name expected by the parent class's set_and_update_values method. |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method signature declares parameters (solution_next, IncShkDstn, LivPrb, DiscFac) but then ignores them and uses self.solution_next, self.IncShkDstn, self.LivPrb, self.DiscFac instead when calling super(). This is confusing and inconsistent. Either remove the unused parameters from the signature, or use the parameters instead of self.* attributes.
| super().set_and_update_values( | |
| self.solution_next, self.IncShkDstn, self.LivPrb, self.DiscFac | |
| ) | |
| super().set_and_update_values(solution_next, IncShkDstn, LivPrb, DiscFac) |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No tests have been added to verify the stable points functionality (mNrmStE and mNrmTrg) for the portfolio model. Given that this is a new feature and there are existing tests for stable points in test_IndShockConsumerType.py and test_PerfForesightConsumerType.py, tests should be added to verify that the stable points are correctly calculated for portfolio consumers.
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The add_stable_points method inherited from ConsIndShockSolver expects the solution object to have a cFunc attribute. However, PortfolioSolution uses cFuncAdj and cFuncFxd instead of cFunc. When add_stable_points calls add_mNrmStE or add_mNrmTrg, these methods will attempt to evaluate solution.cFunc(m), which will fail with an AttributeError. To fix this, either add a cFunc attribute to PortfolioSolution that maps to the appropriate function (likely cFuncAdj), or override add_stable_points in ConsPortfolioSolver to handle the portfolio-specific solution structure.
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The calculation of stable points using the ConsIndShockSolver methodology may not be conceptually appropriate for the portfolio model. The stable points (mNrmStE and mNrmTrg) in ConsIndShockModel represent target wealth levels assuming a single consumption function. However, in the portfolio model, consumption depends on both market resources and the risky portfolio share, with different functions for when the agent can adjust (cFuncAdj) versus when they cannot (cFuncFxd). The stable point calculations should likely account for the portfolio allocation decision and adjustment probability, not just use the adjustable consumption function. Consider developing a portfolio-specific stable points calculation that properly incorporates the two-dimensional nature of the problem.
| self.solution = self.add_stable_points(self.solution) | |
| # Stable points from ConsIndShockSolver are not conceptually appropriate | |
| # for the portfolio model (which is two-dimensional and has cFuncAdj/cFuncFxd). | |
| # Explicitly mark them as unavailable instead of using the 1D logic. | |
| self.solution.mNrmStE = None | |
| self.solution.mNrmTrg = None |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The add_stable_points method inherited from ConsIndShockSolver expects the solution object to have a cFunc attribute. However, PortfolioSolution uses cFuncAdj and cFuncFxd instead of cFunc. When add_stable_points calls add_mNrmStE or add_mNrmTrg, these methods will attempt to evaluate solution.cFunc(m), which will fail with an AttributeError. To fix this, either add a cFunc attribute to PortfolioSolution that maps to the appropriate function (likely cFuncAdj), or override add_stable_points in ConsPortfolioSolver to handle the portfolio-specific solution structure.
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method signature declares parameters (solution_next, IncShkDstn, LivPrb, DiscFac) but then ignores them and uses self.solution_next, self.IncShkDstn, self.LivPrb, self.DiscFac instead when calling super(). This is confusing and inconsistent. Either remove the unused parameters from the signature, or use the parameters instead of self.* attributes.
| super().set_and_update_values( | |
| self.solution_next, self.IncShkDstn, self.LivPrb, self.DiscFac | |
| ) | |
| super().set_and_update_values(solution_next, IncShkDstn, LivPrb, DiscFac) |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The add_stable_points method inherited from ConsIndShockSolver expects the solution object to have a cFunc attribute. However, PortfolioSolution uses cFuncAdj and cFuncFxd instead of cFunc. When add_stable_points calls add_mNrmStE or add_mNrmTrg, these methods will attempt to evaluate solution.cFunc(m), which will fail with an AttributeError. To fix this, either add a cFunc attribute to PortfolioSolution that maps to the appropriate function (likely cFuncAdj), or override add_stable_points in ConsPortfolioSolver to handle the portfolio-specific solution structure.
| # Ensure the solution object has a cFunc attribute for methods inherited | |
| # from ConsIndShockSolver that expect solution.cFunc(m). | |
| if not hasattr(self.solution, "cFunc"): | |
| if hasattr(self.solution, "cFuncAdj"): | |
| self.solution.cFunc = self.solution.cFuncAdj | |
| elif hasattr(self.solution, "cFuncFxd"): | |
| self.solution.cFunc = self.solution.cFuncFxd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class does not call ConsIndShockSetup.init during initialization. (ConsPortfolioSolver.init may be missing a call to a base class init)