Some checks failed
CI / changes (push) Successful in 8s
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 7m37s
CI / backend-tests (pull_request) Successful in 7m42s
Deploy / deploy (push) Blocked by required conditions
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / changes (push) Has been cancelled
#17: detect_velocity_anomalies + GET /analytics/velocity-alerts — z-score drop-detection на domrf_kn_sale_graph (double-gate z≤-2 AND drop≤-30%, starvation-guards). Snapshot=richest (не MAX — prod новейшие частичные), lookback anchored на latest report_month (scrape лаг ~4мес). Prod: ЖК Центральный Парк -69%, ~14ms. #99: mv_ddu_price_indicator (миграция 152) + POST /market/ddu-indicator — ARN-mirror ценовой индекс per quarter×area_bucket из rosreestr_deals (ДДУ регион 66). MVP: subject-level, period Q, window 2025-Q2+, methods 1/2 (basis/previous, prev_period_value honesty). Q1-2026 headline 1.0185 vs ARN 1.03 (±5%). Method 3 blocked (нет pre-2025-Q2 данных) — задокументировано. Closes #17 Closes #99
50 lines
2.2 KiB
Python
50 lines
2.2 KiB
Python
"""Market indicator endpoints (Issue #99) — ARN-framework for primary market.
|
||
|
||
POST /api/v1/market/ddu-indicator — per-quarter price indicator of the PRIMARY
|
||
market (новостройки/ДДУ) for Свердловская обл., ARN-mirror request/response.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Annotated
|
||
|
||
from fastapi import APIRouter, Depends
|
||
from sqlalchemy.orm import Session
|
||
|
||
from app.core.db import get_db
|
||
from app.schemas.market import DduIndicatorRequest, DduIndicatorResponse
|
||
from app.services.analytics import ddu_price_indicator as ddu
|
||
|
||
router = APIRouter()
|
||
|
||
|
||
@router.post("/ddu-indicator", response_model=DduIndicatorResponse)
|
||
def ddu_indicator(
|
||
payload: DduIndicatorRequest,
|
||
db: Annotated[Session, Depends(get_db)],
|
||
) -> DduIndicatorResponse:
|
||
"""ARN-style ценовой индикатор первичного рынка (ДДУ) по кварталам × площади.
|
||
|
||
Принимает то же body, что ARN/НСПД (camelCase). MVP: period_type=Q,
|
||
calc methods 1 (базисный) / 2 (предыдущий), субъект 66. Неподдержанные
|
||
ARN-опции (M/H/Y, method=3, иные субъекты, cad_quarter) не отвергаются —
|
||
отражаются в `notes`. Источник: mv_ddu_price_indicator (migration 152).
|
||
|
||
Killer-USP: «у нас первичка, у НСПД вторичка» — обе нужны девелоперу.
|
||
"""
|
||
result = ddu.get_ddu_indicator(
|
||
db,
|
||
calculation_method=payload.calculation_method,
|
||
period_from=payload.period_from,
|
||
period_to=payload.period_to,
|
||
area_ranges=payload.area_ranges,
|
||
federal_subject=payload.federal_subject,
|
||
indicators=payload.indicators,
|
||
)
|
||
# cadastral_quarter is shape-compat only; flag it if the client sent one.
|
||
if payload.cadastral_quarter:
|
||
result["notes"].append(
|
||
"cadastralQuarter не поддержан: первичка (ДДУ) слишком разрежена "
|
||
"на уровне кад.квартала — индикатор считается по субъекту (66)."
|
||
)
|
||
return DduIndicatorResponse(**result)
|