nautechsystems/nautilus_trader · error · anyhow::Error

Binance Spot does not support native GTD; set use_gtd=false…

Error message

Binance Spot does not support native GTD; set use_gtd=false and enable manage_gtd_expiry on the submitting strategy

What it means

Binance Spot does not support native GTD (Good-Til-Date) time-in-force. `time_in_force_to_binance_spot` rejects `TimeInForce::Gtd` when `use_gtd` is true, telling the caller to disable native GTD (`use_gtd=false`, so GTD is downgraded to GTC) and enable `manage_gtd_expiry` on the submitting strategy so expiry is enforced locally.

Solutions

  1. Set `use_gtd=false` on the Binance Spot exec client config so GTD orders are submitted as GTC with a warning
  2. Enable `manage_gtd_expiry` on the submitting strategy so it cancels the order at expiry locally
  3. Change the strategy to use `TimeInForce::Gtc` or `Ioc`/`Fok` directly instead of Gtd on Spot
  4. Route GTD-dependent strategies to Binance USDT-M Futures, which supports native GTD

Example fix

// before
ExecClientConfig { use_gtd: true, /* strategy submits TimeInForce::Gtd */ }
// after
ExecClientConfig { use_gtd: false }; // + strategy config: manage_gtd_expiry=True
Defensive patterns

Strategy: validation

Validate before calling

fn validate_spot_tif(tif: TimeInForce, use_gtd: bool) -> Result<(), String> {
    if tif == TimeInForce::Gtd && use_gtd {
        return Err("Binance Spot needs use_gtd=false plus manage_gtd_expiry for GTD orders".into());
    }
    Ok(())
}

Type guard

fn is_spot_supported_tif(tif: TimeInForce) -> bool {
    matches!(tif, TimeInForce::Gtc | TimeInForce::Ioc | TimeInForce::Fok
        | TimeInForce::Gtd /* only with use_gtd=false */)
}

Try / catch

match exec_client.submit_order(order) {
    Err(e) if e.to_string().contains("does not support native GTD") => {
        log::warn!("resubmitting GTD order as GTC with local expiry management");
        exec_client.set_use_gtd(false);
        strategy.manage_gtd_expiry = true;
        exec_client.submit_order(order)?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Submitting, modifying, or building params for an order with `TimeInForce::Gtd` via `submit_order` / `modify_order` / `build_new_order_params` / `build_cancel_replace_params` while the exec client's `use_gtd` option is enabled (default true).

Common situations: Reusing a strategy written for Binance Futures (which supports native GTD) on Spot; leaving adapter `use_gtd` at its default while the strategy sets GTD expiry; porting crypto strategies that rely on exchange-side order expiry.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/8dbb3bab51665191. Report an issue: GitHub.

Appendix: source

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

///
/// # Errors
///
/// 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)]

View on GitHub (pinned to 18893faf8b)