# Анализ участка v0.4

POI · Объектив · ставка ЦБ · конкуренция · what-if
Клик по карте подставит координаты. «Тянуть полигон» — точная геометрия из Росреестра.

## Сценарии + сохранить

## ЖК на карте кликни любой точкой для деталей

Загрузка…
🏘 ЖК
точки полигоны (304/380) heatmap районов
📍 Участок · радиусы
300м (~4мин пешком) 500м (~6мин) 1км (~12мин) 15-мин ходьба ≈1.2км

POI вокруг
🌐 POI плотность
heatmap
🔍 Фильтр ЖК
балл от 0
🗺 Подложка
Легенда
участок
ЖК · топ-25%
ЖК · средний
ЖК · ниже
POI

## 📐 Методика расчёта балла

Как 5 источников данных собираются в один балл 0-100
💡 Простыми словами — что мы делаем
Берём любую точку на карте Екатеринбурга и отвечаем на вопрос: «насколько это место подходит для жилого строительства». Сравниваем эту точку с 380 строящимися ЖК и говорим где она в рейтинге.
Балл собирается из 7 факторов: что вокруг (садики, школы, аптеки, транспорт, парки, магазины), какая экономика района (цена м², скорость продаж), и есть ли свободная ниша (мало ли конкурентов рядом). Каждый фактор от 0 до 100, потом всё перемножается на свои веса и складывается. Веса меняются в зависимости от того кому будем продавать квартиры (семьям важна школа, инвестору — скорость продаж).

### 🎬 Сценарий на пальцах

Шаг 1. Подставь координаты участка (или кадастровый номер).
Шаг 2. Система за 7 миллисекунд:
— находит все 39 типов POI в радиусе 2 км (садики, остановки, магазины, …)
— считает расстояние до ближайшего объекта каждого типа
— переводит расстояния в баллы 0-100 (близко = 100, далеко = 0)
— определяет в каком районе участок (по полигонам и kNN)
— достаёт цены и скорость продаж этого района из 303 тысяч квартир Объектива
— складывает 7 компонент с весами выбранной аудитории
Шаг 3. На выходе — балл 0-100, ранг среди 380 ЖК, расшифровка каждого фактора.

### 🧪 Реальный пример: парцель 66:41:0204016:10

Адрес: Маневровая 31А, Старая Сортировка, Железнодорожный район Екб.
Площадь: 0.28 га (2 789 м²) · кадастровая стоимость 23.7 млн ₽.
Профиль: «Семейный» (важны школы и парки).
Что вокруг:
🟢 Образование (вес 30%): детсад в 380 м, школа в 792 м. Школа далековата, но не критично → балл компоненты 79.5.
🟢 Здоровье (12%): аптека 471 м, поликлиника 443 м. Норм → 88.7.
🟢 Ритейл (10%): крупный магазин в 124 м — идеально → 100.
🟡 Транспорт (10%): метро нет, трамвай 177 м, автобус 189 м → 69.7.
🟢 Досуг (13%): детплощадка 163 м, парк 565 м → 98.4.
🔴 Экономика (20%): район мас-маркет (114.9 тыс ₽/м², невысокая цена) → 39.2. Здесь главный минус.
🟢 Рынок (5%): всего 3 конкурента в 1 км, район proven → 88.8.
Сборка: 79.5×0.30 + 88.7×0.12 + 100×0.10 + 69.7×0.10 + 98.4×0.13 + 39.2×0.20 + 88.8×0.05 ≈ 76 баллов.
Ранг: #166 из 381 — это 56-й перцентиль, выше середины.
Вердикт: локация средне-сильная для семейного жилья. Главный сдерживающий фактор — низкая цена района (нельзя поставить премиум за 200 тыс ₽/м²). При попытке построить даже эконом-класс на FAR=2.0 ТЭП показывает −10% маржи — участок убыточный для жилья. Может работать как коммерческая недвижимость или продажа другому застройщику.

### 🎭 Зачем 5 разных «профилей»?

Один и тот же участок может быть отличным для семей и плохим для премиума, или наоборот. Поэтому веса компонент меняются:

- Семейный — образование выше всего (30%), парки, потом цена. Нужны садики и школы рядом.
- Премиум — экономика 40% (хочется продать дороже + быстрее). Транспорт и образование меньше.
- Эконом — транспорт (25%) и магазины (20%). Главное чтобы можно было дёшево добраться куда нужно.
- Инвестор — экономика 45% + рынок 12% (скорость возврата денег важнее всего).
- Сбалансированный — поровну, без перекоса.

В UI можно переключаться live — без перерасчёта компонентов, просто веса другие. Виден другой балл и другая позиция в топе.

### 📏 Как далеко считается «близко»

