nautechsystems/nautilus_trader · error
GTD time in force requires expire_time parameter
Error message
GTD time in force requires expire_time parameter
What it means
Kraken spot order TIF mapping requires a GTD order to carry an expiry time. When a request specifies `TimeInForce::Gtd` but `expire_time` is `None`, this anyhow error is returned instead of producing GTD parameters. It enforces that GTD orders always include a concrete expiration.
Source
Thrown at crates/adapters/kraken/src/http/spot/client.rs:3252
.unwrap_or_else(|| Currency::new(normalized, 2, 0, normalized, CurrencyType::Fiat))
}
fn compute_time_in_force(
is_limit_order: bool,
time_in_force: TimeInForce,
expire_time: Option<UnixNanos>,
) -> anyhow::Result<(Option<String>, Option<String>)> {
if !is_limit_order {
return Ok((None, None));
}
match time_in_force {
TimeInForce::Gtc => Ok((None, None)),
TimeInForce::Ioc => Ok((Some("IOC".to_string()), None)),
TimeInForce::Fok => Ok((Some("FOK".to_string()), None)),
TimeInForce::Gtd => {
let expire = expire_time.ok_or_else(|| {
anyhow::anyhow!("GTD time in force requires expire_time parameter")
})?;
let expire_secs = expire.as_u64() / NANOSECONDS_IN_SECOND;
Ok((Some("GTD".to_string()), Some(expire_secs.to_string())))
}
_ => anyhow::bail!("Unsupported time in force: {time_in_force:?}"),
}
}
#[cfg(test)]
mod tests {
use std::{sync::Arc, time::Duration};
use nautilus_model::instruments::CurrencyPair;
use rstest::rstest;
use super::*;
#[rstest]View on GitHub (pinned to 18893faf8b)
Solutions
- Set `expire_time` (Unix nanoseconds) on the order request when using GTD.
- Use `TimeInForce::Gtc` instead if the order should not expire.
- Ensure the order factory/strategy populates `expire_time` for all GTD orders before submission.
Example fix
// before let tif = TimeInForce::Gtd; // expire_time: None // after let tif = TimeInForce::Gtd; let expire_time = Some(UnixNanos::from(expiry_ts_unix_ns));
Defensive patterns
Strategy: validation
Validate before calling
fn validate_gtd(tif: TimeInForce, expire_time: Option<u64>) -> Result<(), String> {
if tif == TimeInForce::Gtd && expire_time.is_none() {
Err("GTD orders require expire_time".into())
} else { Ok(()) }
} Type guard
fn has_expiry(o: &OrderRequest) -> bool {
o.time_in_force != TimeInForce::Gtd || o.expire_time.is_some()
} Try / catch
match client.submit_order(req).await {
Err(e) if e.to_string().contains("GTD time in force requires expire_time") => {
let mut req = req.clone();
req.expire_time = Some(default_expiry_unix_ns());
client.submit_order(&req).await.map_err(Into::into)
}
other => other,
} Prevention
- Configure the order factory to always set expire_time for GTD orders
- Prefer GTC when no natural expiry exists in strategy logic
- Validate TIF/expiry consistency in strategy pre-trade checks
When it happens
Trigger: Submitting or amending an order with time_in_force = GTD while the request's `expire_time` field is None/unset; converting a Nautilus GTD order whose `expire_time` was never populated.
Common situations: Strategy configured GTD without setting an expiry; order factory created GTD orders relying on defaults that don't exist; upstream code dropped expire_time when translating order requests.
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
- Unsupported time in force: {time_in_force:?}
- Binance Futures goodTillDate must be smaller than {BINANCE_G
- Binance Spot does not support native GTD; set use_gtd=false
- unsupported time in force for Derive: {other:?}
- limit_price is required for order type {order_type:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/4311c076dd2f38c0.
Report an issue: GitHub.