nautechsystems/nautilus_trader · error

FOK time in force only supported for LIMIT orders on Kraken

Error message

FOK time in force only supported for LIMIT orders on Kraken Spot

What it means

Kraken Spot only honors FOK (fill-or-kill) time in force on LIMIT orders. The client validates the combination and bails if TimeInForce::Fok is paired with any non-Limit order type (market, stop, trailing, etc.), since the venue would reject it.

Source

Thrown at crates/adapters/kraken/src/http/spot/client.rs:3042

            OrderType::StopLimit => KrakenOrderType::StopLossLimit,
            OrderType::MarketIfTouched => KrakenOrderType::TakeProfit,
            OrderType::LimitIfTouched => KrakenOrderType::TakeProfitLimit,
            OrderType::TrailingStopMarket => KrakenOrderType::TrailingStop,
            OrderType::TrailingStopLimit => KrakenOrderType::TrailingStopLimit,
            _ => anyhow::bail!("Unsupported order type: {order_type:?}"),
        };

        let mut oflags = Vec::new();
        let is_limit_order = matches!(
            order_type,
            OrderType::Limit
                | OrderType::StopLimit
                | OrderType::LimitIfTouched
                | OrderType::TrailingStopLimit
        );

        if time_in_force == TimeInForce::Fok && order_type != OrderType::Limit {
            anyhow::bail!("FOK time in force only supported for LIMIT orders on Kraken Spot");
        }

        let (timeinforce, expiretm) =
            compute_time_in_force(is_limit_order, time_in_force, expire_time)?;

        if post_only {
            oflags.push(KRAKEN_OFLAG_POST_ONLY);
        }

        if quote_quantity {
            oflags.push(KRAKEN_OFLAG_QUOTE_QUANTITY);
        }

        let mut builder = KrakenSpotAddOrderParamsBuilder::default();
        builder
            .cl_ord_id(truncate_cl_ord_id(&client_order_id))
            .broker(NAUTILUS_KRAKEN_BROKER_ID)
            .pair(raw_symbol)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use OrderType::Limit when TimeInForce::Fok is required.
  2. For market orders use TimeInForce::Gtc (or the venue's supported TIF) instead of FOK.
  3. Validate order_type/time_in_force combinations in strategy config before submission.

Example fix

// before
let order = order_factory.market(instrument_id, side, qty, TimeInForce::Fok, ...);

// after
let order = order_factory.market(instrument_id, side, qty, TimeInForce::Gtc, ...);
Defensive patterns

Strategy: validation

Validate before calling

if time_in_force == TimeInForce::Fok && order_type != OrderType::Limit {
    return Err("FOK requires OrderType::Limit on Kraken Spot");
}

Type guard

fn fok_is_valid(tif: &TimeInForce, ot: &OrderType) -> bool {
    *tif != TimeInForce::Fok || *ot == OrderType::Limit
}

Try / catch

match client.submit_order(order).await {
    Err(e) if e.to_string().contains("FOK time in force only supported") => {
        log::error!("resubmit as LIMIT or switch TIF to GTC");
    }
    Err(e) => return Err(e),
    Ok(r) => r,
}

Prevention

When it happens

Trigger: Submitting a MARKET, STOP_MARKET, TRAILING_STOP_MARKET (or any non-LIMIT) order with time_in_force = TimeInForce::Fok.

Common situations: Strategies that uniformly set FOK on all orders; ported code from venues where FOK applies to market orders; configuration-driven TIF applied without regard to order type.

Related errors


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