rebuild(stage-8): deliver market insight workspaces

This commit is contained in:
leefer
2026-07-30 04:12:04 +08:00
parent a18e8e9d27
commit 976a5cac03
39 changed files with 3671 additions and 14 deletions
+103
View File
@@ -189,6 +189,109 @@ class TushareProvider:
coverage = sum(bool(row["quoted"]) for row in rows) / len(rows)
return ProviderResult(tuple(rows), _metadata(self.source, "mixed", coverage))
def market_insight(
self,
kind: str,
trade_date: str,
previous_trade_date: str = "",
identifier: str = "",
) -> dict[str, ProviderResult | None]:
current = _compact(trade_date)
previous = _compact(previous_trade_date) if previous_trade_date else current
if kind == "auction":
return {
"auction": self._optional_query(
"stk_auction",
{"trade_date": current},
"ts_code,trade_date,vol,price,amount,pre_close,turnover_rate,"
"volume_ratio,float_share",
),
"price_limits": self._optional_query(
"stk_limit",
{"trade_date": current},
"trade_date,ts_code,up_limit,down_limit",
),
"ths_hot": self._optional_query("ths_hot", {"trade_date": previous}, ""),
"dc_hot": self._optional_query("dc_hot", {"trade_date": previous}, ""),
}
if kind == "themes":
return {
"directory": self._optional_query(
"ths_index", {}, "ts_code,name,count,exchange,list_date,type"
),
"daily": self._optional_query(
"ths_daily",
{"trade_date": current},
"ts_code,trade_date,open,high,low,close,pre_close,pct_change,"
"vol,turnover_rate",
),
"hot": self._optional_query("ths_hot", {"trade_date": current}, ""),
}
if kind == "theme-detail":
return {
"members": self._optional_query(
"ths_member",
{"ts_code": identifier, "is_new": "Y"},
"ts_code,con_code,con_name",
),
"daily": self._optional_query(
"daily",
{"trade_date": current},
"ts_code,trade_date,open,high,low,close,pct_chg,vol,amount",
),
}
if kind == "popularity":
return {
"ths": self._optional_query("ths_hot", {"trade_date": current}, ""),
"dc": self._optional_query("dc_hot", {"trade_date": current}, ""),
"previous_ths": self._optional_query(
"ths_hot", {"trade_date": previous}, ""
),
"previous_dc": self._optional_query(
"dc_hot", {"trade_date": previous}, ""
),
}
if kind == "dragon-list":
return {
"official": self._optional_query(
"hm_detail",
{"trade_date": current},
"trade_date,ts_code,ts_name,buy_amount,sell_amount,net_amount,"
"hm_name,hm_orgs,tag",
),
"profiles": self._optional_query("hm_list", {}, "name,desc,orgs"),
"stocks": self._optional_query(
"top_list",
{"trade_date": current},
"trade_date,ts_code,name,pct_change,reason",
),
"seats": self._optional_query(
"top_inst",
{"trade_date": current},
"trade_date,ts_code,exalter,buy,sell,net_buy,side,reason",
),
}
raise ProviderError("不支持的市场洞察数据集")
def realtime_snapshots(
self, identifiers: tuple[str, ...], start_time: str, end_time: str
) -> ProviderResult:
raise ProviderError("Tushare不提供动态竞价快照")
def _optional_query(
self, api_name: str, params: dict[str, Any], fields: str
) -> ProviderResult | None:
try:
return self._query(
api_name,
params,
fields,
unit="mixed",
empty_is_complete=True,
)
except ProviderError:
return None
def _membership_rows(self, params: dict[str, str]) -> list[dict[str, Any]]:
rows: list[dict[str, Any]] = []
fields = (