nautechsystems/nautilus_trader · error · anyhow::Error

Binance Futures goodTillDate requires whole-second precision

Error message

Binance Futures goodTillDate requires whole-second precision

What it means

Binance Futures goodTillDate must be expressed in whole-second precision (millisecond field derived from a second-aligned nanosecond timestamp). If the expire_time nanosecond value is not an exact multiple of one second, the adapter rejects the order rather than silently rounding the expiry, which could expire the order at a different time than the strategy intended.

Solutions

  1. Round the expire_time down (or up) to a whole second before submitting: expire_ns - (expire_ns % 1_000_000_000).
  2. Construct expiries from whole-second Unix timestamps in the strategy.
  3. Ensure any lead-time/latency adjustments applied to expire_time are whole seconds.
  4. Verify timestamps crossing from external systems are normalized to second precision.

Example fix

// before
let expire = ts_now + 90_500_000_000; // 90.5s -> sub-second precision
// after
let expire = (ts_now + 90_000_000_000) / 1_000_000_000 * 1_000_000_000; // whole seconds
Defensive patterns

Strategy: validation

Validate before calling

fn second_aligned(ns: u64) -> bool { ns % 1_000_000_000 == 0 }
let expire_ns = expire_time.as_u64();
if !second_aligned(expire_ns) { /* round to whole second before submit */ }

Prevention

When it happens

Trigger: validate_order / build_futures_order_list_batch with GTD and use_gtd=true where expire_time.as_u64() % 1_000_000_000 != 0 — e.g. expiry computed from a data timestamp, latency-adjusted time, or arbitrary duration addition carrying sub-second nanoseconds.

Common situations: expire_time computed as now + duration (including fractional seconds); expiries derived from bar close timestamps with sub-second resolution; timestamps generated on a different clock resolution and passed unrounded.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

    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}"
    );

    Ok(FuturesOrderLifetime {
        time_in_force,
        good_till_date: Some(i64::try_from(good_till_date)?),
    })
}

fn is_grouped_order(order: &OrderAny) -> bool {
    order.contingency_type().is_some()

View on GitHub (pinned to 18893faf8b)