Каждой категории POI задано два расстояния:
• `ideal_m` — в этом радиусе максимум баллов (100). Для садика — это 300 м, для школы — 400 м.
• `max_m` — за этим радиусом баллов 0. Для садика — 1000 м, для школы — 1500 м.
• Между ними — линейно. Школа в 792 м: `(1500-792)/(1500-400) × 100 = 64.4 балла`.
Эти границы прокалиброваны на основе индустрии:
• «4 минуты пешком» = 300 м — комфорт. «15 минут» = 1.2 км — предел.
• Метро прощается до 1 км (это 12 минут пешком), школа до 1.5 км (родители подвозят).
• Больница может быть в 5 км — туда едут раз в год, а не каждый день.

### 💰 Откуда мы знаем цены и скорость продаж

Из Объектив API — платная аналитика рынка недвижимости РФ. Они сканируют сайты девелоперов и Росреестр. Мы вытащили 303 677 квартир Екатеринбурга: каждая со статусом (продано/в продаже/резерв), ценой, площадью, датой регистрации ДДУ.
Из этих данных собираем:

- Медианная цена м² — берём проданные квартиры района, считаем медиану. Старая Сорт. = 114.9 тыс ₽.
- Скорость продаж (velocity) — сколько ДДУ зарегистрировали в этом районе за последние 6 месяцев / число корпусов / 6. Получается «сколько квартир в среднем продаёт корпус в месяц». Старая Сорт. = 4.23/мес.
- Тренд — скорость последних 6 мес ÷ скорость предыдущих 6 мес. >1 = район разогревается. Старая Сорт. = ×1.15 (медленный рост).
- Распродано % — доля проданных лотов в районе. 48.8% — рынок не дошёл и до середины.

### 🏗 Зачем компонент «рынок»

Если в радиусе 1 км уже строится 15 ЖК — у нового проекта будет тяжёлая конкуренция. Покупатели выбирают. Поэтому считаем `density` = чем меньше конкурентов, тем выше балл.
С другой стороны если в районе sold% = 50% (середина продаж), значит рынок есть и продаётся. Если sold% = 5%, скорее всего что-то не так (район непопулярен или новый). Это `saturation`.
Раньше я делал штраф «за слишком высокий sold%» (мол, рынок на финишной прямой), но это не правильно — высокий sold% = доказанный спрос. Поэтому формула: `min(100, sold% × 100/70)` — плато на 70%, дальше штрафа нет.

### 🚶 Walkability — отдельный показатель «можно ли жить пешком»

Идея от walkscore.com. Не входит в основной балл, показывается рядом.
Логика: для каждого «нужного» POI считаем `1/(1 + расстояние/200)`. На 0 м = 1.0, на 200 м = 0.5, на 1 км = 0.17. Потом умножаем на «важность категории» — кафе важнее музея, садик важнее библиотеки. Суммируем, нормируем к шкале где 60 = «отлично».
Парцель: 44/100 — средне. Большинство нужного есть, но всё в 400-800 м, не в 100 м. Не всё пешком.

### ☀ Инсоляция — будут ли в квартирах окна на солнце

Берём 61 240 контуров зданий Екб из OpenStreetMap. Считаем сколько зданий южнее участка (азимут 135°-225°) и насколько они близко. Чем больше — тем больше «давления» на инсоляцию (тенят).
`shadow_S = Σ 1/(1 + расстояние/50)` по зданиям к югу.
`insolation_score = max(0, 100 − shadow_S × 10)`.
Парцель: 44.5. С юго-запада плотная застройка (21 здание на 500 м) — будет затенять вечернее солнце. Это критично для премиум-жилья (квартиры с видом и солнцем). Для эконом-класса — допустимо.

### ⚠ Риск-скор — что плохого рядом

5 источников риска: железная дорога (шум), магистраль (шум + грязь), промзона (запах + шум), АЗС (пожароопасность близко), пожарка (наоборот, должна быть в 2 км максимум).
Для каждого: ближе к `ideal_m` = больше штраф. Веса — самые сильные у ж/д и магистралей (по 30%), потом промзоны (25%).
Парцель: 31.5/100 — плохо. Магистраль в 44 м (-30%) и ж/д в 160 м (-30%). Для премиума критично, для эконома — надо защитный экран и правильная ориентация окон.

### 📐 ТЭП — выгодно ли тут строить вообще

Простая финмодель: задаёшь `FAR` (плотность застройки), `saleable_share` (доля квартир от общей площади), среднюю площадь квартиры. Получаешь:

- Сколько квартир поместится: GBA × saleable / средняя_площадь.
- Выручка = квартиры × цена_района. Цену берём реальную из Объектива.
- Себестоимость = GBA × construction_cost (типично 75 тыс ₽/м² для комфорт-монолита).
- Soft cost = 10% от выручки (проектные, маркетинг, продажи).
- Прибыль = выручка − себест. − soft. Маржа = прибыль / выручка.
- NPV — учитывает что деньги в будущем дешевле. Если NPV > 0 — проект окупается.
- IRR — годовая доходность при которой NPV = 0. Хорошо если >25%.

