nautechsystems/nautilus_trader · error
expected a COIN-M definition for {instrument_id}
Error message
expected a COIN-M definition for {instrument_id} What it means
When resolving COIN-M open-interest-history request parameters, symbols ending in `_PERP` short-circuit to the pair/`PERPETUAL` tuple; every other symbol is looked up in the client's instruments cache and must yield a `BinanceFuturesInstrument::CoinM` definition. This error means a definition WAS found in the cache but it is a different variant (USD-M), so `pair` and `contract_type` cannot be extracted for the COIN-M endpoint. (A missing cache entry produces the separate 'missing COIN-M definition' context error.)
Source
Thrown at crates/adapters/binance/src/futures/data.rs:468
Ok(period.to_string())
}
fn coinm_open_interest_hist_params(
http: &BinanceFuturesHttpClient,
instrument_id: &InstrumentId,
) -> anyhow::Result<(String, String)> {
let symbol = format_binance_symbol(instrument_id);
if let Some(pair) = symbol.strip_suffix("_PERP") {
return Ok((pair.to_string(), "PERPETUAL".to_string()));
}
let cache = http.instruments_cache();
let definition = cache
.get(&Ustr::from(symbol.as_str()))
.with_context(|| format!("missing COIN-M definition for {instrument_id}"))?;
let BinanceFuturesInstrument::CoinM(definition) = definition.value() else {
anyhow::bail!("expected a COIN-M definition for {instrument_id}");
};
Ok((
definition.pair.to_string(),
definition.contract_type.clone(),
))
}
fn parse_open_interest_decimal(field: &str, value: &str) -> anyhow::Result<Decimal> {
Decimal::from_str_exact(value)
.with_context(|| format!("invalid Binance open interest `{field}` value `{value}`"))
}
fn liquidation_data_type(instrument_id: InstrumentId) -> DataType {
let mut metadata = Params::new();
metadata.insert(
"instrument_id".to_string(),
serde_json::Value::String(instrument_id.to_string()),View on GitHub (pinned to a4b06ed870)
Solutions
- Use a genuine COIN-M instrument id — `BTCUSD_PERP.BINANCE` (short-circuits, no cache lookup) or a dated COIN-M contract like `BTCUSD_250627.BINANCE`
- Make sure the data client's market/instrument_provider configuration matches the instruments you request (COIN-M provider config for COIN-M requests) so the cache holds CoinM definitions
- Verify the instrument definitions were loaded before the request (instruments are fetched via HTTP on connect); request after connect completes
Example fix
# before: USD-M symbol hits the COIN-M definition lookup and fails
meta = {'instrument_id': 'BTCUSDT-PERP.BINANCE', 'period': '1h'}
# after: COIN-M PERP symbol short-circuits to (BTCUSD, PERPETUAL)
meta = {'instrument_id': 'BTCUSD_PERP.BINANCE', 'period': '1h'} Defensive patterns
Strategy: validation
Validate before calling
def is_coinm_instrument_id(instrument_id) -> bool:
sym = instrument_id.symbol.value # e.g. BTCUSD_PERP, BTCUSD_250627, BTCUSDT-PERP
if sym.endswith('_PERP') and not sym.endswith(('USDT_PERP', 'USDC_PERP')):
return True # COIN-M perpetual short-circuits without cache lookup
# dated COIN-M futures look like <BASE>USD_YYMMDD and never quote USDT/USDC
return sym.endswith('USD') and not sym.endswith(('USDT', 'USDC', 'BUSD'))
if not is_coinm_instrument_id(instrument_id):
raise ValueError(f'{instrument_id} is not a COIN-M instrument; use e.g. BTCUSD_PERP.BINANCE') Type guard
def is_coinm_symbol(symbol: str) -> bool:
return symbol.endswith('_PERP') or (symbol.endswith('USD') and not symbol.endswith(('USDT', 'USDC', 'BUSD'))) Try / catch
try:
actor.request_custom_data(data_type, ...)
except Exception as e:
msg = str(e)
if 'expected a COIN-M definition' in msg:
raise ValueError(f'{instrument_id} resolved to a USD-M definition on the COIN-M path; use a COIN-M symbol like BTCUSD_PERP') from e
raise Prevention
- Keep USD-M (…USDT/USDC symbols) and COIN-M (…USD symbols) instruments in separate, clearly named config lists
- Ensure the client's market/instrument_provider settings match the instruments you request so the cache holds the right variant
- For COIN-M PERPs prefer symbols ending in _PERP — they bypass the cache lookup entirely
When it happens
Trigger: Requesting `BinanceFuturesOpenInterestHist` on the COIN-M request path for a non-PERP symbol whose formatted symbol resolves to a USD-M instrument definition in the cache — e.g. a USD-M style symbol such as `BTCUSDT...` routed through `coinm_open_interest_hist_params`. Also possible when the instrument provider loaded USD-M definitions under a symbol the COIN-M path then looks up.
Common situations: Using a USD-M instrument id (BTCUSDT-PERP.BINANCE) with a client/market configured for COIN-M; dated COIN-M futures (e.g. BTCUSD_250627) whose definitions were never loaded or were loaded from the wrong market's exchange info; switching `market` in config while the instruments cache still holds definitions from the other market.
Related errors
- historical open interest request requires `period` metadata
- Binance Futures custom data requires BINANCE venue instrumen
- Invalid price_match value: {s:?}
- Unsupported underlying type '{underlying_type}' for TRADIFI_
- callbackRate {rate}% out of Binance range [{min_rate}, {max_
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/859cab73d2edc104.
Report an issue: GitHub.