Espone private/get_open_orders_by_currency sul router Deribit (pattern gia'
presente per Hyperliquid/IBKR). Serve al reconciler resting di PythagorasGoal:
TP/DSL attesi dai libri vs ordini realmente in book (caso MR02_BTC 2026-06-12:
TP resting fillato di notte + disaster-SL sparito, scoperti solo al close sim).
NB: per i trigger untriggered interrogare anche type='trigger_all' e fare
merge per order_id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Consolidate the cross-cutting data tools onto the unified interface and
remove their per-exchange duplicates.
- /mcp/tools/get_historical: single call, `exchange` now optional. Set →
that venue's candles (native symbol); omitted → cross-exchange consensus
(canonical symbol, median OHLC + div_pct). Folds in the former
/mcp-cross consensus, whose router is deleted.
- /mcp/tools/get_indicators: new common tool computing sma/rsi/atr/macd/adx
over the single-or-consensus series. Computation centralized in
common/indicators.py::compute_indicators (was duplicated per exchange).
- Remove get_historical from /mcp-deribit and /mcp-hyperliquid; remove
get_technical_indicators (deribit) and get_indicators (hyperliquid),
including the now-dead client methods, Req schemas and tool wrappers.
The client get_historical METHODS stay (used by the unified dispatch).
Tests: rewrite cross tests into test_unified (instruments, historical
single + consensus + failures, indicators single + consensus); drop the
old CrossClient test; tighten app-boot surface assertions (/mcp owns the
data tools; no /mcp-cross, no per-exchange historical/indicators).
Docs: API_REFERENCE / README / CLAUDE updated; smoke run_unified.sh now
covers consensus + indicators.
324 passed, ruff clean. Verified live against Deribit/Hyperliquid.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a common cross-exchange interface (/mcp) over the integrated venues
(deribit, hyperliquid):
- get_instruments: uniform schema where each row carries its own
`exchange`, `fees` (maker/taker, live from Deribit, null where the
venue has no per-instrument schedule) and `history_start` (listing
date, live from Deribit creation_timestamp), plus type/tick_size and a
lossless `native` blob. Optional `exchange` filter; fan-out otherwise.
- get_historical: generalized to {exchange, instrument, interval,
start_date, end_date}, returning a single chosen venue's candles.
Consensus merge stays available on /mcp-cross.
New: routers/unified.py, exchanges/cross/instruments.py (normalizers),
UnifiedClient in cross/client.py, schemas in cross/tools.py. Deribit
get_instruments now also surfaces maker/taker_commission and
creation_timestamp (additive).
Retire Bybit and Alpaca from the API surface: move clients, routers,
settings classes and their tests under old/ (history preserved via
git mv); drop them from the builder, /mcp-cross dispatch and symbol_map.
Bybit remains a public funding/OI data source in sentiment (not the
trading client). IBKR is intentionally excluded from /mcp for now.
Docs: rewrite API_REFERENCE.md (remove Bybit/Alpaca, document /mcp,
clarify that data_timestamp is injected globally by middleware).
Tests: add unified-interface coverage; update cross/settings/builder/boot
tests for the reduced venue set. Fix a pre-existing flaky assertion in
the Hyperliquid signing test (r/s use eth_utils.to_hex like the official
SDK, so a leading zero byte yields <66 chars ~1/256 of the time).
323 passed, ruff clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
end_date as a bare date now covers the whole UTC day (23:59:59.999)
instead of stopping at midnight, so end_date=today returns intraday up
to the last closed candle. Dates are parsed as explicit UTC and inline
timestamps (YYYY-MM-DDTHH:MM:SS) are honored for precise windows.
Wide ranges are paged in <=5000-candle windows so Deribit's per-call
cap can no longer silently drop start_date and the oldest candles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Cloudflare 5xx pages from Deribit testnet were leaking through the JSON
parser as JSONDecodeError → UNHANDLED_EXCEPTION. Wrap response parsing so
upstream errors surface as a retryable HTTP_502 envelope instead.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Su errore di Deribit (auth fallita, ecc.) i campi equity/balance/margin/
available/unrealized_pnl/total_pnl ora sono None: signal chiaro di "valore
ignoto" vs "saldo realmente a zero". Risolve ambiguità lato client che
leggevano equity=0 senza accorgersi del campo error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Quando Deribit risponde con {"error": {...}} su public/auth (creds errate,
scope mancante, env mismatch), il client esplodeva con KeyError: 'result' →
500 UNHANDLED_EXCEPTION sui tool privati (get_account_summary, get_positions).
Ora _authenticate solleva DeribitAuthError tipizzata, _request la converte
in error envelope coerente con il resto del flusso.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- /health/ready: ping di tutti i client (exchange, env) cached con
timeout 2s, status ready|degraded|not_ready, opt-in 503 via
READY_FAILS_ON_DEGRADED.
- Middleware mcp.request: 1 riga JSON per HTTP request con request_id,
method, path, status_code, duration_ms, actor, bot_tag, exchange,
tool, client_ip, user_agent.
- request_id propagato in request.state, audit log e error envelope per
correlazione cross-cutting.
- Aggiunto async health() come probe minimo a bybit/alpaca/macro/
sentiment/deribit (hyperliquid lo aveva già).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task 6.1 V2.0.0: copia client.py + leverage_cap.py da services/mcp-deribit
con import riscritti (mcp_common -> cerbero_mcp.common, mcp_deribit ->
cerbero_mcp.exchanges.deribit). Estratte 34 tool async (28 endpoint +
is_testnet/environment_info + helpers) in tools.py: pure logica senza
FastAPI/ACL. Audit calls per ora rimossi (TODO: cabling via router su
request.state.environment).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>