Для парцеля при FAR=2.0 эконом-класс → 76 квартир, выручка 416 млн, прибыль −43 млн (минус 10%). Не строим жильё.

### 📈 ROI-рейтинг районов — где в Екб строить выгодно

Сценарий: «у меня будет участок 3000 м², хочу строить комфорт. В каком районе максимальная отдача?»
Берём 30 районов, для каждого считаем гипотетическую финмодель с одинаковыми параметрами и реальной ценой района. Результат: топ-3 для комфорт-класса — Сибирский 13.2%, Центр 10%, Юго-Зап. 8.9%. Худшие убыточные: Шир. Речка, Завокзальный, Солнечный.
Используется как «куда копать» — где искать участки. Для каждого района мы знаем цены, скорость продаж, sold% — модель честная.

### 🎯 Что считать хорошим баллом

• 85+ — топ-локация, премиум застраивать здесь самое то
• 70-85 — хорошее место, любой класс кроме самого премиума
• 55-70 — средне, ставить нужно эконом / комфорт с правильным позиционированием
• 40-55 — слабо, возможно нерентабельно (как наш парцель)
• < 40 — не строить жильё, искать другое назначение
Распределение по 380 ЖК Екб: медиана ~70, p75 ~80, max ~95. Парцель 75.8 = выше медианы.

### 📊 Формула

balanced_score = Σ (componenti × weighti)
где component ∈ {education, health, retail, transit, leisure, economic, market}
каждый component нормирован к 0..100, weight зависит от audience-профиля.

### 🎯 7 компонент

Компонент | Что измеряет | Источник
--- | --- | ---
education | дистанции до садиков (×1.0), школ (×1.0), ВУЗов (×0.3) | OSM
health | аптеки (×1.0), поликлиники (×1.0), больницы (×0.5) | OSM
retail | max(big-shops, 0.7×med-shops) — крупные приоритетнее | OSM
transit | max(metro, 0.85×tram, 0.7×bus) — лучший вид транспорта | OSM
leisure | парки + площадки + спорт (×0.7) | OSM
economic | 0.50×price + 0.25×velocity + 0.25×liquidity | Объектив API
market | 0.5×density(jk_count_1km) + 0.5×saturation(sold%) | local DB

### 📏 Distance-to-score (POI компоненты)

if d ≤ ideal_m: score = 100
elif d ≥ max_m: score = 0
else: score = 100 × (max_m − d) / (max_m − ideal_m) # piecewise linear
Конкретные ideal_m / max_m для каждой категории

Категория | ideal_m | max_m | weight
--- | --- | --- | ---
kindergarten | 300 | 1000 | 1.0
school | 400 | 1500 | 1.0
university | 1000 | 5000 | 0.3
pharmacy | 300 | 1000 | 1.0
clinic | 500 | 2000 | 1.0
hospital | 1500 | 5000 | 0.5
shop_big (mall, hyper) | 500 | 2000 | 1.0
shop_med (магнит и пр.) | 300 | 1000 | 1.0
metro | 1000 | 3000 | 1.0
tram | 400 | 1500 | 1.0
bus | 200 | 800 | 1.0
park | 500 | 2000 | 1.0
playground | 200 | 700 | 1.0
sports | 500 | 2000 | 0.7

### 🎭 Audience-профили — веса (сумма = 1.0)

Профиль | edu | health | retail | transit | leisure | economic | market
--- | --- | --- | --- | --- | --- | --- | ---
balanced | 0.18 | 0.10 | 0.13 | 0.15 | 0.09 | 0.30 | 0.05
family садики, школы, парки | 0.30 | 0.12 | 0.10 | 0.10 | 0.13 | 0.20 | 0.05
premium цена, топ-локация | 0.10 | 0.10 | 0.10 | 0.10 | 0.15 | 0.40 | 0.05
economy транспорт, базовое | 0.15 | 0.10 | 0.20 | 0.25 | 0.05 | 0.20 | 0.05
investor скорость, ликвидность | 0.10 | 0.08 | 0.08 | 0.12 | 0.05 | 0.45 | 0.12

Live audience swap: при смене профиля компоненты не пересчитываются (они уже кэшированы), просто перевзвешиваются — мгновенно.

### 💰 Economic компонент

economic = 0.50×price_score + 0.25×velocity_score + 0.25×liquidity_score
price_score = norm(district_median_price, [city_min, city_max])
velocity_score = norm(real_velocity_6mo, [0, p90]) × trend_modifier
liquidity_score = max(0, 100 − months_to_sellout × 100/24)
# trend_modifier — prod-style (см. recommend_mix):
trend_factor = clamp(recent_6mo / prior_6mo, 0.7, 2.0)
velocity_score *= 0.5 + 0.5 × (trend_factor / 2)

