// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
#![allow(unused, non_snake_case, clippy::all)]
use crate::Value;
use crate::get_value;
use crate::runtime::*;
// Base methods are now trait methods (review #1: static dispatch). Bring the
// traits into scope so `self.market(...)`, `self.safe_market(...)`,
// `self.load_markets(...)`, … on this Core resolve to the base defaults.
use crate::exchange_generated::ExchangeBase;
use crate::exchange::ExchangeRuntime;
use crate::pro::*;
pub struct MexcCore {
pub parent: crate::exchanges::mexc::MexcCore,
}
impl MexcCore {
pub fn new(config: Option<crate::Value>) -> Self {
let mut s = Self { parent: crate::exchanges::mexc::MexcCore::new(config) };
s.init();
s
}
pub fn init(&mut self) {
let described = MexcCore::describe(self);
self.initialize_properties(described);
<Self as crate::exchange_generated::ExchangeBase>::after_construct(self);
}
/// Compatibility no-op. The old pointer-based dispatch needed a post-move
/// `bind()`; static trait dispatch (review #1) needs no binding, so this
/// just exists so callers that still call it keep compiling.
#[inline]
pub fn bind(&mut self) {}
}
impl crate::exchange::DerivedExchange for MexcCore {
fn nonce(&self, ) -> crate::Value {
crate::exchange::DerivedExchange::nonce(&self.parent)
}
fn parse_ticker(&self, ticker: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_ticker(&self.parent, ticker, market)
}
fn parse_trade(&self, trade: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_trade(&self.parent, trade, market)
}
fn parse_order(&self, order: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_order(&self.parent, order, market)
}
fn parse_market(&self, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_market(&self.parent, market)
}
fn parse_ohlcv(&self, ohlcv: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_ohlcv(&self.parent, ohlcv, market)
}
fn parse_order_book(&self, ob: crate::Value, symbol: crate::Value, ts: crate::Value, bk: crate::Value, ak: crate::Value, pk: crate::Value, ak2: crate::Value, ck: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_order_book(&self.parent, ob, symbol, ts, bk, ak, pk, ak2, ck)
}
fn parse_balance(&self, response: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_balance(&self.parent, response)
}
fn parse_position(&self, position: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_position(&self.parent, position, market)
}
fn parse_funding_rate(&self, rate: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_funding_rate(&self.parent, rate, market)
}
fn parse_deposit(&self, tx: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_deposit(&self.parent, tx, currency)
}
fn parse_deposit_address(&self, depositAddress: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_deposit_address(&self.parent, depositAddress, currency)
}
fn parse_last_price(&self, entry: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_last_price(&self.parent, entry, market)
}
fn parse_withdrawal(&self, tx: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_withdrawal(&self.parent, tx, currency)
}
fn parse_ledger_entry(&self, entry: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_ledger_entry(&self.parent, entry, currency)
}
fn parse_transfer(&self, transfer: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_transfer(&self.parent, transfer, currency)
}
fn parse_currency(&self, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_currency(&self.parent, currency)
}
fn parse_bid_ask(&self, bidask: crate::Value, price_key: crate::Value, amount_key: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_bid_ask(&self.parent, bidask, price_key, amount_key, market)
}
fn parse_open_interest(&self, interest: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_open_interest(&self.parent, interest, market)
}
fn parse_liquidation(&self, liquidation: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_liquidation(&self.parent, liquidation, market)
}
fn parse_funding_rate_history(&self, entry: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_funding_rate_history(&self.parent, entry, market)
}
fn parse_margin_modification(&self, data: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_margin_modification(&self.parent, data, market)
}
fn parse_account(&self, account: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_account(&self.parent, account)
}
fn parse_my_trade(&self, trade: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_my_trade(&self.parent, trade, market)
}
fn parse_transaction(&self, transaction: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_transaction(&self.parent, transaction, currency)
}
fn parse_borrow_interest(&self, info: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_borrow_interest(&self.parent, info, market)
}
fn parse_adl_rank(&self, info: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_adl_rank(&self.parent, info, market)
}
fn parse_income(&self, info: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_income(&self.parent, info, market)
}
fn parse_greeks(&self, greeks: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_greeks(&self.parent, greeks, market)
}
fn parse_margin_mode(&self, margin_mode: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_margin_mode(&self.parent, margin_mode, market)
}
fn parse_conversion(&self, conversion: crate::Value, from_currency: crate::Value, to_currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_conversion(&self.parent, conversion, from_currency, to_currency)
}
fn parse_borrow_rate(&self, info: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_borrow_rate(&self.parent, info, currency)
}
fn parse_leverage(&self, leverage: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_leverage(&self.parent, leverage, market)
}
fn parse_market_leverage_tiers(&self, info: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_market_leverage_tiers(&self.parent, info, market)
}
fn parse_deposit_withdraw_fee(&self, fee: crate::Value, currency: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_deposit_withdraw_fee(&self.parent, fee, currency)
}
fn parse_prediction_trade(&self, trade: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_prediction_trade(&self.parent, trade, market)
}
fn parse_prediction_order(&self, order: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_prediction_order(&self.parent, order, market)
}
fn parse_prediction_position(&self, position: crate::Value, market: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::parse_prediction_position(&self.parent, position, market)
}
fn create_expired_option_market(&self, symbol: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::create_expired_option_market(&self.parent, symbol)
}
fn sign(&self, path: crate::Value, api: crate::Value, method: crate::Value, params: crate::Value, headers: crate::Value, body: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::sign(&self.parent, path, api, method, params, headers, body)
}
fn handle_errors(&self, code: crate::Value, reason: crate::Value, url: crate::Value, method: crate::Value, headers: crate::Value, body: crate::Value, response: crate::Value, request_headers: crate::Value, request_body: crate::Value) -> crate::Value {
crate::exchange::DerivedExchange::handle_errors(&self.parent, code, reason, url, method, headers, body, response, request_headers, request_body)
}
}
impl crate::exchange_generated::ExchangeBase for MexcCore {
fn call_dynamic<'a>(&'a mut self, method: &'a str, args: Vec<crate::Value>)
-> std::pin::Pin<Box<dyn std::future::Future<Output = crate::Value> + Send + 'a>>
{
Box::pin(async move {
match method {
"authenticate" => self.authenticate(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"get_cache_index" => self.get_cache_index(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)),
"handle_message" => { self.handle_message(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_pong" => self.handle_pong(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)),
"handle_protobuf_message" => self.handle_protobuf_message(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)),
"keep_alive_listen_key" => self.keep_alive_listen_key(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"parse_ws_bid_ask" => self.parse_ws_bid_ask(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_ohlcv" => self.parse_ws_ohlcv(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_order" => self.parse_ws_order(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_order_status" => self.parse_ws_order_status(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_order_type" => self.parse_ws_order_type(args.get(0).cloned().unwrap_or(crate::Value::Null)),
"parse_ws_ticker" => self.parse_ws_ticker(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_time_in_force" => self.parse_ws_time_in_force(args.get(0).cloned().unwrap_or(crate::Value::Null)),
"parse_ws_trade" => self.parse_ws_trade(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"ping" => self.ping(args.get(0).cloned().unwrap_or(crate::Value::Null)),
"un_watch_bids_asks" => self.un_watch_bids_asks(&args.get(0..).unwrap_or(&[]).to_vec()[..]).await,
"un_watch_funding_rate" => self.un_watch_funding_rate(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"un_watch_ohlcv" => self.un_watch_ohlcv(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"un_watch_order_book" => self.un_watch_order_book(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"un_watch_ticker" => self.un_watch_ticker(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"un_watch_tickers" => self.un_watch_tickers(&args.get(0..).unwrap_or(&[]).to_vec()[..]).await,
"un_watch_trades" => self.un_watch_trades(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"watch_balance" => self.watch_balance(&args.get(0..).unwrap_or(&[]).to_vec()[..]).await,
"watch_bids_asks" => self.watch_bids_asks(&args.get(0..).unwrap_or(&[]).to_vec()[..]).await,
"watch_funding_rate" => self.watch_funding_rate(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"watch_my_trades" => self.watch_my_trades(&args.get(0..).unwrap_or(&[]).to_vec()[..]).await,
"watch_ohlcv" => self.watch_ohlcv(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"watch_order_book" => self.watch_order_book(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"watch_orders" => self.watch_orders(&args.get(0..).unwrap_or(&[]).to_vec()[..]).await,
"watch_spot_private" => self.watch_spot_private(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null), &args.get(2..).unwrap_or(&[]).to_vec()[..]).await,
"watch_spot_public" => self.watch_spot_public(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null), &args.get(2..).unwrap_or(&[]).to_vec()[..]).await,
"watch_swap_private" => self.watch_swap_private(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"watch_swap_public" => self.watch_swap_public(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null), args.get(2).cloned().unwrap_or(crate::Value::Null), &args.get(3..).unwrap_or(&[]).to_vec()[..]).await,
"watch_ticker" => self.watch_ticker(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
"watch_tickers" => self.watch_tickers(&args.get(0..).unwrap_or(&[]).to_vec()[..]).await,
"watch_trades" => self.watch_trades(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]).await,
// Go-style inheritance: an un-overridden method dispatches to the parent core.
_ => crate::exchange_generated::ExchangeBase::call_dynamic(&mut self.parent, method, args).await,
}
})
}
}
impl MexcCore {
/// Synchronous WS handler dispatch — routes a handler-name string (from the
/// venue's handle_message dispatch table) to the real handler method.
#[allow(dead_code, unreachable_patterns, clippy::all)]
pub fn dispatch_ws_handler(&mut self, __name: &crate::Value, args: &[crate::Value]) -> crate::Value {
let __n = match __name { crate::Value::Str(s) => s.as_str(), _ => return crate::Value::Null };
match __n {
"authenticate" => { crate::exchange_stubs::enqueue_spawn("authenticate", args.to_vec()); crate::Value::Null },
"get_cache_index" => self.get_cache_index(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)),
"handle_balance" => { self.handle_balance(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_bid_ask" => { self.handle_bid_ask(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_bookside_delta" => { self.handle_bookside_delta(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_delta" => { self.handle_delta(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_funding_rate" => { self.handle_funding_rate(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_message" => { self.handle_message(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_my_trade" => { self.handle_my_trade(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null), &args.get(2..).unwrap_or(&[]).to_vec()[..]); crate::Value::Null },
"handle_ohlcv" => { self.handle_ohlcv(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_order" => { self.handle_order(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_order_book" => { self.handle_order_book(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_order_book_subscription" => { self.handle_order_book_subscription(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_pong" => self.handle_pong(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)),
"handle_protobuf_message" => self.handle_protobuf_message(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)),
"handle_subscription_status" => { self.handle_subscription_status(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_ticker" => { self.handle_ticker(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_tickers" => { self.handle_tickers(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_trades" => { self.handle_trades(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"handle_unsubscriptions" => { self.handle_unsubscriptions(args.get(0).cloned().unwrap_or(crate::Value::Null), args.get(1).cloned().unwrap_or(crate::Value::Null)); crate::Value::Null },
"keep_alive_listen_key" => { crate::exchange_stubs::enqueue_spawn("keep_alive_listen_key", args.to_vec()); crate::Value::Null },
"parse_ws_bid_ask" => self.parse_ws_bid_ask(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_ohlcv" => self.parse_ws_ohlcv(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_order" => self.parse_ws_order(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_order_status" => self.parse_ws_order_status(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_order_type" => self.parse_ws_order_type(args.get(0).cloned().unwrap_or(crate::Value::Null)),
"parse_ws_ticker" => self.parse_ws_ticker(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"parse_ws_time_in_force" => self.parse_ws_time_in_force(args.get(0).cloned().unwrap_or(crate::Value::Null)),
"parse_ws_trade" => self.parse_ws_trade(args.get(0).cloned().unwrap_or(crate::Value::Null), &args.get(1..).unwrap_or(&[]).to_vec()[..]),
"ping" => self.ping(args.get(0).cloned().unwrap_or(crate::Value::Null)),
"un_watch_bids_asks" => { crate::exchange_stubs::enqueue_spawn("un_watch_bids_asks", args.to_vec()); crate::Value::Null },
"un_watch_funding_rate" => { crate::exchange_stubs::enqueue_spawn("un_watch_funding_rate", args.to_vec()); crate::Value::Null },
"un_watch_ohlcv" => { crate::exchange_stubs::enqueue_spawn("un_watch_ohlcv", args.to_vec()); crate::Value::Null },
"un_watch_order_book" => { crate::exchange_stubs::enqueue_spawn("un_watch_order_book", args.to_vec()); crate::Value::Null },
"un_watch_ticker" => { crate::exchange_stubs::enqueue_spawn("un_watch_ticker", args.to_vec()); crate::Value::Null },
"un_watch_tickers" => { crate::exchange_stubs::enqueue_spawn("un_watch_tickers", args.to_vec()); crate::Value::Null },
"un_watch_trades" => { crate::exchange_stubs::enqueue_spawn("un_watch_trades", args.to_vec()); crate::Value::Null },
"watch_balance" => { crate::exchange_stubs::enqueue_spawn("watch_balance", args.to_vec()); crate::Value::Null },
"watch_bids_asks" => { crate::exchange_stubs::enqueue_spawn("watch_bids_asks", args.to_vec()); crate::Value::Null },
"watch_funding_rate" => { crate::exchange_stubs::enqueue_spawn("watch_funding_rate", args.to_vec()); crate::Value::Null },
"watch_my_trades" => { crate::exchange_stubs::enqueue_spawn("watch_my_trades", args.to_vec()); crate::Value::Null },
"watch_ohlcv" => { crate::exchange_stubs::enqueue_spawn("watch_ohlcv", args.to_vec()); crate::Value::Null },
"watch_order_book" => { crate::exchange_stubs::enqueue_spawn("watch_order_book", args.to_vec()); crate::Value::Null },
"watch_orders" => { crate::exchange_stubs::enqueue_spawn("watch_orders", args.to_vec()); crate::Value::Null },
"watch_spot_private" => { crate::exchange_stubs::enqueue_spawn("watch_spot_private", args.to_vec()); crate::Value::Null },
"watch_spot_public" => { crate::exchange_stubs::enqueue_spawn("watch_spot_public", args.to_vec()); crate::Value::Null },
"watch_swap_private" => { crate::exchange_stubs::enqueue_spawn("watch_swap_private", args.to_vec()); crate::Value::Null },
"watch_swap_public" => { crate::exchange_stubs::enqueue_spawn("watch_swap_public", args.to_vec()); crate::Value::Null },
"watch_ticker" => { crate::exchange_stubs::enqueue_spawn("watch_ticker", args.to_vec()); crate::Value::Null },
"watch_tickers" => { crate::exchange_stubs::enqueue_spawn("watch_tickers", args.to_vec()); crate::Value::Null },
"watch_trades" => { crate::exchange_stubs::enqueue_spawn("watch_trades", args.to_vec()); crate::Value::Null },
_ => crate::Value::Null,
}
}
}
impl std::ops::Deref for MexcCore {
type Target = crate::exchange::Exchange;
fn deref(&self) -> &crate::exchange::Exchange { std::ops::Deref::deref(&self.parent) }
}
impl std::ops::DerefMut for MexcCore {
fn deref_mut(&mut self) -> &mut crate::exchange::Exchange { std::ops::DerefMut::deref_mut(&mut self.parent) }
}
impl MexcCore {
pub fn describe(&self) -> Value {
return self.deep_extend(self.parent.describe(), &[Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("has".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("ws".to_string(), Value::Bool(true));
m.insert("cancelAllOrdersWs".to_string(), Value::Bool(false));
m.insert("cancelOrdersWs".to_string(), Value::Bool(false));
m.insert("cancelOrderWs".to_string(), Value::Bool(false));
m.insert("createOrderWs".to_string(), Value::Bool(false));
m.insert("editOrderWs".to_string(), Value::Bool(false));
m.insert("fetchBalanceWs".to_string(), Value::Bool(false));
m.insert("fetchOpenOrdersWs".to_string(), Value::Bool(false));
m.insert("fetchOrderWs".to_string(), Value::Bool(false));
m.insert("fetchTradesWs".to_string(), Value::Bool(false));
m.insert("watchBalance".to_string(), Value::Bool(true));
m.insert("watchFundingRate".to_string(), Value::Bool(true));
m.insert("watchFundingRates".to_string(), Value::Bool(false));
m.insert("watchMyTrades".to_string(), Value::Bool(true));
m.insert("watchOHLCV".to_string(), Value::Bool(true));
m.insert("watchOrderBook".to_string(), Value::Bool(true));
m.insert("watchOrders".to_string(), Value::Bool(true));
m.insert("watchTicker".to_string(), Value::Bool(true));
m.insert("watchTickers".to_string(), Value::Bool(true));
m.insert("watchBidsAsks".to_string(), Value::Bool(true));
m.insert("watchTrades".to_string(), Value::Bool(true));
m.insert("watchTradesForSymbols".to_string(), Value::Bool(false));
m.insert("unWatchTicker".to_string(), Value::Bool(true));
m.insert("unWatchTickers".to_string(), Value::Bool(true));
m.insert("unWatchBidsAsks".to_string(), Value::Bool(true));
m.insert("unWatchOHLCV".to_string(), Value::Bool(true));
m.insert("unWatchOrderBook".to_string(), Value::Bool(true));
m.insert("unWatchTrades".to_string(), Value::Bool(true));
m
}));
m.insert("urls".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("api".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("ws".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("spot".to_string(), Value::Str("wss://wbs-api.mexc.com/ws".to_string()));
m.insert("swap".to_string(), Value::Str("wss://contract.mexc.com/edge".to_string()));
m
}));
m
}));
m
}));
m.insert("options".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("listenKeyRefreshRate".to_string(), Value::Int(1200000));
m.insert("decompressBinary".to_string(), Value::Bool(false));
m.insert("timeframes".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("1m".to_string(), Value::Str("Min1".to_string()));
m.insert("5m".to_string(), Value::Str("Min5".to_string()));
m.insert("15m".to_string(), Value::Str("Min15".to_string()));
m.insert("30m".to_string(), Value::Str("Min30".to_string()));
m.insert("1h".to_string(), Value::Str("Min60".to_string()));
m.insert("4h".to_string(), Value::Str("Hour4".to_string()));
m.insert("8h".to_string(), Value::Str("Hour8".to_string()));
m.insert("1d".to_string(), Value::Str("Day1".to_string()));
m.insert("1w".to_string(), Value::Str("Week1".to_string()));
m.insert("1M".to_string(), Value::Str("Month1".to_string()));
m
}));
m.insert("watchOrderBook".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("snapshotDelay".to_string(), Value::Int(25));
m.insert("snapshotMaxRetries".to_string(), Value::Int(3));
m
}));
m.insert("listenKey".to_string(), Value::Null);
m
}));
m.insert("streaming".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("ping".to_string(), Value::Str("ping".to_string()).clone());
m.insert("keepAlive".to_string(), Value::Int(8000));
m
}));
m.insert("exceptions".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
m
})]);
Value::Null
}
/*
* @method
* @name mexc#watchTicker
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://www.mexc.com/api-docs/spot-v3/websocket-market-streams/individual-symbol-book-ticker-streams // spot
* @see https://www.mexc.com/api-docs/futures/websocket-api/get-a-single-ticker // swap
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
pub async fn watch_ticker(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
let mut messageHash: Value = add(&Value::Str("ticker:".to_string()), &get_value(&market, &Value::Str("symbol".to_string())));
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
let mut channel: Value = add(&Value::Str("spot@public.aggre.bookTicker.v3.api.pb@100ms@".to_string()), &get_value(&market, &Value::Str("id".to_string())));
return self.watch_spot_public(channel.clone(), messageHash.clone(), &[params.clone()]).await;
} else {
let mut channel: Value = Value::Str("sub.ticker".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
return self.watch_swap_public(channel.clone(), messageHash.clone(), requestParams.clone(), &[params.clone()]).await;
}
Value::Null
}
pub fn handle_ticker(&mut self, mut client: Value, mut message: Value) {
//
// swap
//
// {
// "symbol": "BTC_USDT",
// "data": {
// "symbol": "BTC_USDT",
// "lastPrice": 76376.1,
// "riseFallRate": -0.0006,
// "fairPrice": 76374.4,
// "indexPrice": 76385.8,
// "volume24": 962062810,
// "amount24": 7344207079.96768,
// "maxBidPrice": 84024.3,
// "minAskPrice": 68747.2,
// "lower24Price": 75620.2,
// "high24Price": 77210,
// "timestamp": 1731137509138,
// "bid1": 76376.2,
// "ask1": 76376.3,
// "holdVol": 95479623,
// "riseFallValue": -46.5,
// "fundingRate": 0.0001,
// "zone": "UTC+8",
// "riseFallRates": [ -0.0006, 0.1008, 0.2262, 0.2628, 0.2439, 1.0564 ],
// "riseFallRatesOfTimezone": [ 0.0065, -0.0013, -0.0006 ]
// },
// "channel": "push.ticker",
// "ts": 1731137509138
// }
//
// spot
//
// {
// "c": "spot@public.bookTicker.v3.api@BTCUSDT",
// "d": {
// "A": "4.70432",
// "B": "6.714863",
// "a": "20744.54",
// "b": "20744.17"
// },
// "s": "BTCUSDT",
// "t": 1678643605721
// }
//
// spot miniTicker
//
// {
// "d": {
// "s": "BTCUSDT",
// "p": "76522",
// "r": "0.0012",
// "tr": "0.0012",
// "h": "77196.3",
// "l": "75630.77",
// "v": "584664223.92",
// "q": "7666.720258",
// "lastRT": "-1",
// "MT": "0",
// "NV": "--",
// "t": "1731135533126"
// },
// "c": "spot@public.miniTicker.v3.api@BTCUSDT@UTC+8",
// "t": 1731135533126,
// "s": "BTCUSDT"
// }
//
self.handle_bid_ask(client.clone(), message.clone());
let mut rawTicker: Value = self.safe_dict_n(message.clone(), Value::List(vec![Value::Str("d".to_string()), Value::Str("data".to_string()), Value::Str("publicAggreBookTicker".to_string())]), &[]);
let mut marketId: Value = self.safe_string2(message.clone(), Value::Str("s".to_string()), Value::Str("symbol".to_string()), &[]);
let mut timestamp: Value = self.safe_integer2(message.clone(), Value::Str("t".to_string()), Value::Str("sendTime".to_string()), &[]);
let mut market: Value = self.safe_market(&[marketId.clone()]);
let mut symbol: Value = get_value(&market, &Value::Str("symbol".to_string()));
let mut ticker: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
ticker = self.parse_ws_ticker(rawTicker.clone(), &[market.clone()]);
add_element_to_object(&mut ticker, &Value::Str("timestamp".to_string()), timestamp.clone());
add_element_to_object(&mut ticker, &Value::Str("datetime".to_string()), self.iso8601(timestamp.clone()));
} else if !is_equal(&rawTicker, &Value::Null) {
ticker = self.parse_ticker(rawTicker.clone(), &[market.clone()]);
} else {
return;
}
add_element_to_object(&mut self.tickers, &symbol, ticker.clone());
let mut messageHash: Value = add(&Value::Str("ticker:".to_string()), &symbol);
client.resolve(&[ticker.clone(), messageHash.clone()]);
}
/*
* @method
* @name mexc#watchTickers
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
* @see https://www.mexc.com/api-docs/futures/websocket-api/tickers
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
pub async fn watch_tickers(&mut self, optional_args: &[Value]) -> Value {
let mut symbols = get_arg(optional_args, 0, Value::Null);
let mut params = get_arg(optional_args, 1, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
symbols = self.market_symbols(&[symbols.clone(), Value::Null]);
let mut messageHashes: Value = Value::List(vec![]);
let mut firstSymbol: Value = self.safe_string(symbols.clone(), Value::Int(0), &[]);
let mut market: Value = Value::Null;
if !is_equal(&firstSymbol, &Value::Null) {
market = self.market(firstSymbol.clone());
}
let mut type_var: Value = Value::Null;
{ let __destr_tmp = self.handle_market_type_and_params(Value::Str("watchTickers".to_string()), &[market.clone(), params.clone()]); type_var = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut isSpot: Value = Value::Bool(is_equal(&type_var, &Value::Str("spot".to_string())));
let mut url: Value = ternary(is_true(&(isSpot)), get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string())), get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string())));
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m
});
if is_true(&isSpot) {
panic!("{}", crate::exchange_errors::not_supported(add(&self.id, &Value::Str(" watchTickers does not support spot markets".to_string()))));
} else {
add_element_to_object(&mut request, &Value::Str("method".to_string()), Value::Str("sub.tickers".to_string()));
add_element_to_object(&mut request, &Value::Str("params".to_string()), Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
append_to_array(&mut messageHashes, Value::Str("ticker".to_string()));
}
let __ws_arg_0 = self.extend(request.clone(), &[params.clone()]);
let mut ticker: Value = self.watch_multiple(url.clone(), messageHashes.clone(), &[__ws_arg_0, messageHashes.clone()]).await;
if is_true(&isSpot) && is_true(&self.newUpdates) {
let mut result: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m
});
add_element_to_object(&mut result, &get_value(&ticker, &Value::Str("symbol".to_string())), ticker.clone());
return result;
}
return self.filter_by_array(self.tickers.clone(), Value::Str("symbol".to_string()), &[symbols.clone()]);
Value::Null
}
pub fn handle_tickers(&mut self, mut client: Value, mut message: Value) {
//
// swap
//
// {
// "channel": "push.tickers",
// "data": [
// {
// "symbol": "ETH_USDT",
// "lastPrice": 2324.5,
// "riseFallRate": 0.0356,
// "fairPrice": 2324.32,
// "indexPrice": 2325.44,
// "volume24": 25868309,
// "amount24": 591752573.9792,
// "maxBidPrice": 2557.98,
// "minAskPrice": 2092.89,
// "lower24Price": 2239.39,
// "high24Price": 2332.59,
// "timestamp": 1725872514111
// }
// ],
// "ts": 1725872514111
// }
//
// spot
//
// {
// "c": "spot@public.bookTicker.v3.api@BTCUSDT",
// "d": {
// "A": "4.70432",
// "B": "6.714863",
// "a": "20744.54",
// "b": "20744.17"
// },
// "s": "BTCUSDT",
// "t": 1678643605721
// }
//
// spot miniTicker
//
// {
// "d": {
// "s": "BTCUSDT",
// "p": "76522",
// "r": "0.0012",
// "tr": "0.0012",
// "h": "77196.3",
// "l": "75630.77",
// "v": "584664223.92",
// "q": "7666.720258",
// "lastRT": "-1",
// "MT": "0",
// "NV": "--",
// "t": "1731135533126"
// },
// "c": "spot@public.miniTicker.v3.api@BTCUSDT@UTC+8",
// "t": 1731135533126,
// "s": "BTCUSDT"
// }
//
let mut data: Value = self.safe_list2(message.clone(), Value::Str("data".to_string()), Value::Str("d".to_string()), &[Value::List(vec![])]);
let mut channel: Value = self.safe_string_k(message.clone(), "c", &[Value::Str("".to_string())]);
let mut marketId: Value = self.safe_string_k(message.clone(), "s", &[]);
let mut market: Value = self.safe_market(&[marketId.clone()]);
let mut channelStartsWithSpot: Value = Value::Bool(starts_with(&channel, &Value::Str("spot".to_string())));
let mut marketIdIsUndefined: bool = is_equal(&marketId, &Value::Null);
let mut isSpot: Value = ternary(is_true(&marketIdIsUndefined), channelStartsWithSpot.clone(), get_value(&market, &Value::Str("spot".to_string())));
let mut spotPrefix: Value = Value::Str("spot:".to_string());
let mut messageHashPrefix: Value = ternary(is_true(&(is_equal(&isSpot, &Value::Bool(true)))), spotPrefix.clone(), Value::Str("".to_string()));
let mut topic: Value = add(&messageHashPrefix, &Value::Str("ticker".to_string()));
let mut result: Value = Value::List(vec![]);
{
let mut i: Value = Value::Int(0);
let mut __for_first_484: bool = true;
while { if !__for_first_484 { i = add(&i, &Value::Int(1)); } __for_first_484 = false; is_less_than(&i, &get_array_length(&data)) } {
let mut entry: Value = get_value(&data, &i);
let mut entry: Value = get_value(&data, &i);
let mut ticker: Value = Value::Null;
if is_equal(&isSpot, &Value::Bool(true)) {
ticker = self.parse_ws_ticker(entry.clone(), &[market.clone()]);
} else {
ticker = self.parse_ticker(entry.clone(), &[]);
}
let mut symbol: Value = get_value(&ticker, &Value::Str("symbol".to_string()));
if !is_equal(&symbol, &Value::Null) {
add_element_to_object(&mut self.tickers, &symbol, ticker.clone());
}
append_to_array(&mut result, ticker.clone());
let mut messageHash: Value = add(&Value::Str("ticker:".to_string()), &symbol);
client.resolve(&[ticker.clone(), messageHash.clone()]);
}
}
client.resolve(&[result.clone(), topic.clone()]);
}
pub fn parse_ws_ticker(&self, mut ticker: Value, optional_args: &[Value]) -> Value {
let mut market = get_arg(optional_args, 0, Value::Null);
// protobuf ticker
// "bidprice": "93387.28", // Best bid price
// "bidquantity": "3.73485", // Best bid quantity
// "askprice": "93387.29", // Best ask price
// "askquantity": "7.669875" // Best ask quantity
//
// spot
//
// {
// "A": "4.70432",
// "B": "6.714863",
// "a": "20744.54",
// "b": "20744.17"
// }
//
// spot miniTicker
//
// {
// "s": "BTCUSDT",
// "p": "76521",
// "r": "0.0012",
// "tr": "0.0012",
// "h": "77196.3",
// "l": "75630.77",
// "v": "584664223.92",
// "q": "7666.720258",
// "lastRT": "-1",
// "MT": "0",
// "NV": "--",
// "t": "1731135533126"
// }
//
let mut marketId: Value = self.safe_string_k(ticker.clone(), "s", &[]);
let mut timestamp: Value = self.safe_integer_k(ticker.clone(), "t", &[]);
let mut price: Value = self.safe_string_k(ticker.clone(), "p", &[]);
return self.safe_ticker(Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("info".to_string(), ticker.clone());
m.insert("symbol".to_string(), self.safe_symbol(marketId.clone(), &[market.clone()]));
m.insert("timestamp".to_string(), timestamp.clone());
m.insert("datetime".to_string(), self.iso8601(timestamp.clone()));
m.insert("open".to_string(), Value::Null);
m.insert("high".to_string(), self.safe_number_k(ticker.clone(), "h", &[]));
m.insert("low".to_string(), self.safe_number_k(ticker.clone(), "l", &[]));
m.insert("close".to_string(), price.clone());
m.insert("last".to_string(), price.clone());
m.insert("bid".to_string(), self.safe_number2(ticker.clone(), Value::Str("b".to_string()), Value::Str("bidPrice".to_string()), &[]));
m.insert("bidVolume".to_string(), self.safe_number2(ticker.clone(), Value::Str("B".to_string()), Value::Str("bidQuantity".to_string()), &[]));
m.insert("ask".to_string(), self.safe_number2(ticker.clone(), Value::Str("a".to_string()), Value::Str("askPrice".to_string()), &[]));
m.insert("askVolume".to_string(), self.safe_number2(ticker.clone(), Value::Str("A".to_string()), Value::Str("askQuantity".to_string()), &[]));
m.insert("vwap".to_string(), Value::Null);
m.insert("previousClose".to_string(), Value::Null);
m.insert("change".to_string(), Value::Null);
m.insert("percentage".to_string(), self.safe_number_k(ticker.clone(), "tr", &[]));
m.insert("average".to_string(), Value::Null);
m.insert("baseVolume".to_string(), self.safe_number_k(ticker.clone(), "v", &[]));
m.insert("quoteVolume".to_string(), self.safe_number_k(ticker.clone(), "q", &[]));
m
}), &[market.clone()]);
Value::Null
}
/*
* @method
* @name mexc#watchBidsAsks
* @see https://www.mexc.com/api-docs/spot-v3/websocket-market-streams/individual-symbol-book-ticker-streams
* @description watches best bid & ask for symbols
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
pub async fn watch_bids_asks(&mut self, optional_args: &[Value]) -> Value {
let mut symbols = get_arg(optional_args, 0, Value::Null);
let mut params = get_arg(optional_args, 1, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
symbols = self.market_symbols(&[symbols.clone(), Value::Null, Value::Bool(true), Value::Bool(false), Value::Bool(true)]);
let mut marketType: Value = Value::Null;
if is_equal(&symbols, &Value::Null) {
panic!("{}", crate::exchange_errors::arguments_required(add(&self.id, &Value::Str(" watchBidsAsks required symbols argument".to_string()))));
}
let mut markets: Value = self.require_value(self.markets_for_symbols(&[symbols.clone()]), &[Value::Str("watchBidsAsks() markets is required".to_string())]);
{ let __destr_tmp = self.handle_market_type_and_params(Value::Str("watchBidsAsks".to_string()), &[get_value(&markets, &Value::Int(0)), params.clone()]); marketType = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut isSpot: bool = is_equal(&marketType, &Value::Str("spot".to_string()));
if !is_true(&isSpot) {
panic!("{}", crate::exchange_errors::not_supported(add(&self.id, &Value::Str(" watchBidsAsks only support spot market".to_string()))));
}
let mut messageHashes: Value = Value::List(vec![]);
let mut topics: Value = Value::List(vec![]);
{
let mut i: Value = Value::Int(0);
let mut __for_first_485: bool = true;
while { if !__for_first_485 { i = add(&i, &Value::Int(1)); } __for_first_485 = false; is_less_than(&i, &get_array_length(&symbols)) } {
if is_true(&isSpot) {
let mut market: Value = self.market(get_value(&symbols, &i));
append_to_array(&mut topics, add(&Value::Str("spot@public.aggre.bookTicker.v3.api.pb@100ms@".to_string()), &get_value(&market, &Value::Str("id".to_string()))));
}
append_to_array(&mut messageHashes, add(&Value::Str("bidask:".to_string()), &get_value(&symbols, &i)));
}
}
let mut url: Value = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string()));
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("method".to_string(), Value::Str("SUBSCRIPTION".to_string()));
m.insert("params".to_string(), topics.clone());
m
});
let __ws_arg_1 = self.extend(request.clone(), &[params.clone()]);
let mut ticker: Value = self.watch_multiple(url.clone(), messageHashes.clone(), &[__ws_arg_1, messageHashes.clone()]).await;
if is_true(&self.newUpdates) {
let mut tickers: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m
});
add_element_to_object(&mut tickers, &get_value(&ticker, &Value::Str("symbol".to_string())), ticker.clone());
return tickers;
}
return self.filter_by_array(self.bidsasks.clone(), Value::Str("symbol".to_string()), &[symbols.clone()]);
Value::Null
}
pub fn handle_bid_ask(&mut self, mut client: Value, mut message: Value) {
//
// {
// "c": "spot@public.bookTicker.v3.api@BTCUSDT",
// "d": {
// "A": "4.70432",
// "B": "6.714863",
// "a": "20744.54",
// "b": "20744.17"
// },
// "s": "BTCUSDT",
// "t": 1678643605721
// }
//
let mut parsedTicker: Value = self.parse_ws_bid_ask(message.clone(), &[]);
let mut symbol: Value = self.safe_string_k(parsedTicker.clone(), "symbol", &[]);
if is_equal(&symbol, &Value::Null) {
return;
}
add_element_to_object(&mut self.bidsasks, &symbol, parsedTicker.clone());
let mut messageHash: Value = add(&Value::Str("bidask:".to_string()), &symbol);
client.resolve(&[parsedTicker.clone(), messageHash.clone()]);
}
pub fn parse_ws_bid_ask(&self, mut ticker: Value, optional_args: &[Value]) -> Value {
let mut market = get_arg(optional_args, 0, Value::Null);
let mut data: Value = self.safe_dict_k(ticker.clone(), "d", &[]);
let mut marketId: Value = self.safe_string_k(ticker.clone(), "s", &[]);
market = self.safe_market(&[marketId.clone(), market.clone()]);
let mut symbol: Value = self.safe_string_k(market.clone(), "symbol", &[]);
let mut timestamp: Value = self.safe_integer_k(ticker.clone(), "t", &[]);
return self.safe_ticker(Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), symbol.clone());
m.insert("timestamp".to_string(), timestamp.clone());
m.insert("datetime".to_string(), self.iso8601(timestamp.clone()));
m.insert("ask".to_string(), self.safe_number_k(data.clone(), "a", &[]));
m.insert("askVolume".to_string(), self.safe_number_k(data.clone(), "A", &[]));
m.insert("bid".to_string(), self.safe_number_k(data.clone(), "b", &[]));
m.insert("bidVolume".to_string(), self.safe_number_k(data.clone(), "B", &[]));
m.insert("info".to_string(), ticker.clone());
m
}), &[market.clone()]);
Value::Null
}
pub async fn watch_spot_public(&mut self, mut channel: Value, mut messageHash: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
let mut unsubscribed: Value = self.safe_bool_k(params.clone(), "unsubscribed", &[Value::Bool(false)]);
params = self.omit(params.clone(), Value::List(vec![Value::Str("unsubscribed".to_string())]), &[]);
let mut url: Value = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string()));
let mut method: Value = ternary(is_true(&(is_equal(&unsubscribed, &Value::Bool(true)))), Value::Str("UNSUBSCRIPTION".to_string()), Value::Str("SUBSCRIPTION".to_string()));
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("method".to_string(), method.clone());
m.insert("params".to_string(), Value::List(vec![channel.clone()]));
m
});
let __ws_arg_2 = self.extend(request.clone(), &[params.clone()]);
return self.watch(url.clone(), messageHash.clone(), &[__ws_arg_2, messageHash.clone()]).await;
Value::Null
}
pub async fn watch_spot_private(&mut self, mut channel: Value, mut messageHash: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
self.check_required_credentials(&[]);
let mut listenKey: Value = self.authenticate(channel.clone(), &[]).await;
let mut url: Value = add(&add(&get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string())), &Value::Str("?listenKey=".to_string())), &listenKey);
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("method".to_string(), Value::Str("SUBSCRIPTION".to_string()));
m.insert("params".to_string(), Value::List(vec![channel.clone()]));
m
});
let __ws_arg_3 = self.extend(request.clone(), &[params.clone()]);
return self.watch(url.clone(), messageHash.clone(), &[__ws_arg_3, channel.clone()]).await;
Value::Null
}
pub async fn watch_swap_public(&mut self, mut channel: Value, mut messageHash: Value, mut requestParams: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
let mut url: Value = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string()));
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("method".to_string(), channel.clone());
m.insert("param".to_string(), requestParams.clone());
m
});
let mut message: Value = self.extend(request.clone(), &[params.clone()]);
return self.watch(url.clone(), messageHash.clone(), &[message.clone(), messageHash.clone()]).await;
Value::Null
}
pub async fn watch_swap_private(&mut self, mut messageHash: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
self.check_required_credentials(&[]);
let mut channel: Value = Value::Str("login".to_string());
let mut url: Value = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string()));
let mut timestamp: Value = to_string_val(&self.milliseconds());
let mut payload: Value = add(&self.apiKey, ×tamp);
let mut signature: Value = self.hmac(self.encode(payload.clone()), self.encode(self.secret.clone()), Value::Str("sha256".to_string()), &[]);
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("method".to_string(), channel.clone());
m.insert("param".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("apiKey".to_string(), self.apiKey.clone());
m.insert("signature".to_string(), signature.clone());
m.insert("reqTime".to_string(), timestamp.clone());
m
}));
m
});
let mut message: Value = self.extend(request.clone(), &[params.clone()]);
return self.watch(url.clone(), messageHash.clone(), &[message.clone(), channel.clone()]).await;
Value::Null
}
/*
* @method
* @name mexc#watchOHLCV
* @see https://www.mexc.com/api-docs/spot-v3/websocket-market-streams/k-line-streams // spot
* @see https://www.mexc.com/api-docs/futures/websocket-api/k-line-data // swap
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} timeframe the length of time each candle represents
* @param {int} [since] timestamp in ms of the earliest candle to fetch
* @param {int} [limit] the maximum amount of candles to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
pub async fn watch_ohlcv(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut timeframe = get_arg(optional_args, 0, Value::Str("1m".to_string()));
let mut since = get_arg(optional_args, 1, Value::Null);
let mut limit = get_arg(optional_args, 2, Value::Null);
let mut params = get_arg(optional_args, 3, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
let mut timeframes: Value = self.safe_value_k(self.options.clone(), "timeframes", &[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
let mut timeframeId: Value = self.safe_string(timeframes.clone(), timeframe.clone(), &[]);
let mut messageHash: Value = add(&add(&add(&Value::Str("candles:".to_string()), &symbol), &Value::Str(":".to_string())), &timeframe);
let mut ohlcv: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
let mut channel: Value = add(&add(&add(&Value::Str("spot@public.kline.v3.api.pb@".to_string()), &get_value(&market, &Value::Str("id".to_string()))), &Value::Str("@".to_string())), &timeframeId);
ohlcv = self.watch_spot_public(channel.clone(), messageHash.clone(), &[params.clone()]).await;
} else {
let mut channel: Value = Value::Str("sub.kline".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m.insert("interval".to_string(), timeframeId.clone());
m
});
ohlcv = self.watch_swap_public(channel.clone(), messageHash.clone(), requestParams.clone(), &[params.clone()]).await;
}
ohlcv = self.require_value(ohlcv.clone(), &[Value::Str("watchOHLCV() ohlcv is required".to_string())]);
if is_true(&self.newUpdates) {
limit = ohlcv.get_limit(symbol.clone(), limit.clone());
}
return self.filter_by_since_limit(ohlcv.clone(), &[since.clone(), limit.clone(), Value::Int(0), Value::Bool(true)]);
Value::Null
}
pub fn handle_ohlcv(&mut self, mut client: Value, mut message: Value) {
//
// spot
//
// {
// "d": {
// "e": "spot@public.kline.v3.api",
// "k": {
// "t": 1678642261,
// "o": 20626.94,
// "c": 20599.69,
// "h": 20626.94,
// "l": 20597.06,
// "v": 27.678686,
// "a": 570332.77,
// "T": 1678642320,
// "i": "Min1"
// }
// },
// "c": "spot@public.kline.v3.api@BTCUSDT@Min1",
// "t": 1678642276459,
// "s": "BTCUSDT"
// }
//
// swap
//
// {
// "channel": "push.kline",
// "data": {
// "a": 325653.3287,
// "c": 38839,
// "h": 38909.5,
// "interval": "Min1",
// "l": 38833,
// "o": 38901.5,
// "q": 83808,
// "rc": 38839,
// "rh": 38909.5,
// "rl": 38833,
// "ro": 38909.5,
// "symbol": "BTC_USDT",
// "t": 1651230660
// },
// "symbol": "BTC_USDT",
// "ts": 1651230713067
// }
// protobuf
// {
// "channel":"spot@public.kline.v3.api.pb@BTCUSDT@Min1",
// "symbol":"BTCUSDT",
// "symbolId":"2fb942154ef44a4ab2ef98c8afb6a4a7",
// "createTime":"1754737941062",
// "publicSpotKline":{
// "interval":"Min1",
// "windowStart":"1754737920",
// "openingPrice":"117317.31",
// "closingPrice":"117325.26",
// "highestPrice":"117341",
// "lowestPrice":"117317.3",
// "volume":"3.12599854",
// "amount":"366804.43",
// "windowEnd":"1754737980"
// }
// }
//
let mut parsed: Value = Value::Null;
let mut symbol: Value = Value::Null;
let mut timeframe: Value = Value::Null;
if is_true(&Value::Bool(in_op(&message, &Value::Str("publicSpotKline".to_string())))) {
symbol = self.symbol(self.safe_string_k(message.clone(), "symbol", &[]));
let mut data: Value = self.safe_dict_k(message.clone(), "publicSpotKline", &[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
let mut timeframeId: Value = self.safe_string_k(data.clone(), "interval", &[]);
timeframe = self.find_timeframe(timeframeId.clone(), &[get_value(&self.options, &Value::Str("timeframes".to_string()))]);
parsed = self.parse_ws_ohlcv(data.clone(), &[self.safe_market(&[symbol.clone()])]);
} else {
let mut d: Value = self.safe_value2(message.clone(), Value::Str("d".to_string()), Value::Str("data".to_string()), &[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
let mut rawOhlcv: Value = self.safe_value_k(d.clone(), "k", &[d.clone()]);
let mut timeframeId: Value = self.safe_string2(rawOhlcv.clone(), Value::Str("i".to_string()), Value::Str("interval".to_string()), &[]);
let mut timeframes: Value = self.safe_value_k(self.options.clone(), "timeframes", &[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
timeframe = self.find_timeframe(timeframeId.clone(), &[timeframes.clone()]);
let mut marketId: Value = self.safe_string2(message.clone(), Value::Str("s".to_string()), Value::Str("symbol".to_string()), &[]);
let mut market: Value = self.safe_market(&[marketId.clone()]);
symbol = get_value(&market, &Value::Str("symbol".to_string()));
parsed = self.parse_ws_ohlcv(rawOhlcv.clone(), &[market.clone()]);
}
let mut messageHash: Value = add(&add(&add(&Value::Str("candles:".to_string()), &symbol), &Value::Str(":".to_string())), &timeframe);
let mut symbolOhlcvs: Value = self.safe_value(self.ohlcvs.clone(), symbol.clone(), &[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
add_element_to_object(&mut self.ohlcvs, &symbol, symbolOhlcvs.clone());
let mut stored: Value = self.safe_value(symbolOhlcvs.clone(), timeframe.clone(), &[]);
if is_equal(&stored, &Value::Null) {
let mut limit: Value = self.safe_integer_k(self.options.clone(), "OHLCVLimit", &[Value::Int(1000)]);
stored = ArrayCacheByTimestamp::new(limit.clone());
if !is_equal(&timeframe, &Value::Null) {
add_element_to_object(&mut symbolOhlcvs, &timeframe, stored.clone());
}
}
stored.append(parsed.clone());
client.resolve(&[stored.clone(), messageHash.clone()]);
}
pub fn parse_ws_ohlcv(&self, mut ohlcv: Value, optional_args: &[Value]) -> Value {
let mut market = get_arg(optional_args, 0, Value::Null);
//
// spot
//
// {
// "t": 1678642260,
// "o": 20626.94,
// "c": 20599.69,
// "h": 20626.94,
// "l": 20597.06,
// "v": 27.678686,
// "a": 570332.77,
// "T": 1678642320,
// "i": "Min1"
// }
//
// swap
// {
// "symbol": "BTC_USDT",
// "interval": "Min1",
// "t": 1680055080,
// "o": 27301.9,
// "c": 27301.8,
// "h": 27301.9,
// "l": 27301.8,
// "a": 8.19054,
// "q": 3,
// "ro": 27301.8,
// "rc": 27301.8,
// "rh": 27301.8,
// "rl": 27301.8
// }
// protobuf
//
// "interval":"Min1",
// "windowStart":"1754737920",
// "openingPrice":"117317.31",
// "closingPrice":"117325.26",
// "highestPrice":"117341",
// "lowestPrice":"117317.3",
// "volume":"3.12599854",
// "amount":"366804.43",
// "windowEnd":"1754737980"
//
let mut volume: Value = self.safe_number2(ohlcv.clone(), Value::Str("v".to_string()), Value::Str("volume".to_string()), &[]);
// MEXC swap websocket klines publish contracts volume in `q`,
// while spot/protobuf uses `v`/`volume`.
if is_true(&(!is_equal(&market, &Value::Null))) && is_true(&(!is_equal(&self.safe_bool_k(market.clone(), "spot", &[]), &Value::Bool(true)))) && is_true(&(is_equal(&volume, &Value::Null))) {
volume = self.safe_number2(ohlcv.clone(), Value::Str("q".to_string()), Value::Str("v".to_string()), &[]);
}
return Value::List(vec![self.safe_timestamp2(ohlcv.clone(), Value::Str("t".to_string()), Value::Str("windowStart".to_string()), &[]), self.safe_number2(ohlcv.clone(), Value::Str("o".to_string()), Value::Str("openingPrice".to_string()), &[]), self.safe_number2(ohlcv.clone(), Value::Str("h".to_string()), Value::Str("highestPrice".to_string()), &[]), self.safe_number2(ohlcv.clone(), Value::Str("l".to_string()), Value::Str("lowestPrice".to_string()), &[]), self.safe_number2(ohlcv.clone(), Value::Str("c".to_string()), Value::Str("closingPrice".to_string()), &[]), volume.clone()]);
Value::Null
}
/*
* @method
* @name mexc#watchOrderBook
* @see https://www.mexc.com/api-docs/spot-v3/websocket-market-streams/diffdepth-stream // spot
* @see https://www.mexc.com/api-docs/futures/websocket-api/order-book-depth // swap
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int} [limit] the maximum amount of order book entries to return
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string} [params.frequency] the frequency of the order book updates, default is '10ms', can be '100ms' or '10ms
* @returns {object} an [order book structure]{@link https://docs.ccxt.com/?id=order-book-structure}
*/
pub async fn watch_order_book(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut limit = get_arg(optional_args, 0, Value::Null);
let mut params = get_arg(optional_args, 1, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
let mut messageHash: Value = add(&Value::Str("orderbook:".to_string()), &symbol);
let mut orderbook: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
let mut frequency: Value = Value::Null;
{ let __destr_tmp = self.handle_option_and_params(params.clone(), Value::Str("watchOrderBook".to_string()), Value::Str("frequency".to_string()), &[Value::Str("100ms".to_string())]); frequency = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut channel: Value = add(&add(&add(&Value::Str("spot@public.aggre.depth.v3.api.pb@".to_string()), &frequency), &Value::Str("@".to_string())), &get_value(&market, &Value::Str("id".to_string())));
orderbook = self.watch_spot_public(channel.clone(), messageHash.clone(), &[params.clone()]).await;
} else {
let mut channel: Value = Value::Str("sub.depth".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
orderbook = self.watch_swap_public(channel.clone(), messageHash.clone(), requestParams.clone(), &[params.clone()]).await;
}
orderbook = self.require_value(orderbook.clone(), &[Value::Str("watchOrderBook() orderbook is required".to_string())]);
return orderbook.limit();
Value::Null
}
pub fn handle_order_book_subscription(&mut self, mut client: Value, mut message: Value) {
// spot
// { id: 0, code: 0, msg: "spot@public.increase.depth.v3.api@BTCUSDT" }
//
let mut msg: Value = self.safe_string_k(message.clone(), "msg", &[Value::Str("".to_string())]);
let mut parts: Value = split(&msg, &Value::Str("@".to_string()));
let mut marketId: Value = self.safe_string(parts.clone(), Value::Int(2), &[]);
let mut symbol: Value = self.safe_symbol(marketId.clone(), &[]);
{ let __be_tmp = self.order_book(&[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]); add_element_to_object(&mut self.orderbooks, &symbol, __be_tmp); };
}
pub fn get_cache_index(&self, mut orderbook: Value, mut cache: Value) -> Value {
// return the first index of the cache that can be applied to the orderbook or -1 if not possible
let mut nonce: Value = self.safe_integer_k(orderbook.clone(), "nonce", &[]);
let mut firstDelta: Value = self.safe_value(cache.clone(), Value::Int(0), &[]);
let mut firstDeltaNonce: Value = self.safe_integer_n(firstDelta.clone(), Value::List(vec![Value::Str("r".to_string()), Value::Str("version".to_string()), Value::Str("fromVersion".to_string())]), &[]);
if is_true(&(is_equal(&nonce, &Value::Null))) || is_true(&(is_equal(&firstDeltaNonce, &Value::Null))) {
return negate(&Value::Int(1));
}
if is_less_than(&nonce, &subtract(&firstDeltaNonce, &Value::Int(1))) {
return negate(&Value::Int(1));
}
{
let mut i: Value = Value::Int(0);
let mut __for_first_486: bool = true;
while { if !__for_first_486 { i = add(&i, &Value::Int(1)); } __for_first_486 = false; is_less_than(&i, &get_array_length(&cache)) } {
let mut delta: Value = get_value(&cache, &i);
let mut delta: Value = get_value(&cache, &i);
let mut deltaNonce: Value = self.safe_integer_n(delta.clone(), Value::List(vec![Value::Str("r".to_string()), Value::Str("version".to_string()), Value::Str("fromVersion".to_string())]), &[]);
if is_equal(&deltaNonce, &Value::Null) {
continue;
}
if is_greater_than_or_equal(&deltaNonce, &nonce) {
return i;
}
}
}
return get_array_length(&cache);
Value::Null
}
pub fn handle_order_book(&mut self, mut client: Value, mut message: Value) {
//
// spot
// {
// "c": "spot@public.increase.depth.v3.api@BTCUSDT",
// "d": {
// "asks": [{
// "p": "20290.89",
// "v": "0.000000"
// }],
// "e": "spot@public.increase.depth.v3.api",
// "r": "3407459756"
// },
// "s": "BTCUSDT",
// "t": 1661932660144
// }
//
//
//
// swap
// {
// "channel":"push.depth",
// "data":{
// "asks":[
// [
// 39146.5,
// 11264,
// 1
// ]
// ],
// "bids":[
// [
// 39144,
// 35460,
// 1
// ]
// ],
// "end":4895965272,
// "begin":4895965271
// },
// "symbol":"BTC_USDT",
// "ts":1651239652372
// }
// protofbuf
// {
// "channel":"spot@public.aggre.depth.v3.api.pb@100ms@BTCUSDT",
// "symbol":"BTCUSDT",
// "sendTime":"1754741322152",
// "publicAggreDepths":{
// "asks":[
// {
// "price":"117145.49",
// "quantity":"0"
// }
// ],
// "bids":[
// {
// "price":"117053.41",
// "quantity":"1.86837271"
// }
// ],
// "eventType":"spot@public.aggre.depth.v3.api.pb@100ms",
// "fromVersion":"43296363236",
// "toVersion":"43296363255"
// }
// }
//
let mut data: Value = self.safe_dict_n(message.clone(), Value::List(vec![Value::Str("d".to_string()), Value::Str("data".to_string()), Value::Str("publicAggreDepths".to_string())]), &[]);
let mut marketId: Value = self.safe_string2(message.clone(), Value::Str("s".to_string()), Value::Str("symbol".to_string()), &[]);
let mut symbol: Value = self.safe_symbol(marketId.clone(), &[]);
let mut messageHash: Value = add(&Value::Str("orderbook:".to_string()), &symbol);
let mut subscription: Value = self.safe_value(get_value(&client, &Value::Str("subscriptions".to_string())), messageHash.clone(), &[]);
let mut limit: Value = self.safe_integer_k(subscription.clone(), "limit", &[]);
if !is_true(&(Value::Bool(in_op(&self.orderbooks, &symbol)))) {
{ let __be_tmp = self.order_book(&[]); add_element_to_object(&mut self.orderbooks, &symbol, __be_tmp); };
}
let mut storedOrderBook: Value = get_value(&self.orderbooks, &symbol);
let mut nonce: Value = self.safe_integer_k(storedOrderBook.clone(), "nonce", &[]);
let mut shouldReturn: bool = false;
if is_equal(&nonce, &Value::Null) {
let mut cacheLength: Value = get_array_length(&get_value(&storedOrderBook, &Value::Str("cache".to_string())));
let mut snapshotDelay: Value = self.handle_option(Value::Str("watchOrderBook".to_string()), Value::Str("snapshotDelay".to_string()), &[Value::Int(25)]);
if is_equal(&cacheLength, &snapshotDelay) {
self.spawn(&[Value::Str("load_order_book".to_string()).clone(), client.clone(), messageHash.clone(), symbol.clone(), limit.clone(), Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
}
crate::runtime::append_to_object_array(&mut storedOrderBook, &Value::Str("cache".to_string()), data.clone());
return;
}
let _try_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
self.handle_delta(storedOrderBook.clone(), data.clone());
let mut timestamp: Value = self.safe_integer_n(message.clone(), Value::List(vec![Value::Str("t".to_string()), Value::Str("ts".to_string()), Value::Str("sendTime".to_string())]), &[]);
add_element_to_object(&mut storedOrderBook, &Value::Str("timestamp".to_string()), timestamp.clone());
add_element_to_object(&mut storedOrderBook, &Value::Str("datetime".to_string()), self.iso8601(timestamp.clone()));
#[allow(unreachable_code)] { Value::Null }}));
if let Err(_try_err) = _try_result { let e: Value = panic_to_value(_try_err);
remove(&mut get_value(&client, &Value::Str("subscriptions".to_string())), &messageHash);
client.reject(&[e.clone(), messageHash.clone()]);
// return;
shouldReturn = true;
}
if is_true(&shouldReturn) {
return;
}
client.resolve(&[storedOrderBook.clone(), messageHash.clone()]);
}
pub fn handle_bookside_delta(&self, mut bookside: Value, mut bidasks: Value) {
{
let mut i: Value = Value::Int(0);
let mut __for_first_487: bool = true;
while { if !__for_first_487 { i = add(&i, &Value::Int(1)); } __for_first_487 = false; is_less_than(&i, &get_array_length(&bidasks)) } {
let mut bidask: Value = get_value(&bidasks, &i);
let mut bidask: Value = get_value(&bidasks, &i);
if is_true(&Value::Bool(is_array(&bidask))) {
bookside.store_array(bidask.clone());
} else {
let mut price: Value = self.safe_float2(bidask.clone(), Value::Str("p".to_string()), Value::Str("price".to_string()), &[]);
let mut amount: Value = self.safe_float2(bidask.clone(), Value::Str("v".to_string()), Value::Str("quantity".to_string()), &[]);
bookside.store(price.clone(), amount.clone());
}
}
}
}
pub fn handle_delta(&self, mut orderbook: Value, mut delta: Value) {
let mut existingNonce: Value = self.safe_integer_k(orderbook.clone(), "nonce", &[]);
let mut deltaNonce: Value = self.safe_integer_n(delta.clone(), Value::List(vec![Value::Str("r".to_string()), Value::Str("version".to_string()), Value::Str("fromVersion".to_string())]), &[]);
if is_true(&(!is_equal(&deltaNonce, &Value::Null))) && is_true(&(!is_equal(&existingNonce, &Value::Null))) && is_true(&(is_less_than(&deltaNonce, &existingNonce))) {
return;
}
add_element_to_object(&mut orderbook, &Value::Str("nonce".to_string()), deltaNonce.clone());
let mut asks: Value = self.safe_list_k(delta.clone(), "asks", &[Value::List(vec![])]);
let mut bids: Value = self.safe_list_k(delta.clone(), "bids", &[Value::List(vec![])]);
let mut asksOrderSide: Value = get_value(&orderbook, &Value::Str("asks".to_string()));
let mut bidsOrderSide: Value = get_value(&orderbook, &Value::Str("bids".to_string()));
self.handle_bookside_delta(asksOrderSide.clone(), asks.clone());
self.handle_bookside_delta(bidsOrderSide.clone(), bids.clone());
}
/*
* @method
* @name mexc#watchTrades
* @see https://www.mexc.com/api-docs/spot-v3/websocket-market-streams/trade-streams // spot
* @see https://www.mexc.com/api-docs/futures/websocket-api/deal // swap
* @description get the list of most recent trades for a particular symbol
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int} [since] timestamp in ms of the earliest trade to fetch
* @param {int} [limit] the maximum amount of trades to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
*/
pub async fn watch_trades(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut since = get_arg(optional_args, 0, Value::Null);
let mut limit = get_arg(optional_args, 1, Value::Null);
let mut params = get_arg(optional_args, 2, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
let mut messageHash: Value = add(&Value::Str("trades:".to_string()), &symbol);
let mut trades: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
let mut channel: Value = add(&Value::Str("spot@public.aggre.deals.v3.api.pb@100ms@".to_string()), &get_value(&market, &Value::Str("id".to_string())));
trades = self.watch_spot_public(channel.clone(), messageHash.clone(), &[params.clone()]).await;
} else {
let mut channel: Value = Value::Str("sub.deal".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
trades = self.watch_swap_public(channel.clone(), messageHash.clone(), requestParams.clone(), &[params.clone()]).await;
}
trades = self.require_value(trades.clone(), &[Value::Str("watchTrades() trades is required".to_string())]);
if is_true(&self.newUpdates) {
limit = trades.get_limit(symbol.clone(), limit.clone());
}
return self.filter_by_since_limit(trades.clone(), &[since.clone(), limit.clone(), Value::Str("timestamp".to_string()), Value::Bool(true)]);
Value::Null
}
pub fn handle_trades(&mut self, mut client: Value, mut message: Value) {
// protobuf
// {
// "channel": "spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT",
// "publicdeals": {
// "dealsList": [
// {
// "price": "93220.00", // Trade price
// "quantity": "0.04438243", // Trade quantity
// "tradetype": 2, // Trade type (1: Buy, 2: Sell)
// "time": 1736409765051 // Trade time
// }
// ],
// "eventtype": "spot@public.aggre.deals.v3.api.pb@100ms" // Event type
// },
// "symbol": "BTCUSDT", // Trading pair
// "sendtime": 1736409765052 // Event time
// }
//
// {
// "c": "spot@public.deals.v3.api@BTCUSDT",
// "d": {
// "deals": [{
// "p": "20382.70",
// "v": "0.043800",
// "S": 1,
// "t": 1678593222456,
// }, ],
// "e": "spot@public.deals.v3.api",
// },
// "s": "BTCUSDT",
// "t": 1678593222460,
// }
//
// swap
// {
// "symbol": "BTC_USDT",
// "data": [
// {
// "p": 114350.4,
// "v": 4,
// "T": 2,
// "O": 3,
// "M": 2,
// "t": 1760368563597
// }
// ],
// "channel": "push.deal",
// "ts": 1680055941870
// }
//
let mut marketId: Value = self.safe_string2(message.clone(), Value::Str("s".to_string()), Value::Str("symbol".to_string()), &[]);
let mut market: Value = self.safe_market(&[marketId.clone()]);
let mut symbol: Value = get_value(&market, &Value::Str("symbol".to_string()));
let mut messageHash: Value = add(&Value::Str("trades:".to_string()), &symbol);
let mut stored: Value = self.safe_value(self.trades.clone(), symbol.clone(), &[]);
if is_equal(&stored, &Value::Null) {
let mut limit: Value = self.safe_integer_k(self.options.clone(), "tradesLimit", &[Value::Int(1000)]);
stored = ArrayCache::new(limit.clone());
add_element_to_object(&mut self.trades, &symbol, stored.clone());
}
let mut d: Value = self.safe_dict_n(message.clone(), Value::List(vec![Value::Str("d".to_string()), Value::Str("publicAggreDeals".to_string())]), &[]);
let mut trades: Value = self.safe_list2(d.clone(), Value::Str("deals".to_string()), Value::Str("dealsList".to_string()), &[Value::List(vec![d.clone()])]);
if is_equal(&d, &Value::Null) {
trades = self.safe_list_k(message.clone(), "data", &[Value::List(vec![])]);
}
{
let mut j: Value = Value::Int(0);
let mut __for_first_488: bool = true;
while { if !__for_first_488 { j = add(&j, &Value::Int(1)); } __for_first_488 = false; is_less_than(&j, &get_array_length(&trades)) } {
let mut parsedTrade: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
parsedTrade = self.parse_ws_trade(get_value(&trades, &j), &[market.clone()]);
} else {
parsedTrade = self.parse_trade(get_value(&trades, &j), &[market.clone()]);
}
stored.append(parsedTrade.clone());
}
}
client.resolve(&[stored.clone(), messageHash.clone()]);
}
/*
* @method
* @name mexc#watchMyTrades
* @see https://www.mexc.com/api-docs/spot-v3/websocket-user-data-streams/spot-account-deals // spot
* @see https://www.mexc.com/api-docs/futures/websocket-api/fill-details // swap
* @description watches information on multiple trades made by the user
* @param {string} symbol unified market symbol of the market trades were made in
* @param {int} [since] the earliest time in ms to fetch trades for
* @param {int} [limit] the maximum number of trade structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
*/
pub async fn watch_my_trades(&mut self, optional_args: &[Value]) -> Value {
let mut symbol = get_arg(optional_args, 0, Value::Null);
let mut since = get_arg(optional_args, 1, Value::Null);
let mut limit = get_arg(optional_args, 2, Value::Null);
let mut params = get_arg(optional_args, 3, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut messageHash: Value = Value::Str("myTrades".to_string());
let mut market: Value = Value::Null;
if !is_equal(&symbol, &Value::Null) {
market = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
messageHash = add(&add(&messageHash, &Value::Str(":".to_string())), &symbol);
}
let mut type_var: Value = Value::Null;
{ let __destr_tmp = self.handle_market_type_and_params(Value::Str("watchMyTrades".to_string()), &[market.clone(), params.clone()]); type_var = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut trades: Value = Value::Null;
if is_equal(&type_var, &Value::Str("spot".to_string())) {
let mut channel: Value = Value::Str("spot@private.deals.v3.api.pb".to_string());
trades = self.watch_spot_private(channel.clone(), messageHash.clone(), &[params.clone()]).await;
} else {
trades = self.watch_swap_private(messageHash.clone(), &[params.clone()]).await;
}
trades = self.require_value(trades.clone(), &[Value::Str("watchMyTrades() trades is required".to_string())]);
if is_true(&self.newUpdates) {
limit = trades.get_limit(symbol.clone(), limit.clone());
}
return self.filter_by_symbol_since_limit(trades.clone(), &[symbol.clone(), since.clone(), limit.clone(), Value::Bool(true)]);
Value::Null
}
pub fn handle_my_trade(&mut self, mut client: Value, mut message: Value, optional_args: &[Value]) {
let mut subscription = get_arg(optional_args, 0, Value::Null);
//
// {
// "c": "spot@private.deals.v3.api",
// "d": {
// "p": "22339.99",
// "v": "0.000235",
// "S": 1,
// "T": 1678670940695,
// "t": "9f6a47fb926442e496c5c4c104076ae3",
// "c": '',
// "i": "e2b9835d1b6745f8a10ab74a81a16d50",
// "m": 0,
// "st": 0
// },
// "s": "BTCUSDT",
// "t": 1678670940700
// }
// {
// channel: "spot@private.deals.v3.api.pb",
// symbol: "MXUSDT",
// sendTime: 1736417034332,
// privateDeals {
// price: "3.6962",
// quantity: "1",
// amount: "3.6962",
// tradeType: 2,
// tradeId: "505979017439002624X1",
// orderId: "C02__505979017439002624115",
// feeAmount: "0.0003998377369698171",
// feeCurrency: "MX",
// time: 1736417034280
// }
// }
//
let mut messageHash: Value = Value::Str("myTrades".to_string());
let mut data: Value = self.safe_dict_n(message.clone(), Value::List(vec![Value::Str("d".to_string()), Value::Str("data".to_string()), Value::Str("privateDeals".to_string())]), &[]);
let mut futuresMarketId: Value = self.safe_string_k(data.clone(), "symbol", &[]);
let mut marketId: Value = self.safe_string2(message.clone(), Value::Str("s".to_string()), Value::Str("symbol".to_string()), &[futuresMarketId.clone()]);
let mut market: Value = self.safe_market(&[marketId.clone()]);
let mut symbol: Value = get_value(&market, &Value::Str("symbol".to_string()));
let mut trade: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
trade = self.parse_ws_trade(data.clone(), &[market.clone()]);
} else if !is_equal(&data, &Value::Null) {
trade = self.parse_trade(data.clone(), &[market.clone()]);
} else {
return;
}
let mut trades: Value = self.myTrades.clone();
if is_equal(&trades, &Value::Null) {
let mut limit: Value = self.safe_integer_k(self.options.clone(), "tradesLimit", &[Value::Int(1000)]);
trades = ArrayCacheBySymbolById::new(limit.clone());
self.myTrades = trades.clone();
}
trades.append(trade.clone());
client.resolve(&[trades.clone(), messageHash.clone()]);
let mut symbolSpecificMessageHash: Value = add(&add(&messageHash, &Value::Str(":".to_string())), &symbol);
client.resolve(&[trades.clone(), symbolSpecificMessageHash.clone()]);
}
pub fn parse_ws_trade(&self, mut trade: Value, optional_args: &[Value]) -> Value {
let mut market = get_arg(optional_args, 0, Value::Null);
//
// public trade (protobuf)
// {
// "p": "20382.70",
// "v": "0.043800",
// "S": 1,
// "t": 1678593222456,
// }
// private trade
// {
// "S": 1,
// "T": 1661938980268,
// "c": "",
// "i": "c079b0fcb80a46e8b128b281ce4e4f38",
// "m": 1,
// "p": "1.008",
// "st": 0,
// "t": "4079b1522a0b40e7919f609e1ea38d44",
// "v": "5"
// }
//
// d: {
// p: '1.0005',
// v: '5.71',
// a: '5.712855',
// S: 1,
// T: 1714325698237,
// t: 'edafcd9fdc2f426e82443d114691f724',
// c: '',
// i: 'C02__413321238354677760043',
// m: 0,
// st: 0,
// n: '0.005712855',
// N: 'USDT'
// }
// protobuf
//
// {
// price: "3.6962",
// quantity: "1",
// amount: "3.6962",
// tradeType: 2,
// tradeId: "505979017439002624X1",
// orderId: "C02__505979017439002624115",
// feeAmount: "0.0003998377369698171",
// feeCurrency: "MX",
// time: 1736417034280
// }
//
let mut timestamp: Value = self.safe_integer2(trade.clone(), Value::Str("T".to_string()), Value::Str("time".to_string()), &[]);
let mut tradeId: Value = self.safe_string2(trade.clone(), Value::Str("t".to_string()), Value::Str("tradeId".to_string()), &[]);
if is_equal(×tamp, &Value::Null) {
timestamp = self.safe_integer_k(trade.clone(), "t", &[]);
tradeId = Value::Null;
}
let mut priceString: Value = self.safe_string2(trade.clone(), Value::Str("p".to_string()), Value::Str("price".to_string()), &[]);
let mut amountString: Value = self.safe_string2(trade.clone(), Value::Str("v".to_string()), Value::Str("quantity".to_string()), &[]);
let mut rawSide: Value = self.safe_string2(trade.clone(), Value::Str("S".to_string()), Value::Str("tradeType".to_string()), &[]);
let mut side: Value = ternary(is_true(&(is_equal(&rawSide, &Value::Str("1".to_string())))), Value::Str("buy".to_string()), Value::Str("sell".to_string()));
let mut isMaker: Value = self.safe_integer_k(trade.clone(), "m", &[]);
let mut feeAmount: Value = self.safe_string2(trade.clone(), Value::Str("n".to_string()), Value::Str("feeAmount".to_string()), &[]);
let mut feeCurrencyId: Value = self.safe_string2(trade.clone(), Value::Str("N".to_string()), Value::Str("feeCurrency".to_string()), &[]);
return self.safe_trade(Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("info".to_string(), trade.clone());
m.insert("id".to_string(), tradeId.clone());
m.insert("order".to_string(), self.safe_string2(trade.clone(), Value::Str("i".to_string()), Value::Str("orderId".to_string()), &[]));
m.insert("timestamp".to_string(), timestamp.clone());
m.insert("datetime".to_string(), self.iso8601(timestamp.clone()));
m.insert("symbol".to_string(), self.safe_symbol(Value::Null, &[market.clone()]));
m.insert("type".to_string(), Value::Null);
m.insert("side".to_string(), side.clone());
m.insert("takerOrMaker".to_string(), ternary(is_true(&(!is_equal(&isMaker, &Value::Null) && !is_equal(&isMaker, &Value::Null) && !is_equal(&isMaker, &Value::Int(0)))), Value::Str("maker".to_string()), Value::Str("taker".to_string())));
m.insert("price".to_string(), priceString.clone());
m.insert("amount".to_string(), amountString.clone());
m.insert("cost".to_string(), self.safe_string_k(trade.clone(), "amount", &[]));
m.insert("fee".to_string(), Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("cost".to_string(), feeAmount.clone());
m.insert("currency".to_string(), self.safe_currency_code(feeCurrencyId.clone(), &[]));
m
}));
m
}), &[market.clone()]);
Value::Null
}
/*
* @method
* @name mexc#watchOrders
* @see https://www.mexc.com/api-docs/spot-v3/websocket-user-data-streams/spot-account-orders // spot
* @see https://www.mexc.com/api-docs/futures/websocket-api/order // swap
* @description watches information on multiple orders made by the user
* @param {string} symbol unified market symbol of the market orders were made in
* @param {int} [since] the earliest time in ms to fetch orders for
* @param {int} [limit] the maximum number of order structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string|undefined} params.type the type of orders to retrieve, can be 'spot' or 'swap'
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
*/
pub async fn watch_orders(&mut self, optional_args: &[Value]) -> Value {
let mut symbol = get_arg(optional_args, 0, Value::Null);
let mut since = get_arg(optional_args, 1, Value::Null);
let mut limit = get_arg(optional_args, 2, Value::Null);
let mut params = get_arg(optional_args, 3, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut messageHash: Value = Value::Str("orders".to_string());
let mut market: Value = Value::Null;
if !is_equal(&symbol, &Value::Null) {
market = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
messageHash = add(&add(&messageHash, &Value::Str(":".to_string())), &symbol);
}
let mut type_var: Value = Value::Null;
{ let __destr_tmp = self.handle_market_type_and_params(Value::Str("watchOrders".to_string()), &[market.clone(), params.clone()]); type_var = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut orders: Value = Value::Null;
if is_equal(&type_var, &Value::Str("spot".to_string())) {
let mut channel: Value = Value::Str("spot@private.orders.v3.api.pb".to_string());
orders = self.watch_spot_private(channel.clone(), messageHash.clone(), &[params.clone()]).await;
} else {
orders = self.watch_swap_private(messageHash.clone(), &[params.clone()]).await;
}
orders = self.require_value(orders.clone(), &[Value::Str("watchOrders() orders is required".to_string())]);
if is_true(&self.newUpdates) {
limit = orders.get_limit(symbol.clone(), limit.clone());
}
return self.filter_by_symbol_since_limit(orders.clone(), &[symbol.clone(), since.clone(), limit.clone(), Value::Bool(true)]);
Value::Null
}
pub fn handle_order(&mut self, mut client: Value, mut message: Value) {
//
// spot
// {
// "c": "spot@private.orders.v3.api",
// "d": {
// "A":8.0,
// "O":1661938138000,
// "S":1,
// "V":10,
// "a":8,
// "c":"",
// "i":"e03a5c7441e44ed899466a7140b71391",
// "m":0,
// "o":1,
// "p":0.8,
// "s":1,
// "v":10,
// "ap":0,
// "cv":0,
// "ca":0
// },
// "s": "MXUSDT",
// "t": 1661938138193
// }
// spot - stop
// {
// "c": "spot@private.orders.v3.api",
// "d": {
// "N":"USDT",
// "O":1661938853715,
// "P":0.9,
// "S":1,
// "T":"LE",
// "i":"f6d82e5f41d745f59fe9d3cafffd80b5",
// "o":100,
// "p":1.01,
// "s":"NEW",
// "v":6
// },
// "s": "MXUSDT",
// "t": 1661938853727
// }
// margin
// {
// "c": "margin@private.orders.v3.api",
// "d":{
// "O":1661938138000,
// "p":"0.8",
// "a":"8",
// "v":"10",
// "da":"0",
// "dv":"0",
// "A":"8.0",
// "V":"10",
// "n": "0",
// "N": "USDT",
// "S":1,
// "o":1,
// "s":1,
// "i":"e03a5c7441e44ed899466a7140b71391",
// },
// "s": "MXUSDT",
// "t":1661938138193
// }
// protobuf
// {
// channel: "spot@private.orders.v3.api.pb",
// symbol: "MXUSDT",
// sendTime: 1736417034281,
// privateOrders {}
// }
//
let mut messageHash: Value = Value::Str("orders".to_string());
let mut data: Value = self.safe_dict_n(message.clone(), Value::List(vec![Value::Str("d".to_string()), Value::Str("data".to_string()), Value::Str("privateOrders".to_string())]), &[]);
let mut futuresMarketId: Value = self.safe_string_k(data.clone(), "symbol", &[]);
let mut marketId: Value = self.safe_string2(message.clone(), Value::Str("s".to_string()), Value::Str("symbol".to_string()), &[futuresMarketId.clone()]);
let mut market: Value = self.safe_market(&[marketId.clone()]);
let mut symbol: Value = get_value(&market, &Value::Str("symbol".to_string()));
let mut parsed: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
parsed = self.parse_ws_order(data.clone(), &[market.clone()]);
let mut sendTime: Value = self.safe_integer_k(message.clone(), "sendTime", &[]);
if !is_equal(&sendTime, &Value::Null) {
add_element_to_object(&mut parsed, &Value::Str("lastTradeTimestamp".to_string()), sendTime.clone());
}
} else if !is_equal(&data, &Value::Null) {
parsed = self.parse_order(data.clone(), &[market.clone()]);
} else {
return;
}
let mut orders: Value = self.orders.clone();
if is_equal(&orders, &Value::Null) {
let mut limit: Value = self.safe_integer_k(self.options.clone(), "ordersLimit", &[Value::Int(1000)]);
orders = ArrayCacheBySymbolById::new(limit.clone());
self.orders = orders.clone();
}
orders.append(parsed.clone());
client.resolve(&[orders.clone(), messageHash.clone()]);
let mut symbolSpecificMessageHash: Value = add(&add(&messageHash, &Value::Str(":".to_string())), &symbol);
client.resolve(&[orders.clone(), symbolSpecificMessageHash.clone()]);
}
pub fn parse_ws_order(&self, mut order: Value, optional_args: &[Value]) -> Value {
let mut market = get_arg(optional_args, 0, Value::Null);
//
// spot
// {
// "A":8.0,
// "O":1661938138000,
// "S":1,
// "V":10,
// "a":8,
// "c":"",
// "i":"e03a5c7441e44ed899466a7140b71391",
// "m":0,
// "o":1,
// "p":0.8,
// "s":1,
// "v":10,
// "ap":0,
// "cv":0,
// "ca":0
// }
// spot - stop
// {
// "N":"USDT",
// "O":1661938853715,
// "P":0.9,
// "S":1,
// "T":"LE",
// "i":"f6d82e5f41d745f59fe9d3cafffd80b5",
// "o":100,
// "p":1.01,
// "s":"NEW",
// "v":6
// }
// margin
// {
// "O":1661938138000,
// "p":"0.8",
// "a":"8",
// "v":"10",
// "da":"0",
// "dv":"0",
// "A":"8.0",
// "V":"10",
// "n": "0",
// "N": "USDT",
// "S":1,
// "o":1,
// "s":1,
// "i":"e03a5c7441e44ed899466a7140b71391",
// }
// protofbuf spot order
// {
// "id":"C02__583905164440776704043",
// "price":"0.001053",
// "quantity":"2000",
// "amount":"0",
// "avgPrice":"0.001007",
// "orderType":5,
// "tradeType":1,
// "remainAmount":"0.092",
// "remainQuantity":"0",
// "lastDealQuantity":"2000",
// "cumulativeQuantity":"2000",
// "cumulativeAmount":"2.014",
// "status":2,
// "createTime":"1754996075502"
// }
//
let mut timestamp: Value = self.safe_integer_k(order.clone(), "createTime", &[]);
let mut side: Value = self.safe_string_k(order.clone(), "tradeType", &[]);
let mut status: Value = self.safe_string2(order.clone(), Value::Str("status".to_string()), Value::Str("state".to_string()), &[]);
let mut type_var: Value = self.safe_string_k(order.clone(), "orderType", &[]);
let mut fee: Value = Value::Null;
let mut feeCurrency: Value = self.safe_string_k(order.clone(), "N", &[]);
if !is_equal(&feeCurrency, &Value::Null) {
fee = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("currency".to_string(), feeCurrency.clone());
m.insert("cost".to_string(), Value::Null);
m
});
}
return self.safe_order(Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("id".to_string(), self.safe_string_k(order.clone(), "id", &[]));
m.insert("clientOrderId".to_string(), self.safe_string_k(order.clone(), "clientId", &[]));
m.insert("timestamp".to_string(), timestamp.clone());
m.insert("datetime".to_string(), self.iso8601(timestamp.clone()));
m.insert("lastTradeTimestamp".to_string(), Value::Null);
m.insert("status".to_string(), self.parse_ws_order_status(status.clone(), &[market.clone()]));
m.insert("symbol".to_string(), self.safe_symbol(Value::Null, &[market.clone()]));
m.insert("type".to_string(), self.parse_ws_order_type(type_var.clone()));
m.insert("timeInForce".to_string(), self.parse_ws_time_in_force(type_var.clone()));
m.insert("side".to_string(), ternary(is_true(&(is_equal(&side, &Value::Str("1".to_string())))), Value::Str("buy".to_string()), Value::Str("sell".to_string())));
m.insert("price".to_string(), self.safe_string_k(order.clone(), "price", &[]));
m.insert("stopPrice".to_string(), self.safe_string2(order.clone(), Value::Str("triggerPrice".to_string()), Value::Str("P".to_string()), &[]));
m.insert("triggerPrice".to_string(), self.safe_string2(order.clone(), Value::Str("triggerPrice".to_string()), Value::Str("P".to_string()), &[]));
m.insert("average".to_string(), self.safe_string_k(order.clone(), "avgPrice", &[]));
m.insert("amount".to_string(), self.safe_string_k(order.clone(), "quantity", &[]));
m.insert("cost".to_string(), self.safe_string_k(order.clone(), "amount", &[]));
m.insert("filled".to_string(), self.safe_string_k(order.clone(), "cumulativeQuantity", &[]));
m.insert("remaining".to_string(), self.safe_string_k(order.clone(), "remainQuantity", &[]));
m.insert("fee".to_string(), fee.clone());
m.insert("trades".to_string(), Value::Null);
m.insert("info".to_string(), order.clone());
m
}), &[market.clone()]);
Value::Null
}
pub fn parse_ws_order_status(&self, mut status: Value, optional_args: &[Value]) -> Value {
let mut market = get_arg(optional_args, 0, Value::Null);
let mut statuses: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("0".to_string(), Value::Str("open".to_string()));
m.insert("1".to_string(), Value::Str("open".to_string()));
m.insert("2".to_string(), Value::Str("closed".to_string()));
m.insert("3".to_string(), Value::Str("open".to_string()));
m.insert("4".to_string(), Value::Str("canceled".to_string()));
m.insert("5".to_string(), Value::Str("closed".to_string()));
m.insert("NEW".to_string(), Value::Str("open".to_string()));
m.insert("CANCELED".to_string(), Value::Str("canceled".to_string()));
m.insert("EXECUTED".to_string(), Value::Str("closed".to_string()));
m.insert("FAILED".to_string(), Value::Str("rejected".to_string()));
m
});
return self.safe_string(statuses.clone(), status.clone(), &[status.clone()]);
Value::Null
}
pub fn parse_ws_order_type(&self, mut type_var: Value) -> Value {
let mut types: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("1".to_string(), Value::Str("limit".to_string()));
m.insert("2".to_string(), Value::Str("limit".to_string()));
m.insert("3".to_string(), Value::Null);
m.insert("4".to_string(), Value::Null);
m.insert("5".to_string(), Value::Str("market".to_string()));
m.insert("100".to_string(), Value::Str("limit".to_string()));
m.insert("101".to_string(), Value::Str("limit".to_string()));
m.insert("102".to_string(), Value::Str("limit".to_string()));
m
});
return self.safe_string(types.clone(), type_var.clone(), &[]);
Value::Null
}
pub fn parse_ws_time_in_force(&self, mut timeInForce: Value) -> Value {
let mut timeInForceIds: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("1".to_string(), Value::Str("GTC".to_string()));
m.insert("2".to_string(), Value::Str("PO".to_string()));
m.insert("3".to_string(), Value::Str("IOC".to_string()));
m.insert("4".to_string(), Value::Str("FOK".to_string()));
m.insert("5".to_string(), Value::Str("GTC".to_string()));
m.insert("100".to_string(), Value::Str("GTC".to_string()));
m.insert("101".to_string(), Value::Str("GTC".to_string()));
m.insert("102".to_string(), Value::Str("GTC".to_string()));
m
});
return self.safe_string(timeInForceIds.clone(), timeInForce.clone(), &[]);
Value::Null
}
/*
* @method
* @name mexc#watchBalance
* @see https://www.mexc.com/api-docs/spot-v3/websocket-user-data-streams/spot-account-update // spot
* @see https://www.mexc.com/api-docs/futures/websocket-api/assets // swap
* @description watch balance and get the amount of funds available for trading or funds locked in orders
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
*/
pub async fn watch_balance(&mut self, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut type_var: Value = Value::Null;
{ let __destr_tmp = self.handle_market_type_and_params(Value::Str("watchBalance".to_string()), &[Value::Null, params.clone()]); type_var = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut messageHash: Value = add(&Value::Str("balance:".to_string()), &type_var);
if is_equal(&type_var, &Value::Str("spot".to_string())) {
let mut channel: Value = Value::Str("spot@private.account.v3.api.pb".to_string());
return self.watch_spot_private(channel.clone(), messageHash.clone(), &[params.clone()]).await;
} else {
return self.watch_swap_private(messageHash.clone(), &[params.clone()]).await;
}
Value::Null
}
pub fn handle_balance(&mut self, mut client: Value, mut message: Value) {
//
// spot
//
// {
// channel: "spot@private.account.v3.api.pb",
// createTime: "1758134605364",
// sendTime: "1758134605373",
// privateAccount: {
// vcoinName: "USDT",
// coinId: "128f589271cb4951b03e71e6323eb7be",
// balanceAmount: "0.006016465074677006",
// balanceAmountChange: "-4.4022",
// frozenAmount: "4.4022",
// frozenAmountChange: "4.4022",
// type: "ENTRUST_PLACE",
// time: "1758134605364",
// }
// }
//
//
// swap balance
//
// {
// "channel": "push.personal.asset",
// "data": {
// "availableBalance": 67.2426683348,
// "bonus": 0,
// "currency": "USDT",
// "frozenBalance": 0,
// "positionMargin": 1.36945756
// },
// "ts": 1680059188191
// }
//
let mut channel: Value = self.safe_string_k(message.clone(), "channel", &[]);
let mut type_var: Value = ternary(is_true(&(is_equal(&channel, &Value::Str("spot@private.account.v3.api.pb".to_string())))), Value::Str("spot".to_string()), Value::Str("swap".to_string()));
let mut messageHash: Value = add(&Value::Str("balance:".to_string()), &type_var);
let mut data: Value = self.safe_dict_n(message.clone(), Value::List(vec![Value::Str("data".to_string()), Value::Str("privateAccount".to_string())]), &[]);
let mut futuresTimestamp: Value = self.safe_integer2(message.clone(), Value::Str("ts".to_string()), Value::Str("createTime".to_string()), &[]);
let mut timestamp: Value = self.safe_integer2(data.clone(), Value::Str("time".to_string()), futuresTimestamp.clone(), &[]);
if !is_true(&(Value::Bool(in_op(&self.balance, &type_var)))) {
add_element_to_object(&mut self.balance, &type_var, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
}
add_element_to_object(get_value_mut(unsafe { crate::runtime::coerce_value_to_mut(&self.balance) }, &type_var), &Value::Str("info".to_string()), data.clone());
add_element_to_object(get_value_mut(unsafe { crate::runtime::coerce_value_to_mut(&self.balance) }, &type_var), &Value::Str("timestamp".to_string()), timestamp.clone());
{ let __be_tmp = self.iso8601(timestamp.clone()); add_element_to_object(get_value_mut(unsafe { crate::runtime::coerce_value_to_mut(&self.balance) }, &type_var), &Value::Str("datetime".to_string()), __be_tmp); };
let mut currencyId: Value = self.safe_string2(data.clone(), Value::Str("currency".to_string()), Value::Str("vcoinName".to_string()), &[]);
let mut code: Value = self.safe_currency_code(currencyId.clone(), &[]);
let mut account: Value = self.account();
add_element_to_object(&mut account, &Value::Str("free".to_string()), self.safe_string2(data.clone(), Value::Str("balanceAmount".to_string()), Value::Str("availableBalance".to_string()), &[]));
add_element_to_object(&mut account, &Value::Str("used".to_string()), self.safe_string2(data.clone(), Value::Str("frozenBalance".to_string()), Value::Str("frozenAmount".to_string()), &[]));
if !is_equal(&code, &Value::Null) {
add_element_to_object(get_value_mut(unsafe { crate::runtime::coerce_value_to_mut(&self.balance) }, &type_var), &code, account.clone());
}
{ let __be_tmp = self.safe_balance(get_value(&self.balance, &type_var)); add_element_to_object(&mut self.balance, &type_var, __be_tmp); };
client.resolve(&[get_value(&self.balance, &type_var), messageHash.clone()]);
}
/*
* @method
* @name mexc#watchFundingRate
* @description watch the current funding rate
* @see https://www.mexc.com/api-docs/futures/websocket-api/funding-rate
* @param {string} symbol unified market symbol
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/?id=funding-rate-structure}
*/
pub async fn watch_funding_rate(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
let mut messageHash: Value = add(&Value::Str("fundingRate:".to_string()), &get_value(&market, &Value::Str("symbol".to_string())));
let mut channel: Value = Value::Str("sub.funding.rate".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
return self.watch_swap_public(channel.clone(), messageHash.clone(), requestParams.clone(), &[params.clone()]).await;
Value::Null
}
/*
* @method
* @name mexc#unWatchFundingRate
* @description unWatches the current funding rate for a symbol
* @see https://www.mexc.com/api-docs/futures/websocket-api/funding-rate
* @param {string} symbol unified symbol of the market
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/?id=funding-rate-structure}
*/
pub async fn un_watch_funding_rate(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
let mut messageHash: Value = add(&Value::Str("unsubscribe:fundingRate:".to_string()), &get_value(&market, &Value::Str("symbol".to_string())));
let mut url: Value = Value::Null;
let mut channel: Value = Value::Str("unsub.funding.rate".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string()));
self.call_dynamic("watch_swap_public", vec![channel.clone(), messageHash.clone(), requestParams.clone(), params.clone()]).await;
let mut client: Value = self.client(&[url.clone()]);
self.handle_unsubscriptions(client.clone(), Value::List(vec![messageHash.clone()]));
return Value::Null;
Value::Null
}
pub fn handle_funding_rate(&mut self, mut client: Value, mut message: Value) {
//
// {
// "symbol": "BTC_USDT",
// "data": {
// "symbol": "BTC_USDT",
// "rate": -0.000021,
// "nextSettleTime": 1771084800000
// },
// "channel": "push.funding.rate",
// "ts": 1771069020506
// }
//
let mut data: Value = self.safe_dict_k(message.clone(), "data", &[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
let mut fundingRate: Value = self.parse_funding_rate(data.clone(), &[]);
let mut symbol: Value = get_value(&fundingRate, &Value::Str("symbol".to_string()));
if !is_equal(&symbol, &Value::Null) {
add_element_to_object(&mut self.fundingRates, &symbol, fundingRate.clone());
}
let mut messageHash: Value = add(&Value::Str("fundingRate:".to_string()), &symbol);
client.resolve(&[fundingRate.clone(), messageHash.clone()]);
}
/*
* @method
* @name mexc#unWatchTicker
* @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
pub async fn un_watch_ticker(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
let mut messageHash: Value = add(&Value::Str("unsubscribe:ticker:".to_string()), &get_value(&market, &Value::Str("symbol".to_string())));
let mut url: Value = Value::Null;
let mut channel: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
channel = add(&Value::Str("spot@public.aggre.bookTicker.v3.api.pb@100ms@".to_string()), &get_value(&market, &Value::Str("id".to_string())));
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string()));
add_element_to_object(&mut params, &Value::Str("unsubscribed".to_string()), Value::Bool(true));
self.spawn(&[Value::Str("watch_spot_public".to_string()).clone(), channel.clone(), messageHash.clone(), params.clone()]);
} else {
channel = Value::Str("unsub.ticker".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string()));
self.spawn(&[Value::Str("watch_swap_public".to_string()).clone(), channel.clone(), messageHash.clone(), requestParams.clone(), params.clone()]);
}
let mut client: Value = self.client(&[url.clone()]);
self.handle_unsubscriptions(client.clone(), Value::List(vec![messageHash.clone()]));
return Value::Null;
Value::Null
}
/*
* @method
* @name mexc#unWatchTickers
* @description unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
pub async fn un_watch_tickers(&mut self, optional_args: &[Value]) -> Value {
let mut symbols = get_arg(optional_args, 0, Value::Null);
let mut params = get_arg(optional_args, 1, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
symbols = self.market_symbols(&[symbols.clone(), Value::Null]);
let mut messageHashes: Value = Value::List(vec![]);
let mut firstSymbol: Value = self.safe_string(symbols.clone(), Value::Int(0), &[]);
let mut market: Value = Value::Null;
if !is_equal(&firstSymbol, &Value::Null) {
market = self.market(firstSymbol.clone());
}
let mut type_var: Value = Value::Null;
{ let __destr_tmp = self.handle_market_type_and_params(Value::Str("watchTickers".to_string()), &[market.clone(), params.clone()]); type_var = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut isSpot: Value = Value::Bool(is_equal(&type_var, &Value::Str("spot".to_string())));
let mut url: Value = ternary(is_true(&(isSpot)), get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string())), get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string())));
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m
});
if is_true(&isSpot) {
panic!("{}", crate::exchange_errors::not_supported(add(&self.id, &Value::Str(" watchTickers does not support spot markets".to_string()))));
} else {
add_element_to_object(&mut request, &Value::Str("method".to_string()), Value::Str("unsub.tickers".to_string()));
add_element_to_object(&mut request, &Value::Str("params".to_string()), Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
append_to_array(&mut messageHashes, Value::Str("unsubscribe:ticker".to_string()));
}
let mut client: Value = self.client(&[url.clone()]);
let __ws_arg_4 = self.extend(request.clone(), &[params.clone()]);
self.watch_multiple(url.clone(), messageHashes.clone(), &[__ws_arg_4, messageHashes.clone()]).await;
self.handle_unsubscriptions(client.clone(), messageHashes.clone());
return Value::Null;
Value::Null
}
/*
* @method
* @name mexc#unWatchBidsAsks
* @description unWatches best bid & ask for symbols
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
*/
pub async fn un_watch_bids_asks(&mut self, optional_args: &[Value]) -> Value {
let mut symbols = get_arg(optional_args, 0, Value::Null);
let mut params = get_arg(optional_args, 1, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
symbols = self.market_symbols(&[symbols.clone(), Value::Null, Value::Bool(true), Value::Bool(false), Value::Bool(true)]);
let mut marketType: Value = Value::Null;
if is_equal(&symbols, &Value::Null) {
panic!("{}", crate::exchange_errors::arguments_required(add(&self.id, &Value::Str(" watchBidsAsks required symbols argument".to_string()))));
}
let mut markets: Value = self.require_value(self.markets_for_symbols(&[symbols.clone()]), &[Value::Str("unWatchBidsAsks() markets is required".to_string())]);
{ let __destr_tmp = self.handle_market_type_and_params(Value::Str("watchBidsAsks".to_string()), &[get_value(&markets, &Value::Int(0)), params.clone()]); marketType = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut isSpot: bool = is_equal(&marketType, &Value::Str("spot".to_string()));
if !is_true(&isSpot) {
panic!("{}", crate::exchange_errors::not_supported(add(&self.id, &Value::Str(" watchBidsAsks only support spot market".to_string()))));
}
let mut messageHashes: Value = Value::List(vec![]);
let mut topics: Value = Value::List(vec![]);
{
let mut i: Value = Value::Int(0);
let mut __for_first_489: bool = true;
while { if !__for_first_489 { i = add(&i, &Value::Int(1)); } __for_first_489 = false; is_less_than(&i, &get_array_length(&symbols)) } {
if is_true(&isSpot) {
let mut market: Value = self.market(get_value(&symbols, &i));
append_to_array(&mut topics, add(&Value::Str("spot@public.aggre.bookTicker.v3.api.pb@100ms@".to_string()), &get_value(&market, &Value::Str("id".to_string()))));
}
append_to_array(&mut messageHashes, add(&Value::Str("unsubscribe:bidask:".to_string()), &get_value(&symbols, &i)));
}
}
let mut url: Value = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string()));
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("method".to_string(), Value::Str("UNSUBSCRIPTION".to_string()));
m.insert("params".to_string(), topics.clone());
m
});
let mut client: Value = self.client(&[url.clone()]);
let __ws_arg_5 = self.extend(request.clone(), &[params.clone()]);
self.watch_multiple(url.clone(), messageHashes.clone(), &[__ws_arg_5, messageHashes.clone()]).await;
self.handle_unsubscriptions(client.clone(), messageHashes.clone());
return Value::Null;
Value::Null
}
/*
* @method
* @name mexc#unWatchOHLCV
* @description unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} timeframe the length of time each candle represents
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {object} [params.timezone] if provided, kline intervals are interpreted in that timezone instead of UTC, example '+08:00'
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
pub async fn un_watch_ohlcv(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut timeframe = get_arg(optional_args, 0, Value::Str("1m".to_string()));
let mut params = get_arg(optional_args, 1, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
let mut timeframes: Value = self.safe_value_k(self.options.clone(), "timeframes", &[Value::Map({
let mut m = indexmap::IndexMap::new();
m
})]);
let mut timeframeId: Value = self.safe_string(timeframes.clone(), timeframe.clone(), &[]);
let mut messageHash: Value = add(&add(&add(&Value::Str("unsubscribe:candles:".to_string()), &symbol), &Value::Str(":".to_string())), &timeframe);
let mut url: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string()));
let mut channel: Value = add(&add(&add(&Value::Str("spot@public.kline.v3.api.pb@".to_string()), &get_value(&market, &Value::Str("id".to_string()))), &Value::Str("@".to_string())), &timeframeId);
add_element_to_object(&mut params, &Value::Str("unsubscribed".to_string()), Value::Bool(true));
self.spawn(&[Value::Str("watch_spot_public".to_string()).clone(), channel.clone(), messageHash.clone(), params.clone()]);
} else {
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string()));
let mut channel: Value = Value::Str("unsub.kline".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m.insert("interval".to_string(), timeframeId.clone());
m
});
self.spawn(&[Value::Str("watch_swap_public".to_string()).clone(), channel.clone(), messageHash.clone(), requestParams.clone(), params.clone()]);
}
let mut client: Value = self.client(&[url.clone()]);
self.handle_unsubscriptions(client.clone(), Value::List(vec![messageHash.clone()]));
return Value::Null;
Value::Null
}
/*
* @method
* @name mexc#unWatchOrderBook
* @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @param {string} symbol unified array of symbols
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string} [params.frequency] the frequency of the order book updates, default is '10ms', can be '100ms' or '10ms
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure}
*/
pub async fn un_watch_order_book(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
let mut messageHash: Value = add(&Value::Str("unsubscribe:orderbook:".to_string()), &symbol);
let mut url: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string()));
let mut frequency: Value = Value::Null;
{ let __destr_tmp = self.handle_option_and_params(params.clone(), Value::Str("watchOrderBook".to_string()), Value::Str("frequency".to_string()), &[Value::Str("100ms".to_string())]); frequency = get_value(&__destr_tmp, &Value::Int(0)); params = get_value(&__destr_tmp, &Value::Int(1)); }
let mut channel: Value = add(&add(&add(&Value::Str("spot@public.aggre.depth.v3.api.pb@".to_string()), &frequency), &Value::Str("@".to_string())), &get_value(&market, &Value::Str("id".to_string())));
add_element_to_object(&mut params, &Value::Str("unsubscribed".to_string()), Value::Bool(true));
self.spawn(&[Value::Str("watch_spot_public".to_string()).clone(), channel.clone(), messageHash.clone(), params.clone()]);
} else {
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string()));
let mut channel: Value = Value::Str("unsub.depth".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
self.spawn(&[Value::Str("watch_swap_public".to_string()).clone(), channel.clone(), messageHash.clone(), requestParams.clone(), params.clone()]);
}
let mut client: Value = self.client(&[url.clone()]);
self.handle_unsubscriptions(client.clone(), Value::List(vec![messageHash.clone()]));
return Value::Null;
Value::Null
}
/*
* @method
* @name mexc#unWatchTrades
* @description unsubscribes from the trades channel
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string} [params.name] the name of the method to call, 'trade' or 'aggTrade', default is 'trade'
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
*/
pub async fn un_watch_trades(&mut self, mut symbol: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&self.markets, &Value::Null) {
self.load_markets(&[]).await;
}
let mut market: Value = self.market(symbol.clone());
symbol = get_value(&market, &Value::Str("symbol".to_string()));
let mut messageHash: Value = add(&Value::Str("unsubscribe:trades:".to_string()), &symbol);
let mut url: Value = Value::Null;
if is_equal(&get_value(&market, &Value::Str("spot".to_string())), &Value::Bool(true)) {
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string()));
let mut channel: Value = add(&Value::Str("spot@public.aggre.deals.v3.api.pb@100ms@".to_string()), &get_value(&market, &Value::Str("id".to_string())));
add_element_to_object(&mut params, &Value::Str("unsubscribed".to_string()), Value::Bool(true));
self.spawn(&[Value::Str("watch_spot_public".to_string()).clone(), channel.clone(), messageHash.clone(), params.clone()]);
} else {
url = get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("swap".to_string()));
let mut channel: Value = Value::Str("unsub.deal".to_string());
let mut requestParams: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("symbol".to_string(), get_value(&market, &Value::Str("id".to_string())));
m
});
self.spawn(&[Value::Str("watch_swap_public".to_string()).clone(), channel.clone(), messageHash.clone(), requestParams.clone(), params.clone()]);
}
let mut client: Value = self.client(&[url.clone()]);
self.handle_unsubscriptions(client.clone(), Value::List(vec![messageHash.clone()]));
return Value::Null;
Value::Null
}
pub fn handle_unsubscriptions(&mut self, mut client: Value, mut messageHashes: Value) {
{
let mut i: Value = Value::Int(0);
let mut __for_first_491: bool = true;
while { if !__for_first_491 { i = add(&i, &Value::Int(1)); } __for_first_491 = false; is_less_than(&i, &get_array_length(&messageHashes)) } {
let mut messageHash: Value = get_value(&messageHashes, &i);
let mut messageHash: Value = get_value(&messageHashes, &i);
let mut subMessageHash: Value = replace_str(&messageHash, &Value::Str("unsubscribe:".to_string()), &Value::Str("".to_string()));
self.clean_unsubscription(client.clone(), subMessageHash.clone(), messageHash.clone(), &[]);
if is_greater_than_or_equal(&get_index_of(&messageHash, &Value::Str("ticker".to_string())), &Value::Int(0)) {
let mut symbol: Value = replace_str(&messageHash, &Value::Str("unsubscribe:ticker:".to_string()), &Value::Str("".to_string()));
if is_greater_than_or_equal(&get_index_of(&symbol, &Value::Str("unsubscribe".to_string())), &Value::Int(0)) {
// unWatchTickers
let mut symbols: Value = object_keys(&self.tickers);
{
let mut j: Value = Value::Int(0);
let mut __for_first_490: bool = true;
while { if !__for_first_490 { j = add(&j, &Value::Int(1)); } __for_first_490 = false; is_less_than(&j, &get_array_length(&symbols)) } {
remove(&mut self.tickers, &get_value(&symbols, &j));
}
}
} else if is_true(&Value::Bool(in_op(&self.tickers, &symbol))) {
remove(&mut self.tickers, &symbol);
}
} else if is_greater_than_or_equal(&get_index_of(&messageHash, &Value::Str("bidask".to_string())), &Value::Int(0)) {
let mut symbol: Value = replace_str(&messageHash, &Value::Str("unsubscribe:bidask:".to_string()), &Value::Str("".to_string()));
if is_true(&Value::Bool(in_op(&self.bidsasks, &symbol))) {
remove(&mut self.bidsasks, &symbol);
}
} else if is_greater_than_or_equal(&get_index_of(&messageHash, &Value::Str("candles".to_string())), &Value::Int(0)) {
let mut splitHashes: Value = split(&messageHash, &Value::Str(":".to_string()));
let mut symbol: Value = self.safe_string(splitHashes.clone(), Value::Int(2), &[]);
let mut splitHashesLength: Value = get_array_length(&splitHashes); // hoisted - inline .length within conditionals becomes strlen for php, fatal on arrays
if is_greater_than(&splitHashesLength, &Value::Int(4)) {
symbol = add(&symbol, &add(&Value::Str(":".to_string()), &self.safe_string(splitHashes.clone(), Value::Int(3), &[])));
}
if is_true(&(!is_equal(&symbol, &Value::Null))) && is_true(&(Value::Bool(in_op(&self.ohlcvs, &symbol)))) {
remove(&mut self.ohlcvs, &symbol);
}
} else if is_greater_than_or_equal(&get_index_of(&messageHash, &Value::Str("orderbook".to_string())), &Value::Int(0)) {
let mut symbol: Value = replace_str(&messageHash, &Value::Str("unsubscribe:orderbook:".to_string()), &Value::Str("".to_string()));
if is_true(&Value::Bool(in_op(&self.orderbooks, &symbol))) {
remove(&mut self.orderbooks, &symbol);
}
} else if is_greater_than_or_equal(&get_index_of(&messageHash, &Value::Str("trades".to_string())), &Value::Int(0)) {
let mut symbol: Value = replace_str(&messageHash, &Value::Str("unsubscribe:trades:".to_string()), &Value::Str("".to_string()));
if is_true(&Value::Bool(in_op(&self.trades, &symbol))) {
remove(&mut self.trades, &symbol);
}
} else if is_greater_than_or_equal(&get_index_of(&messageHash, &Value::Str("fundingRate".to_string())), &Value::Int(0)) {
let mut symbol: Value = replace_str(&messageHash, &Value::Str("unsubscribe:fundingRate:".to_string()), &Value::Str("".to_string()));
if is_true(&Value::Bool(in_op(&self.fundingRates, &symbol))) {
remove(&mut self.fundingRates, &symbol);
}
}
}
}
}
pub async fn authenticate(&mut self, mut subscriptionHash: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
// we only need one listenKey since ccxt shares connections
let mut listenKey: Value = self.safe_string_k(self.options.clone(), "listenKey", &[]);
if !is_equal(&listenKey, &Value::Null) {
return listenKey;
}
// guard against concurrent listenKey requests with a future on the base
// spot ws client - the first caller fetches the listenKey, concurrent
// callers wait on the future and resume when the listenKey is ready,
// otherwise the user-data subscriptions would be split across two connections
let __ws_arg_6 = get_value(&self.urls, &Value::Str("api".to_string()));
let mut client: Value = self.client(&[get_value(&get_value(&__ws_arg_6, &Value::Str("ws".to_string())), &Value::Str("spot".to_string()))]);
let mut messageHash: Value = Value::Str("authenticate:listenKey".to_string());
let mut isFetching: Value = self.safe_bool_k(self.options.clone(), "listenKeyFetching", &[Value::Bool(false)]);
if is_equal(&isFetching, &Value::Bool(true)) {
crate::exchange_stubs::ws_await_flight(&client.future(&[messageHash.clone()])).await;
return self.safe_string_k(self.options.clone(), "listenKey", &[]);
}
add_element_to_object(&mut self.options, &Value::Str("listenKeyFetching".to_string()), Value::Bool(true));
client.future(&[messageHash.clone()]); // created ahead of the request below, so concurrent callers can find it
let mut response: Value = Value::Null;
let _try_result = futures::FutureExt::catch_unwind(std::panic::AssertUnwindSafe(async {
response = self.parent.spot_private_post_user_data_stream(&[params.clone()]).await;
#[allow(unreachable_code)] { Value::Null }})).await;
if let Err(_try_err) = _try_result { let e: Value = panic_to_value(_try_err);
add_element_to_object(&mut self.options, &Value::Str("listenKeyFetching".to_string()), Value::Bool(false));
client.reject(&[e.clone(), messageHash.clone()]);
panic!("{}", e);
}
add_element_to_object(&mut self.options, &Value::Str("listenKeyFetching".to_string()), Value::Bool(false));
//
// {
// "listenKey": "pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1"
// }
//
listenKey = self.safe_string_k(response.clone(), "listenKey", &[]);
add_element_to_object(&mut self.options, &Value::Str("listenKey".to_string()), listenKey.clone());
client.resolve(&[listenKey.clone(), messageHash.clone()]);
let mut listenKeyRefreshRate: Value = self.safe_integer_k(self.options.clone(), "listenKeyRefreshRate", &[Value::Int(1200000)]);
self.delay(listenKeyRefreshRate.clone(), &[Value::Str("keep_alive_listen_key".to_string()).clone(), listenKey.clone(), params.clone()]).await;
return listenKey;
Value::Null
}
pub async fn keep_alive_listen_key(&mut self, mut listenKey: Value, optional_args: &[Value]) -> Value {
let mut params = get_arg(optional_args, 0, Value::Map({
let mut m = indexmap::IndexMap::new();
m
}));
if is_equal(&listenKey, &Value::Null) {
return Value::Null;
}
let mut request: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("listenKey".to_string(), listenKey.clone());
m
});
let _try_result = futures::FutureExt::catch_unwind(std::panic::AssertUnwindSafe(async {
let __ws_arg_7 = self.extend(request.clone(), &[params.clone()]);
self.parent.spot_private_put_user_data_stream(&[__ws_arg_7]).await;
let mut listenKeyRefreshRate: Value = self.safe_integer_k(self.options.clone(), "listenKeyRefreshRate", &[Value::Int(1200000)]);
self.delay(listenKeyRefreshRate.clone(), &[Value::Str("keep_alive_listen_key".to_string()).clone(), listenKey.clone(), params.clone()]).await;
#[allow(unreachable_code)] { Value::Null }})).await;
if let Err(_try_err) = _try_result { let error: Value = panic_to_value(_try_err);
let mut url: Value = add(&add(&get_value(&get_value(&get_value(&self.urls, &Value::Str("api".to_string())), &Value::Str("ws".to_string())), &Value::Str("spot".to_string())), &Value::Str("?listenKey=".to_string())), &listenKey);
let mut client: Value = self.client(&[url.clone()]);
add_element_to_object(&mut self.options, &Value::Str("listenKey".to_string()), Value::Null);
client.reject(&[Value::from(error.clone())]);
remove(&mut self.clients, &url);
}
Value::Null
}
pub fn handle_pong(&self, mut client: Value, mut message: Value) -> Value {
crate::set_value(&mut client, &Value::Str("lastPong".to_string()), self.milliseconds());
return message;
Value::Null
}
pub fn handle_subscription_status(&mut self, mut client: Value, mut message: Value) {
//
// {
// "id": 0,
// "code": 0,
// "msg": "spot@public.increase.depth.v3.api@BTCUSDT"
// }
// Set the default to an empty string if the message is empty during the test.
let mut msg: Value = self.safe_string_k(message.clone(), "msg", &[Value::Str("".to_string())]);
if is_equal(&msg, &Value::Str("PONG".to_string())) {
self.handle_pong(client.clone(), message.clone());
} else if is_greater_than(&get_index_of(&msg, &Value::Str("@".to_string())), &negate(&Value::Int(1))) {
let mut parts: Value = split(&msg, &Value::Str("@".to_string()));
let mut channel: Value = self.safe_string(parts.clone(), Value::Int(1), &[]);
let mut methods: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("public.increase.depth.v3.api".to_string(), Value::Str("handle_order_book_subscription".to_string()).clone());
m.insert("public.aggre.depth.v3.api.pb".to_string(), Value::Str("handle_order_book_subscription".to_string()).clone());
m
});
let mut method: Value = self.safe_value(methods.clone(), channel.clone(), &[]);
if !is_equal(&method, &Value::Null) {
self.dispatch_ws_handler(&method, &[client.clone(), message.clone()]);
}
}
}
pub fn handle_protobuf_message(&mut self, mut client: Value, mut message: Value) -> Value {
// protobuf message decoded
// {
// "channel":"spot@public.kline.v3.api.pb@BTCUSDT@Min1",
// "symbol":"BTCUSDT",
// "symbolId":"2fb942154ef44a4ab2ef98c8afb6a4a7",
// "createTime":"1754737941062",
// "publicSpotKline":{
// "interval":"Min1",
// "windowStart":"1754737920",
// "openingPrice":"117317.31",
// "closingPrice":"117325.26",
// "highestPrice":"117341",
// "lowestPrice":"117317.3",
// "volume":"3.12599854",
// "amount":"366804.43",
// "windowEnd":"1754737980"
// }
// }
let mut channel: Value = self.safe_string_k(message.clone(), "channel", &[Value::Str("".to_string())]);
let mut channelParts: Value = split(&channel, &Value::Str("@".to_string()));
let mut channelId: Value = self.safe_string(channelParts.clone(), Value::Int(1), &[]);
if is_equal(&channelId, &Value::Str("public.kline.v3.api.pb".to_string())) {
self.handle_ohlcv(client.clone(), message.clone());
} else if is_equal(&channelId, &Value::Str("public.aggre.deals.v3.api.pb".to_string())) {
self.handle_trades(client.clone(), message.clone());
} else if is_equal(&channelId, &Value::Str("public.aggre.bookTicker.v3.api.pb".to_string())) {
self.handle_ticker(client.clone(), message.clone());
} else if is_equal(&channelId, &Value::Str("public.aggre.depth.v3.api.pb".to_string())) {
self.handle_order_book(client.clone(), message.clone());
} else if is_equal(&channelId, &Value::Str("private.account.v3.api.pb".to_string())) {
self.handle_balance(client.clone(), message.clone());
} else if is_equal(&channelId, &Value::Str("private.deals.v3.api.pb".to_string())) {
self.handle_my_trade(client.clone(), message.clone(), &[]);
} else if is_equal(&channelId, &Value::Str("private.orders.v3.api.pb".to_string())) {
self.handle_order(client.clone(), message.clone());
}
return Value::Bool(true);
Value::Null
}
pub fn handle_message(&mut self, mut client: Value, mut message: Value) {
if is_string(&message) {
if is_equal(&message, &Value::Str("Invalid listen key".to_string())) {
let mut error = Value::from(crate::exchange_errors::authentication_error(add(&self.id, &Value::Str(" invalid listen key".to_string()))));
client.reject(&[Value::from(error.clone())]);
return;
}
}
if is_true(&self.is_binary_message(message.clone(), &[])) {
message = self.decode_proto_msg(&[message.clone()]);
self.handle_protobuf_message(client.clone(), message.clone());
return;
}
if is_true(&Value::Bool(in_op(&message, &Value::Str("msg".to_string())))) {
self.handle_subscription_status(client.clone(), message.clone());
return;
}
let mut c: Value = self.safe_string_k(message.clone(), "c", &[]);
let mut channel: Value = Value::Null;
if is_equal(&c, &Value::Null) {
channel = self.safe_string_k(message.clone(), "channel", &[]);
} else {
let mut parts: Value = split(&c, &Value::Str("@".to_string()));
channel = self.safe_string(parts.clone(), Value::Int(1), &[Value::Str("".to_string())]);
}
let mut methods: Value = Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("public.deals.v3.api".to_string(), Value::Str("handle_trades".to_string()).clone());
m.insert("push.deal".to_string(), Value::Str("handle_trades".to_string()).clone());
m.insert("public.kline.v3.api".to_string(), Value::Str("handle_ohlcv".to_string()).clone());
m.insert("push.kline".to_string(), Value::Str("handle_ohlcv".to_string()).clone());
m.insert("public.bookTicker.v3.api".to_string(), Value::Str("handle_ticker".to_string()).clone());
m.insert("public.miniTicker.v3.api".to_string(), Value::Str("handle_ticker".to_string()).clone());
m.insert("public.miniTickers.v3.api".to_string(), Value::Str("handle_tickers".to_string()).clone());
m.insert("push.ticker".to_string(), Value::Str("handle_ticker".to_string()).clone());
m.insert("push.tickers".to_string(), Value::Str("handle_tickers".to_string()).clone());
m.insert("public.increase.depth.v3.api".to_string(), Value::Str("handle_order_book".to_string()).clone());
m.insert("push.depth".to_string(), Value::Str("handle_order_book".to_string()).clone());
m.insert("private.orders.v3.api".to_string(), Value::Str("handle_order".to_string()).clone());
m.insert("push.personal.order".to_string(), Value::Str("handle_order".to_string()).clone());
m.insert("private.account.v3.api".to_string(), Value::Str("handle_balance".to_string()).clone());
m.insert("push.personal.asset".to_string(), Value::Str("handle_balance".to_string()).clone());
m.insert("private.deals.v3.api".to_string(), Value::Str("handle_my_trade".to_string()).clone());
m.insert("push.personal.order.deal".to_string(), Value::Str("handle_my_trade".to_string()).clone());
m.insert("pong".to_string(), Value::Str("handle_pong".to_string()).clone());
m.insert("push.funding.rate".to_string(), Value::Str("handle_funding_rate".to_string()).clone());
m
});
if is_true(&(!is_equal(&channel, &Value::Null))) && is_true(&(Value::Bool(in_op(&methods, &channel)))) {
let mut method: Value = get_value(&methods, &channel);
let mut method: Value = get_value(&methods, &channel);
self.dispatch_ws_handler(&method, &[client.clone(), message.clone()]);
}
}
pub fn ping(&self, mut client: Value) -> Value {
return Value::Map({
let mut m = indexmap::IndexMap::new();
m.insert("method".to_string(), Value::Str("ping".to_string()));
m
});
Value::Null
}
}