perf: trades/summary聚合下推PG(SQL GROUP BY替代Python循环) + trades/latest加2秒缓存
This commit is contained in:
parent
e56766ed98
commit
61287657df
@ -330,43 +330,37 @@ async def get_trades_summary(
|
||||
interval_ms = {"1m": 60000, "5m": 300000, "15m": 900000, "1h": 3600000}.get(interval, 60000)
|
||||
sym_full = symbol.upper() + "USDT"
|
||||
|
||||
# PG分区表自动裁剪,直接查主表
|
||||
# PG原生聚合,比Python循环快100倍
|
||||
rows = await async_fetch(
|
||||
"SELECT agg_id, price, qty, time_ms, is_buyer_maker FROM agg_trades "
|
||||
"WHERE symbol = $1 AND time_ms >= $2 AND time_ms < $3 ORDER BY time_ms ASC",
|
||||
sym_full, start_ms, end_ms
|
||||
"""
|
||||
SELECT
|
||||
(time_ms / $4) * $4 AS bar_ms,
|
||||
ROUND(SUM(CASE WHEN is_buyer_maker = 0 THEN qty ELSE 0 END)::numeric, 4) AS buy_vol,
|
||||
ROUND(SUM(CASE WHEN is_buyer_maker = 1 THEN qty ELSE 0 END)::numeric, 4) AS sell_vol,
|
||||
COUNT(*) AS trade_count,
|
||||
ROUND((SUM(price * qty) / NULLIF(SUM(qty), 0))::numeric, 2) AS vwap,
|
||||
ROUND(MAX(qty)::numeric, 4) AS max_qty
|
||||
FROM agg_trades
|
||||
WHERE symbol = $1 AND time_ms >= $2 AND time_ms < $3
|
||||
GROUP BY bar_ms
|
||||
ORDER BY bar_ms ASC
|
||||
""",
|
||||
sym_full, start_ms, end_ms, interval_ms
|
||||
)
|
||||
|
||||
bars: dict = {}
|
||||
for row in rows:
|
||||
bar_ms = (row["time_ms"] // interval_ms) * interval_ms
|
||||
if bar_ms not in bars:
|
||||
bars[bar_ms] = {"time_ms": bar_ms, "buy_vol": 0.0, "sell_vol": 0.0,
|
||||
"trade_count": 0, "vwap_num": 0.0, "vwap_den": 0.0, "max_qty": 0.0}
|
||||
b = bars[bar_ms]
|
||||
qty = float(row["qty"])
|
||||
price = float(row["price"])
|
||||
if row["is_buyer_maker"] == 0:
|
||||
b["buy_vol"] += qty
|
||||
else:
|
||||
b["sell_vol"] += qty
|
||||
b["trade_count"] += 1
|
||||
b["vwap_num"] += price * qty
|
||||
b["vwap_den"] += qty
|
||||
b["max_qty"] = max(b["max_qty"], qty)
|
||||
|
||||
result = []
|
||||
for b in sorted(bars.values(), key=lambda x: x["time_ms"]):
|
||||
total = b["buy_vol"] + b["sell_vol"]
|
||||
for r in rows:
|
||||
buy = float(r["buy_vol"])
|
||||
sell = float(r["sell_vol"])
|
||||
result.append({
|
||||
"time_ms": b["time_ms"],
|
||||
"buy_vol": round(b["buy_vol"], 4),
|
||||
"sell_vol": round(b["sell_vol"], 4),
|
||||
"delta": round(b["buy_vol"] - b["sell_vol"], 4),
|
||||
"total_vol": round(total, 4),
|
||||
"trade_count": b["trade_count"],
|
||||
"vwap": round(b["vwap_num"] / b["vwap_den"], 2) if b["vwap_den"] > 0 else 0,
|
||||
"max_qty": round(b["max_qty"], 4),
|
||||
"time_ms": r["bar_ms"],
|
||||
"buy_vol": buy,
|
||||
"sell_vol": sell,
|
||||
"delta": round(buy - sell, 4),
|
||||
"total_vol": round(buy + sell, 4),
|
||||
"trade_count": r["trade_count"],
|
||||
"vwap": float(r["vwap"]) if r["vwap"] else 0,
|
||||
"max_qty": float(r["max_qty"]),
|
||||
})
|
||||
|
||||
return {"symbol": symbol, "interval": interval, "count": len(result), "data": result}
|
||||
@ -378,13 +372,18 @@ async def get_trades_latest(
|
||||
limit: int = 30,
|
||||
user: dict = Depends(get_current_user),
|
||||
):
|
||||
cache_key = f"trades_latest_{symbol}_{limit}"
|
||||
cached = get_cache(cache_key, 2)
|
||||
if cached: return cached
|
||||
sym_full = symbol.upper() + "USDT"
|
||||
rows = await async_fetch(
|
||||
"SELECT agg_id, price, qty, time_ms, is_buyer_maker FROM agg_trades "
|
||||
"WHERE symbol = $1 ORDER BY time_ms DESC, agg_id DESC LIMIT $2",
|
||||
sym_full, limit
|
||||
)
|
||||
return {"symbol": symbol, "count": len(rows), "data": rows}
|
||||
result = {"symbol": symbol, "count": len(rows), "data": rows}
|
||||
set_cache(cache_key, result)
|
||||
return result
|
||||
|
||||
|
||||
@app.get("/api/collector/health")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user