### 🏘 Market компонент (конкуренция)

density_score = max(0, 100 − jk_count_1km × 100/15)
saturation_score = min(100, sold% × 100/70) # >70% sold = плато, sold% подтверждает спрос
market = 0.5 × density + 0.5 × saturation

### 🚶 Walkability (отдельный показатель)

walkability = Σ_categories (weightcat × Σ_pois 1/(1 + distance/200m)) / 0.6
# Веса по категориям (топ-3):
shop_med 1.5 · kindergarten 1.5 · school 1.5 · metro 1.5 · park 1.2 · pharmacy 1.0
# Радиус: 1500 м, decay 1/(1 + d/200)
Этот показатель — отдельный (показан рядом с баллом), не входит в основную формулу. Идея от Walk Score (walkscore.com).

### ☀ Инсоляция (открытость на юг)

shadow_S = Σ_buildings_in_500m_south 1/(1 + d/50) # юг = bearing 135°-225°
insolation_score = max(0, 100 − shadow_S × 10)

### ⚠ Risk-score

Источник риска | ideal_m | max_m | weight
--- | --- | --- | ---
railway | 200 | 800 | 0.30
highway (motorway/trunk/primary) | 80 | 400 | 0.30
industry zones | 200 | 800 | 0.25
fuel stations | 80 | 300 | 0.05
fire stations (далеко = плохо) | 500 | 2000 | 0.10

per_risk_penalty = weight × 100 × (max_m − d) / (max_m − ideal_m) # clamp 0..weight×100
risk_score = max(0, 100 − Σ penalties)

### 📐 ТЭП-калькулятор

GBA = parcel_area × FAR
saleable = GBA × saleable_share # typ. 0.55-0.75
n_units = saleable / avg_unit_area
revenue = saleable × district_median_price × 1000
construction = GBA × construction_cost_per_m2
soft_cost = revenue × soft_cost_pct # typ. 10%
profit = revenue − construction − soft_cost
NPV = −0.20×construction + Σ_months (revenue/M − cost/M) / (1+r)^month
IRR = bisect(npv_at_rate(r) = 0, lo=0, hi=5)

### 📊 Sources of truth

Источник | Что даёт | Объём
--- | --- | ---
OSM (Overpass) | POI 39 категорий, building footprints для insolation | 17 627 POI · 61 240 buildings
DOM.РФ kn-API | 380 ЖК Екб с координатами, девелопер, класс | через прод PostgreSQL
Объектив API | per-flat данные: цена, статус, площадь, контракт-дата | 303 677 квартир
ЦБ РФ | средневз. ставка ипотеки Свердл | Янв 2026 = 7.84%
Росреестр (rosreestr2coord) | точная геометрия + кад.стоимость участка | по запросу
Nominatim (OSM) | обратное геокодирование — адрес | cached
NSPD AEGGIS | 8 admin полигонов Екб для PostGIS-assignment | через прод

Где числа — экспертная калибровка: ideal_m / max_m для POI-категорий, audience-веса, walkability-decay (1/(1+d/200)). Не валидированы на real-world данных продаж — это hand-tuned heuristics из прод-кода `recommend_mix` + индустриальные практики (Walk Score, urban planning).
Что точно из данных: цены / velocity / sold% / геометрия — реальные числа. Веса — гипотезы для проверки.

### 📚 Глоссарий терминов

Все понятия, формулы, единицы измерения. Для each термина — определение + источник данных + конкретный пример с реальным числом из системы.
🎯 Балл и ранжирование

weighted_score | Итоговый балл 0-100, взвешенная сумма 7 компонент. Главное число. Пример: парцель 66:41:0204016:10 на family-профиле = 75.83
rank_overall | Позиция точки среди 380 строящихся ЖК Екб. Ниже = лучше. Пример: #166 / 381 → топ-43% = 56-й перцентиль
percentile | Доля ЖК с меньшим баллом. `(1 − rank/total) × 100`. Пример: 56.7% — выше середины, но не топ
audience profile | Набор весов для 7 компонент. balanced/family/premium/economy/investor. Live swap: при смене профиля компоненты не пересчитываются, только перевзвешиваются (мгновенно)

🏘 Локационные компоненты (POI distance)

