Коэффициент перехода от цены предложения к цене сделки считается по каждому региону #3518

Merged
lekss361 merged 1 commit from feat/asking-to-sold-per-region into main 2026-09-13 11:38:27 +00:00
Owner

Коэффициент считался только по Екатеринбургу и применялся к любому адресу. В таблице лежало ровно шесть строк без какого-либо ключа региона, а резолвер в оценщике региона вообще не получал — московская оценка брала свердловский коэффициент. Рынки при этом разные: медиана сделок за год 90 278 ₽/м² на Урале, 161 176 в области, 322 976 в Москве.

Миграция 304 добавляет колонку региона и перестраивает первичный ключ на тройку регион плюс комната плюс район. Существующие шесть строк получают 66. Идемпотентна, с таймаутом блокировки, по образцу миграции 298.

Расчёт для Свердловской области остался байт-в-байт прежним, включая городскую квоту и порог. Для остальных регионов добавлен симметричный путь с тем же порогом и окном, но отбором по региону вместо имени города. Резолвер в оценщике получает регион цели — тот же, которым уже скоупится коридор ДКП, и кэш ключуется парой регион плюс корзина комнат.

Если для региона строки нет, коэффициент не подменяется чужим: оценка идёт по сырой медиане предложения, поля ожидаемой цены продажи пустые, основание коэффициента пустое. Явная деградация вместо тихой подмены.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs

Коэффициент считался только по Екатеринбургу и применялся к любому адресу. В таблице лежало ровно шесть строк без какого-либо ключа региона, а резолвер в оценщике региона вообще не получал — московская оценка брала свердловский коэффициент. Рынки при этом разные: медиана сделок за год 90 278 ₽/м² на Урале, 161 176 в области, 322 976 в Москве. Миграция 304 добавляет колонку региона и перестраивает первичный ключ на тройку регион плюс комната плюс район. Существующие шесть строк получают 66. Идемпотентна, с таймаутом блокировки, по образцу миграции 298. Расчёт для Свердловской области остался байт-в-байт прежним, включая городскую квоту и порог. Для остальных регионов добавлен симметричный путь с тем же порогом и окном, но отбором по региону вместо имени города. Резолвер в оценщике получает регион цели — тот же, которым уже скоупится коридор ДКП, и кэш ключуется парой регион плюс корзина комнат. Если для региона строки нет, коэффициент не подменяется чужим: оценка идёт по сырой медиане предложения, поля ожидаемой цены продажи пустые, основание коэффициента пустое. Явная деградация вместо тихой подмены. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs
lekss361 added 1 commit 2026-09-13 10:48:16 +00:00
fix(tradein): коэффициент цена предложения -> цена сделки стал региональным (#3512)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 18s
CI / changes (pull_request) Successful in 20s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m28s
35c8ef4445
asking_to_sold_ratios (миграция 080) считался ИСКЛЮЧИТЕЛЬНО по рынку Екатеринбурга
(деривация фильтровала обе стороны на city ILIKE '%Екатеринбург%'), а estimator
читал строку только по rooms_bucket/district и применял этот коэффициент к любому
адресу — включая Москву и Московскую область, чей рынок дороже на порядок (медиана
ДКП за 12 мес: 66 - 90 278 руб/кв.м, 50 - 161 176, 77 - 322 976).

Миграция 304 добавляет asking_to_sold_ratios.region_code (существующие 6 строк -
регион 66) и перестраивает PK на (region_code, rooms_bucket, district).

app/tasks/asking_to_sold_ratio.py: деривация региона 66 осталась байт-в-байт прежней
(та же городская квота, тот же порог 30/30, то же окно 12 мес) - числа для 66 не
меняются. Для каждого региона из реестра app.services.regions (кроме 66) добавлен
отдельный derivation-путь, симметрично скоупленный по region_code без городской
квоты (она была костылём конкретно исторического asking-покрытия ЕКБ).

app/services/estimator.py: _get_asking_sold_ratio теперь получает region_code цели
(target_region_code, тот же код, что уже скоупит ДКП-коридор) и ищет строку по нему;
кэш ключуется на (region_code, bucket), а не на голый bucket. Регион без единой
строки (ни per-bucket, ни global -1) деградирует явно - (None, None), без подмены
чужим региональным коэффициентом - ratio_basis в ответе честно остаётся None.
lekss361 merged commit 0af80b4395 into main 2026-09-13 11:38:27 +00:00
lekss361 deleted branch feat/asking-to-sold-per-region 2026-09-13 11:38:28 +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#3518
No description provided.