nautilus_binance/spot/
enums.rs1use nautilus_model::enums::{OrderType, TimeInForce};
19use serde::{Deserialize, Serialize};
20
21use crate::common::enums::BinanceTimeInForce;
22
23#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
25#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
26pub enum BinanceSpotOrderType {
27 Limit,
29 Market,
31 StopLoss,
33 StopLossLimit,
35 TakeProfit,
37 TakeProfitLimit,
39 LimitMaker,
41 #[serde(other)]
43 Unknown,
44}
45
46#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
48#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
49pub enum BinanceOrderResponseType {
50 Ack,
52 Result,
54 #[default]
56 Full,
57}
58
59#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
61#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
62pub enum BinanceCancelReplaceMode {
63 StopOnFailure,
65 AllowFailure,
67}
68
69pub fn order_type_to_binance_spot(
75 order_type: OrderType,
76 post_only: bool,
77) -> anyhow::Result<BinanceSpotOrderType> {
78 match (order_type, post_only) {
79 (OrderType::Market, _) => Ok(BinanceSpotOrderType::Market),
80 (OrderType::Limit, true) => Ok(BinanceSpotOrderType::LimitMaker),
81 (OrderType::Limit, false) => Ok(BinanceSpotOrderType::Limit),
82 (OrderType::StopMarket, _) => Ok(BinanceSpotOrderType::StopLoss),
83 (OrderType::StopLimit, _) => Ok(BinanceSpotOrderType::StopLossLimit),
84 (OrderType::MarketIfTouched, _) => Ok(BinanceSpotOrderType::TakeProfit),
85 (OrderType::LimitIfTouched, _) => Ok(BinanceSpotOrderType::TakeProfitLimit),
86 _ => anyhow::bail!("Unsupported order type for Binance Spot: {order_type:?}"),
87 }
88}
89
90pub fn time_in_force_to_binance_spot(tif: TimeInForce) -> anyhow::Result<BinanceTimeInForce> {
99 match tif {
100 TimeInForce::Gtc => Ok(BinanceTimeInForce::Gtc),
101 TimeInForce::Ioc => Ok(BinanceTimeInForce::Ioc),
102 TimeInForce::Fok => Ok(BinanceTimeInForce::Fok),
103 _ => anyhow::bail!("Unsupported time in force for Binance Spot: {tif:?}"),
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use rstest::rstest;
110
111 use super::*;
112
113 #[rstest]
114 #[case(OrderType::Market, false, BinanceSpotOrderType::Market)]
115 #[case(OrderType::Limit, false, BinanceSpotOrderType::Limit)]
116 #[case(OrderType::Limit, true, BinanceSpotOrderType::LimitMaker)]
117 #[case(OrderType::StopMarket, false, BinanceSpotOrderType::StopLoss)]
118 #[case(OrderType::StopLimit, false, BinanceSpotOrderType::StopLossLimit)]
119 #[case(OrderType::MarketIfTouched, false, BinanceSpotOrderType::TakeProfit)]
120 #[case(
121 OrderType::LimitIfTouched,
122 false,
123 BinanceSpotOrderType::TakeProfitLimit
124 )]
125 fn test_order_type_to_binance_spot(
126 #[case] order_type: OrderType,
127 #[case] post_only: bool,
128 #[case] expected: BinanceSpotOrderType,
129 ) {
130 let result = order_type_to_binance_spot(order_type, post_only).unwrap();
131 assert_eq!(result, expected);
132 }
133
134 #[rstest]
135 #[case(OrderType::TrailingStopMarket)]
136 fn test_order_type_to_binance_spot_unsupported(#[case] order_type: OrderType) {
137 let result = order_type_to_binance_spot(order_type, false);
138 assert!(result.is_err());
139 }
140
141 #[rstest]
142 #[case(TimeInForce::Gtc, BinanceTimeInForce::Gtc)]
143 #[case(TimeInForce::Ioc, BinanceTimeInForce::Ioc)]
144 #[case(TimeInForce::Fok, BinanceTimeInForce::Fok)]
145 fn test_time_in_force_to_binance_spot(
146 #[case] tif: TimeInForce,
147 #[case] expected: BinanceTimeInForce,
148 ) {
149 let result = time_in_force_to_binance_spot(tif).unwrap();
150 assert_eq!(result, expected);
151 }
152
153 #[rstest]
154 #[case(TimeInForce::Gtd)]
155 fn test_time_in_force_to_binance_spot_rejects_gtd(#[case] tif: TimeInForce) {
156 let result = time_in_force_to_binance_spot(tif);
157 assert!(result.is_err());
158 }
159}