nautilus_binance/common/
symbol.rs1use nautilus_model::identifiers::InstrumentId;
19use ustr::Ustr;
20
21use super::{consts::BINANCE_VENUE, enums::BinanceProductType};
22
23#[must_use]
33pub fn format_instrument_id(symbol: &Ustr, product_type: BinanceProductType) -> InstrumentId {
34 let nautilus_symbol = match product_type {
35 BinanceProductType::UsdM => {
36 format!("{symbol}-PERP")
38 }
39 BinanceProductType::CoinM => {
40 symbol.to_string()
42 }
43 _ => symbol.to_string(),
44 };
45 InstrumentId::new(nautilus_symbol.into(), *BINANCE_VENUE)
46}
47
48#[must_use]
59pub fn format_binance_symbol(instrument_id: &InstrumentId) -> String {
60 let symbol = instrument_id.symbol.as_str();
61
62 if symbol.ends_with("-PERP") {
63 symbol.trim_end_matches("-PERP").to_string()
64 } else {
65 symbol.to_string()
66 }
67}
68
69#[must_use]
73pub fn format_binance_stream_symbol(instrument_id: &InstrumentId) -> String {
74 format_binance_symbol(instrument_id).to_lowercase()
75}
76
77#[cfg(test)]
78mod tests {
79 use rstest::rstest;
80
81 use super::*;
82
83 #[rstest]
84 #[case("BTCUSDT-PERP.BINANCE", "BTCUSDT")]
85 #[case("ETHUSDT-PERP.BINANCE", "ETHUSDT")]
86 #[case("BTCUSD_PERP.BINANCE", "BTCUSD_PERP")]
87 #[case("BTCUSDT.BINANCE", "BTCUSDT")]
88 #[case("ETHBTC.BINANCE", "ETHBTC")]
89 fn test_format_binance_symbol(#[case] input: &str, #[case] expected: &str) {
90 let instrument_id = InstrumentId::from(input);
91 assert_eq!(format_binance_symbol(&instrument_id), expected);
92 }
93
94 #[rstest]
95 #[case("BTCUSDT-PERP.BINANCE", "btcusdt")]
96 #[case("ETHUSDT-PERP.BINANCE", "ethusdt")]
97 #[case("BTCUSD_PERP.BINANCE", "btcusd_perp")]
98 fn test_format_binance_stream_symbol(#[case] input: &str, #[case] expected: &str) {
99 let instrument_id = InstrumentId::from(input);
100 assert_eq!(format_binance_stream_symbol(&instrument_id), expected);
101 }
102
103 #[rstest]
104 #[case::usdm_perp("BTCUSDT", BinanceProductType::UsdM, "BTCUSDT-PERP.BINANCE")]
105 #[case::usdm_eth("ETHUSDT", BinanceProductType::UsdM, "ETHUSDT-PERP.BINANCE")]
106 #[case::coinm_perp("BTCUSD_PERP", BinanceProductType::CoinM, "BTCUSD_PERP.BINANCE")]
107 #[case::coinm_eth("ETHUSD_PERP", BinanceProductType::CoinM, "ETHUSD_PERP.BINANCE")]
108 #[case::spot("BTCUSDT", BinanceProductType::Spot, "BTCUSDT.BINANCE")]
109 #[case::spot_eth("ETHBTC", BinanceProductType::Spot, "ETHBTC.BINANCE")]
110 #[case::margin("BTCUSDT", BinanceProductType::Margin, "BTCUSDT.BINANCE")]
111 #[case::options(
112 "BTC-240329-70000-C",
113 BinanceProductType::Options,
114 "BTC-240329-70000-C.BINANCE"
115 )]
116 fn test_format_instrument_id(
117 #[case] raw_symbol: &str,
118 #[case] product_type: BinanceProductType,
119 #[case] expected: &str,
120 ) {
121 let symbol = Ustr::from(raw_symbol);
122 let instrument_id = format_instrument_id(&symbol, product_type);
123 assert_eq!(instrument_id.to_string(), expected);
124 }
125}