windows-desktop: C端基线(Windows 本地实时分析器 + 采集器 bug 修复)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
龙虎榜采集器
|
||||
主方案:AkShare stock_lhb_detail_daily_sina(已实测可用,含上榜原因)
|
||||
备选:东财 datacenter 接口(报表名不确定,暂时注释备用)
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
|
||||
import akshare as ak
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
from src.storage.db import upsert_df, upsert_log, get_last_fetch
|
||||
|
||||
|
||||
def fetch_lhb_date(trade_date: str) -> pd.DataFrame:
|
||||
"""
|
||||
获取单日龙虎榜
|
||||
trade_date: "YYYY-MM-DD" 或 "YYYYMMDD"
|
||||
"""
|
||||
# 统一为 YYYYMMDD 格式
|
||||
ds = trade_date.replace("-", "")
|
||||
try:
|
||||
df = ak.stock_lhb_detail_daily_sina(date=ds)
|
||||
except Exception as e:
|
||||
print(f" [WARN] LHB Sina failed for {trade_date}: {e}")
|
||||
return pd.DataFrame()
|
||||
|
||||
if df is None or df.empty:
|
||||
return pd.DataFrame()
|
||||
|
||||
# Sina 返回列(实测):序号, 股票代码, 股票名称, 收盘价, 涨跌幅, 成交额, 成交额, 上榜原因
|
||||
# 编码问题导致中文列名显示乱码,用位置索引映射
|
||||
# 0=序号, 1=代码, 2=名称, 3=收盘, 4=涨跌幅, 5=成交额, 6=??? 7=上榜原因
|
||||
df.columns = ["no", "ts_code", "name", "close", "pct_change", "amount", "amount2", "reason"]
|
||||
|
||||
df["trade_date"] = trade_date.replace("-", "")
|
||||
# 格式化为 YYYY-MM-DD
|
||||
df["trade_date"] = pd.to_datetime(df["trade_date"]).dt.strftime("%Y-%m-%d")
|
||||
|
||||
# 保留有用字段
|
||||
keep = ["trade_date", "ts_code", "name", "close", "pct_change", "amount", "reason"]
|
||||
df = df[[c for c in keep if c in df.columns]]
|
||||
return df
|
||||
|
||||
|
||||
def fetch_lhb_range(start_date: str, end_date: str = None) -> pd.DataFrame:
|
||||
"""抓取日期区间的龙虎榜(逐日)"""
|
||||
end_date = end_date or datetime.today().strftime("%Y-%m-%d")
|
||||
all_days = []
|
||||
cur = datetime.strptime(start_date.replace("-", ""), "%Y%m%d")
|
||||
end = datetime.strptime(end_date.replace("-", ""), "%Y%m%d")
|
||||
while cur <= end:
|
||||
ds = cur.strftime("%Y-%m-%d")
|
||||
df = fetch_lhb_date(ds)
|
||||
if df is not None and not df.empty:
|
||||
all_days.append(df)
|
||||
cur += timedelta(days=1)
|
||||
if all_days:
|
||||
return pd.concat(all_days, ignore_index=True)
|
||||
return pd.DataFrame()
|
||||
|
||||
|
||||
def incremental_lhb(source: str = "lhb_daily") -> pd.DataFrame:
|
||||
"""增量采集:只抓上次之后的新交易日"""
|
||||
last = get_last_fetch(source)
|
||||
start = last.get("last_date") or (datetime.today() - timedelta(days=7)).strftime("%Y-%m-%d")
|
||||
end = datetime.today().strftime("%Y-%m-%d")
|
||||
df = fetch_lhb_range(start, end)
|
||||
if df is not None and not df.empty:
|
||||
upsert_df(df, "lhb_daily")
|
||||
upsert_log(source, param="", last_date=end)
|
||||
return df
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import fire
|
||||
fire.Fire({
|
||||
"date": lambda d: upsert_df(fetch_lhb_date(d), "lhb_daily"),
|
||||
"range": lambda s, e=None: upsert_df(fetch_lhb_range(s, e), "lhb_daily"),
|
||||
"incr": lambda: incremental_lhb(),
|
||||
})
|
||||
Reference in New Issue
Block a user