1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
//!
//! The exchange info symbol.
//!

pub mod filter;
pub mod status;

use rust_decimal::Decimal;
use serde::Deserialize;

use crate::data::order_type::OrderType;
use crate::data::permission::Permission;

use self::filter::Filter;
use self::status::Status;

///
/// The trading symbol data.
///
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Symbol {
    /// The symbol name.
    pub symbol: String,
    /// The symbol status on the exchange.
    pub status: Status,
    /// The secondary token in the trading pair.
    pub base_asset: String,
    /// The generic number of fractional digits in the secondary token.
    /// Do not use for the price scale!
    pub base_asset_precision: usize,
    /// The primary token in the trading pair.
    pub quote_asset: String,
    /// The generic number of fractional digits in the primary token.
    /// Do not use for the price scale!
    pub quote_precision: usize,
    /// The order types allowed for the symbol.
    pub order_types: Vec<OrderType>,
    /// If iceberd order is allowed for the symbol.
    pub iceberg_allowed: bool,
    /// The conditions Binance puts on the symbol.
    pub filters: Vec<Filter>,
    /// The allowed trading methods like spot, margin, etc.
    pub permissions: Vec<Permission>,
}

impl Symbol {
    ///
    /// If the symbol is active and can be normally traded.
    ///
    pub fn is_trading(&self) -> bool {
        matches!(self.status, Status::Trading)
    }

    ///
    /// If margin trading is allowed for the symbol.
    ///
    pub fn has_margin(&self) -> bool {
        self.permissions.contains(&Permission::Margin)
    }

    ///
    /// The number of fractional digits in the symbol price.
    ///
    /// E.g. `0.000256` has `6` fractional digits.
    /// E.g. `0.42` has `2` fractional digits.
    ///
    pub fn price_scale(&self) -> Option<u32> {
        for filter in self.filters.iter() {
            if let Filter::PriceFilter { tick_size, .. } = filter {
                let mut scale = 8;
                let mut tick_size_check = Decimal::new(1, scale);
                while *tick_size > tick_size_check && scale > 0 {
                    tick_size_check *= Decimal::new(10, 0);
                    scale -= 1;
                }
                return Some(scale);
            }
        }
        None
    }

    ///
    /// The number of fractional digits in the symbol quantity.
    ///
    pub fn quantity_scale(&self) -> Option<u32> {
        for filter in self.filters.iter() {
            if let Filter::LotSize { step_size, .. } = filter {
                let mut scale = 8;
                let mut step_size_check = Decimal::new(1, scale);
                while *step_size > step_size_check && scale > 0 {
                    step_size_check *= Decimal::new(10, 0);
                    scale -= 1;
                }
                return Some(scale);
            }
        }
        None
    }
}