[tradein][analytics] Связать ДКП-сделки Росреестра с listings (Avito/Cian/Yandex) — sales-vs-asks матчинг #564

Closed
opened 2026-05-25 06:02:32 +00:00 by lekss361 · 1 comment
Owner

Цель

Дать продактам/оценщикам сравнение фактических цен сделок ДКП vs текущие/исторические asking-цены на площадках — для конкретной улицы/района/дома (где возможно).

Текущее состояние

Что есть

  • rosreestr_deals (49 791 ДКП EKB) — есть addr_street, cad_num (с улицей но без номера дома), price, area, deal_date. Constraint: open dataset агрегирует адреса до улицы, не до дома (Session_TradeIn_Dkp_Roadmap_May25).
  • listings (avito/cian/yandex/n1) — address_fingerprint, cad_num, price, area, geometry, listing_date.
  • house_address_aliases — fingerprint fuzzy match index.
  • Per-street view уже реализован: PR #555 GET /street-deals, PR #556 StreetDealsCard (UI на target адрес).

Чего нет

  • Нет таблицы/view связывающей ДКП с конкретными listings.
  • Нет time-series sales-vs-asks (как соотносятся ASK на дату X и реальная сделка на дату X+N).
  • Estimator не учитывает rosreestr_deals (NOTE 2026-05-24 disabled).

Что предлагается

1. Per-street SQL view v_street_sales_vs_listings

SELECT
  street_normalized,
  cad_block,          -- 66:41:xxxxxxx (улица-уровень)
  d.deal_date,
  d.price_per_m2 AS dkp_price_per_m2,
  d.area AS dkp_area,
  l.listing_id,
  l.source AS listing_source,
  l.price_per_m2 AS ask_price_per_m2,
  l.listing_date,
  l.cad_num AS listing_cad,
  (d.deal_date - l.listing_date) AS days_listing_to_deal,
  (d.price_per_m2 - l.price_per_m2) / l.price_per_m2 AS discount_pct
FROM rosreestr_deals d
LEFT JOIN listings l ON
  normalize_street(l.address) = normalize_street(d.addr_street)
  AND ABS(l.area - d.area) <= 5
  AND l.listing_date BETWEEN d.deal_date - INTERVAL '180 days' AND d.deal_date
WHERE d.cad_num LIKE '66:41:%';

2. Per-house матчинг (где cad_num полный)

Часть rosreestr_deals имеет полный cad_num (с участком земли). Для них — JOIN по cad_num exact match, confidence 1.0.

3. Metric: "discount_to_asking" per-street

Median (sale_price - last_ask_within_180d) / ask. Полезно для prediction: "если сейчас продают за X, реально уйдёт за X * (1 - discount_median)".

4. UI: StreetDealsCard расширить

Добавить столбец "Связанные объявления" — clickable list (avito link + дата + цена). User видит на каком ASK дом стоял до того как ушёл по ДКП.

5. Estimator: подключить rosreestr_deals обратно

Убрать NOTE 2026-05-24 disabled, добавить rosreestr_deals в actual_deals с правильной фильтрацией по distance/area window. Confidence tier per row (per-house cad match = T0, street match = T1).

Sub-tasks

  • DDL: data/sql/NNN_v_street_sales_vs_listings.sql
  • Backend service services/sales_listings_match.py
  • API endpoint GET /api/v1/sales-vs-listings?street=... или расширить /street-deals
  • Frontend: StreetDealsCard дополнить "связанные ASK"
  • Estimator: revert NOTE 2026-05-24 + tier logic
  • Backfill: precompute discount_to_asking_median per street → cache в материал. view

Acceptance

  • View возвращает ≥ 5K (deal, listing) pairs для EKB.
  • Median linkage rate per улица ≥ 30% (для streets с ≥ 10 ДКП).
  • UI показывает на странице улицы: "Из 50 ДКП за 2024 — 18 имеют связанное avito объявление до сделки".
  • Estimator показывает в response actual_deals.rosreestr_count > 0.

