重置项目

This commit is contained in:
2026-07-04 15:59:20 +08:00
parent 374e587f2d
commit 648a8b7f1c
224 changed files with 19700 additions and 9547 deletions
+123 -7
View File
@@ -38,6 +38,9 @@ _table_cache: dict[str, dict | None] = {
"index_daily": None,
"index_enriched": None,
"index_instruments": None,
"etf_daily": None,
"etf_enriched": None,
"etf_instruments": None,
"minute": None,
"adj_factor": None,
"instruments": None,
@@ -262,6 +265,85 @@ def _safe_aggregate_index_instruments(repo) -> dict | None:
}
def _safe_aggregate_etf_instruments(repo) -> dict | None:
"""ETF instruments 统计 — 优先独立 instruments_etf,兼容旧 instruments_index。"""
queries = [
"""SELECT count(*) AS rows,
count(DISTINCT symbol) AS symbols,
count_if(name IS NOT NULL AND name != '') AS named
FROM instruments_etf""",
"""SELECT count(*) AS rows,
count(DISTINCT symbol) AS symbols,
count_if(name IS NOT NULL AND name != '') AS named
FROM instruments_index
WHERE asset_type = 'etf'""",
]
for sql in queries:
try:
row = repo.execute_one(sql)
except Exception as e: # noqa: BLE001
logger.debug("aggregate etf instruments fallback failed: %s", e)
continue
if row and row[0]:
return {
"rows": int(row[0]),
"symbols_covered": int(row[1] or 0),
"latest_as_of": None,
"named": int(row[2] or 0),
}
return None
def _safe_aggregate_etf_enriched(repo) -> dict | None:
"""ETF enriched 统计 — 独立 kline_etf_enriched。"""
fields = 0
try:
cols = repo.execute_all("DESCRIBE kline_etf_enriched")
fields = len(cols)
except Exception: # noqa: BLE001
pass
stats = _safe_aggregate(repo, "kline_etf_enriched")
if not stats:
return None
return {**stats, "fields": fields}
def _safe_aggregate_etf_daily(repo) -> dict | None:
"""ETF 日K统计 — 优先独立 kline_etf_daily,兼容旧 index 存储。"""
queries = [
"""SELECT count(*) AS rows,
min(date) AS earliest,
max(date) AS latest,
count(DISTINCT symbol) AS symbols,
count(DISTINCT date) AS trading_days
FROM kline_etf_daily""",
"""SELECT count(*) AS rows,
min(date) AS earliest,
max(date) AS latest,
count(DISTINCT symbol) AS symbols,
count(DISTINCT date) AS trading_days
FROM kline_index_daily
WHERE symbol IN (
SELECT DISTINCT symbol FROM instruments_index WHERE asset_type = 'etf'
)""",
]
for sql in queries:
try:
row = repo.execute_one(sql)
except Exception as e: # noqa: BLE001
logger.debug("aggregate etf daily fallback failed: %s", e)
continue
if row and row[0]:
return {
"rows": int(row[0]),
"earliest_date": str(row[1]) if row[1] else None,
"latest_date": str(row[2]) if row[2] else None,
"symbols_covered": int(row[3] or 0),
"trading_days": int(row[4] or 0),
}
return None
def _safe_aggregate_adj_factor(repo) -> dict | None:
"""adj_factor 视图统计,日期范围对齐日 K 覆盖区间。"""
try:
@@ -405,6 +487,10 @@ def _compute_storage(data_dir: Path) -> dict:
"index_daily": data_dir / "kline_index_daily",
"index_enriched": data_dir / "kline_index_enriched",
"index_instruments": data_dir / "instruments_index",
"etf_daily": data_dir / "kline_etf_daily",
"etf_enriched": data_dir / "kline_etf_enriched",
"etf_instruments": data_dir / "instruments_etf",
"etf_adj_factor": data_dir / "adj_factor_etf",
"minute": data_dir / "kline_minute",
"adj_factor": data_dir / "adj_factor",
"instruments": data_dir / "instruments",
@@ -507,10 +593,13 @@ def status(request: Request) -> dict:
return {
"daily": _get_table_stats("daily", lambda: _safe_aggregate_daily(repo)),
"enriched": _get_table_stats("enriched", lambda: _safe_aggregate_enriched(repo)),
"index_daily": _get_table_stats("index_daily", lambda: _safe_aggregate_index_daily(repo)),
"index_enriched": _get_table_stats("index_enriched", lambda: _safe_aggregate_index_enriched(repo)),
"index_instruments": _get_table_stats("index_instruments", lambda: _safe_aggregate_index_instruments(repo)),
"minute": _get_table_stats("minute", lambda: _safe_aggregate_minute(repo)),
"index_daily": _get_table_stats("index_daily", lambda: _safe_aggregate_index_daily(repo)),
"index_enriched": _get_table_stats("index_enriched", lambda: _safe_aggregate_index_enriched(repo)),
"index_instruments": _get_table_stats("index_instruments", lambda: _safe_aggregate_index_instruments(repo)),
"etf_daily": _get_table_stats("etf_daily", lambda: _safe_aggregate_etf_daily(repo)),
"etf_enriched": _get_table_stats("etf_enriched", lambda: _safe_aggregate_etf_enriched(repo)),
"etf_instruments": _get_table_stats("etf_instruments", lambda: _safe_aggregate_etf_instruments(repo)),
"minute": _get_table_stats("minute", lambda: _safe_aggregate_minute(repo)),
"adj_factor": _get_table_stats("adj_factor", lambda: _safe_aggregate_adj_factor(repo)),
"instruments": _get_table_stats("instruments", lambda: _safe_aggregate_instruments(repo)),
"financials": _get_table_stats("financials", lambda: _safe_aggregate_financials(repo)),
@@ -537,8 +626,9 @@ def clear_data(request: Request):
deleted = 0
for sub in (
"kline_daily", "kline_daily_enriched", "kline_index_daily", "kline_index_enriched", "kline_minute",
"adj_factor", "instruments", "instruments_index", "pools", "financials",
"kline_daily", "kline_daily_enriched", "kline_index_daily", "kline_index_enriched",
"kline_etf_daily", "kline_etf_enriched", "kline_etf_minute", "kline_minute",
"adj_factor", "adj_factor_etf", "instruments", "instruments_index", "instruments_etf", "pools", "financials",
"backtest_results", "screener_results", "ai_cache",
):
d = data_dir / sub
@@ -596,10 +686,15 @@ def clear_data(request: Request):
"kline_enriched": f"{d}/kline_daily_enriched/**/*.parquet",
"kline_index_daily": f"{d}/kline_index_daily/**/*.parquet",
"kline_index_enriched": f"{d}/kline_index_enriched/**/*.parquet",
"kline_etf_daily": f"{d}/kline_etf_daily/**/*.parquet",
"kline_etf_enriched": f"{d}/kline_etf_enriched/**/*.parquet",
"kline_etf_minute": f"{d}/kline_etf_minute/**/*.parquet",
"kline_minute": f"{d}/kline_minute/**/*.parquet",
"adj_factor": f"{d}/adj_factor/**/*.parquet",
"adj_factor_etf": f"{d}/adj_factor_etf/**/*.parquet",
"instruments": f"{d}/instruments/**/*.parquet",
"instruments_index": f"{d}/instruments_index/**/*.parquet",
"instruments_etf": f"{d}/instruments_etf/**/*.parquet",
}.items():
try:
repo.db.execute(
@@ -638,6 +733,17 @@ _TABLE_FIELD_DESC: dict[str, dict[str, str]] = {
"amount": "成交额",
},
"kline_index_enriched": ENRICHED_COLUMNS,
"kline_etf_daily": {
"symbol": "ETF代码",
"date": "交易日期",
"open": "开盘价",
"high": "最高价",
"low": "最低价",
"close": "收盘价",
"volume": "成交量",
"amount": "成交额",
},
"kline_etf_enriched": ENRICHED_COLUMNS,
"kline_minute": {
"symbol": "股票代码",
"datetime": "分钟时间戳",
@@ -675,6 +781,13 @@ _TABLE_FIELD_DESC: dict[str, dict[str, str]] = {
"code": "指数编码(纯数字)",
"asset_type": "资产类型(index)",
},
"instruments_etf": {
"symbol": "ETF代码",
"name": "ETF名称",
"code": "ETF编码(纯数字)",
"asset_type": "资产类型(etf)",
"source": "数据源",
},
}
# view 名 → DuckDB 视图名
@@ -684,6 +797,9 @@ _SCHEMA_VIEWS: dict[str, str] = {
"index_daily": "kline_index_daily",
"index_enriched": "kline_index_enriched",
"index_instruments": "instruments_index",
"etf_daily": "kline_etf_daily",
"etf_enriched": "kline_etf_enriched",
"etf_instruments": "instruments_etf",
"minute": "kline_minute",
"adj_factor": "adj_factor",
"instruments": "instruments",
@@ -730,7 +846,7 @@ def get_version(request: Request) -> dict:
"""
from app import __version__
# 1. 优先用 app.__version__ (开发期 bump_version.py 写入)
# 1. 优先用 app.__version__ (唯一权威版本, 打包期由 PyInstaller 注入)
if __version__:
v = __version__.strip()
return {"version": v if v.startswith("v") else f"v{v}"}