education | Близость объектов образования. `(1.0 × kindergarten + 1.0 × school + 0.3 × university) / Σweights`. Парцель: 79.5 (садик 380 м, школа 792 м, ВУЗ 906 м)
health | Близость аптек, поликлиник, больниц. `(1.0 × pharmacy + 1.0 × clinic + 0.5 × hospital)`. Парцель: 88.7 (аптека 471 м, поликлиника 443 м, больница 1626 м)
retail | Лучший из «крупный магазин» или 70% «средний». Большие приоритетнее. `retail = max(big_score, 0.7 × med_score)` Парцель: 100 (большой магаз в 124 м — идеал)
transit | Лучший вид транспорта с штрафом. `max(metro, 0.85 × tram, 0.7 × bus)` Парцель: 69.7 (метро нет, трамвай 177 м с весом 0.85)
leisure | Парки, площадки, спорт. `(1.0 × park + 1.0 × playground + 0.7 × sports)`. Парцель: 98.4 (площадка 163 м, парк 565 м)
distance scoring | Piecewise linear: `≤ ideal_m → 100; ≥ max_m → 0; иначе линейно`. Пример: school ideal 400, max 1500. d=792 → 100×(1500−792)/(1500−400) = 64.4
nearest_m | Расстояние до ближайшей точки данной категории, в метрах (haversine).
count_500m / count_1km | Число POI данной категории в радиусе. Информационно, не в скоре.

💰 Economic компонент

economic | Экономическая привлекательность района. `0.5 × price + 0.25 × velocity + 0.25 × liquidity`. Парцель: 39.2 (недорогой район, средняя скорость, медленный sellout)
price_score | Нормированная медианная цена района. `(price − city_min) × 100 / (city_max − city_min)` Старая Сортировка 114.9 тыс/м² · city_min=82.7 (УНЦ) · city_max=272.4 (Центр старая выгрузка) → 30.6
real_median_price_m2 | Медиана цены за м² по реальным per-flat сделкам района из Объектива. Старая Сортировка: 114.9 тыс ₽/м² (P25=92, P75=132)
velocity_score | Скорость продаж, нормированная к p90 города. `min(100, vel × 100 / vmax)` × trend_modifier. vmax = p90 = 8.96 ДДУ/корп/мес. Старая Сортировка vel=4.23 → 47.2 × 1.07 (тренд) = 50.4
real_velocity_6mo | Зарегистрированных ДДУ в районе за recent 6 месяцев / число корпусов / 6. Источник: register_date в objective_lots
real_velocity_prior_6mo | То же, но за пред. 6 месяцев (мес 7-12 от today). Используется для расчёта тренда
trend_factor | `clamp(real_trend_ratio, 0.7, 2.0)` где ratio = recent_6mo / prior_6mo. Из прод-кода `recommend_mix`. Velocity_score умножается на (0.5 + 0.5 × tf/2). Старая Сортировка ratio=1.15 (район разогревается) → tf=1.15 → ×0.79
liquidity_score | Скорость распродажи стока. `max(0, 100 − months_to_sellout × 100/24)`. Если sellout 12 мес → 50, если 24 мес → 0, если 0 → 100
months_to_sellout | `district_stock_m2 / (sold_volume_90d / 3)`. Старая Сортировка: 16 мес. Гоголя 21 (per-ЖК): 29.2 мес
real_sold_pct | Доля проданных лотов в районе из per-flat данных. `n_sold / n_total × 100`. Старая Сортировка: 4078 / 8356 = 48.8%
real_avg_readiness_pct | Средняя готовность строительства проектов в районе. От 0% до 100%. Старая Сортировка: 76% (большинство проектов на финальной стадии)
weighted_price_m2 (corp_sum) | Старая метрика из Сводные/Корпуса (взвешена по объёму проданных м²). Хуже real_median_price_m2 — оставлена для cross-check.

🏗 Market компонент (конкурентный)

market | Рыночная оценка позиции в окружении. `0.5 × density + 0.5 × saturation`. Парцель: 88.8 (мало конкурентов в 1 км, район proven)
jk_count_1km | Число других строящихся ЖК в радиусе 1 км от точки. Парцель: 3 (мало конкурентов рядом — плюс)
density_score | `max(0, 100 − jk_count_1km × 100/15)`. Чем меньше конкурентов — тем выше. Парцель: max(0, 100 − 3×100/15) = 80
saturation_score | `min(100, real_sold_pct × 100/70)`. Высокий sold% подтверждает спрос, не штраф. Плато на 70%+ — район proven, дальше плюсы не растут. Старая Сортировка sold 48.8% → 69.7
sat_factor | prod-style: `1 + (sold% − 50)/100 × 0.30`. Используется отдельно как мультипликатор. Не входит напрямую в market. Зрелые рынки получают +30% к velocity

📍 География и районы

admin_district | Один из 8 админ-районов Екб (Верх-Исетский, Чкаловский, …). PostGIS ST_Contains по полигонам из `ekb_districts_geom`. Парцель: Железнодорожный
obj_district | Микрорайон Объектива (Старая Сортировка, Академический, …). 31 район. Назначается через kNN-voting: 7 ближайших matched-ЖК голосуют, выигрывает большинство. Парцель: Старая Сортировка
district_method | Способ assignment: `name_match` (если ЖК сматчен с Объективом) / `knn_vote_5` (по соседям).
nearest_jk_dist_m | Дистанция до ближайшего matched-ЖК (для knn-методов).
jk_objective_match | Связь между обр.домрф obj_id и Объектив project (по имени ЖК). Match score: SequenceMatcher ratio ≥ 0.80 после нормализации. Покрытие: 229 из 380 ЖК (60%)

