Skip to content

[WIP] Add stable points for PortfolioConsumerType#1259

Open
alanlujan91 wants to merge 4 commits intoecon-ark:mainfrom
alanlujan91:portfolio_target
Open

[WIP] Add stable points for PortfolioConsumerType#1259
alanlujan91 wants to merge 4 commits intoecon-ark:mainfrom
alanlujan91:portfolio_target

Conversation

@alanlujan91
Copy link
Member

This is inheriting the way to calculate stable points from ConsIndShock, which might not be appropriate for PortfolioConsumerType but provides a starting point.

  • Tests for new functionality/models or Tests to reproduce the bug-fix in code.
  • Updated documentation of features that add new functionality.
  • Update CHANGELOG.md with major/minor changes.

@alanlujan91 alanlujan91 requested a review from sbenthall April 20, 2023 13:59
@codecov
Copy link

codecov bot commented Apr 20, 2023

Codecov Report

Patch coverage: 100.00% and project coverage change: +0.04 🎉

Comparison is base (09f1843) 72.55% compared to head (72e0018) 72.59%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1259      +/-   ##
==========================================
+ Coverage   72.55%   72.59%   +0.04%     
==========================================
  Files          78       78              
  Lines       13009    13028      +19     
==========================================
+ Hits         9439     9458      +19     
  Misses       3570     3570              
Impacted Files Coverage Δ
HARK/ConsumptionSaving/ConsPortfolioModel.py 90.23% <100.00%> (+0.41%) ⬆️
HARK/ConsumptionSaving/ConsRiskyAssetModel.py 44.36% <100.00%> (ø)

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@llorracc
Copy link
Collaborator

Alan,

Seb has a PR to the LucasAssetPrice that has a formula that, if it is correct, should be the right impatience condition for the portfolio choice model (when the risky return from the standpoint of the portfolio choice consumer is the portfolio-weighted return). I don’t have time to review Seb’s PR right now — I did the derivations for the approximate formula, which were what was needed for the pedagogical purpose of the handout, and Seb has tried to turn that into the exact formula in levels (that’s what his PR does). If you could review that, then incorporate that formula into the PortfolioConsumerType model (with a comment linking to the LAP lecture notes as the justification), that would be great.

cc’ing Akshay because I’ve mentioned to him that this would be a useful small extension to the derivations in the BufferStockTheory paper that he is reviewing for me. Presumably the condition in my LAP model is identical to impatience formulas in Stachurski, Ma, and Toda (if I am right that their model is one with only rate-of-return risk).

PS. I've added all three of you as collaborators, so that Alan can merge Seb's PR after review.

@alanlujan91 alanlujan91 changed the title Add stable points for PortfolioConsumerType [WIP] Add stable points for PortfolioConsumerType Jun 7, 2023
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This work-in-progress PR attempts to add stable point calculations (mNrmStE and mNrmTrg) to the PortfolioConsumerType by inheriting functionality from ConsIndShockSolver. The PR author acknowledges this approach might not be appropriate for the portfolio model but provides a starting point.

Changes:

  • Changed ConsPortfolioSolver to inherit from ConsIndShockSolver instead of MetricObject
  • Added attributes (mNrmMin, hNrm, MPCmin, MPCmax) to terminal solutions to support parent class methods
  • Integrated add_MPC_and_human_wealth and add_stable_points methods into the solve process

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
HARK/ConsumptionSaving/ConsRiskyAssetModel.py Removed inline comment from import statement (minor cleanup)
HARK/ConsumptionSaving/ConsPortfolioModel.py Changed solver inheritance structure, added terminal solution attributes, integrated stable points calculation into solve methods

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +478 to +480
super().set_and_update_values(
self.solution_next, self.IncShkDstn, self.LivPrb, self.DiscFac
)
Copy link

Copilot AI Jan 28, 2026

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.

Suggested change
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 uses AI. Check for mistakes.
Comment on lines +1042 to +1044
super().set_and_update_values(
self.solution_next, self.IncShkDstn, self.LivPrb, self.DiscFac
)
Copy link

Copilot AI Jan 28, 2026

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.

Suggested change
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 uses AI. Check for mistakes.
Comment on lines +946 to +948
self.solution = self.add_MPC_and_human_wealth(self.solution)
self.solution.mNrmMin = self.mNrmMinNow
self.solution = self.add_stable_points(self.solution)
Copy link

Copilot AI Jan 28, 2026

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 uses AI. Check for mistakes.
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
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "this is a hack" is not sufficiently descriptive. Consider expanding it to explain why this assignment is necessary, something like: "Map portfolio-specific vFuncAdj and vPfuncAdj to the generic vFunc and vPfunc names expected by the parent class's set_and_update_values method."

Suggested change
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 uses AI. Check for mistakes.
Comment on lines +946 to +948
self.solution = self.add_MPC_and_human_wealth(self.solution)
self.solution.mNrmMin = self.mNrmMinNow
self.solution = self.add_stable_points(self.solution)
Copy link

Copilot AI Jan 28, 2026

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 uses AI. Check for mistakes.
Comment on lines +1020 to +1022
self.solution = self.add_MPC_and_human_wealth(self.solution)
self.solution.mNrmMin = self.mNrmMinNow
self.solution = self.add_stable_points(self.solution)
Copy link

Copilot AI Jan 28, 2026

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 uses AI. Check for mistakes.
@@ -1220,6 +1250,10 @@ def solve(self):

self.make_porfolio_solution()

Copy link

Copilot AI Jan 28, 2026

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.

Suggested change
# 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

Copilot uses AI. Check for mistakes.

self.solution = self.add_MPC_and_human_wealth(self.solution)
self.solution.mNrmMin = self.mNrmMinNow
self.solution = self.add_stable_points(self.solution)
Copy link

Copilot AI Jan 28, 2026

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.

Suggested change
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 uses AI. Check for mistakes.


class ConsPortfolioSolver(MetricObject):
class ConsPortfolioSolver(ConsIndShockSolver):
Copy link

Copilot AI Jan 28, 2026

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)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Stale

Development

Successfully merging this pull request may close these issues.

Set starting aNrm for Lucas population near equilibrium Compute mNrmStE for the PortfolioConsumerType

3 participants