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's goodTillDate is expressed in milliseconds with second granularity, so the client requires the order's expire_time (UnixNanos) to be a whole number of seconds — expire_ns must be a multiple of 1_000_000_000. Any sub-second component (nanoseconds remainder) makes the request unrepresentable and the lifetime resolution fails fast rather than silently truncating the expiry.
Source
Thrown at crates/adapters/binance/src/futures/execution.rs:1188
}
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 a4b06ed870)
Solutions
- Round the expire_time down (or up, mind the minimum lead) to whole seconds before submitting
- Build expiries as seconds-precision datetimes (e.g. UnixNanos from a second-aligned timestamp)
- Check the remainder: expire_ns % 1_000_000_000 == 0
Example fix
// before let expire = UnixNanos::now().checked_add(15 * 60 * 1_000_000_000)?; // may carry ns remainder // after const NS_PER_SEC: u64 = 1_000_000_000; let expire = UnixNanos::from((UnixNanos::now().as_u64() / NS_PER_SEC + 15 * 60) * NS_PER_SEC);
Defensive patterns
Strategy: validation
Validate before calling
const NS_PER_SEC: u64 = 1_000_000_000; let ns = expire_time.as_u64(); anyhow::ensure!(ns.is_multiple_of(NS_PER_SEC), "expire_time must be whole seconds"); // or normalize first: expire = (ns / NS_PER_SEC) * NS_PER_SEC;
Type guard
fn is_whole_second_expiry(ns: u64) -> bool {
ns.is_multiple_of(1_000_000_000)
} Prevention
- Always construct expiries from second-aligned timestamps (e.g. datetime truncated to seconds)
- Add an assertion helper for expiry invariants used by every strategy setting GTD
When it happens
Trigger: Setting an expire_time derived from a sub-second-precise timestamp, e.g. now + 15*60*1e9 + 123ms of drift from a nanosecond clock, or a datetime parsed with millisecond/microsecond fractions.
Common situations: Expiries computed from UnixNanos::now() plus an offset without rounding; expiry datetimes from configs or external systems that carry fractional seconds.
Related errors
- Binance Futures goodTillDate must be strictly greater than c
- Binance Futures goodTillDate must be smaller than {BINANCE_G
- Binance Futures does not support GTD for order type {order_t
- Binance Futures GTD cannot be post-only
- Binance {product_type:?} Futures does not support native GTD
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/b1e8e7adc39c2212.
Report an issue: GitHub.