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)
|
interval_ms = {"1m": 60000, "5m": 300000, "15m": 900000, "1h": 3600000}.get(interval, 60000)
|
||||||
sym_full = symbol.upper() + "USDT"
|
sym_full = symbol.upper() + "USDT"
|
||||||
|
|
||||||
# PG分区表自动裁剪,直接查主表
|
# PG原生聚合,比Python循环快100倍
|
||||||
rows = await async_fetch(
|
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",
|
SELECT
|
||||||
sym_full, start_ms, end_ms
|
(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 = []
|
result = []
|
||||||
for b in sorted(bars.values(), key=lambda x: x["time_ms"]):
|
for r in rows:
|
||||||
total = b["buy_vol"] + b["sell_vol"]
|
buy = float(r["buy_vol"])
|
||||||
|
sell = float(r["sell_vol"])
|
||||||
result.append({
|
result.append({
|
||||||
"time_ms": b["time_ms"],
|
"time_ms": r["bar_ms"],
|
||||||
"buy_vol": round(b["buy_vol"], 4),
|
"buy_vol": buy,
|
||||||
"sell_vol": round(b["sell_vol"], 4),
|
"sell_vol": sell,
|
||||||
"delta": round(b["buy_vol"] - b["sell_vol"], 4),
|
"delta": round(buy - sell, 4),
|
||||||
"total_vol": round(total, 4),
|
"total_vol": round(buy + sell, 4),
|
||||||
"trade_count": b["trade_count"],
|
"trade_count": r["trade_count"],
|
||||||
"vwap": round(b["vwap_num"] / b["vwap_den"], 2) if b["vwap_den"] > 0 else 0,
|
"vwap": float(r["vwap"]) if r["vwap"] else 0,
|
||||||
"max_qty": round(b["max_qty"], 4),
|
"max_qty": float(r["max_qty"]),
|
||||||
})
|
})
|
||||||
|
|
||||||
return {"symbol": symbol, "interval": interval, "count": len(result), "data": result}
|
return {"symbol": symbol, "interval": interval, "count": len(result), "data": result}
|
||||||
@ -378,13 +372,18 @@ async def get_trades_latest(
|
|||||||
limit: int = 30,
|
limit: int = 30,
|
||||||
user: dict = Depends(get_current_user),
|
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"
|
sym_full = symbol.upper() + "USDT"
|
||||||
rows = await async_fetch(
|
rows = await async_fetch(
|
||||||
"SELECT agg_id, price, qty, time_ms, is_buyer_maker FROM agg_trades "
|
"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",
|
"WHERE symbol = $1 ORDER BY time_ms DESC, agg_id DESC LIMIT $2",
|
||||||
sym_full, limit
|
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")
|
@app.get("/api/collector/health")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user