[tradein][analytics] Point-in-time backtest estimator через listing_source_snapshots (#570) #667

Open
opened 2026-05-29 14:16:53 +00:00 by Light1YT · 5 comments
Owner

Follow-up #648. Текущий backtest-харнесс (scripts/backtest_estimator.py) сравнивает ТЕКУЩИЕ активные listings vs ПРОШЛЫЕ ДКП-сделки (time-mismatch — не point-in-time). Когда listing_source_snapshots (#570, daily-snapshot запущен 2026-05-30) накопит историю asking-цен по датам — переписать харнесс на point-in-time: для каждой сделки брать asking-медиану на дату сделки из снапшотов. Это уберёт дрейф рынка из замера bias/MAPE и из вывода asking→sold ratio (#648/#647).

Не срочно: ждёт ~1-3 мес накопления снапшотов. priority/low.

Refs: scripts/backtest_estimator.py (caveat (a) в docstring), #570, #648, #647.

**Follow-up #648.** Текущий backtest-харнесс (`scripts/backtest_estimator.py`) сравнивает ТЕКУЩИЕ активные listings vs ПРОШЛЫЕ ДКП-сделки (time-mismatch — не point-in-time). Когда `listing_source_snapshots` (#570, daily-snapshot запущен 2026-05-30) накопит историю asking-цен по датам — переписать харнесс на point-in-time: для каждой сделки брать asking-медиану *на дату сделки* из снапшотов. Это уберёт дрейф рынка из замера bias/MAPE и из вывода asking→sold ratio (#648/#647). Не срочно: ждёт ~1-3 мес накопления снапшотов. priority/low. Refs: scripts/backtest_estimator.py (caveat (a) в docstring), #570, #648, #647.
Light1YT added the
analytics
tradein
labels 2026-05-29 14:16:53 +00:00
lekss361 added the
scope/backend
status/blocked
labels 2026-05-30 15:03:11 +00:00
Owner

+status/blocked — ждёт накопления listing_source_snapshots (~1-3 мес, #570) для point-in-time backtest. priority/low. Разблокировать когда снапшоты накопятся. +scope/backend.

`+status/blocked` — ждёт накопления `listing_source_snapshots` (~1-3 мес, #570) для point-in-time backtest. priority/low. Разблокировать когда снапшоты накопятся. `+scope/backend`.
lekss361 added this to the Praktika demo — Mon 2026-06-01 milestone 2026-05-30 17:21:12 +00:00
Collaborator

Статус 2026-05-31

listing_source_snapshot (scrape_schedules id=106) реально тикает ежедневно (last_run 2026-05-31 01:00), снапшоты копятся с ~2026-05-29/30 → пока ~1-2 дня истории. Для point-in-time backtest нужно ~1-3 мес накопления (как и помечено). Корректно отложено, time-based блокер — не код. Без действий до накопления. (Сегодняшний бектест #877-контекста гонялся на текущем current-vs-past харнессе с caveat (a) — bias +24% частично от рыночного дрейфа, что этот issue и уберёт когда снапшотов хватит.)

## Статус 2026-05-31 `listing_source_snapshot` (scrape_schedules id=106) реально тикает ежедневно (last_run 2026-05-31 01:00), снапшоты копятся с ~2026-05-29/30 → пока **~1-2 дня истории**. Для point-in-time backtest нужно ~1-3 мес накопления (как и помечено). Корректно отложено, time-based блокер — не код. Без действий до накопления. (Сегодняшний бектест #877-контекста гонялся на текущем current-vs-past харнессе с caveat (a) — bias +24% частично от рыночного дрейфа, что этот issue и уберёт когда снапшотов хватит.)
Collaborator

Уточнение фактами (БД, 2026-05-31)

listing_source_snapshots: 37 059 строк, но диапазон дат = 2026-05-30 → 2026-05-31 (всего 2 дня). listings_snapshots: 2332 строки, тоже 2 дня. Ежедневный снапшот (scrape_schedules id=106) реально тикает — копится корректно, но истории пока ~2 дня.

Двойной блокер (важно): point-in-time backtest = для сделки на дату D брать asking-медиану из снапшота на дату D. Но:

  1. Снапшоты есть только с 30.05 → нет покрытия прошлых дат.
  2. Rosreestr ДКП заморожены на Q1'26 (#724) → нет НОВЫХ сделок с датами ≥30.05, чтобы пересечься со снапшотами.
    → Пересечения deal_date ∩ snapshot_date = 0 сейчас. Point-in-time станет возможен только когда (а) снапшоты накопят месяцы И (б) появятся свежие сделки (#724 разморозит Rosreestr). Оценка ~1-3 мес — нижняя граница, реально зависит и от #724.

Корректно отложено, не код. Зависимость от #724 стоит явно прописать.

## Уточнение фактами (БД, 2026-05-31) `listing_source_snapshots`: 37 059 строк, но диапазон дат = **2026-05-30 → 2026-05-31 (всего 2 дня)**. `listings_snapshots`: 2332 строки, тоже 2 дня. Ежедневный снапшот (`scrape_schedules` id=106) реально тикает — копится корректно, но истории пока ~2 дня. **Двойной блокер (важно):** point-in-time backtest = для сделки на дату D брать asking-медиану *из снапшота на дату D*. Но: 1. Снапшоты есть только с 30.05 → нет покрытия прошлых дат. 2. Rosreestr ДКП **заморожены на Q1'26** (#724) → нет НОВЫХ сделок с датами ≥30.05, чтобы пересечься со снапшотами. → Пересечения deal_date ∩ snapshot_date = **0** сейчас. Point-in-time станет возможен только когда (а) снапшоты накопят месяцы И (б) появятся свежие сделки (#724 разморозит Rosreestr). Оценка ~1-3 мес — нижняя граница, реально зависит и от #724. Корректно отложено, не код. Зависимость от #724 стоит явно прописать.
Collaborator

Зависимость (явно): #667 заблокирован на свежих ДКП-сделках, не только на снапшотах

Главный блокер — НЕ объём снапшотов, а temporal overlap:

  • Point-in-time матчит deal_date ↔ snapshot_date. Снапшоты есть только с 30.05.2026 вперёд (прошлое не доснапшотить).
  • deals.deal_date max = 2026-01-01 (Rosreestr заморожен; root cause в #724 — закрыт как needs-human strategic decision). Проверено в БД 31.05: max по-прежнему Q1'26.
  • → пересечение deal_date ≥ 30.05 ∩ snapshot_date = 0. Даже с месяцами снапшотов backtest невозможен, пока не появятся свежие сделки.

depends-on #724 (разморозка bulk Rosreestr ingest). #724 закрыт — решение задокументировано там, но операционно источник ещё заморожен. Пока deals не станут свежими (deal_date ≥ старта снапшотов), #667 неисполним в принципе.

Вторичное условие: снапшоты должны быть осмысленными → листинги нужно регулярно ре-скрейпить (расписание sweep'ов, #581/#880-watchdog), иначе «asking на дату» — плоская стоялая серия.

Итог: #667 ждёт (1) фактической разморозки Rosreestr [#724] + (2) накопления снапшотов с регулярным ре-скрейпом. Без (1) — мёртвая зависимость. Оставляю status/blocked, добавил явную связь.

## Зависимость (явно): #667 заблокирован на свежих ДКП-сделках, не только на снапшотах Главный блокер — НЕ объём снапшотов, а **temporal overlap**: - Point-in-time матчит deal_date ↔ snapshot_date. Снапшоты есть только с 30.05.2026 вперёд (прошлое не доснапшотить). - `deals.deal_date` max = **2026-01-01** (Rosreestr заморожен; root cause в #724 — закрыт как needs-human strategic decision). Проверено в БД 31.05: max по-прежнему Q1'26. - → пересечение `deal_date ≥ 30.05` ∩ snapshot_date = **0**. Даже с месяцами снапшотов backtest невозможен, пока не появятся свежие сделки. **depends-on #724** (разморозка bulk Rosreestr ingest). #724 закрыт — решение задокументировано там, но операционно источник ещё заморожен. Пока deals не станут свежими (deal_date ≥ старта снапшотов), #667 неисполним в принципе. Вторичное условие: снапшоты должны быть осмысленными → листинги нужно регулярно ре-скрейпить (расписание sweep'ов, #581/#880-watchdog), иначе «asking на дату» — плоская стоялая серия. Итог: #667 ждёт (1) фактической разморозки Rosreestr [#724] + (2) накопления снапшотов с регулярным ре-скрейпом. Без (1) — мёртвая зависимость. Оставляю status/blocked, добавил явную связь.
Collaborator

Реальный горизонт + переоценка важности (после #727 root-cause)

#727 (closed/done) установил: заморозка = upstream-лаг Росреестра (поквартально, ~3.5 мес лаг). Q1'26 опубл. 16.04, Q2'26 ~авг 2026. deal_date в tradein = начало квартала (агрегат, 9 distinct дат), НЕ дата транзакции.

Горизонт #667 (хуже изначальной оценки)

  • Q2'26 (deal_date 2026-04-01, ~авг) < старт снапшотов 30.05 → нет overlap.
  • Первый матчируемый квартал = Q3'26 (deal_date 2026-07-01, публикация ~ноябрь 2026).
  • point-in-time будет поквартальным, не дневным (deal_date — квартал-агрегат).

НО это НЕ блокер продукта (важно)

#667 — измерительный инструмент точности (bias/MAPE point-in-time), НЕ продуктовая фича. Estimator работает без него:

  • Сделки дают только asking_to_sold_ratio (структурно стабилен квартал-к-кварталу), а НЕ абсолютную цену.
  • Headline = свежая asking-медиана × ratio → заякорен на свежих данных, квартальный лаг сделок не двигает оценку.
  • Внутриквартальный дрейф рынка правится time-adjust через СберИндекс (#794, помесячно до 2026-04).
  • Сегодняшний current-vs-past бектест уже даёт corrected MAPE ~20% (caveat (a) — рыночный дрейф, что #667 уберёт когда станет возможен).

Вывод: держать как low-prio measurement-задачу, разблокируется ~Q3'26 органически (когда Росреестр опубликует + снапшоты накопятся). Продукт/демо не страдают. Можно понизить приоритет; не тратить усилия до ~ноября 2026.

## Реальный горизонт + переоценка важности (после #727 root-cause) #727 (closed/done) установил: заморозка = **upstream-лаг Росреестра** (поквартально, ~3.5 мес лаг). Q1'26 опубл. 16.04, Q2'26 ~авг 2026. `deal_date` в tradein = **начало квартала** (агрегат, 9 distinct дат), НЕ дата транзакции. ### Горизонт #667 (хуже изначальной оценки) - Q2'26 (deal_date 2026-04-01, ~авг) < старт снапшотов 30.05 → нет overlap. - Первый матчируемый квартал = **Q3'26** (deal_date 2026-07-01, публикация ~ноябрь 2026). - point-in-time будет **поквартальным**, не дневным (deal_date — квартал-агрегат). ### НО это НЕ блокер продукта (важно) #667 — измерительный инструмент точности (bias/MAPE point-in-time), НЕ продуктовая фича. Estimator работает без него: - Сделки дают только `asking_to_sold_ratio` (структурно стабилен квартал-к-кварталу), а НЕ абсолютную цену. - Headline = свежая asking-медиана × ratio → заякорен на свежих данных, квартальный лаг сделок не двигает оценку. - Внутриквартальный дрейф рынка правится time-adjust через СберИндекс (#794, помесячно до 2026-04). - Сегодняшний current-vs-past бектест уже даёт corrected MAPE ~20% (caveat (a) — рыночный дрейф, что #667 уберёт когда станет возможен). **Вывод:** держать как low-prio measurement-задачу, разблокируется ~Q3'26 органически (когда Росреестр опубликует + снапшоты накопятся). Продукт/демо не страдают. Можно понизить приоритет; не тратить усилия до ~ноября 2026.
Sign in to join this conversation.
No project
No assignees
3 participants
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#667
No description provided.