{"record":{"id":"122c8b51303ca120","repo":"nautechsystems/nautilus_trader","slug":"funding-rates-are-only-available-for-perpetual-ins","errorCode":null,"errorMessage":"Funding rates are only available for perpetual instruments","messagePattern":"Funding rates are only available for perpetual instruments","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/hyperliquid/src/data.rs","lineNumber":1435,"sourceCode":"                log::error!(\"Failed to send public trades response: {e}\");\n            }\n            Ok(())\n        });\n\n        Ok(())\n    }\n\n    fn request_funding_rates(&self, request: RequestFundingRates) -> anyhow::Result<()> {\n        let instrument_id = request.instrument_id;\n        log::debug!(\"Requesting funding rates for {instrument_id}\");\n\n        let instruments = self.instruments.load();\n        let instrument = instruments\n            .get(&instrument_id)\n            .ok_or_else(|| InstrumentLookupError::not_found(instrument_id))?;\n\n        if !matches!(instrument, InstrumentAny::CryptoPerpetual(_)) {\n            anyhow::bail!(\"Funding rates are only available for perpetual instruments\");\n        }\n\n        let coin = instrument.raw_symbol().to_string();\n        let http = self.http_client.clone();\n        let sender = self.data_sender.clone();\n        let client_id = request.client_id.unwrap_or(self.client_id);\n        let request_id = request.request_id;\n        let params = request.params;\n        let clock = self.clock;\n        let limit = request.limit.map(|n| n.get());\n        let start_dt = request.start;\n        let end_dt = request.end;\n        let start_nanos = datetime_to_unix_nanos(start_dt);\n        let end_nanos = datetime_to_unix_nanos(end_dt);\n\n        let now_ms = Timestamp::now().as_millisecond() as u64;\n\n        // Hyperliquid requires a startTime; default to a 7-day lookback when none given","sourceCodeStart":1417,"sourceCodeEnd":1453,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/hyperliquid/src/data.rs#L1417-L1453","documentation":"The Hyperliquid data adapter only serves funding rates for perpetual instruments, since funding rates are a perpetual-futures concept (periodic payments between longs and shorts). The adapter checks that the requested instrument is a CryptoPerpetual and bails with this error otherwise (spot tokens, outcomes, etc. are rejected).","triggerScenarios":"Calling request_funding_rates with an instrument_id that resolves to a non-perpetual instrument — e.g. a Hyperliquid spot token like ARB/USDC or a HIP-4 outcome token — after the instrument has been successfully loaded into the adapter's instrument cache.","commonSituations":"Requesting funding rates for every instrument in a portfolio that mixes spot and perp positions; using a spot symbol string that looks valid but has no perpetual equivalent; subscribing funding data for a symbol that only trades spot on Hyperliquid.","solutions":["Verify the instrument is a CryptoPerpetual before requesting funding rates (check instrument type in the cache/catalog).","Use the perpetual symbol (e.g. the raw symbol without spot suffix) when requesting funding rates.","Route spot instruments to a different data request (trades/bars) instead of funding rates.","If the symbol genuinely trades as a perp on Hyperliquid, confirm the adapter's instrument loading picked up the perpetual definition, not a spot one."],"exampleFix":"// before\nlet rates = adapter.request_funding_rates(request).await?;\n// after\nlet instrument = adapter.instruments().get(&request.instrument_id)?;\nif matches!(instrument, nautilus_model::instruments::InstrumentAny::CryptoPerpetual(_)) {\n    let rates = adapter.request_funding_rates(request).await?;\n} else {\n    log::warn!(\"skipping funding rates for non-perp {instrument}\");\n}","handlingStrategy":"validation","validationCode":"fn is_perp(instrument: &InstrumentAny) -> bool {\n    matches!(instrument, InstrumentAny::CryptoPerpetual(_))\n}","typeGuard":"fn as_perp(instrument: &InstrumentAny) -> Option<&CryptoPerpetual> {\n    match instrument { InstrumentAny::CryptoPerpetual(p) => Some(p), _ => None }\n}","tryCatchPattern":null,"preventionTips":["Check instrument type before requesting funding rates","Only request funding data for perpetual symbol IDs","Keep a list of perp-only data capabilities per venue"],"tags":["rust","hyperliquid","funding-rates","unsupported-instrument"],"backgroundTag":"unsupported-operation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}