Skip to content

Debt, construction, depreciation, and PTC schedules use anchored dates - #49

Merged
dylanjm merged 4 commits into
anchored-escalationfrom
anchored-finance-tax
Oct 15, 2026
Merged

dylanjm merged 4 commits into
anchored-escalationfrom
anchored-finance-tax

Conversation

@j-bryan

@j-bryan j-bryan commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Related to #38 (does not close it). Closes #50. Stacked on #46, in stack #51.

Debt, construction, depreciation, and PTC schedules now date each period from the schedule start using add_periods, instead of stepping from the previous date, and each one takes end_of_month (keyword-only, default True).

  • Amortization: AmortizationSchedule.builder / .build, amortize, and AmortizationBuilder take end_of_month. Payment dates and interest_free(from_date=..., to_date=...) both use the anchored dates. When payments are spread over calendar periods, the final payment covers the period up to the next anchored boundary.
  • Construction: ConstructionSpendConfig.end_of_month, also accepted by ConstructionSpendBuilder and construction_spend_schedule. Interest servicing periods are anchored at the construction start. The implicit escalation uses the same flag; a user-supplied escalation_policy keeps its own setting.
  • Depreciation: macrs_schedule and both vdb_schedule date loops (the "none" convention, and the half-year/mid-quarter conventions without schedule_dates) use anchored dates. A Feb 29 placed-in-service date no longer raises in macrs_schedule.
  • PTC: the eligibility end is the anchored anniversary, so 3 years from Feb 28, 2029 ends Feb 29, 2032 with the flag on. incentives.py no longer imports dateutil.
  • Tests: tests/unit/test_finance_tax_anchoring.py checks every schedule's dates against the anchored boundaries, plus worked examples for Apr 30 starts and February placements under both settings. Here the boundaries come from a temporary anchored_boundary test helper; Property tests use independent references instead of reimplemented calendar oracles #52 switches these tests to add_periods (tested against hand values in Anchored schedule boundaries with an end-of-month rule #45) and removes the helper.

MACRS table correction

A separate commit, a7dd644, corrects two columns of the mid-quarter tables to match IRS Publication 946. In 15-year, Q4, years 9–15 had the 0.0590/0.0591 alternation shifted by one position, and the column summed to 1.0001. In 20-year, Q4, year 18 was 0.04458 instead of 0.04459, and the column summed to 0.99999. Every table now sums to exactly 1.0. This changes depreciation amounts for Q4 mid-quarter placements of 15- and 20-year property. It was found by the MACRS property test and isn't related to anchoring.

Behavior changes

With end_of_month=True as the default:

  • Schedules starting on the 29th–31st no longer drift after a short month: amortization payments, VDB dates, and construction interest periods all return to the start's day (or month-end) after February.
  • Schedules starting on the last day of a 30-day month or of February follow month-ends: Apr 30 monthly gives May 31, Jun 30, Jul 31. Examples: monthly construction interest from Apr 30 is booked May 31/Jun 30/Jul 31, not May 30/Jun 30/Jul 30 plus a one-day stub. A MACRS or PTC schedule from Feb 28 of a year before a leap year reaches Feb 29.
  • A Feb 29 MACRS placement returns a schedule dated Feb 28 in non-leap years and Feb 29 in leap years.

Not in this PR

Testing

uv run ruff check, uv run mypy dcaf/, and uv run pytest pass (961 tests), and the Hypothesis properties also pass at 3,000 examples each. No existing test changed result. ruff format --check flags one unwrapped parametrize entry in tests/unit/test_finance_tax_anchoring.py; #52 reformats it.

🤖 Generated with Claude Code

j-bryan and others added 3 commits October 13, 2026 15:55
…s and take end_of_month

Co-Authored-By: Claude <noreply@anthropic.com>

@dylanjm dylanjm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes are good, basically adds end_of_month bool to relevant methods and fixes MACRS tables.

@dylanjm
dylanjm merged commit 272df4f into main Oct 15, 2026
1 check passed
@dylanjm
dylanjm deleted the anchored-finance-tax branch October 15, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Correct IRS mid-quarter MACRS rates for 15- and 20-year Q4 property

2 participants