Limitations (документировать)

  • Open dataset до улицы. Per-house только когда cad_num rosreestr-сделки совпадает с listing.cad_num exact.
  • listing_date в yandex заполнен ~40% (см. отдельный issue про PR-6).
  • Cian price_history пустой (см. отдельный issue про PR #525 unblock).

Refs

  • sessions/Session_TradeIn_Dkp_Roadmap_May25
  • services/matching/listings.py — Tier 0-3 matching pattern
  • decisions/Decision_TradeIn_PerSource_Listing_History
  • PR #555, #556, #557 (street-deals stack)
## Цель Дать продактам/оценщикам **сравнение фактических цен сделок ДКП vs текущие/исторические asking-цены на площадках** — для конкретной улицы/района/дома (где возможно). ## Текущее состояние ### Что есть - `rosreestr_deals` (49 791 ДКП EKB) — есть `addr_street`, `cad_num` (с улицей но без номера дома), `price`, `area`, `deal_date`. **Constraint**: open dataset агрегирует адреса до улицы, не до дома (Session_TradeIn_Dkp_Roadmap_May25). - `listings` (avito/cian/yandex/n1) — `address_fingerprint`, `cad_num`, `price`, `area`, geometry, `listing_date`. - `house_address_aliases` — fingerprint fuzzy match index. - **Per-street view** уже реализован: PR #555 `GET /street-deals`, PR #556 `StreetDealsCard` (UI на target адрес). ### Чего нет - Нет таблицы/view связывающей ДКП с конкретными listings. - Нет time-series sales-vs-asks (как соотносятся ASK на дату X и реальная сделка на дату X+N). - Estimator не учитывает rosreestr_deals (NOTE 2026-05-24 disabled). ## Что предлагается ### 1. Per-street SQL view `v_street_sales_vs_listings` ```sql SELECT street_normalized, cad_block, -- 66:41:xxxxxxx (улица-уровень) d.deal_date, d.price_per_m2 AS dkp_price_per_m2, d.area AS dkp_area, l.listing_id, l.source AS listing_source, l.price_per_m2 AS ask_price_per_m2, l.listing_date, l.cad_num AS listing_cad, (d.deal_date - l.listing_date) AS days_listing_to_deal, (d.price_per_m2 - l.price_per_m2) / l.price_per_m2 AS discount_pct FROM rosreestr_deals d LEFT JOIN listings l ON normalize_street(l.address) = normalize_street(d.addr_street) AND ABS(l.area - d.area) <= 5 AND l.listing_date BETWEEN d.deal_date - INTERVAL '180 days' AND d.deal_date WHERE d.cad_num LIKE '66:41:%'; ``` ### 2. Per-house матчинг (где cad_num полный) Часть rosreestr_deals имеет полный `cad_num` (с участком земли). Для них — JOIN по cad_num exact match, confidence 1.0. ### 3. Metric: "discount_to_asking" per-street Median (sale_price - last_ask_within_180d) / ask. Полезно для prediction: "если сейчас продают за X, реально уйдёт за X * (1 - discount_median)". ### 4. UI: StreetDealsCard расширить Добавить столбец "Связанные объявления" — clickable list (avito link + дата + цена). User видит на каком ASK дом стоял до того как ушёл по ДКП. ### 5. Estimator: подключить rosreestr_deals обратно Убрать NOTE 2026-05-24 disabled, добавить rosreestr_deals в `actual_deals` с правильной фильтрацией по distance/area window. Confidence tier per row (per-house cad match = T0, street match = T1). ## Sub-tasks - [ ] DDL: `data/sql/NNN_v_street_sales_vs_listings.sql` - [ ] Backend service `services/sales_listings_match.py` - [ ] API endpoint `GET /api/v1/sales-vs-listings?street=...` или расширить `/street-deals` - [ ] Frontend: StreetDealsCard дополнить "связанные ASK" - [ ] Estimator: revert NOTE 2026-05-24 + tier logic - [ ] Backfill: precompute `discount_to_asking_median` per street → cache в материал. view ## Acceptance - View возвращает ≥ 5K (deal, listing) pairs для EKB. - Median linkage rate per улица ≥ 30% (для streets с ≥ 10 ДКП). - UI показывает на странице улицы: "Из 50 ДКП за 2024 — 18 имеют связанное avito объявление до сделки". - Estimator показывает в response `actual_deals.rosreestr_count > 0`. ## Limitations (документировать) - Open dataset до улицы. Per-house только когда `cad_num` rosreestr-сделки совпадает с listing.cad_num exact. - listing_date в yandex заполнен ~40% (см. отдельный issue про PR-6). - Cian price_history пустой (см. отдельный issue про PR #525 unblock). ## Refs - `sessions/Session_TradeIn_Dkp_Roadmap_May25` - `services/matching/listings.py` — Tier 0-3 matching pattern - `decisions/Decision_TradeIn_PerSource_Listing_History` - PR #555, #556, #557 (street-deals stack)
lekss361 added the
analytics
enhancement
tradein
data
feedback/max
labels 2026-05-25 06:02:32 +00:00
Author
Owner

⚠️ Blocker noted: #582 — несовпадение адресов / точек между нашими данными и Яндекс/2ГИС. Пока этот баг не пофикшен, accuracy linkage ДКП↔Listings будет страдать (особенно per-house tier T0).

⚠️ **Blocker noted**: #582 — несовпадение адресов / точек между нашими данными и Яндекс/2ГИС. Пока этот баг не пофикшен, accuracy linkage ДКП↔Listings будет страдать (особенно per-house tier T0).
Sign in to join this conversation.
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#564
No description provided.