nautechsystems/nautilus_trader · error · anyhow::Error

Binance Futures GTD requires an expire_time

Error message

Binance Futures GTD requires an expire_time

What it means

A GTD order with use_gtd=true must carry an expire_time (UnixNanos); determine_futures_order_lifetime uses anyhow's context to convert a None expire_time into this error. Without a timestamp the adapter cannot compute Binance's goodTillDate parameter.

Source

Thrown at crates/adapters/binance/src/futures/execution.rs:1510

    }

    anyhow::ensure!(
        matches!(
            order_type,
            OrderType::Limit | OrderType::StopLimit | OrderType::LimitIfTouched
        ),
        "Binance Futures does not support GTD for order type {order_type:?}"
    );
    anyhow::ensure!(!post_only, "Binance Futures GTD cannot be post-only");

    anyhow::ensure!(
        product_type == BinanceProductType::UsdM,
        "Binance {product_type:?} Futures does not support native GTD"
    );

    let expire_time = expire_time.context("Binance Futures GTD requires an expire_time")?;
    let expire_ns = expire_time.as_u64();
    anyhow::ensure!(
        expire_ns.is_multiple_of(NANOSECONDS_IN_SECOND),
        "Binance Futures goodTillDate requires whole-second precision"
    );

    let minimum_ns = ts_now
        .as_u64()
        .checked_add(BINANCE_GTD_MIN_LEAD_SECS * NANOSECONDS_IN_SECOND)
        .context("Binance Futures GTD minimum timestamp overflow")?;
    anyhow::ensure!(
        expire_ns > minimum_ns,
        "Binance Futures goodTillDate must be strictly greater than current time plus {BINANCE_GTD_MIN_LEAD_SECS} seconds"
    );

    let good_till_date = expire_ns / NANOSECONDS_IN_MILLISECOND;
    anyhow::ensure!(
        good_till_date < BINANCE_GTD_MAX_MILLIS,
        "Binance Futures goodTillDate must be smaller than {BINANCE_GTD_MAX_MILLIS}"
    );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass the expire_time (UnixNanos) when creating the GTD order in the OrderFactory.
  2. Enable manage_gtd_expiry on the submitting strategy so expiries are tracked and supplied.
  3. Use TimeInForce Gtc if no expiry timestamp is available.
  4. Verify the order's expire_time was not lost during serialization/replay before submission.

Example fix

// before
order_factory.limit(instrument_id, Side::Buy, price, qty, TimeInForce::Gtd, None);
// after
order_factory.limit(instrument_id, Side::Buy, price, qty, TimeInForce::Gtd, Some(expire_time_ns));
Defensive patterns

Strategy: validation

Validate before calling

if tif == TimeInForce::Gtd && use_gtd && expire_time.is_none() {
    return Err("GTD order submitted without expire_time");
}

Try / catch

match exec_client.generate_order_status_reports(None, ts_now).await {
    Ok(_) => {},
    Err(e) if e.to_string().contains("expire_time") => log::warn!("order missing GTD expiry"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: validate_order / build_futures_order_list_batch with TimeInForce=Gtd, use_gtd=true, post_only=false, product_type UsdM, order type Limit/StopLimit/LimitIfTouched — but the order/request has expire_time=None (e.g. order factory called without the expiry argument).

Common situations: Order factory calls where the expire_time argument was omitted or defaulted to None; strategies where time_in_force is Gtd but expiry handling was delegated away (no manage_gtd_expiry) losing the timestamp; deserialized orders that dropped the expire field.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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