nautechsystems/nautilus_trader · error · anyhow::Error
Take profit sell trigger_price ({trigger_price}) must be >=
Error message
Take profit sell trigger_price ({trigger_price}) must be >= limit price ({price}) What it means
The dYdX adapter validates conditional (take-profit) orders before submitting them. For a take-profit SELL, the trigger price must be at or above the limit price, otherwise the order could never fill sensibly; validate_conditional_order bails with anyhow when this invariant is violated.
Source
Thrown at crates/adapters/dydx/src/http/parse.rs:271
}
OrderSide::Sell if trigger_price > price => {
anyhow::bail!(
"Stop sell trigger_price ({trigger_price}) must be <= limit price ({price})"
);
}
_ => {}
}
}
DydxOrderType::TakeProfitLimit | DydxOrderType::TakeProfitMarket => {
// Take profit: trigger when price rises (sell) or falls (buy)
match side {
OrderSide::Buy if trigger_price > price => {
anyhow::bail!(
"Take profit buy trigger_price ({trigger_price}) must be <= limit price ({price})"
);
}
OrderSide::Sell if trigger_price < price => {
anyhow::bail!(
"Take profit sell trigger_price ({trigger_price}) must be >= limit price ({price})"
);
}
_ => {}
}
}
_ => {}
}
Ok(())
}
/// Parses a dYdX perpetual market into a Nautilus [`InstrumentAny`].
///
/// dYdX v4 only supports perpetual markets, so this function creates a
/// [`CryptoPerpetual`] instrument with the appropriate fields mapped from
/// the dYdX market definition.
///View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure trigger_price >= price for sell-side take-profit orders before calling the API.
- If you actually want trigger below the limit for a sell, you need a stop-limit (OrderSide::Sell stop) not a take-profit.
- Swap prices or fix the side if you accidentally built a sell TP with buy semantics (buy requires trigger <= price).
Example fix
// before let trigger = price!(100); let limit = price!(110); validate_conditional_order(OrderSide::Sell, trigger, limit)?; // after let trigger = price!(120); // sell TP: trigger must be >= limit validate_conditional_order(OrderSide::Sell, trigger, limit)?;
Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_take_profit(side: OrderSide, trigger: Price, limit: Price) -> bool {
match side {
OrderSide::Buy => trigger <= limit,
OrderSide::Sell => trigger >= limit,
_ => false,
}
}
if !is_valid_take_profit(side, trigger_price, price) { return Err(/* fix before submit */); } Try / catch
match validate_conditional_order(side, trigger, limit) {
Ok(()) => submit(order),
Err(e) => log::warn!("conditional order rejected: {e}"), // adjust trigger/limit
} Prevention
- Encode the buy/sell trigger-vs-limit rules in a shared helper used everywhere TPs are built.
- Derive trigger and limit from the same reference price.
- Add unit tests mirroring the adapter's validation for both sides.
When it happens
Trigger: Calling validate_conditional_order (or submitting a TAKE_PROFIT limit order through the dYdX adapter) with OrderSide::Sell and trigger_price < price. Note the buy case has the mirror-image rule (trigger <= limit).
Common situations: Computing the trigger from a percentage move but forgetting the limit price uses a different reference; mixing up buy/sell TP rules; hardcoding prices in tests or configs; sign conventions from another venue carried over to dYdX.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Stop market order missing trigger_price
- Stop limit order missing trigger_price
- Stop limit order missing limit price
- Take profit market order missing trigger_price
- Take profit limit order missing trigger_price
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e16e53e5a7bceda1.
Report an issue: GitHub.