Refactor market K-line storage with tiered retention and chunked loading.

Store 1m/5m/1h/12h/1d/1w with per-timeframe policies, aggregate 15m and 2h/4h on read, and support left-pan history fetches via before_ms.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-08 07:27:16 +08:00
parent 41bdee2416
commit 11cc482599
5 changed files with 762 additions and 148 deletions
+30 -3
View File
@@ -15,7 +15,15 @@ if str(_REPO_ROOT) not in sys.path:
sys.path.insert(0, str(_REPO_ROOT))
from hub_kline_store import format_ohlcv_detail, resolve_chart_bars, retention_days
from hub_ohlcv_lib import CHART_TIMEFRAME_ORDER, CHART_TIMEFRAMES, bar_limit_for_timeframe
from hub_ohlcv_lib import (
CHART_TIMEFRAME_ORDER,
CHART_TIMEFRAMES,
bar_limit_for_timeframe,
chart_chunk_limit,
chart_initial_limit,
chart_memory_cap,
retention_policy_meta,
)
from hub_symbol_archive_lib import (
ARCHIVE_DEFAULT_TIMEFRAME,
ARCHIVE_SEED_LOOKBACK_DAYS,
@@ -629,7 +637,11 @@ def api_chart_meta():
"ok": True,
"timeframes": [tf for tf in tfs if tf in CHART_TIMEFRAMES],
"retention_days": retention_days(),
"retention_policy": retention_policy_meta(),
"limits": {tf: bar_limit_for_timeframe(tf) for tf in tfs if tf in CHART_TIMEFRAMES},
"initial_limits": {tf: chart_initial_limit(tf) for tf in tfs if tf in CHART_TIMEFRAMES},
"chunk_limits": {tf: chart_chunk_limit(tf) for tf in tfs if tf in CHART_TIMEFRAMES},
"memory_caps": {tf: chart_memory_cap(tf) for tf in tfs if tf in CHART_TIMEFRAMES},
"exchanges": exchanges,
}
@@ -640,6 +652,8 @@ def api_chart_ohlcv(
symbol: str = "",
timeframe: str = "1d",
refresh: str = "",
limit: int = 0,
before_ms: str = "",
):
ex = _find_exchange_by_key(exchange_key)
if not ex:
@@ -651,14 +665,23 @@ def api_chart_ohlcv(
raise HTTPException(status_code=400, detail="请输入币种")
ex_key = str(ex.get("key") or "").strip().lower()
force = (refresh or "").strip().lower() in ("1", "true", "yes", "on")
lim = int(limit) if int(limit or 0) > 0 else None
bms_raw = (before_ms or "").strip()
bms = None
if bms_raw:
try:
bms = int(bms_raw)
except ValueError:
raise HTTPException(status_code=400, detail="before_ms 无效")
def remote_fetch(**kwargs):
tf_use = kwargs.get("timeframe") or timeframe
return _fetch_instance_ohlcv_sync(
ex,
symbol=kwargs.get("symbol") or sym,
timeframe=kwargs.get("timeframe") or timeframe,
timeframe=tf_use,
since_ms=kwargs.get("since_ms"),
limit=int(kwargs.get("limit") or bar_limit_for_timeframe(timeframe)),
limit=int(kwargs.get("limit") or bar_limit_for_timeframe(tf_use)),
)
result = resolve_chart_bars(
@@ -667,9 +690,13 @@ def api_chart_ohlcv(
timeframe,
remote_fetch,
force_refresh=force,
limit=lim,
before_ms=bms,
)
if not result.get("ok"):
raise HTTPException(status_code=502, detail=result.get("msg") or "K线加载失败")
if not result.get("candles") and result.get("before_ms") is None:
raise HTTPException(status_code=502, detail=result.get("msg") or "无 K 线")
tick = result.get("price_tick")
last = result["candles"][-1] if result.get("candles") else None
result["ohlcv"] = format_ohlcv_detail(