🚶 Walkability (отдельный показатель)

walkability | Индекс «дойти пешком до всего нужного» 0..100. Идея от Walk Score (walkscore.com). В основной балл не входит, показывается рядом. Парцель: 44/100 — средне
decay function | `1 / (1 + distance/200)`. На 0 м → 1.0, на 200 м → 0.5, на 1000 м → 0.17. Реалистично моделирует «дойти не лень».
walk_w (веса) | Daily-need POI получают больший вес: shop_med 1.5 / kindergarten 1.5 / school 1.5 / metro 1.5 / park 1.2 / pharmacy 1.0 / clinic 0.8 / cafe 0.6 / shop_big 0.6 / sports 0.5 / atm 0.4 / bank 0.3 / restaurant 0.4 / playground 1.0 / library 0.3 / post 0.4 / bus 0.8 / tram 1.0.
radius | 1500 м (15 мин ходьбы). Top-10 точек каждой категории.
normalization | `walkability = min(100, walk_score_raw × 100/60)`. 60 = «отличное» по экспериментальной калибровке.

☀ Insolation (открытость на юг)

insolation_score | Сколько солнца получит будущее ЖК. `max(0, 100 − shadow_S × 10)`. Парцель: 44.5 — средне (плотная застройка SW)
shadow_pressure_S | Сумма «давления» зданий с юга (bearing 135-225°): `Σ 1/(1 + d/50)`. Чем ближе и больше зданий южнее — тем выше shadow_S. Парцель: 5.55. 1 здание прямо на юге в 50 м даёт +0.5 единицы
octants | Распределение зданий в 500 м по 8 сторонам света (N/NE/E/SE/S/SW/W/NW). Парцель: SW=21 (самая плотная сторона), N=13, S=14
n_buildings_500m | Всего зданий в радиусе 500 м. Источник: 61 240 OSM building centroids. Парцель: 121

⚠ Risk-score

risk_score | `max(0, 100 − Σ penalties)`. Чем выше — тем меньше шум/опасность рядом. Парцель: 31.5/100 (магистраль 44 м, ж/д 160 м — критично)
penalty_pct | Штраф по конкретному типу: `weight × 100 × (max_m − d) / (max_m − ideal_m)` с clamp 0..weight×100.
railway | Линия ж/д. weight=0.30, ideal=200 м, max=800 м. Самый сильный штраф.
highway | motorway / trunk / primary / secondary. weight=0.30, ideal=80 м, max=400 м.
industry | Промзоны (зарезервировано, реализация в planned).
fuel | АЗС близко (<80 м) — небольшой штраф. weight=0.05.
fire | Пожарка ДАЛЕКО (>2 км) = плохо. weight=0.10. Inverted score (близко = хорошо).

📐 ТЭП-калькулятор и финмодель

parcel_area_m2 | Площадь земельного участка из Росреестра. Парцель: 2 788.7 м² (0.28 га)
FAR (Floor Area Ratio) | Плотность застройки = total_GBA / parcel_area. Регулируется ПЗЗ (правилами землепользования). Типично 1.5-3.5 для жилья. Дефолт = 2.0
GBA (Gross Building Area) | Общая надземная площадь корпусов. `parcel × FAR`. 2789 × 2.0 = 5578 м²
saleable_share | Доля квартир в GBA (остальное — coridory, lobby, technical). Типично 0.55-0.75. Дефолт = 0.65
saleable_m2 | `GBA × saleable_share`. Это то что реально продаётся. 5578 × 0.65 = 3625 м²
n_units | `round(saleable_m2 / avg_unit_area_m2)`. Сколько квартир. 3625 / 48 ≈ 76 квартир
revenue | `saleable_m2 × price_per_m2`. 3625 × 114 900 ₽ = 416.4 млн ₽
construction_cost_per_m2 | Себестоимость стройки за 1 м² GBA. Вкл. бетон, отделку, сети. Дефолт 75 000 ₽/м² (комфорт-класс монолит) панель ~50 000, премиум монолит ~150 000
construction | `GBA × construction_cost_per_m2`. 5578 × 75 000 = 418.3 млн ₽
soft_cost_pct | Доля проектных + маркетинг + landlord. Типично 8-15% от выручки. Дефолт 10%
soft_cost | `revenue × soft_cost_pct`. 416.4 × 0.10 = 41.6 млн ₽
profit | `revenue − construction − soft_cost`. 416.4 − 418.3 − 41.6 = −43.5 млн ₽ (убыток)
profit_margin_pct | `profit / revenue × 100`. Норма 12-18%. Парцель: −10.4% (нерентабельно)
NPV (Net Present Value) | Дисконтированная сумма будущих cashflows. Положительный = проект окупается с учётом стоимости денег. `NPV = −0.20×construction + Σ_months (rev_i − cost_i) / (1+r_m)^month` −0.20 — 20% upfront stroyka. r_m = (1+R_yearly)^(1/12)−1
IRR (Internal Rate of Return) | Доходность при которой NPV = 0. Бисекция между 0..500% годовых. Если <15% — слабо, <25% — средне, >25% — хорошо. Парцель: IRR не сходится (NPV всегда отрицателен)
discount_rate | Годовая стоимость капитала (для дисконтирования). Дефолт 18%. Соответствует целевому ROIC застройщика (выше ставки ЦБ + спред риска)
cashflow_months | `max(months_to_complete, n_units / velocity)`. Сколько месяцев денежные потоки.

