feat(HEL-382): 搭建 datahub 底座和盘后正式数据链路
新增独立 xiaobai-datahub 服务(SQLite WAL、Tushare 盘后发布、/v1 契约和管理后台),不改现站页面与数据链路。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Cursor
multica-agent
parent
c2ebc0ab91
commit
3498dd7a4b
@@ -0,0 +1,64 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime, time, timedelta, timezone
|
||||
from typing import Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
SHANGHAI = ZoneInfo("Asia/Shanghai")
|
||||
|
||||
|
||||
def now_shanghai(clock: datetime | None = None) -> datetime:
|
||||
if clock is not None:
|
||||
if clock.tzinfo is None:
|
||||
return clock.replace(tzinfo=SHANGHAI)
|
||||
return clock.astimezone(SHANGHAI)
|
||||
return datetime.now(SHANGHAI)
|
||||
|
||||
|
||||
def isoformat(value: datetime | None = None) -> str:
|
||||
current = now_shanghai(value)
|
||||
return current.isoformat(timespec="seconds")
|
||||
|
||||
|
||||
def yyyymmdd(value: date | datetime | str | None = None) -> str:
|
||||
if value is None:
|
||||
return now_shanghai().strftime("%Y%m%d")
|
||||
if isinstance(value, str):
|
||||
digits = value.replace("-", "")[:8]
|
||||
if len(digits) != 8 or not digits.isdigit():
|
||||
raise ValueError(f"invalid trade_date: {value}")
|
||||
return digits
|
||||
if isinstance(value, datetime):
|
||||
return value.astimezone(SHANGHAI).strftime("%Y%m%d")
|
||||
return value.strftime("%Y%m%d")
|
||||
|
||||
|
||||
def parse_trade_date(value: str) -> date:
|
||||
text = yyyymmdd(value)
|
||||
return date(int(text[:4]), int(text[4:6]), int(text[6:8]))
|
||||
|
||||
|
||||
def session_phase(clock: datetime | None, is_open_day: bool) -> str:
|
||||
"""pre | intradaily | lunch | eod | closed"""
|
||||
if not is_open_day:
|
||||
return "closed"
|
||||
current = now_shanghai(clock).time()
|
||||
if current < time(9, 15):
|
||||
return "pre"
|
||||
if current < time(11, 30) or (time(13, 0) <= current <= time(15, 5)):
|
||||
return "intraday"
|
||||
if current < time(13, 0):
|
||||
return "lunch"
|
||||
if current <= time(23, 40):
|
||||
return "eod"
|
||||
return "closed"
|
||||
|
||||
|
||||
def add_days(trade_date: str, days: int) -> str:
|
||||
return (parse_trade_date(trade_date) + timedelta(days=days)).strftime("%Y%m%d")
|
||||
|
||||
|
||||
def utc_timestamp(value: Any) -> str:
|
||||
if isinstance(value, datetime):
|
||||
return isoformat(value)
|
||||
return isoformat()
|
||||
Reference in New Issue
Block a user