use nautilus_model::identifiers::InstrumentId;
use ustr::Ustr;
use super::{consts::BINANCE_VENUE, enums::BinanceProductType};
#[must_use]
pub fn format_instrument_id(symbol: &Ustr, product_type: BinanceProductType) -> InstrumentId {
let nautilus_symbol = match product_type {
BinanceProductType::UsdM => {
format!("{symbol}-PERP")
}
BinanceProductType::CoinM => {
symbol.to_string()
}
_ => symbol.to_string(),
};
InstrumentId::new(nautilus_symbol.into(), *BINANCE_VENUE)
}
#[must_use]
pub fn format_binance_symbol(instrument_id: &InstrumentId) -> String {
let symbol = instrument_id.symbol.as_str();
if symbol.ends_with("-PERP") {
symbol.trim_end_matches("-PERP").to_string()
} else {
symbol.to_string()
}
}
#[must_use]
pub fn format_binance_stream_symbol(instrument_id: &InstrumentId) -> String {
format_binance_symbol(instrument_id).to_lowercase()
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
#[case("BTCUSDT-PERP.BINANCE", "BTCUSDT")]
#[case("ETHUSDT-PERP.BINANCE", "ETHUSDT")]
#[case("BTCUSD_PERP.BINANCE", "BTCUSD_PERP")]
#[case("BTCUSDT.BINANCE", "BTCUSDT")]
#[case("ETHBTC.BINANCE", "ETHBTC")]
fn test_format_binance_symbol(#[case] input: &str, #[case] expected: &str) {
let instrument_id = InstrumentId::from(input);
assert_eq!(format_binance_symbol(&instrument_id), expected);
}
#[rstest]
#[case("BTCUSDT-PERP.BINANCE", "btcusdt")]
#[case("ETHUSDT-PERP.BINANCE", "ethusdt")]
#[case("BTCUSD_PERP.BINANCE", "btcusd_perp")]
fn test_format_binance_stream_symbol(#[case] input: &str, #[case] expected: &str) {
let instrument_id = InstrumentId::from(input);
assert_eq!(format_binance_stream_symbol(&instrument_id), expected);
}
#[rstest]
#[case::usdm_perp("BTCUSDT", BinanceProductType::UsdM, "BTCUSDT-PERP.BINANCE")]
#[case::usdm_eth("ETHUSDT", BinanceProductType::UsdM, "ETHUSDT-PERP.BINANCE")]
#[case::coinm_perp("BTCUSD_PERP", BinanceProductType::CoinM, "BTCUSD_PERP.BINANCE")]
#[case::coinm_eth("ETHUSD_PERP", BinanceProductType::CoinM, "ETHUSD_PERP.BINANCE")]
#[case::spot("BTCUSDT", BinanceProductType::Spot, "BTCUSDT.BINANCE")]
#[case::spot_eth("ETHBTC", BinanceProductType::Spot, "ETHBTC.BINANCE")]
#[case::margin("BTCUSDT", BinanceProductType::Margin, "BTCUSDT.BINANCE")]
#[case::options(
"BTC-240329-70000-C",
BinanceProductType::Options,
"BTC-240329-70000-C.BINANCE"
)]
fn test_format_instrument_id(
#[case] raw_symbol: &str,
#[case] product_type: BinanceProductType,
#[case] expected: &str,
) {
let symbol = Ustr::from(raw_symbol);
let instrument_id = format_instrument_id(&symbol, product_type);
assert_eq!(instrument_id.to_string(), expected);
}
}