gendesign/backend/app/schemas/market.py
Light1YT 658d724075
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
feat(analytics): velocity-anomaly alerts (#17) + ARN ДДУ price indicator (#99)
#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
2026-06-13 22:04:49 +05:00

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]