РПА Компас

# Методология РПА Компас (MCP)

Машинно-читаемый контракт метрик для инструментов MCP-сервера. Если число в ответе инструмента расходится с вашим пересчётом — сверяйтесь с формулами ниже; inputs для пересчёта приведены в тексте ответа рядом с метрикой.

## 1. Источники данных

Три независимых источника. Разные инструменты используют разные источники — это главная причина «несовпадающих» чисел.

| Источник | Таблица/поле | Периодичность | Что это |
|---|---|---|---|
| **Витрина** | `flat_prices` (ежедневные снапшоты прайса) | ежедневно | Активные лоты, выставленные в прайс: цена, площадь, этаж, ссылка |
| **Декларации** | наш.дом.рф → `inventory_report.periods`, `building_monthly_stats` | ежемесячно (~10-е число) | Всего/продано/остаток по проектной декларации, включая НЕ выставленное в прайс |
| **Сделки** | `sales_monthly_statistics_by_object` → `sales_statistics` | ежемесячно | Зарегистрированные сделки (эскроу): количество, сумма, средняя цена м² сделки |

**Почему «непроданных по декларациям» ≠ «лотов на витрине»** (пример округа 260: 31 239 vs 11 000): декларация учитывает все непроданные квартиры проекта, витрина — только выставленные в активном прайсе. Застройщик обычно выставляет лишь часть остатка. В текстах инструментов это разведено подписями: «непроданных квартир по декларациям» vs «активных лотов на витрине» / «остаток по декларации (лотов на витрине: N)».

## 2. Формулы KPI

### Темп продаж (velocity)
`темп = Σ sold_count / число месяцев` — по последним ≤ 6 месяцам с данными (`sales_statistics[m].apartment.sold_count != null`); если месяцев < 3 — темп не считается. Аномальные месяцы (sold_count > 999) исключаются как ошибочные.

### Необходимый темп (needed)
`активный_остаток = max(0, остаток_по_декларации − round(всего × 0.20))` — стратегический резерв 20% (цель — 80% проданности к сдаче).
`месяцы_до_сдачи = max(1, месяцев до квартала сдачи)`.
`необходимый_темп = активный_остаток / месяцы_до_сдачи`.
Если необходимый темп = 0 → «план выполнен» (целевая проданность уже достигнута). Это НЕ темп распродажи полного остатка.

### Ratio (запас темпа)
`ratio = темп / необходимый_темп`. ratio > 1 — продажи быстрее необходимого. В отчётах кламп: значения ≥ 10 показываются как «≥10x»; при активном остатке < 5 квартир ratio скрывается (недостаточная база).

### Прогноз остатка к сдаче
`прогноз_% = max(0, остаток − темп × месяцы_до_сдачи) / всего × 100`. 0% = успевает распродать декларационный остаток к сдаче.

### Спред прайс/сделка — две конвенции, у каждой подпись с формулой
- **Скидка сделки к прайсу** = (прайс − сделка) / прайс × 100 — используется в `analyze_complex`, `generate_competitive_report`. Насколько реальные сделки дешевле прайса.
- **Премия витрины к сделке** = (витрина / сделка − 1) × 100 — используется в `reposition_spread`. Витрина = медиана м² **эффективной цены** (`discount_price`, если есть, иначе `price`). Там же выводится «рекл. скидка» = зачёркнутый прайс vs эффективная цена (маркетинговая скидка витрины).
Одни и те же данные дают разные проценты в разных конвенциях (пример: прайс 508, сделка 412 → скидка 18,9%, премия 23,3%). Всегда смотрите подпись с формулой. Внимание: зачёркнутый прайс (до витринной скидки) в расчётах не используется — только эффективная цена.

**Потиповой спред** (таблица по комнатности в `generate_competitive_report`): база продаж — последняя эффективная цена **вымытых лотов того же типа** (адресные продажи витрины, `_canon.washed_lots_by_room`), а не общая средняя сделки ЖК. Расчётная средняя декларации (Σ сумма / Σ площадь за месяц) искажается миксом проданных площадей и для потиповых сравнений не используется. Если вымытых лотов по типу < 3 — показывается fallback на общую среднюю с пометкой.

### Средняя цена рынка (в отчётах)
Средневзвешенная по лотам: `Σ стоимость лотов / Σ площадь лотов`. НЕ среднее средних по ЖК (оно завышено премиум-хвостом с малым числом лотов).

