Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions crates/exchanges/binance/src/convert/market_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ pub(crate) fn market_info_from_exchange_symbol(
.quote_asset
.ok_or_else(|| crate::error::missing_field(operation, "quoteAsset"))?,
)
.base_asset_precision(symbol_definition.base_asset_precision)
.quote_precision(symbol_definition.quote_precision)
.quote_asset_precision(symbol_definition.quote_asset_precision)
.trading_permissions(trading_permissions)
.trading_constraints(trading_constraints)
.build()
Expand Down Expand Up @@ -458,3 +461,61 @@ pub(crate) fn klines_from_rows(
})
.collect()
}

#[cfg(test)]
mod tests {
use super::market_info_from_exchange_symbol;
use binance_sdk::spot::rest_api::{
ExchangeInfoResponseSymbolsInner, ExchangeInfoSymbolStatusEnum, LotSizeFilter, PriceFilter,
SymbolFilters,
};
use rust_decimal::Decimal;
use std::str::FromStr;

#[test]
fn market_info_preserves_symbol_precision_fields() {
let symbol = ExchangeInfoResponseSymbolsInner {
symbol: Some(String::from("BTCUSDT")),
status: Some(ExchangeInfoSymbolStatusEnum::Trading.as_str().to_string()),
base_asset: Some(String::from("BTC")),
base_asset_precision: Some(8),
quote_asset: Some(String::from("USDT")),
quote_precision: Some(8),
quote_asset_precision: Some(8),
order_types: Some(vec![String::from("MARKET")]),
quote_order_qty_market_allowed: Some(true),
is_spot_trading_allowed: Some(true),
filters: Some(vec![
SymbolFilters::PriceFilter(Box::new(PriceFilter {
filter_type: Some(String::from("PRICE_FILTER")),
price_exponent: None,
min_price: Some(String::from("0.01000000")),
max_price: Some(String::from("1000000.00000000")),
tick_size: Some(String::from("0.01000000")),
})),
SymbolFilters::LotSize(Box::new(LotSizeFilter {
filter_type: Some(String::from("LOT_SIZE")),
qty_exponent: None,
min_qty: Some(String::from("0.00001000")),
max_qty: Some(String::from("9000.00000000")),
step_size: Some(String::from("0.00001000")),
})),
]),
..ExchangeInfoResponseSymbolsInner::new()
};

let market = market_info_from_exchange_symbol(symbol, "spot.exchange_info")
.expect("market should convert");

assert_eq!(market.base_asset_precision, Some(8));
assert_eq!(market.quote_precision, Some(8));
assert_eq!(market.quote_asset_precision, Some(8));
assert_eq!(
market
.trading_constraints
.price_filter
.and_then(|filter| filter.tick_size),
Some(Decimal::from_str("0.01").expect("decimal"))
);
}
}
27 changes: 27 additions & 0 deletions crates/mkt-types/src/market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,14 +388,41 @@ impl TradingConstraints {
#[derive(Debug, Clone, PartialEq, Builder)]
#[builder(pattern = "owned", setter(into))]
pub struct MarketInfo {
/// Canonical exchange identifier for the venue that exposed this market.
pub exchange_id: ExchangeId,
/// Unified symbol descriptor, including market kind and venue-specific symbol string.
pub symbol: Symbol,
/// Current lifecycle status reported by the exchange.
pub status: MarketStatus,
/// Venue-reported base asset code for this market.
pub base_asset: String,
/// Venue-reported quote asset code for this market.
pub quote_asset: String,
#[builder(default)]
/// Exchange-reported precision for base-asset quantities at the symbol level, when available.
///
/// This is raw venue metadata. It may differ from executable step-size filters and should not
/// be treated as a substitute for lot-size validation.
pub base_asset_precision: Option<i64>,
#[builder(default)]
/// Exchange-reported precision for quote-denominated values at the symbol level, when
/// available.
///
/// On venues such as Binance spot, this is the most relevant symbol-level precision hint for
/// quote-sized order entry like `quoteOrderQty`.
pub quote_precision: Option<i64>,
#[builder(default)]
/// Exchange-reported precision for the quote asset at the symbol level, when available.
///
/// Some venues expose both `quote_precision` and `quote_asset_precision`. When they differ,
/// adapter code should prefer the field that the venue documents for order-entry precision and
/// treat this field as auxiliary metadata or fallback.
pub quote_asset_precision: Option<i64>,
#[builder(default)]
/// Venue capabilities describing which order types, sides, and quantity modes are supported.
pub trading_permissions: TradingPermissions,
#[builder(default)]
/// Venue execution constraints such as price filters, lot sizes, and notional limits.
pub trading_constraints: TradingConstraints,
}

Expand Down
Loading