ba29572e93
- scripts/build-push.sh: replica job CI in locale (8 image, cache buildx, tag :latest + :sha-X) - scripts/deploy-noclone.sh: deploy VPS senza clone (curl raw config + image pull) - rimossa .gitea/workflows/ci.yml - README + DEPLOYMENT aggiornati: laptop -> registry -> VPS, paths /docker/cerbero_mcp - ruff fix su 3 test (I001, SIM117, UP037, F821) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
154 lines
6.2 KiB
Markdown
154 lines
6.2 KiB
Markdown
# Cerbero_mcp
|
||
|
||
Server MCP riusabili (exchange + market data) per la suite Cerbero.
|
||
Spinta da `Cerbero/` (commit `pre-split-2026-04-27`) come parte dello
|
||
split documentato in `docs/superpowers/specs/2026-04-27-split-mcp-core-design.md`
|
||
(nel repo storico).
|
||
|
||
## Servizi
|
||
- `mcp-alpaca`, `mcp-bybit`, `mcp-deribit`, `mcp-hyperliquid` — exchange
|
||
con `place_order`, `environment_info`, leverage cap server-side
|
||
- `mcp-deribit` e `mcp-bybit` espongono inoltre `place_combo_order`:
|
||
- Deribit: `private/create_combo` + ordine sul combo → 1 sola crociata
|
||
di spread invece di N (slippage atteso ridotto su strutture liquide).
|
||
- Bybit: `place_batch_order` su `category=option` → multi-leg atomico
|
||
in un solo round-trip API (no sconto fee, solo atomicità + latenza).
|
||
- `mcp-macro`, `mcp-sentiment` — read-only market data
|
||
|
||
## Indicatori quantitativi disponibili
|
||
|
||
### Common (`mcp_common.indicators` + `options` + `microstructure` + `stats`)
|
||
- Tecnici: `sma`, `rsi`, `macd`, `atr`, `adx`
|
||
- Volatilità: `vol_cone` (RV multi-window con percentili), `garch11_forecast`
|
||
- Statistici: `hurst_exponent`, `half_life_mean_reversion`, `autocorrelation`,
|
||
`cointegration_test` (Engle-Granger)
|
||
- Risk: `rolling_sharpe` (Sharpe + Sortino), `var_cvar` (historical VaR/ES)
|
||
- Microstructure: `orderbook_imbalance` (ratio + microprice + slope)
|
||
- Options: `oi_weighted_skew`, `smile_asymmetry`, `atm_vs_wings_vol`,
|
||
`dealer_gamma_profile`, `vanna_charm_aggregate`
|
||
|
||
### Deribit (esposti come tool MCP)
|
||
DVOL, GEX, P/C ratio, skew_25d, term_structure, iv_rank, realized_vol,
|
||
indicatori tecnici, find_by_delta, calculate_spread_payoff.
|
||
**Nuovi**: `get_dealer_gamma_profile`, `get_vanna_charm`,
|
||
`get_oi_weighted_skew`, `get_smile_asymmetry`, `get_atm_vs_wings_vol`,
|
||
`get_orderbook_imbalance`.
|
||
|
||
### Bybit
|
||
Ticker, orderbook, OHLCV, funding rate (current+history), open interest,
|
||
basis spot/perp, indicatori tecnici. **Nuovi**: `get_orderbook_imbalance`,
|
||
`get_basis_term_structure`.
|
||
|
||
### Macro
|
||
Treasury yields, FRED indicators, equity futures, asset prices, calendar.
|
||
**Nuovi**: `get_yield_curve_slope` (slope 2y10y/5y30y + butterfly + regime),
|
||
`get_breakeven_inflation` (T5YIE/T10YIE/T5YIFR), `get_cot_tff` (TFF report
|
||
CFTC equity/financial: ES/NQ/RTY/ZN/ZB/6E/6J/DX), `get_cot_disaggregated`
|
||
(Disaggregated report CFTC commodities: CL/GC/SI/HG/ZW/ZC/ZS),
|
||
`get_cot_extreme_positioning` (scanner percentile ≤5/≥95 su watchlist).
|
||
|
||
### Sentiment
|
||
News (CryptoPanic/CoinDesk), social (LunarCrush), funding multi-exchange,
|
||
OI history. **Nuovi**: `get_funding_arb_spread` (opportunità arb compatte),
|
||
`get_liquidation_heatmap` (heuristic da OI delta + funding extreme),
|
||
`get_cointegration_pairs` (Engle-Granger su coppie crypto).
|
||
|
||
## Build & deploy pipeline
|
||
|
||
Niente CI/CD su Gitea: la build delle 8 image è responsabilità della
|
||
macchina di sviluppo, fatta da `scripts/build-push.sh`. Il flusso è:
|
||
|
||
1. **Quality gate locale** (sul laptop, prima di pushare):
|
||
- `uv run ruff check services/`
|
||
- `uv run mypy services/common/src/mcp_common`
|
||
- `uv run pytest services/`
|
||
- `docker compose -f docker-compose.prod.yml config -q`
|
||
2. **Build & push** (sul laptop):
|
||
```bash
|
||
export GITEA_PAT='<PAT_write:package>'
|
||
./scripts/build-push.sh # tutte le 8 image
|
||
./scripts/build-push.sh base mcp-bybit # solo specifiche
|
||
```
|
||
Tagga `:latest` + `:sha-<short_HEAD>` per rollback puntuali. Cache
|
||
buildx via registry stesso (run successivi 5-10× più veloci).
|
||
3. **Auto-rollover su VPS**: Watchtower polla il registry ogni 5 min e
|
||
aggiorna i container quando il digest del tag `:latest` cambia.
|
||
|
||
Vedi [`DEPLOYMENT.md`](DEPLOYMENT.md) per build & push, deploy VPS
|
||
no-clone (`scripts/deploy-noclone.sh`), smoke test, rollback.
|
||
|
||
## Avvio locale (dev)
|
||
|
||
```bash
|
||
docker compose up -d
|
||
bash tests/smoke/run.sh
|
||
```
|
||
|
||
## Configurazione
|
||
|
||
Vedi `secrets/*.json` e variabili `*_TESTNET` / `ALPACA_PAPER` in
|
||
`docker-compose.yml` per override ambiente.
|
||
|
||
### Deploy su VPS pubblica (`cerbero-mcp.tielogic.xyz`)
|
||
|
||
Vedi [`DEPLOYMENT.md`](DEPLOYMENT.md) per il runbook completo end-to-end.
|
||
|
||
Il gateway Caddy è configurato per:
|
||
- TLS automatico via Let's Encrypt (richiede DNS A/AAAA che punti al
|
||
VPS e porte 80+443 raggiungibili).
|
||
- HSTS preload, header di sicurezza (`X-Content-Type-Options`,
|
||
`X-Frame-Options`, `Referrer-Policy`).
|
||
- Rate limit per IP (60 req/min su read, 10 req/min su write) tramite
|
||
plugin `mholt/caddy-ratelimit`.
|
||
- Allowlist IP sui write endpoint (`place_*`, `cancel_*`, `set_*`,
|
||
`close_*`, `transfer_*`, `amend_*`, `switch_*`): IP non presenti in
|
||
`WRITE_ALLOWLIST` ricevono `403 forbidden`.
|
||
|
||
Variabili d'ambiente per il deploy:
|
||
|
||
```bash
|
||
# .env (su VPS)
|
||
ACME_EMAIL=adrianodalpastro@tielogic.com
|
||
GATEWAY_HTTP_PORT=80
|
||
GATEWAY_HTTPS_PORT=443
|
||
|
||
# Allowlist write endpoint (CIDR space-separated). Default copre:
|
||
# - loopback IPv4/IPv6 (bot sull'host VPS chiama http://localhost)
|
||
# - Docker bridge 172.16.0.0/12 (bot in container nella stessa compose network)
|
||
# Aggiungi gli IP pubblici dei tuoi bot esterni se li hai.
|
||
WRITE_ALLOWLIST="127.0.0.1/32 ::1/128 172.16.0.0/12 1.2.3.4/32"
|
||
```
|
||
|
||
Tre scenari per il trading bot:
|
||
1. Bot container nella stessa compose network → chiama `http://gateway:80`
|
||
internamente. Source IP = Docker bridge → coperto dalla default.
|
||
2. Bot processo sull'host VPS → chiama `http://localhost`. Source IP =
|
||
`127.0.0.1` → coperto dalla default.
|
||
3. Bot esterno (laptop, altro server) → chiama
|
||
`https://cerbero-mcp.tielogic.xyz` con TLS. Devi aggiungere l'IP
|
||
pubblico del bot in `WRITE_ALLOWLIST`.
|
||
|
||
Senza configurare `WRITE_ALLOWLIST` la default è loopback + Docker bridge:
|
||
nessun IP pubblico esterno può triggerare ordini.
|
||
|
||
Sull'host VPS i secret devono avere permessi restrittivi:
|
||
|
||
```bash
|
||
chmod 600 secrets/*.json secrets/*.token
|
||
```
|
||
|
||
### Risoluzione environment (testnet/mainnet)
|
||
|
||
Ogni servizio exchange usa `mcp_common.environment.resolve_environment()`
|
||
che applica la precedenza:
|
||
|
||
1. env var di override (`DERIBIT_TESTNET`, `BYBIT_TESTNET`,
|
||
`HYPERLIQUID_TESTNET`, `ALPACA_PAPER`)
|
||
2. flag nel secret JSON (`testnet` o `paper` per alpaca)
|
||
3. default `testnet`
|
||
|
||
Gli URL canonici live/testnet sono passati come kwargs
|
||
`default_base_url_live` / `default_base_url_testnet` direttamente al
|
||
resolver — non serve duplicarli nel secret JSON, ma se presenti
|
||
prevalgono sui default del codice.
|