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
47 lines
2.1 KiB
Python
47 lines
2.1 KiB
Python
"""IO contracts for the market indicator endpoints (Issue #99).
|
|
|
|
POST /api/v1/market/ddu-indicator — mirrors the ARN/НСПД request body so the
|
|
frontend can reuse one UI pattern for primary (наша ДДУ) vs secondary (ARN).
|
|
Field names are camelCase (ARN-compatible) via validation aliases; snake_case
|
|
also accepted (populate_by_name).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class DduIndicatorRequest(BaseModel):
|
|
"""ARN-shaped request body. Unsupported options are reported in `notes`
|
|
of the response rather than rejected (MVP supports Q / methods 1,2 / subj 66).
|
|
"""
|
|
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
# ARN indicator types M/Q/H/Y. MVP supports only 'Q'.
|
|
indicators: list[str] | None = Field(default=None)
|
|
# 1 = basis, 2 = previous, (3 = year-ago — unsupported in MVP).
|
|
calculation_method: int = Field(default=2, ge=1, le=3, alias="calculationMethod")
|
|
# ARN-style period bounds, e.g. '2025-Q2' .. '2026-Q1'. None = unbounded.
|
|
period_from: str | None = Field(default=None, alias="periodFrom", max_length=10)
|
|
period_to: str | None = Field(default=None, alias="periodTo", max_length=10)
|
|
# ARN federal district ids (e.g. [6] = Уральский). Informational in MVP.
|
|
federal_district: list[int] | None = Field(default=None, alias="federalDistrict")
|
|
# ARN subject codes. Only '66' (Свердловская обл.) is backed by data.
|
|
federal_subject: list[str] | None = Field(default=None, alias="federalSubject")
|
|
# ARN cadastral quarters. NOT supported (primary-market ДДУ too sparse per
|
|
# cad_quarter) — accepted for shape-compat, reported as unsupported.
|
|
cadastral_quarter: list[str] | None = Field(default=None, alias="cadastralQuarter")
|
|
# ARN area-range ids 1..6 (0 = all-area headline). None → all present.
|
|
area_ranges: list[int] | None = Field(default=None, alias="areaRanges")
|
|
|
|
|
|
class DduIndicatorResponse(BaseModel):
|
|
"""Free-form ARN-mirror response (table + graph + meta + notes)."""
|
|
|
|
meta: dict[str, Any]
|
|
table: list[dict[str, Any]]
|
|
graph: list[dict[str, Any]]
|
|
notes: list[str]
|