{"record":{"id":"f0189318926926af","repo":"nautechsystems/nautilus_trader","slug":"binance-futures-goodtilldate-must-be-strictly-grea","errorCode":null,"errorMessage":"Binance Futures goodTillDate must be strictly greater than current time plus {BINANCE_GTD_MIN_LEAD_SECS} seconds","messagePattern":"Binance Futures goodTillDate must be strictly greater than current time plus (.+?) seconds","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/execution.rs","lineNumber":1525,"sourceCode":"\n    let expire_time = expire_time.context(\"Binance Futures GTD requires an expire_time\")?;\n    let expire_ns = expire_time.as_u64();\n    anyhow::ensure!(\n        expire_ns.is_multiple_of(NANOSECONDS_IN_SECOND),\n        \"Binance Futures goodTillDate requires whole-second precision\"\n    );\n\n    let minimum_ns = ts_now\n        .as_u64()\n        .checked_add(BINANCE_GTD_MIN_LEAD_SECS * NANOSECONDS_IN_SECOND)\n        .context(\"Binance Futures GTD minimum timestamp overflow\")?;\n    anyhow::ensure!(\n        expire_ns > minimum_ns,\n        \"Binance Futures goodTillDate must be strictly greater than current time plus {BINANCE_GTD_MIN_LEAD_SECS} seconds\"\n    );\n\n    let good_till_date = expire_ns / NANOSECONDS_IN_MILLISECOND;\n    anyhow::ensure!(\n        good_till_date < BINANCE_GTD_MAX_MILLIS,\n        \"Binance Futures goodTillDate must be smaller than {BINANCE_GTD_MAX_MILLIS}\"\n    );\n\n    Ok(FuturesOrderLifetime {\n        time_in_force,\n        good_till_date: Some(i64::try_from(good_till_date)?),\n    })\n}\n\nfn is_grouped_order(order: &OrderAny) -> bool {\n    order.contingency_type().is_some()\n        || order\n            .linked_order_ids()\n            .is_some_and(|linked_order_ids| !linked_order_ids.is_empty())\n}\n\nfn binance_side_wire(side: BinanceSide) -> &'static str {","sourceCodeStart":1507,"sourceCodeEnd":1543,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/binance/src/futures/execution.rs#L1507-L1543","documentation":"This error is raised by determine_futures_order_lifetime in the Binance Futures execution client when a GTD (Good-Till-Date) order's expire_time is not far enough in the future. Binance requires the native goodTillDate timestamp to be strictly greater than the current time plus BINANCE_GTD_MIN_LEAD_SECS, so NautilusTrader validates this locally before submitting and rejects orders that would be immediately rejected or misinterpreted by the exchange. It is a pre-submission sanity check to avoid a guaranteed API rejection.","triggerScenarios":"Submitting a Limit/StopLimit/LimitIfTouched order with TimeInForce::Gtd and manage_gtd_expiry enabled (use_gtd=true) on USD-M Futures where expire_time is set to now, in the past, or within BINANCE_GTD_MIN_LEAD_SECS seconds of now. Also hit by validate_order paths and batch order building when a strategy computes expire_time from a stale clock value.","commonSituations":"A strategy sets a GTD expiry too close to 'now' (e.g. expire = now + a few seconds), backtest logic reuses a cached timestamp, clock skew between the machine and exchange time, or a config where expire_time was computed before a long preprocessing delay so it is stale by submission time.","solutions":["Set the order's expire_time (TIF GTD) to strictly more than BINANCE_GTD_MIN_LEAD_SECS seconds in the future relative to submission time.","Compute expire_time as close to submit as possible, e.g. using the live clock (clock.timestamp_ns()) rather than a cached value captured earlier in the strategy.","If you do not need native exchange-side expiry, disable manage_gtd_expiry / set use_gtd=false so GTD orders are downgraded to GTC with a warning instead of an error.","Check machine clock synchronization (NTP) if expire_time appears correct but still fails."],"exampleFix":"// before\nlet expire = self.clock.timestamp_ns() + 5_000_000_000; // 5s lead, too short\norder_factory.limit(..., time_in_force=TimeInForce::Gtd, expire_time=expire);\n\n// after\nlet expire = self.clock.timestamp_ns() + 120_000_000_000; // >= BINANCE_GTD_MIN_LEAD_SECS + margin\norder_factory.limit(..., time_in_force=TimeInForce::Gtd, expire_time=expire);","handlingStrategy":"validation","validationCode":"const MIN_LEAD_SECS: u64 = /* BINANCE_GTD_MIN_LEAD_SECS */;\nlet now_ns = clock.timestamp_ns().as_u64();\nanyhow::ensure!(\n    expire_ns > now_ns + MIN_LEAD_SECS * 1_000_000_000,\n    \"GTD expire_time must exceed now + {MIN_LEAD_SECS}s\"\n);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always compute GTD expire_time from the live clock immediately before submission","Add generous margin (minutes, not seconds) above the minimum lead time","Use manage_gtd_expiry=false if native exchange expiry is not required"],"tags":["binance","gtd","time-in-force","validation","order-expiry"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}