feat(V2): shared Candle validator + uniform 'candles' response key
Introduce common/candles.py with a Pydantic Candle model enforcing OHLC consistency (high≥max, low≤min), non-negative volume and positive timestamp. validate_candles() coerces upstream rows, sorts by timestamp and raises HTTPException(502) on malformed data — surfacing upstream data corruption as a retryable envelope instead of silently returning nonsense. Wired into all five exchange historical endpoints (Bybit, Hyperliquid, Deribit, Alpaca, IBKR). BREAKING: Alpaca get_bars and IBKR get_bars now return 'candles' (was 'bars') to align with the other exchanges. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import httpx
|
||||
|
||||
from cerbero_mcp.common import indicators as ind
|
||||
from cerbero_mcp.common import microstructure as micro
|
||||
from cerbero_mcp.common.candles import validate_candles
|
||||
|
||||
BASE_MAINNET = "https://api.bybit.com"
|
||||
BASE_TESTNET = "https://api-testnet.bybit.com"
|
||||
@@ -254,18 +255,17 @@ class BybitClient:
|
||||
params["end"] = end
|
||||
resp = await self._request_public("GET", "/v5/market/kline", params=params)
|
||||
rows = (resp.get("result") or {}).get("list") or []
|
||||
rows_sorted = sorted(rows, key=lambda r: int(r[0]))
|
||||
candles = [
|
||||
candles = validate_candles([
|
||||
{
|
||||
"timestamp": int(r[0]),
|
||||
"open": float(r[1]),
|
||||
"high": float(r[2]),
|
||||
"low": float(r[3]),
|
||||
"close": float(r[4]),
|
||||
"volume": float(r[5]),
|
||||
"open": r[1],
|
||||
"high": r[2],
|
||||
"low": r[3],
|
||||
"close": r[4],
|
||||
"volume": r[5],
|
||||
}
|
||||
for r in rows_sorted
|
||||
]
|
||||
for r in rows
|
||||
])
|
||||
return {"symbol": symbol, "candles": candles}
|
||||
|
||||
async def get_indicators(
|
||||
|
||||
Reference in New Issue
Block a user