{"record":{"id":"3ea90ccd0c5a86ce","repo":"nautechsystems/nautilus_trader","slug":"gtd-time-in-force-requires-expire-time-parameter","errorCode":null,"errorMessage":"GTD time in force requires expire_time parameter","messagePattern":"GTD time in force requires expire_time parameter","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/kraken/src/common/order_params.rs","lineNumber":230,"sourceCode":"\npub(crate) fn compute_ws_time_in_force(\n    is_limit_order: bool,\n    time_in_force: TimeInForce,\n    expire_time: Option<UnixNanos>,\n) -> anyhow::Result<Option<KrakenTimeInForce>> {\n    if !is_limit_order {\n        return Ok(None);\n    }\n\n    match time_in_force {\n        TimeInForce::Gtc => Ok(None),\n        TimeInForce::Ioc => Ok(Some(KrakenTimeInForce::ImmediateOrCancel)),\n        TimeInForce::Fok => {\n            anyhow::bail!(\"FOK time in force is not supported on Kraken WS v2; use REST\")\n        }\n        TimeInForce::Gtd => {\n            expire_time.ok_or_else(|| {\n                anyhow::anyhow!(\"GTD time in force requires expire_time parameter\")\n            })?;\n            Ok(Some(KrakenTimeInForce::GoodTilDate))\n        }\n        _ => anyhow::bail!(\"Unsupported time in force: {time_in_force:?}\"),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use nautilus_core::{UUID4, UnixNanos};\n    use nautilus_model::identifiers::{\n        ClientOrderId, InstrumentId, StrategyId, TraderId, VenueOrderId,\n    };\n    use rstest::rstest;\n    use rust_decimal_macros::dec;\n\n    use super::*;\n","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/kraken/src/common/order_params.rs#L212-L248","documentation":"On Kraken WS v2, a GTD (Good-Til-Date) order requires an explicit expire_time; compute_ws_time_in_force bails with this error when TimeInForce::Gtd is requested without one. The library throws it because the Kraken AddOrder message cannot express GTD without an expiry timestamp.","triggerScenarios":"Calling build_add_order_params or build_batch_order with an order whose time_in_force is Gtd while the expire_time option is None.","commonSituations":"Building orders from a strategy that sets TIF=Gtd but never sets expiry; mapping an upstream order request that carries Gtd without an expiry field; tests like test_compute_ws_time_in_force_fok_bails exercising TIF handling.","solutions":["Provide expire_time (as a Unix timestamp) when constructing the order with TimeInForce::Gtd.","Fall back to Gtc if no expiry is meaningful for the strategy.","Validate at the strategy/order-builder layer that Gtd orders always carry an expiry before submission.","Use the REST API instead of WS v2 if the order router cannot supply expire_time."],"exampleFix":"// before\nlet tif = TimeInForce::Gtd;\nbuild_add_order_params(&order, None)?; // expire_time not passed\n// after\nlet expire_time = order.expire_time.expect(\"GTD orders require expire_time\");\nbuild_add_order_params(&order, Some(expire_time))?;","handlingStrategy":"validation","validationCode":"// Rust: check before submitting\nif order.time_in_force == TimeInForce::Gtd && order.expire_time.is_none() {\n    return Err(anyhow::anyhow!(\"order {} is GTD but has no expire_time\", order.client_order_id));\n}","typeGuard":null,"tryCatchPattern":"match provider.submit_order(order) {\n    Err(e) if e.to_string().contains(\"GTD time in force requires expire_time\") => {\n        // resubmit as GTC or attach expire_time\n    }\n    other => other,\n}","preventionTips":["Make expire_time a required field of your GTD order constructor.","Default GTD orders to an explicit expiry computed at strategy level.","Add an order-validation unit test covering every TimeInForce variant.","Use Gtc when no meaningful expiry exists."],"tags":["order-params","time-in-force","kraken","websocket","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}