📊 ROI-ranking по районам

roi_annual_pct | Грубая годовая отдача на инвестицию. `(profit / construction) × 12 / months_to_sellout × 100` Топ для комфорт-класса: Сибирский 13.2%, Центр 10%
price_kr_class | Цена м² для класса в данном районе. `baseline × (district_price / 130)`. Например, комфорт baseline 130 тыс. В Старой Сорт. районе цена ниже на 12% → 114.9

🏛 Кадастр и геометрия

cad / cad_num | Кадастровый номер. Формат `RR:DD:KKKKKKK:NN`. RR=регион (66=Свердл), DD=район (41=Екб), KKKKKKK=кадастровый квартал, NN=участок в квартале. Пример: 66:41:0204016:10
parcel polygon | GeoJSON Polygon из Росреестра через `rosreestr2coord` (обходит NSPD WAF). Пример: 17 vertices в WGS84
cost_value | Кадастровая стоимость участка (от Росреестра). Парцель: 23 706 714 ₽
cost_index | Уд. кад. стоимость = cost / area. Парцель: 8 497 ₽/м²
cad_quarter | Кадастровый квартал (сегмент 3). Используется для spatial-join с ДДУ из Росреестра.
building footprint | Полигон здания. У нас 1 394 OSM-building footprints для 304 ЖК + 76 fallback rings 45 м для остальных.

🌐 POI-категории

🎓 Образование (4)
kindergarten | Детский сад. OSM `amenity=kindergarten`
childcare | Ясли / частные детсады. `amenity=childcare`
school | Школа. `amenity=school`
university | ВУЗ или колледж. `amenity=university|college`
⚕ Здоровье (5)
pharmacy | Аптека. `amenity=pharmacy`
clinic | Поликлиника / врач-специалист. `amenity=clinic|doctors`
hospital | Больница. `amenity=hospital`
dentist | Стоматология. `amenity=dentist`
vet | Ветеринар. `amenity=veterinary`
🚇 Транспорт (5)
bus_stop | Автобусная остановка. `highway=bus_stop`
tram_stop | Трамвайная. `railway=tram_stop`
metro | Метро. `station=subway` (в Екб строится 2-я линия)
parking | Парковка (любая, OSM). 4246 точек в bbox.
car_rental | Прокат / такси-стоянка. `amenity=car_rental|taxi`
🛒 Магазины (4)
shop_big | Крупные. `shop=mall|supermarket|department_store|hypermarket`
shop_med | Средние. `shop=convenience|grocery|bakery`
shop_small | Малые / киоски. `shop=kiosk|newsagent`
marketplace | Рынок. `amenity=marketplace`
☕ Еда / отдых (3)
cafe | Кафе. `amenity=cafe`
restaurant | Ресторан / fast food. `amenity=restaurant|fast_food`
nightclub | Бар / паб / клуб. `amenity=nightclub|bar|pub`
💰 Деньги / Сервис (8)
atm | Банкомат. `amenity=atm`
bank | Отделение банка. `amenity=bank`
post | Почта. `amenity=post_office`
courier | Постамат / почтовый ящик. `amenity=parcel_locker|post_box`
library | Библиотека. `amenity=library`
worship | Храм / место поклонения. `amenity=place_of_worship`
fuel | АЗС. `amenity=fuel`
car_wash | Автомойка. `amenity=car_wash`
hotel | Отель / хостел. `tourism=hotel|hostel|apartment`
🛡 Безопасность (2)
police | Полиция. `amenity=police`
fire | Пожарная часть. `amenity=fire_station`
🌳 Досуг / культура (7)
park | Парк / сад. `leisure=park|garden`
playground | Детская площадка. `leisure=playground`
sports | Спорткомплекс / поле. `leisure=sports_centre|fitness_centre|pitch`
gym | Фитнес. `leisure=fitness_centre`
theater | Театр. `amenity=theatre`
cinema | Кинотеатр. `amenity=cinema`
museum | Музей. `tourism=museum`

🔬 Источники данных

