rebuild(stage-8): deliver market insight workspaces
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime, time
|
||||
from typing import Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from backend.data.contracts import ProviderResult
|
||||
|
||||
SHANGHAI = ZoneInfo("Asia/Shanghai")
|
||||
|
||||
|
||||
def auction_phase(requested: str, trade_date: str, clock: datetime) -> str:
|
||||
if requested != clock.date().isoformat() or trade_date != clock.date().isoformat():
|
||||
return "archive"
|
||||
local = clock.time().replace(tzinfo=None)
|
||||
if local < time(9, 15):
|
||||
return "pending"
|
||||
if local < time(9, 25):
|
||||
return "observing"
|
||||
if local < time(9, 30):
|
||||
return "selection"
|
||||
return "finalized"
|
||||
|
||||
|
||||
def decorate(
|
||||
payload: dict[str, Any],
|
||||
requested: str,
|
||||
phase: str,
|
||||
carried_forward: bool,
|
||||
message: str,
|
||||
current_available: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
**payload,
|
||||
"requested_date": requested,
|
||||
"phase": phase,
|
||||
"carried_forward": carried_forward,
|
||||
"message": message or str(payload.get("message") or ""),
|
||||
"current_available": current_available,
|
||||
}
|
||||
|
||||
|
||||
def standard(payload: dict[str, Any], requested: str, message: str = "") -> dict[str, Any]:
|
||||
trade_date = str(payload.get("trade_date") or "")
|
||||
return {
|
||||
**payload,
|
||||
"requested_date": requested,
|
||||
"carried_forward": trade_date != requested,
|
||||
"message": message or str(payload.get("message") or ""),
|
||||
}
|
||||
|
||||
|
||||
def empty_standard(requested: str, trade_date: str, message: str) -> dict[str, Any]:
|
||||
return {
|
||||
"requested_date": requested,
|
||||
"trade_date": trade_date,
|
||||
"observed_at": None,
|
||||
"state": None,
|
||||
"carried_forward": trade_date != requested,
|
||||
"message": message,
|
||||
"summary": {},
|
||||
"items": [],
|
||||
"combined": [],
|
||||
"ths": [],
|
||||
"dc": [],
|
||||
}
|
||||
|
||||
|
||||
def empty_auction(
|
||||
requested: str, trade_date: str, phase: str, message: str
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
**empty_standard(requested, trade_date, message),
|
||||
"phase": phase,
|
||||
"current_available": False,
|
||||
"expectations": {"超预期": 0, "符合预期": 0, "低于预期": 0},
|
||||
"themes": {"carry": [], "new_themes": []},
|
||||
"amount_history": [],
|
||||
"focus_rows": [],
|
||||
"one_price_rows": [],
|
||||
"rows": [],
|
||||
"watchlist_rows": [],
|
||||
"watchlist_ready": False,
|
||||
}
|
||||
|
||||
|
||||
def result(value: Any) -> ProviderResult | None:
|
||||
return value if isinstance(value, ProviderResult) else None
|
||||
|
||||
|
||||
def rows(value: Any) -> tuple[dict[str, Any], ...]:
|
||||
provider_result = result(value)
|
||||
return provider_result.rows if provider_result else ()
|
||||
|
||||
|
||||
def serialized_rows(value: Any) -> list[dict[str, Any]] | None:
|
||||
provider_result = result(value)
|
||||
return [dict(row) for row in provider_result.rows] if provider_result else None
|
||||
|
||||
|
||||
def tuple_or_none(value: Any) -> tuple[dict[str, Any], ...] | None:
|
||||
if value is None:
|
||||
return None
|
||||
return tuple(dict(row) for row in value)
|
||||
|
||||
|
||||
def valid_date(value: str) -> str:
|
||||
try:
|
||||
return date.fromisoformat(value).isoformat()
|
||||
except ValueError as exc:
|
||||
raise ValueError("日期格式无效") from exc
|
||||
|
||||
|
||||
def clock(value: datetime | None) -> datetime:
|
||||
current = value or datetime.now(SHANGHAI)
|
||||
return (
|
||||
current.replace(tzinfo=SHANGHAI)
|
||||
if current.tzinfo is None
|
||||
else current.astimezone(SHANGHAI)
|
||||
)
|
||||
|
||||
|
||||
def number(value: Any, default: float = 0.0) -> float:
|
||||
try:
|
||||
parsed = float(value)
|
||||
return parsed if parsed == parsed else default
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
Reference in New Issue
Block a user