df_hyperliquid_core/trade/orders/
trigger.rs1use crate::trade::error::TradeError;
5use crate::trade::orders::limit::limit_on;
6use crate::trade::orders::{Order, Side, Tpsl};
7use crate::trade::ticket::{Market, Refusal, positive};
8use crate::utils::rounding::Grid;
9use crate::utils::{Dec, Round};
10
11pub const TRIGGER_SLIPPAGE: Dec = Dec::lit::<1>(1);
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum ExitPrice {
18 Market { slippage: Dec },
20 Limit(Dec),
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct Exit {
27 pub trigger: Dec,
28 pub price: ExitPrice,
29}
30
31impl Exit {
32 #[must_use]
34 pub const fn market(trigger: Dec) -> Exit {
35 Exit::market_within(trigger, TRIGGER_SLIPPAGE)
36 }
37
38 #[must_use]
40 pub const fn market_within(trigger: Dec, slippage: Dec) -> Exit {
41 Exit { trigger, price: ExitPrice::Market { slippage } }
42 }
43
44 #[must_use]
46 pub const fn limit(trigger: Dec, price: Dec) -> Exit {
47 Exit { trigger, price: ExitPrice::Limit(price) }
48 }
49}
50
51pub(crate) fn trigger_on(grid: Grid, trigger: Dec) -> Result<Dec, Refusal> {
54 let trigger = positive(trigger, "a trigger price")?;
55 grid.tick(trigger, Round::Nearest).ok_or(Refusal::Trade(TradeError::NoPrice(trigger)))
56}
57
58pub(crate) fn fill_price(grid: Grid, trigger: Dec, price: ExitPrice, side: Side) -> Result<(Dec, bool), Refusal> {
61 match price {
62 ExitPrice::Market { slippage } => Ok((grid.market_bound(trigger, slippage, side)?, true)),
63 ExitPrice::Limit(price) => Ok((limit_on(grid, price, side, "a limit price")?, false)),
64 }
65}
66
67pub(crate) fn exit_order(market: &Market, side: Side, size: Dec, tpsl: Tpsl, exit: Exit) -> Result<Order, Refusal> {
69 let trigger = trigger_on(market.grid(), exit.trigger)?;
70 let (price, is_market) = fill_price(market.grid(), trigger, exit.price, side)?;
71 Ok(Order::trigger(market.asset(), side, price, size, trigger, tpsl, is_market).reduce_only())
72}
73
74#[cfg(test)]
75#[path = "tests/trigger.rs"]
76mod tests;