OSM (Overpass) | POI 39 категорий + building footprints. Cache: 17 627 POI / 61 240 buildings. Pulled через 12_more_pois.py с overpass-api.de
DOM.РФ kn-API | 4 548 ЖК РФ (наш.дом.рф). Через прод PostgreSQL: `domrf_kn_objects` · 380 строящихся в Екб. Поля: obj_id, comm_name, addr, latitude, longitude, dev_name, obj_class
Объектив API | Платная аналитика недвижимости РФ. Per-flat данные. 4 отчёта × ReportType×Name. 2 работают, 2 = HTTP 500 (тариф). 303 677 квартир Екб + 19 738 corp_sum строк
ЦБ РФ | Средневзв. ставка ипотеки по региону. `cbr_mortgage_series` в проде. Свердл, Янв 2026 = 7.84%
Росреестр | Через `rosreestr2coord` Python lib. Геометрия + кадастровая стоимость. Обходит блокировку NSPD WAF (которая блокирует direct API).
NSPD AEGGIS | Полигоны 8 админ-районов Екб (через прод PostgreSQL `ekb_districts_geom`). Был получен раньше через ESIA-доступ + Playwright.
Nominatim | Обратное геокодирование (lat/lon → адрес). Open-source OSM. Кешируется в cache/geocode_cache.json

⚙ UI и интерактив

buffer rings | Концентрические круги 300/500/1000 м и 15-мин ходьба ≈1.2 км вокруг участка. Показывают «что входит в радиус».
cluster (ЖК) | При z < 13 близкие ЖК группируются в badge с числом. Цвет — средний балл группы.
POI cluster | При z < 16 близкие POI разных категорий в одной точке объединяются в один значок с числом.
what-if POI | Гипотетический POI добавляется на карту через клик. Score пересчитывается с этим POI как будто он есть. Используется для «а что если построить рядом метро?»
scenario | Именованный сохранённый state {parcel, audience, what_if, remove_cats}. localStorage.
saved view | Сохранённый набор {filter_class, filter_district, score_min, audience, basemap}. Для повторного применения.
pinned parcels | До N участков, закреплённых на карте через 📍+. Side-by-side compare.
A/B compare | До 3 ЖК vs участка. Радар-чарт + таблица 7 компонент.
leaderboard | Топ-30 ЖК Екб ранжированы по audience-весам. Live re-rank при смене профиля.
smart suggestions | До 5 ЖК рядом (≤3 км) с баллом ВЫШЕ участка. «Альтернативы».
time-machine | Series 12 мес по району: deals/median_price/volume/active_corpuses. Из per-flat данных.
POI-vs-district | Δ% по 12 категориям относительно среднего по району. «Сильные/слабые стороны» ЖК.
service worker | Кэш тайлов (cache-first stale-while-revalidate). Survives sessions.
BroadcastChannel | Sync recent/scenarios между вкладками (одна сессия).

🔢 Единицы измерения и условные обозначения

тыс ₽/м² | Цена м² жилья в тысячах рублей. Стандарт рынка РФ. Например 130 тыс/м² = 130 000 ₽/м² = 6.5 млн за 50 м² квартиру
ДДУ | Договор Долевого Участия. Юр. форма продажи строящегося жилья по 214-ФЗ.
ДКП | Договор Купли-Продажи. Готовые квартиры (после ввода).
ЖК | Жилой Комплекс. Объект в DOM.РФ обозначается obj_id.
обр. кв. кадастра | Сегмент 7 цифр в кадастровом номере. `RR:DD:KKKKKKK:NN`
velocity | ДДУ/корпус/мес. Скорость продаж нормированная на корпус. 2.0 — средне, 5+ — горячий рынок, <1 — застой
sellout | Полная распродажа стока. `months_to_sellout` = когда придёт.
upside | Потенциал роста. В контексте — насколько ROI ЖК выше benchmark.

### 📖 Worked example: парцель 66:41:0204016:10 family-профиль

# Распаковка балла 75.83
education = 79.5 × 0.30 = 23.85
health = 88.7 × 0.12 = 10.64
retail = 100.0 × 0.10 = 10.00
transit = 69.7 × 0.10 = 6.97
leisure = 98.4 × 0.13 = 12.79
economic = 39.2 × 0.20 = 7.84
market = 88.8 × 0.05 = 4.44
──────────────────────────
weighted_score = 76.53 ≈ 75.83 (rounding в Python)
# 4 фактора влияют на score:
• Слабые: economic 39 (низкая цена района) · transit 70 (нет метро)
• Сильные: retail 100 (магазин в 124 м) · leisure 98 (площадка 163 м)
• walkability 44 — средне (плохой пешеходный доступ к ВУЗам/больницам)
• risk_score 31 — критично (магистраль 44 м, ж/д 160 м)

## A/B сравнение: участок vs выбранные ЖК