"""Router /mcp-deribit/* — DI per env, client e (write) creds. Mappa 1:1 i tool di `cerbero_mcp.exchanges.deribit.tools` a endpoint `POST /mcp-deribit/tools/{tool_name}`. L'autenticazione bearer è gestita dal middleware in `cerbero_mcp.auth`; qui leggiamo solo `request.state.environment`. """ from __future__ import annotations from typing import Literal, cast from fastapi import APIRouter, Depends, Request from cerbero_mcp.client_registry import ClientRegistry from cerbero_mcp.common.audit_helpers import audit_call from cerbero_mcp.exchanges.deribit import tools as t from cerbero_mcp.exchanges.deribit.client import DeribitClient Environment = Literal["testnet", "mainnet"] def get_environment(request: Request) -> Environment: return cast(Environment, request.state.environment) async def get_deribit_client( request: Request, env: Environment = Depends(get_environment) ) -> DeribitClient: registry: ClientRegistry = request.app.state.registry return cast(DeribitClient, await registry.get("deribit", env)) def _build_creds(request: Request) -> dict: """Costruisce dict `creds` minimale per leverage cap / metadata. Le credenziali vere sono già iniettate nel client da ClientRegistry; qui passiamo solo il cap di leverage e il client_id (metadata audit). """ settings = request.app.state.settings return { "max_leverage": settings.deribit.max_leverage, "client_id": settings.deribit.client_id, } def make_router() -> APIRouter: r = APIRouter(prefix="/mcp-deribit", tags=["deribit"]) # === READ tools === @r.post("/tools/is_testnet") async def _is_testnet(client: DeribitClient = Depends(get_deribit_client)): return await t.is_testnet(client) @r.post("/tools/environment_info") async def _environment_info( request: Request, client: DeribitClient = Depends(get_deribit_client), ): creds = _build_creds(request) return await t.environment_info(client, creds=creds) @r.post("/tools/get_ticker") async def _get_ticker( params: t.GetTickerReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_ticker(client, params) @r.post("/tools/get_ticker_batch") async def _get_ticker_batch( params: t.GetTickerBatchReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_ticker_batch(client, params) @r.post("/tools/get_instruments") async def _get_instruments( params: t.GetInstrumentsReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_instruments(client, params) @r.post("/tools/get_orderbook") async def _get_orderbook( params: t.GetOrderbookReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_orderbook(client, params) @r.post("/tools/get_orderbook_imbalance") async def _get_orderbook_imbalance( params: t.OrderbookImbalanceReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_orderbook_imbalance(client, params) @r.post("/tools/get_positions") async def _get_positions( params: t.GetPositionsReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_positions(client, params) @r.post("/tools/get_account_summary") async def _get_account_summary( params: t.GetAccountSummaryReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_account_summary(client, params) @r.post("/tools/get_trade_history") async def _get_trade_history( params: t.GetTradeHistoryReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_trade_history(client, params) @r.post("/tools/get_historical") async def _get_historical( params: t.GetHistoricalReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_historical(client, params) @r.post("/tools/get_dvol") async def _get_dvol( params: t.GetDvolReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_dvol(client, params) @r.post("/tools/get_gex") async def _get_gex( params: t.GetGexReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_gex(client, params) @r.post("/tools/get_dealer_gamma_profile") async def _get_dealer_gamma_profile( params: t.OptionFlowReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_dealer_gamma_profile(client, params) @r.post("/tools/get_vanna_charm") async def _get_vanna_charm( params: t.OptionFlowReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_vanna_charm(client, params) @r.post("/tools/get_oi_weighted_skew") async def _get_oi_weighted_skew( params: t.OptionFlowReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_oi_weighted_skew(client, params) @r.post("/tools/get_smile_asymmetry") async def _get_smile_asymmetry( params: t.OptionFlowReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_smile_asymmetry(client, params) @r.post("/tools/get_atm_vs_wings_vol") async def _get_atm_vs_wings_vol( params: t.OptionFlowReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_atm_vs_wings_vol(client, params) @r.post("/tools/get_pc_ratio") async def _get_pc_ratio( params: t.GetPcRatioReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_pc_ratio(client, params) @r.post("/tools/get_skew_25d") async def _get_skew_25d( params: t.GetSkew25dReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_skew_25d(client, params) @r.post("/tools/get_term_structure") async def _get_term_structure( params: t.GetTermStructureReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_term_structure(client, params) @r.post("/tools/run_backtest") async def _run_backtest( params: t.RunBacktestReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.run_backtest(client, params) @r.post("/tools/calculate_spread_payoff") async def _calculate_spread_payoff( params: t.CalculateSpreadPayoffReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.calculate_spread_payoff(client, params) @r.post("/tools/find_by_delta") async def _find_by_delta( params: t.FindByDeltaReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.find_by_delta(client, params) @r.post("/tools/get_iv_rank") async def _get_iv_rank( params: t.GetIvRankReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_iv_rank(client, params) @r.post("/tools/get_dvol_history") async def _get_dvol_history( params: t.GetDvolHistoryReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_dvol_history(client, params) @r.post("/tools/get_realized_vol") async def _get_realized_vol( params: t.GetRealizedVolReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_realized_vol(client, params) @r.post("/tools/get_technical_indicators") async def _get_technical_indicators( params: t.GetIndicatorsReq, client: DeribitClient = Depends(get_deribit_client), ): return await t.get_technical_indicators(client, params) # === WRITE tools (richiedono creds per leverage cap / audit) === @r.post("/tools/place_order") async def _place_order( params: t.PlaceOrderReq, request: Request, client: DeribitClient = Depends(get_deribit_client), ): creds = _build_creds(request) return await audit_call( request=request, exchange="deribit", action="place_order", target_field="instrument_name", params=params, tool_fn=lambda: t.place_order(client, params, creds=creds), ) @r.post("/tools/place_combo_order") async def _place_combo_order( params: t.PlaceComboOrderReq, request: Request, client: DeribitClient = Depends(get_deribit_client), ): creds = _build_creds(request) return await audit_call( request=request, exchange="deribit", action="place_combo_order", params=params, tool_fn=lambda: t.place_combo_order(client, params, creds=creds), ) @r.post("/tools/cancel_order") async def _cancel_order( params: t.CancelOrderReq, request: Request, client: DeribitClient = Depends(get_deribit_client), ): return await audit_call( request=request, exchange="deribit", action="cancel_order", target_field="order_id", params=params, tool_fn=lambda: t.cancel_order(client, params), ) @r.post("/tools/set_stop_loss") async def _set_stop_loss( params: t.SetStopLossReq, request: Request, client: DeribitClient = Depends(get_deribit_client), ): return await audit_call( request=request, exchange="deribit", action="set_stop_loss", target_field="order_id", params=params, tool_fn=lambda: t.set_stop_loss(client, params), ) @r.post("/tools/set_take_profit") async def _set_take_profit( params: t.SetTakeProfitReq, request: Request, client: DeribitClient = Depends(get_deribit_client), ): return await audit_call( request=request, exchange="deribit", action="set_take_profit", target_field="order_id", params=params, tool_fn=lambda: t.set_take_profit(client, params), ) @r.post("/tools/close_position") async def _close_position( params: t.ClosePositionReq, request: Request, client: DeribitClient = Depends(get_deribit_client), ): return await audit_call( request=request, exchange="deribit", action="close_position", target_field="instrument_name", params=params, tool_fn=lambda: t.close_position(client, params), ) return r