### Вымываемость (washout)
`washout_% = лоты, исчезнувшие с витрины за период / лоты на витрине в начале периода × 100`. Исчезновение лота ≈ продажа или снятие с прайса (различить без декларации нельзя).

### Ипотека
Аннуитет: ставка семейной 6% (или рыночная), ПВ 30%, срок 30 лет. Платёж считается от эффективной цены лота: `min(price, discount_price)`, где 0/null discount = price.

### Рекомендации акций (price_engine / get_promo_recommendations)
Для лота дороже конкурента по платежу считаются пути: субсидия ставки (1 п.п. ≈ 2,75% цены), скидка (потолок 25%), и **комбо** — часть разрыва ценой (в пределах потолка), остаток ставкой (не ниже bankMin 12%); комбо выбирается по минимальной суммарной стоимости и предлагается, когда чистые пути недостижимы. «Окно разблокировки» — доводка цены лота до лимита субсидируемой программы (платёж падает в разы без бюджета).

**Ветка «перепозиционирование» — НЕ рекомендация снизить цену.** Показанные там ставка/скидка (напр. «ставка 4,2% или −32%») — расчёт, доказывающий, что разрыв платежа с данным конкурентом нельзя закрыть ни ставкой (ниже пола банка), ни ценой (за потолком 25%). Читать так: «ценой не догонять — нужен ипотечный продукт, другой ассортимент или другой конкурентный якорь». Никогда не интерпретируйте эти проценты как совет по скидке.

## 3. Матрица «Темп × Цена» (квадранты)

Единый канон для дашборда и всех скиллов (`ai-signal-engine.js`).

Входы: `прогноз_остатка_%` и `изменение_цены_3м` (первый не-null `three_months_change_percent` из `apartments_by_type[*].historical_sqm_prices`).

| Квадрант | Условие |
|---|---|
| 🟢 Сильный спрос | прогноз ≤ 20% И цена +> 1,0% за 3 мес |
| 🔵 Здоровый баланс | прогноз ≤ 20% И цена стабильна (±1,0%) |
| 🟡 Демпинг | прогноз ≤ 20% И цена −> 1,0% |
| 🔴 Переоценён | прогноз > 20% И цена +> 1,0% |
| ⚪ Ждут | прогноз > 20% И цена стабильна |
| 🔴 Паника | прогноз > 20% И цена −> 1,0% |

**Квадрант НЕ считается («--»), если**: нет inventory (total/unsold), меньше 3 месяцев продаж, ЖК сдан (месяцев до сдачи ≤ 0 → кламп 1), или нет `three_months_change_percent` (типично для ЖК, вышедших в экспозицию < 3 месяцев назад). «--» = недостаточно данных, а не «стабильно» и не «0».

## 4. Семантика специальных значений

| Значение | Смысл |
|---|---|
| `--` | Недостаточно данных для расчёта (не 0, не «стабильно», не ошибка) |
| `null` в JSON | Нет данных |
| `0` | Реальный ноль (например, 0 продаж в месяце с данными) |
| `≥10x` | ratio больше 10 (кламп) |

## 5. Ключи комнатности

`Studio`, `1-room`, `2-room`, `3-room`, `4+-room` (внимание: именно `4+-room`, не `4-plus-room`). В параметре `rooms` промо-инструмента: `'0'`=студия … `'4'`=4+.

## 6. Язык и термины

Все ответы и отчёты — на русском. Коды действий в JSON (`action`) — машинные значения полей; в тексте, таблицах и презентациях используйте русские термины:

| Код (`action`) | Русский термин |
|---|---|
| `raise` | повышение цены |
| `reposition` | перепозиционирование лота (доводка цены) |
| `buydown` | субсидия ставки (выкуп ставки застройщиком) |
| `discount` | скидка |
| `nothing` | без изменений |

Сопутствующие термины: «окно разблокировки» — лот, чья доводка цены переводит его на субсидируемую (семейную) ставку; «blanket discount» недопустим в выводах — пишите «общая скидка на весь прайс». Англицизмы допустимы только в именах инструментов и полей JSON.

## 7. Снапшоты и версии данных

- `data.json` округа регенерируется ежедневно из БД; `_meta.data_as_of` в ответе инструмента — дата среза витрины (mtime файла).
- Продажи и декларации обновляются ежемесячно (~10-е число) — они могут отставать от витрины до месяца.
- Если два инструмента вызваны в разные дни, их срезы могут различаться — сверяйте `_meta.data_as_of` / `_meta.generated_at`.