nautechsystems/nautilus_trader · error · anyhow::Error

Unsupported time in force for Binance Spot: {tif:?}

Error message

Unsupported time in force for Binance Spot: {tif:?}

What it means

time_in_force_to_binance_spot accepts only GTC, IOC and FOK (plus GTD under the use_gtd downgrade rule). Binance Spot has no equivalent for other Nautilus TimeInForce variants such as DAY, AT_THE_OPEN or AT_THE_CLOSE, so the conversion bails for anything else.

Source

Thrown at crates/adapters/binance/src/spot/enums.rs:144

/// Returns an error if the time in force is not supported on Binance Spot.
pub fn time_in_force_to_binance_spot(
    tif: TimeInForce,
    use_gtd: bool,
) -> anyhow::Result<BinanceTimeInForce> {
    match tif {
        TimeInForce::Gtc => Ok(BinanceTimeInForce::Gtc),
        TimeInForce::Ioc => Ok(BinanceTimeInForce::Ioc),
        TimeInForce::Fok => Ok(BinanceTimeInForce::Fok),
        TimeInForce::Gtd if !use_gtd => {
            log::warn!(
                "Binance Spot does not support GTD; submitting as GTC because use_gtd=false. Enable manage_gtd_expiry on the submitting strategy"
            );
            Ok(BinanceTimeInForce::Gtc)
        }
        TimeInForce::Gtd => anyhow::bail!(
            "Binance Spot does not support native GTD; set use_gtd=false and enable manage_gtd_expiry on the submitting strategy"
        ),
        _ => anyhow::bail!("Unsupported time in force for Binance Spot: {tif:?}"),
    }
}

#[cfg(test)]
mod tests {
    use rstest::rstest;

    use super::*;

    #[rstest]
    #[case(OrderType::Market, false, BinanceSpotOrderType::Market)]
    #[case(OrderType::Limit, false, BinanceSpotOrderType::Limit)]
    #[case(OrderType::Limit, true, BinanceSpotOrderType::LimitMaker)]
    #[case(OrderType::StopMarket, false, BinanceSpotOrderType::StopLoss)]
    #[case(OrderType::StopLimit, false, BinanceSpotOrderType::StopLossLimit)]
    #[case(OrderType::MarketIfTouched, false, BinanceSpotOrderType::TakeProfit)]
    #[case(
        OrderType::LimitIfTouched,

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Use GTC (open-ended), IOC or FOK on Binance Spot
  2. Map DAY semantics to GTC plus a strategy-side cancellation at session end
  3. Pre-validate time_in_force against the supported set before creating orders

Example fix

# before
order = self.order_factory.limit(..., time_in_force=TimeInForce.DAY)

# after
order = self.order_factory.limit(..., time_in_force=TimeInForce.GTC)
# strategy cancels remaining quantity at session end
Defensive patterns

Strategy: type-guard

Validate before calling

fn ensure_supported_spot_tif(tif: TimeInForce) -> anyhow::Result<()> {
    anyhow::ensure!(
        matches!(tif, TimeInForce::Gtc | TimeInForce::Ioc | TimeInForce::Fok),
        "time in force {tif:?} is not available on Binance Spot"
    );
    Ok(())
}

Type guard

fn is_supported_binance_spot_tif(tif: TimeInForce) -> bool {
    matches!(tif, TimeInForce::Gtc | TimeInForce::Ioc | TimeInForce::Fok)
}

Try / catch

match submit_order(cmd) {
    Err(e) if e.to_string().contains("Unsupported time in force for Binance Spot") => {
        self.emitter.emit_order_denied(&order, &e.to_string());
    }
    other => other?,
}

Prevention

When it happens

Trigger: Submitting an order with any TimeInForce other than Gtc/Ioc/Fok/Gtd — e.g. TimeInForce::Day — through submit, modify or order-list paths that build venue params.

Common situations: Porting equity-style strategies that use DAY orders; sharing an order factory across venues where DAY is valid; typo'd or defaulted TIF fields from config files.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/c6b6833cc8f3aeda. Report an issue: GitHub.