feat(V2): unified /mcp interface; retire Bybit/Alpaca to old/
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>
This commit is contained in:
+124
-72
@@ -4,11 +4,16 @@ Documento di riferimento completo per tutti gli endpoint HTTP e i tool MCP
|
||||
esposti dal container `cerbero-mcp`. Generato dall'analisi diretta dei
|
||||
router FastAPI in `src/cerbero_mcp/routers/`.
|
||||
|
||||
> **Nota V2** — Bybit e Alpaca sono stati ritirati dalla superficie API
|
||||
> (codice archiviato in `old/`). Gli exchange di trading attivi sono
|
||||
> **Deribit**, **Hyperliquid** e **IBKR**; **Macro** e **Sentiment** restano
|
||||
> data-provider read-only.
|
||||
|
||||
---
|
||||
|
||||
## 1. Autenticazione
|
||||
|
||||
Tutte le chiamate ai namespace `/mcp-*` richiedono:
|
||||
Tutte le chiamate ai namespace `/mcp*` richiedono:
|
||||
|
||||
| Header | Valore | Note |
|
||||
|---|---|---|
|
||||
@@ -45,20 +50,78 @@ richiede `X-Bot-Tag`.
|
||||
|
||||
| Namespace | Tool | Tipo | Note |
|
||||
|---|---|---|---|
|
||||
| `/mcp/tools/*` | 2 | **interfaccia comune** | schema strumenti uniforme + storico per-exchange |
|
||||
| `/mcp-deribit/tools/*` | 33 | exchange (options-first) | DVOL, GEX, dealer gamma, spread payoff |
|
||||
| `/mcp-bybit/tools/*` | 30 | exchange (spot + perp + options) | basis, funding, batch orders |
|
||||
| `/mcp-hyperliquid/tools/*` | 16 | exchange (perp DEX) | L1 signing, leverage cap |
|
||||
| `/mcp-alpaca/tools/*` | 18 | exchange (US stocks + options) | clock/calendar, fractional |
|
||||
| `/mcp-ibkr/tools/*` | 24 | exchange (multi-asset broker) | OAuth 1.0a, streaming WS, bracket/OCO/OTO |
|
||||
| `/mcp-macro/tools/*` | 11 | data provider (read-only) | yields, FRED, COT |
|
||||
| `/mcp-sentiment/tools/*` | 9 | data provider (read-only) | news, social, funding cross-exchange |
|
||||
| `/mcp-cross/tools/*` | 1 | aggregator | storico consensus multi-exchange |
|
||||
|
||||
**Totale**: ~142 tool MCP.
|
||||
I router per-exchange (`/mcp-deribit`, …) restano disponibili durante la
|
||||
transizione; per nuovi consumatori è raccomandata l'interfaccia comune `/mcp`.
|
||||
|
||||
---
|
||||
|
||||
## 5. `/mcp-deribit/tools/*`
|
||||
## 5. `/mcp/tools/*` — interfaccia comune (raccomandata)
|
||||
|
||||
Interfaccia unica trasversale agli exchange integrati: il **campo `exchange`
|
||||
è dentro ogni risultato**, non nel path. Exchange supportati: `deribit`,
|
||||
`hyperliquid`.
|
||||
|
||||
### `get_instruments` — schema strumenti uniforme
|
||||
|
||||
Request body:
|
||||
|
||||
| Campo | Tipo | Default | Note |
|
||||
|---|---|---|---|
|
||||
| `exchange` | `"deribit"\|"hyperliquid"` \| null | `null` | se omesso → fan-out su tutti gli exchange integrati |
|
||||
| `currency` | str | `"BTC"` | solo Deribit |
|
||||
| `kind` | str \| null | `"future"` | solo Deribit (`future`/`option`/`spot`) |
|
||||
|
||||
Ogni elemento di `instruments[]` ha **schema uniforme**:
|
||||
|
||||
```json
|
||||
{
|
||||
"exchange": "deribit",
|
||||
"symbol": "BTC-PERPETUAL",
|
||||
"asset_class": "crypto",
|
||||
"type": "perpetual", // perpetual | future | option | spot
|
||||
"fees": {"maker": 0.0, "taker": 0.0005}, // null se l'exchange non lo espone
|
||||
"history_start": "2018-08-13", // data inizio storico, null se ignota
|
||||
"tick_size": 0.5,
|
||||
"native": { /* campi specifici dell'exchange, lossless */ }
|
||||
}
|
||||
```
|
||||
|
||||
Risposta: `{ "instruments": [...], "failed_sources": [{exchange, error}] }`.
|
||||
|
||||
> **Copertura `fees` / `history_start`** — popolati live dall'upstream dove
|
||||
> disponibili. Oggi: **Deribit** li espone (commissioni maker/taker +
|
||||
> `creation_timestamp` → `history_start`); **Hyperliquid** ha fee a livello
|
||||
> account e nessuna data di listing per-strumento → entrambi `null`.
|
||||
|
||||
### `get_historical` — storico di un singolo exchange
|
||||
|
||||
Request body:
|
||||
|
||||
| Campo | Tipo | Default | Note |
|
||||
|---|---|---|---|
|
||||
| `exchange` | `"deribit"\|"hyperliquid"` | — | **obbligatorio**: sceglie la sorgente |
|
||||
| `instrument` | str | — | simbolo nativo sull'exchange scelto |
|
||||
| `interval` | str | `"1h"` | `1m`/`5m`/`15m`/`1h`/`4h`/`1d` |
|
||||
| `start_date` | str | — | `YYYY-MM-DD` o ISO datetime (UTC) |
|
||||
| `end_date` | str | — | idem |
|
||||
|
||||
Risposta: `{ "exchange", "instrument", "interval", "candles": [...] }` con la
|
||||
chiave uniforme `candles: [{timestamp(ms), open, high, low, close, volume}]`.
|
||||
|
||||
Per il **consenso** multi-exchange (mediana cross-venue) usare invece
|
||||
`/mcp-cross/tools/get_historical` (sezione 11).
|
||||
|
||||
---
|
||||
|
||||
## 6. `/mcp-deribit/tools/*`
|
||||
|
||||
### Info
|
||||
- `is_testnet` — flag ambiente corrente
|
||||
@@ -108,38 +171,6 @@ richiede `X-Bot-Tag`.
|
||||
|
||||
---
|
||||
|
||||
## 6. `/mcp-bybit/tools/*`
|
||||
|
||||
### Info
|
||||
- `environment_info`
|
||||
|
||||
### Market data
|
||||
- `get_ticker`, `get_ticker_batch`
|
||||
- `get_orderbook`, `get_orderbook_imbalance`
|
||||
- `get_historical`
|
||||
- `get_instruments`, `get_option_chain`
|
||||
- `get_trade_history`
|
||||
|
||||
### Derivati
|
||||
- `get_funding_rate`, `get_funding_history`
|
||||
- `get_open_interest`
|
||||
- `get_basis_spot_perp`, `get_basis_term_structure`
|
||||
|
||||
### Account
|
||||
- `get_positions`, `get_account_summary`, `get_open_orders`
|
||||
|
||||
### Technicals
|
||||
- `get_indicators`
|
||||
|
||||
### Write
|
||||
- `place_order`, `place_combo_order`
|
||||
- `amend_order`, `cancel_order`, `cancel_all_orders`
|
||||
- `set_stop_loss`, `set_take_profit`, `close_position`
|
||||
- `set_leverage`, `switch_position_mode`
|
||||
- `transfer_asset`
|
||||
|
||||
---
|
||||
|
||||
## 7. `/mcp-hyperliquid/tools/*`
|
||||
|
||||
### Info
|
||||
@@ -163,35 +194,16 @@ richiede `X-Bot-Tag`.
|
||||
|
||||
---
|
||||
|
||||
## 8. `/mcp-alpaca/tools/*`
|
||||
|
||||
### Info / calendar
|
||||
- `environment_info`, `get_clock`, `get_calendar`
|
||||
|
||||
### Market data
|
||||
- `get_assets`, `get_ticker`
|
||||
- `get_bars`, `get_snapshot`
|
||||
- `get_option_chain`
|
||||
|
||||
### Account
|
||||
- `get_account`, `get_positions`, `get_activities`, `get_open_orders`
|
||||
|
||||
### Write
|
||||
- `place_order`, `amend_order`
|
||||
- `cancel_order`, `cancel_all_orders`
|
||||
- `close_position`, `close_all_positions`
|
||||
|
||||
> **Nota**: override URL applicato solo all'endpoint trading. Gli
|
||||
> endpoint dati (`data.alpaca.markets`) restano i default SDK.
|
||||
|
||||
---
|
||||
|
||||
## 9. `/mcp-ibkr/tools/*`
|
||||
## 8. `/mcp-ibkr/tools/*`
|
||||
|
||||
Auth via OAuth 1.0a Self-Service con minting di session token
|
||||
unattended. Setup one-time per ambiente (paper + live) — vedi sezione
|
||||
"IBKR Setup" del README.
|
||||
|
||||
> IBKR non è ancora integrato nell'interfaccia comune `/mcp` (il suo endpoint
|
||||
> bars usa un `period` relativo invece di `(start, end)`); usare il router
|
||||
> dedicato `/mcp-ibkr`.
|
||||
|
||||
### Info / clock
|
||||
- `environment_info`, `get_clock`
|
||||
|
||||
@@ -219,7 +231,7 @@ unattended. Setup one-time per ambiente (paper + live) — vedi sezione
|
||||
|
||||
---
|
||||
|
||||
## 10. `/mcp-macro/tools/*` (read-only)
|
||||
## 9. `/mcp-macro/tools/*` (read-only)
|
||||
|
||||
| Tool | Sorgente |
|
||||
|---|---|
|
||||
@@ -237,7 +249,7 @@ unattended. Setup one-time per ambiente (paper + live) — vedi sezione
|
||||
|
||||
---
|
||||
|
||||
## 11. `/mcp-sentiment/tools/*` (read-only)
|
||||
## 10. `/mcp-sentiment/tools/*` (read-only)
|
||||
|
||||
| Tool | Fonte |
|
||||
|---|---|
|
||||
@@ -251,9 +263,13 @@ unattended. Setup one-time per ambiente (paper + live) — vedi sezione
|
||||
| `get_liquidation_heatmap` | heatmap liquidazioni |
|
||||
| `get_cointegration_pairs` | screening coppie cointegrate |
|
||||
|
||||
> Le fonti di funding/OI includono endpoint pubblici multi-venue (Binance,
|
||||
> Bybit, OKX, Hyperliquid): qui Bybit è una **sorgente dati pubblica**, non il
|
||||
> client di trading ritirato.
|
||||
|
||||
---
|
||||
|
||||
## 12. `/mcp-cross/tools/*`
|
||||
## 11. `/mcp-cross/tools/*`
|
||||
|
||||
### `get_historical`
|
||||
Aggregatore cross-exchange. Fan-out a tutti gli exchange che supportano
|
||||
@@ -264,10 +280,8 @@ Aggregatore cross-exchange. Fan-out a tutti gli exchange che supportano
|
||||
- `sources` = numero di exchange che hanno contribuito al bar
|
||||
- `div_pct = (max - min) / median` → quality gate per i bot
|
||||
|
||||
**Crypto** (`asset_class: "crypto"`): BTC, ETH, SOL via Bybit +
|
||||
Hyperliquid + Deribit.
|
||||
**Stocks** (`asset_class: "stocks"`): AAPL, SPY, QQQ, TSLA, NVDA via
|
||||
Alpaca.
|
||||
**Crypto** (`asset_class: "crypto"`): BTC, ETH via Hyperliquid + Deribit;
|
||||
SOL via Hyperliquid.
|
||||
|
||||
In caso di fallimento parziale ritorna i bar disponibili più
|
||||
`failed_sources: [...]`. Se *tutti* gli upstream falliscono → `502
|
||||
@@ -275,7 +289,7 @@ Bad Gateway` retryable.
|
||||
|
||||
---
|
||||
|
||||
## 13. Observability
|
||||
## 12. Observability
|
||||
|
||||
### Request log (`mcp.request`)
|
||||
Una riga JSON per richiesta con: `request_id`, `method`, `path`,
|
||||
@@ -290,17 +304,55 @@ Rotazione configurabile via `AUDIT_LOG_BACKUP_DAYS`.
|
||||
Lo stesso `request_id` appare in `mcp.request`, `mcp.audit` e
|
||||
nell'envelope di errore restituito al client.
|
||||
|
||||
### `data_timestamp`
|
||||
Ogni risposta JSON sotto `/tools/*` riceve dal middleware un campo
|
||||
`data_timestamp` (ISO UTC) al top level — oltre all'header `X-Data-Timestamp`.
|
||||
|
||||
---
|
||||
|
||||
## 14. Esempio chiamata
|
||||
## 13. Esempio chiamata
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9000/mcp-bybit/tools/get_ticker \
|
||||
# Interfaccia comune: storico Deribit
|
||||
curl -X POST http://localhost:9000/mcp/tools/get_historical \
|
||||
-H "Authorization: Bearer $MAINNET_TOKEN" \
|
||||
-H "X-Bot-Tag: scanner-alpha-prod" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"symbol":"BTCUSDT","category":"linear"}'
|
||||
-d '{"exchange":"deribit","instrument":"BTC-PERPETUAL","interval":"1h","start_date":"2026-05-01","end_date":"2026-05-29"}'
|
||||
```
|
||||
|
||||
Per lo schema completo dei body di richiesta e risposta:
|
||||
<http://localhost:9000/apidocs>.
|
||||
|
||||
---
|
||||
|
||||
## 14. Discovery strumenti & schemi candele
|
||||
|
||||
Schemi verificati sulle risposte live. Tutti i `get_historical` ritornano la
|
||||
chiave uniforme `candles: [{timestamp(ms), open, high, low, close, volume}]`.
|
||||
|
||||
### Lista strumenti
|
||||
| Interfaccia | Tool | Request body | Risposta (campi principali) |
|
||||
|---|---|---|---|
|
||||
| `/mcp` (comune) | `get_instruments` | `{exchange?, currency:"BTC", kind:"future"}` | `instruments[]` uniforme: `exchange`, `symbol`, `asset_class`, `type`, `fees`, `history_start`, `tick_size`, `native` · `failed_sources[]` |
|
||||
| Deribit (`/mcp-deribit`) | `get_instruments` | `{currency:"BTC"\|…, kind:"future", offset:int, limit:100}` — **paginato** (`has_more`) | `instruments[]`: `name`, `expiry`, `option_type`, `tick_size`, `min_trade_amount`, `maker_commission`, `taker_commission`, `creation_timestamp` · meta: `total`, `offset`, `limit`, `has_more`, `testnet`, `data_timestamp` |
|
||||
| Hyperliquid (`/mcp-hyperliquid`) | `get_markets` | `{}` | lista `{asset, mark_price, funding_rate, open_interest, volume_24h, max_leverage}` |
|
||||
|
||||
### `get_historical` — body per exchange
|
||||
| Interfaccia | Body | Note risoluzione |
|
||||
|---|---|---|
|
||||
| `/mcp` (comune) | `{exchange, instrument, interval, start_date, end_date}` | `1m`/`5m`/`15m`/`1h`/`4h`/`1d` · ritorna il singolo exchange |
|
||||
| Deribit | `{instrument, start_date:"YYYY-MM-DD", end_date, resolution}` | `1`/`5`/`15`/`60`/`1D` (paginazione interna, no cap) |
|
||||
| Hyperliquid | `{asset\|instrument, start_date, end_date, resolution, interval?, limit:50}` | `1m`/`5m`/`15m`/`1h`/`1d` · `limit` default **50** (alzare per finestre lunghe) |
|
||||
|
||||
### Convenzione simboli Deribit
|
||||
- **BTC/ETH** → perpetui *inverse*: `BTC-PERPETUAL`, `ETH-PERPETUAL`
|
||||
- **Altcoin** → perpetui *lineari USDC*: `<COIN>_USDC-PERPETUAL` (es. `SOL_USDC-PERPETUAL`), storia da ~2022
|
||||
- Esistono anche `BTC_USDC-PERPETUAL` / `ETH_USDC-PERPETUAL` (varianti lineari)
|
||||
- ⚠️ `LTC-PERPETUAL` / `ADA-PERPETUAL` (inverse) **non esistono** (0 candele); `SOL-PERPETUAL` è elencato ma è un contratto vuoto/stale (prezzo ~9.6 vs SOL reale ~82) → usare `SOL_USDC-PERPETUAL`
|
||||
|
||||
### Nota testnet
|
||||
Con `TESTNET_TOKEN` le risposte includono `"testnet": true` (ticker,
|
||||
get_instruments, …) e i prezzi possono divergere dal mainnet. Su testnet
|
||||
alcuni feed sono inaffidabili: validare la congruenza cross-exchange prima di
|
||||
usare i dati per backtest/trading.
|
||||
|
||||
Reference in New Issue
Block a user