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:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user