Коэффициент asking→sold приводится к сегодняшнему дню #3544
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3544
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/ratio-time-adjust"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Проблема
Числитель
asking_to_sold_ratios— сырые цены сделок Росреестра за трейлинг-12 месяцев (на проде фактическое окно 2025-10…2026-04, центр ≈ декабрь 2025). Знаменатель — медиана объявлений заLISTINGS_FRESH_DAYS, то есть сегодня. На растущем рынке ratio занижен ровно на дрейф рынка за половину окна, и прод отдаёт цену позапрошлого квартала.Это и есть «систематическая недооценка на свежих сделках» из отчёта тестировщика. Зависимость от возраста сделки (Москва): сделки с 2026-03 → −12.7 %, с 2025-06 → −3.4 %, с 2024-06 → +1.8 % — подпись сдвига по времени, а не перекоса модели.
Отдельно:
estimator._fetch_dkp_corridorуже приводит ДКП-коридор к сегодня (#794), а ratio — нет. Две стороны одного расчёта стояли на разных временных шкалах.Что сделано
Каждая сделка домножается на sber-фактор приведения к последнему месяцу ряда:
idx[последний месяц] / idx[месяц сделки], clampSBER_TIME_FACTOR_MIN/MAX(0.7/1.6). Ряд выбирается той же картой регион→ряд (sber_region_series_name) и тем же приоритетом дашбордов (SBER_COEFF_DASHBOARDS), что у эстиматора — вторая карта не заводится. Применено к обоим путям деривации: ЕКБ (deal_side/deal_global) и региональному гео-взвешенному (deal_geo→ весь Ласпейрес проезжает приведение автоматически).Двойного учёта нет — проверено
_sber_time_factorв эстиматоре зовётся ровно в двух местах, оба внутри_fetch_dkp_corridor(estimator.py:2219,:2291). Коридор оттуда уходит в Tier-C anchor gate (:3569) и в_apply_corridor_clamp(:3989) — то есть работает потолком для ASKING-медианы. Множитель изasking_to_sold_ratiosприменяется отдельно и позже:expected_sold_per_m2 = median_ppm2 * effective_ratio(estimator.py:4058). Один множитель на одно число дважды не ложится; после правки обе стороны просто оказываются на одной шкале.quarter_index/_apply_quarter_index— поправка пространственная (кадастровый квартал), к вопросу не относится.Замер на проде (read-only, 2026-09-16)
Окно сделок 2025-10…2026-04, ряд
real_estate_dealsсвоего региона, clamp 0.7/1.6:Ожидаемые ratio после первого пересчёта: 0.729 → 0.811 (77), 0.811 → 0.896 (50), 0.728 → 0.762 (66). Все ниже 1.0 — клампа
estimate_expected_sold_le_askingне задевают.Как это увидит бэктест
Бэктест меряет предсказание против СЫРЫХ исторических цен сделок, поэтому его bias после включения уедет в плюс примерно на те же 4-11 %. Это не регресс: прод обязан отдавать цену сегодняшнего рынка, а таргет бэктеста — цена декабря 2025. Инструмент по построению не видит этот дефект, поэтому и не может его подтвердить.
Замороженный регресс-гейт не двигается: фикстура несёт готовый ratio и через этот таск не ходит — проверено прогоном.
Откат и деградация
ASKING_RATIO_TIME_ADJUST_ENABLED=false→ factor = 1.0 для каждой сделки, байт-в-байт прежнее поведение, без деплоя.sber_time_adjust_regions_missing_seriesи WARNING. Молчаливой деградации нет.estimator._sber_time_factor).Тесты
tests/test_asking_to_sold_ratio.py tests/test_estimator_sber_time_adjust.py tests/test_ratio_geography_match_3529.py tests/test_estimator_ratio_per_region_3512.py tests/test_estimator_pi_by_region.py tests/test_backtest_regression_gate.py tests/test_estimator_requires_analogs.py→ 69 passed.ruff check/ruff formatчисто,CAST(:x AS type)соблюдён.Два структурных теста обновлены под намеренное изменение SQL: нормализатор
_drop_sber_time_adjustв проверке «080-сид ⊆ refresh SQL» (снимает новые CTE/JOIN дословной подстановкой констант, не regex) и счётчик exec-вызовов у fake-db (+1 presence-check на регион).🤖 Generated with Claude Code
https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs