239 lines
6.1 KiB
Python
239 lines
6.1 KiB
Python
from typing import Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
Precision = Literal["realtime_exact", "close_final", "historical_exact", "unavailable"]
|
|
MarketState = Literal["pre_open", "trading_am", "midday_break", "trading_pm", "finalizing", "closed"]
|
|
PushStatus = Literal["pending", "sent", "failed", "skipped"]
|
|
|
|
|
|
class HealthResponse(BaseModel):
|
|
status: str
|
|
|
|
|
|
class ValueWithStatus(BaseModel):
|
|
amount_hkd_billion: float | None = None
|
|
precision: Precision
|
|
label: str
|
|
|
|
|
|
class OverviewSnapshot(BaseModel):
|
|
trade_date: str
|
|
snapshot_time: str | None = None
|
|
market_state: MarketState
|
|
total_net_inflow: ValueWithStatus
|
|
cumulative_net_inflow: ValueWithStatus
|
|
shanghai_net_inflow: ValueWithStatus
|
|
shenzhen_net_inflow: ValueWithStatus
|
|
buy_amount: ValueWithStatus
|
|
sell_amount: ValueWithStatus
|
|
net_buy_amount: ValueWithStatus
|
|
one_min_change: ValueWithStatus
|
|
five_min_change: ValueWithStatus
|
|
threshold_progress: float = Field(ge=0, le=1)
|
|
next_threshold_hkd_billion: float
|
|
source_name: str
|
|
source_url: str | None = None
|
|
updated_at: str | None = None
|
|
unavailable_reason: str | None = None
|
|
|
|
|
|
class TimelinePoint(BaseModel):
|
|
timestamp: str
|
|
amount_hkd_billion: float | None = None
|
|
precision: Precision
|
|
|
|
|
|
class BenchmarkTimelinePoint(BaseModel):
|
|
timestamp: str
|
|
value: float | None = None
|
|
|
|
|
|
class BenchmarkTimelineSeries(BaseModel):
|
|
key: str
|
|
label: str
|
|
unit: str
|
|
detail_url: str | None = None
|
|
points: list[BenchmarkTimelinePoint]
|
|
|
|
|
|
class PushRecord(BaseModel):
|
|
id: str
|
|
triggered_at: str
|
|
push_type: str
|
|
rule_code: str
|
|
trigger_value_hkd_billion: float | None = None
|
|
description: str
|
|
email_subject: str
|
|
email_summary: str
|
|
status: PushStatus
|
|
error_message: str | None = None
|
|
|
|
|
|
class PushRecordsResponse(BaseModel):
|
|
records: list[PushRecord]
|
|
|
|
|
|
class OverviewResponse(BaseModel):
|
|
snapshot: OverviewSnapshot
|
|
minute_timeline: list[TimelinePoint]
|
|
benchmark_series: list[BenchmarkTimelineSeries]
|
|
recent_push_records: list[PushRecord]
|
|
|
|
|
|
class StatPoint(BaseModel):
|
|
period: str
|
|
amount_hkd_billion: float
|
|
|
|
|
|
class RecentTradeDay(BaseModel):
|
|
trade_date: str
|
|
total_net_inflow_hkd_billion: float
|
|
precision: Precision
|
|
|
|
|
|
class HistorySummary(BaseModel):
|
|
cumulative_net_inflow_hkd_billion: float
|
|
trading_day_count: int
|
|
max_single_day_inflow_hkd_billion: float
|
|
max_single_day_outflow_hkd_billion: float
|
|
longest_inflow_streak: int
|
|
longest_outflow_streak: int
|
|
|
|
|
|
class HistoryResponse(BaseModel):
|
|
start_date: str
|
|
daily: list[StatPoint]
|
|
weekly: list[StatPoint]
|
|
monthly: list[StatPoint]
|
|
cumulative: list[StatPoint]
|
|
benchmark_history: dict[str, list[StatPoint]]
|
|
recent_trade_days: list[RecentTradeDay]
|
|
summary: HistorySummary
|
|
|
|
|
|
class RuleItem(BaseModel):
|
|
key: str
|
|
label: str
|
|
value: str
|
|
description: str
|
|
|
|
|
|
class RulesResponse(BaseModel):
|
|
items: list[RuleItem]
|
|
|
|
|
|
class SourceDiagnosticsResponse(BaseModel):
|
|
source_name: str
|
|
realtime_available: bool
|
|
historical_available: bool
|
|
last_success_at: str | None = None
|
|
last_failure_at: str | None = None
|
|
last_error_reason: str | None = None
|
|
last_success_url: str | None = None
|
|
last_persisted_at: str | None = None
|
|
|
|
|
|
class MetaResponse(BaseModel):
|
|
product_name: str
|
|
version: str
|
|
timezone: str
|
|
market_state: MarketState
|
|
current_trade_date: str
|
|
source_name: str
|
|
source_strategy: str
|
|
note: str
|
|
|
|
|
|
class AShareFlowRecord(BaseModel):
|
|
trade_date: str
|
|
code: str
|
|
name: str
|
|
detail_url: str | None = None
|
|
latest_price: float | None = None
|
|
change_amount: float | None = None
|
|
change_percent: float | None = None
|
|
main_net_inflow: float | None = None
|
|
main_net_inflow_ratio: float | None = None
|
|
super_large_net_inflow: float | None = None
|
|
super_large_net_inflow_ratio: float | None = None
|
|
large_net_inflow: float | None = None
|
|
large_net_inflow_ratio: float | None = None
|
|
medium_net_inflow: float | None = None
|
|
medium_net_inflow_ratio: float | None = None
|
|
small_net_inflow: float | None = None
|
|
small_net_inflow_ratio: float | None = None
|
|
rolling_net_inflow_5d: float | None = None
|
|
rolling_net_inflow_10d: float | None = None
|
|
rolling_net_inflow_30d: float | None = None
|
|
rolling_net_inflow_60d: float | None = None
|
|
rolling_net_inflow_90d: float | None = None
|
|
updated_at: str | None = None
|
|
source_name: str
|
|
source_url: str | None = None
|
|
precision: Precision
|
|
snapshot_time: str | None = None
|
|
sector_type: str | None = None
|
|
sector_type_label: str | None = None
|
|
|
|
|
|
class AShareSectorGroup(BaseModel):
|
|
label: str
|
|
records: list[AShareFlowRecord]
|
|
|
|
|
|
class AShareIndexFlowResponse(BaseModel):
|
|
trade_date: str
|
|
updated_at: str | None = None
|
|
source_name: str
|
|
source_url: str | None = None
|
|
precision: Precision
|
|
records: list[AShareFlowRecord]
|
|
|
|
|
|
class AShareSectorFlowResponse(BaseModel):
|
|
trade_date: str
|
|
updated_at: str | None = None
|
|
source_name: str
|
|
source_url: str | None = None
|
|
precision: Precision
|
|
sector_types: dict[str, AShareSectorGroup]
|
|
|
|
|
|
class EtfRealtimeRecord(BaseModel):
|
|
trade_date: str
|
|
code: str
|
|
name: str
|
|
fund_name: str | None = None
|
|
detail_url: str | None = None
|
|
source_url: str | None = None
|
|
latest_price: float | None = None
|
|
change_amount: float | None = None
|
|
change_percent: float | None = None
|
|
previous_close: float | None = None
|
|
open_price: float | None = None
|
|
high_price: float | None = None
|
|
low_price: float | None = None
|
|
volume: int | None = None
|
|
turnover_amount: float | None = None
|
|
turnover_rate: float | None = None
|
|
change_percent_1m: float | None = None
|
|
change_percent_3m: float | None = None
|
|
change_percent_4m: float | None = None
|
|
updated_at: str | None = None
|
|
snapshot_time: str | None = None
|
|
source_name: str
|
|
precision: Precision
|
|
is_trading: bool = False
|
|
|
|
|
|
class EtfRealtimeResponse(BaseModel):
|
|
trade_date: str
|
|
updated_at: str | None = None
|
|
source_name: str
|
|
source_url: str | None = None
|
|
precision: Precision
|
|
group: str
|
|
records: list[EtfRealtimeRecord]
|