feat(finmodel): monthly DCF — real NPV/IRR/PBP, replace IRR-proxy (epic #1881 PR-3) #1884

Merged
bot-backend merged 1 commit from feat/finmodel-dcf into main 2026-06-23 17:02:55 +00:00
Collaborator

Summary

Эпик #1881 PR-3 — помесячный DCF → НАСТОЯЩИЕ NPV/IRR/PBP, заменяет IRR-proxy. Hand-rolled (без numpy-financial / новых deps), чистая детерминированная математика.

Что

  • _npv / _irr_monthly (bisection + bracket-guard) / _payback_months над помесячным cashflow из статического каскада (PR-1) + калиброванной цены (PR-2).
  • Дефолтные нормативы фаз (документированы как допущения): ПИР 6мес → СМР по development_type (24/36/48) → распродажа, дисконт 15%.
  • ИНВАРИАНТ: налоги прорейтятся на признание выручки → Σ недисконтированного cashflow == net_profit (тест — гарантия что DCF не разошёлся со статикой; diff 0.0).
  • IRR настоящий при смене знака; вырожденный поток → roi-proxy fallback (irr_is_proxy=True, честно).
  • График продаж привязан к завершению стройки: sales_end = max(sales_start+длит, construction_end) — продажи не заканчиваются раньше ввода (РФ ДДУ/эскроу). Иначе high_rise распродавался за 12 мес ДО ввода → двойная смена знака → profitable-проект молча падал в proxy + инверсия NPV (найдено code-review, исправлено + регресс-тесты).
  • FinancialModel +npv_rub/payback_months/discount_rate_used/schedule_is_default (additive).
  • UI/PDF: NPV/IRR/PBP + честный caveat «график — типовое допущение, точность зависит от него».

Test plan

  • hand-roll DCF на учебных значениях ([-1000,0,0,1331]→IRR 10%/мес, PBP 2.75)
  • ИНВАРИАНТ Σ==net_profit (profitable/loss/все dev_types) — diff 0.0
  • IRR real-vs-proxy обе ветки; profitable high_rise → настоящий IRR (регресс на баг); sales_end≥construction_end все типы
  • mypy strict clean (generative.*); ruff/tsc/lint clean; api-types регенерён авторитетно; deps не тронуты (hand-roll)
  • code-reviewer APPROVE (re-review после фикса графика — симуляция подтвердила 1 смену знака)
  • post-deploy: concept-отчёт показывает NPV/IRR/PBP (DCF) с caveat

Follow-up

PR-4: мост в site-finder cockpit Investment Clearance (ТЭП из buildability) + подключить §22 sales-pace вместо дефолта + финансирование (кредит/займы 15%).

Refs #1881

🤖 Generated with Claude Code

## Summary Эпик #1881 **PR-3** — помесячный **DCF → НАСТОЯЩИЕ NPV/IRR/PBP**, заменяет IRR-proxy. Hand-rolled (без numpy-financial / новых deps), чистая детерминированная математика. ## Что - `_npv` / `_irr_monthly` (bisection + bracket-guard) / `_payback_months` над помесячным cashflow из статического каскада (PR-1) + калиброванной цены (PR-2). - Дефолтные нормативы фаз (документированы как допущения): ПИР 6мес → СМР по `development_type` (24/36/48) → распродажа, дисконт 15%. - **ИНВАРИАНТ**: налоги прорейтятся на признание выручки → `Σ недисконтированного cashflow == net_profit` (тест — гарантия что DCF не разошёлся со статикой; diff 0.0). - IRR настоящий при смене знака; вырожденный поток → roi-proxy fallback (`irr_is_proxy=True`, честно). - **График продаж привязан к завершению стройки**: `sales_end = max(sales_start+длит, construction_end)` — продажи не заканчиваются раньше ввода (РФ ДДУ/эскроу). Иначе high_rise распродавался за 12 мес ДО ввода → двойная смена знака → profitable-проект молча падал в proxy + инверсия NPV (найдено code-review, исправлено + регресс-тесты). - `FinancialModel` +`npv_rub`/`payback_months`/`discount_rate_used`/`schedule_is_default` (additive). - UI/PDF: NPV/IRR/PBP + честный caveat «график — типовое допущение, точность зависит от него». ## Test plan - [x] hand-roll DCF на учебных значениях ([-1000,0,0,1331]→IRR 10%/мес, PBP 2.75) - [x] **ИНВАРИАНТ Σ==net_profit** (profitable/loss/все dev_types) — diff 0.0 - [x] IRR real-vs-proxy обе ветки; profitable high_rise → настоящий IRR (регресс на баг); sales_end≥construction_end все типы - [x] mypy strict clean (generative.*); ruff/tsc/lint clean; api-types регенерён авторитетно; deps не тронуты (hand-roll) - [x] code-reviewer ✅ APPROVE (re-review после фикса графика — симуляция подтвердила 1 смену знака) - [ ] post-deploy: concept-отчёт показывает NPV/IRR/PBP (DCF) с caveat ## Follow-up PR-4: мост в site-finder cockpit Investment Clearance (ТЭП из buildability) + подключить §22 sales-pace вместо дефолта + финансирование (кредит/займы 15%). Refs #1881 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bot-backend added 1 commit 2026-06-23 16:52:28 +00:00
feat(finmodel): monthly DCF — real NPV/IRR/PBP, replace IRR-proxy (epic #1881 PR-3)
All checks were successful
CI / frontend-tests (pull_request) Successful in 57s
CI / backend-tests (pull_request) Successful in 9m54s
CI / changes (pull_request) Successful in 6s
CI / openapi-codegen-check (pull_request) Successful in 1m53s
d4068a255b
Hand-rolled детерминированный DCF (без numpy-financial/новых deps): _npv /
_irr_monthly (bisection с bracket-guard) / _payback_months над помесячным
cashflow, построенным из статического каскада (PR-1) + калиброванной цены
(PR-2) по дефолтным нормативам фаз (ПИР 6мес → СМР по development_type
24/36/48 → распродажа, дисконт 15%).

- Налоги прорейтятся на признание выручки → Σ недисконтированного cashflow ==
  net_profit (ИНВАРИАНТ, тест — гарантия что DCF не разошёлся со статикой).
- IRR настоящий когда есть смена знака; вырожденный поток → fallback на
  roi-proxy (irr_is_proxy=True). Честно помечено.
- График продаж привязан к завершению стройки: sales_end = max(sales_start +
  длительность, construction_end) — продажи не заканчиваются раньше ввода
  (РФ ДДУ/эскроу). Без этого high_rise распродавался за 12 мес ДО ввода →
  двойная смена знака → profitable-проект молча падал в proxy + инверсия NPV.
- FinancialModel +npv_rub/payback_months/discount_rate_used/schedule_is_default
  (additive). development_type проброшен через placement.
- UI/PDF: NPV/IRR/PBP + честный caveat «график — типовое допущение, точность
  зависит от него». api-types регенерён авторитетно.

mypy strict clean (generative.*), +15 тестов (DCF helpers на учебных значениях,
ИНВАРИАНТ, IRR real-vs-proxy обе ветки, PBP, sales≥construction для всех типов,
profitable high_rise → настоящий IRR). 48 passed.

Refs #1881
bot-backend merged commit ae90f84c90 into main 2026-06-23 17:02:55 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1884
No description provided.