use std::cmp::Ordering; use std::str::FromStr; use rust_decimal::{Decimal}; use rust_decimal::prelude::FromPrimitive; use rust_decimal_macros::dec; use tracing::{error, info}; use exchanges::response_base::ResponseData; use global::public_params; use crate::exchange::ExchangeEnum; use crate::{binance_swap_handle, gate_swap_handle, bybit_swap_handle, bitget_swap_handle, kucoin_handle}; use crate::{Account, MarketOrder, Position, SpecialDepth, SpecialOrder, SpecialTicker}; #[allow(dead_code)] pub struct HandleSwapInfo; pub struct DepthParam { pub depth_asks: Vec, pub depth_bids: Vec, pub t: Decimal, pub create_at: i64 } #[allow(dead_code)] impl HandleSwapInfo { // 处理账号信息 pub fn handle_account_info(exchange: ExchangeEnum, res_data: &ResponseData, symbol: &String) -> Account { match exchange { // ExchangeEnum::BinanceSwap => { // error!("暂未提供此交易所方法!handle_account_info:{:?}", exchange); // panic!("暂未提供此交易所方法!handle_account_info:{:?}", exchange); // } ExchangeEnum::GateSwap => { gate_swap_handle::handle_account_info(res_data, symbol) } // ExchangeEnum::KucoinSwap => { // kucoin_handle::handle_account_info(res_data, symbol) // } // ExchangeEnum::KucoinSpot => { // kucoin_spot_handle::handle_account_info(res_data, symbol) // } // ExchangeEnum::OkxSwap => { // okx_handle::handle_account_info(res_data, symbol) // } // ExchangeEnum::BitgetSpot => { // bitget_spot_handle::handle_account_info(res_data, symbol) // }, ExchangeEnum::BitgetSwap => { bitget_swap_handle::handle_account_info(res_data, symbol) }, ExchangeEnum::BybitSwap => { bybit_swap_handle::handle_account_info(res_data, symbol) } _ => { error!("未找到该交易所!handle_account_info: {:?}",exchange); panic!("未找到该交易所!handle_account_info: {:?}", exchange); } } } // 处理Ticker信息 pub fn handle_book_ticker(exchange: ExchangeEnum, res_data: &ResponseData) -> SpecialDepth { match exchange { // ExchangeEnum::BinanceSpot => { // binance_spot_handle::handle_special_ticker(res_data) // } ExchangeEnum::BinanceSwap => { binance_swap_handle::handle_book_ticker(res_data) } ExchangeEnum::GateSwap => { gate_swap_handle::handle_book_ticker(res_data) } ExchangeEnum::KucoinSwap => { kucoin_handle::handle_book_ticker(res_data) } // ExchangeEnum::KucoinSpot => { // kucoin_spot_handle::handle_special_ticker(res_data) // } // ExchangeEnum::KucoinSpot => { // kucoin_spot_handle::handle_special_ticker(res_data) // } // ExchangeEnum::OkxSwap => { // okx_handle::handle_special_ticker(res_data) // } // ExchangeEnum::BitgetSpot => { // bitget_spot_handle::handle_special_ticker(res_data) // }, ExchangeEnum::BitgetSwap => { info!(?res_data); panic!("BitgetSwap 85 未实现格式化"); // bitget_swap_handle::handle_special_ticker(res_data) }, ExchangeEnum::BybitSwap => { bybit_swap_handle::handle_ticker(res_data) } } } // 处理position信息 pub fn handle_position(exchange: ExchangeEnum, res_data: &ResponseData, ct_val: &Decimal) -> Vec { match exchange { ExchangeEnum::BinanceSwap => { error!("暂未提供此交易所方法!handle_position:{:?}", exchange); panic!("暂未提供此交易所方法!handle_position:{:?}", exchange); } ExchangeEnum::GateSwap => { gate_swap_handle::handle_position(res_data, ct_val) } ExchangeEnum::KucoinSwap => { kucoin_handle::handle_position(res_data, ct_val) } // ExchangeEnum::KucoinSpot => { // error!("暂未提供此交易所方法!handle_position:{:?}", exchange); // panic!("暂未提供此交易所方法!handle_position:{:?}", exchange); // } // ExchangeEnum::OkxSwap => { // okx_handle::handle_position(res_data, ct_val) // } // ExchangeEnum::BitgetSpot => { // error!("暂未提供此交易所方法!handle_position:{:?}", exchange); // panic!("暂未提供此交易所方法!handle_position:{:?}", exchange); // }, ExchangeEnum::BitgetSwap => { bitget_swap_handle::handle_position(res_data, ct_val) }, ExchangeEnum::BybitSwap => { bybit_swap_handle::handle_position(res_data, ct_val) } } } // 处理订单信息 pub fn handle_order(exchange: ExchangeEnum, res_data: ResponseData, ct_val: Decimal) -> SpecialOrder { match exchange { ExchangeEnum::BinanceSwap => { error!("暂未提供此交易所方法!handle_order:{:?}", exchange); panic!("暂未提供此交易所方法!handle_order:{:?}", exchange); } ExchangeEnum::GateSwap => { gate_swap_handle::handle_order(res_data, ct_val) } ExchangeEnum::KucoinSwap => { kucoin_handle::handle_order(res_data, ct_val) } // ExchangeEnum::KucoinSpot => { // kucoin_spot_handle::handle_order(res_data, ct_val) // } // ExchangeEnum::OkxSwap => { // okx_handle::handle_order(res_data, ct_val) // } // ExchangeEnum::BitgetSpot => { // bitget_spot_handle::handle_order(res_data, ct_val) // }, ExchangeEnum::BitgetSwap => { bitget_swap_handle::handle_order(res_data, ct_val) }, ExchangeEnum::BybitSwap => { bybit_swap_handle::handle_order(res_data, ct_val) } } } // 处理深度信息 pub fn handle_special_depth(exchange: ExchangeEnum, res_data: &ResponseData) -> SpecialDepth { let label = res_data.label.clone(); // 格式化 let mut format_depth = format_depth(exchange, res_data); // 运算、组装 make_special_depth(label, &mut format_depth.depth_asks, &mut format_depth.depth_bids, format_depth.t, format_depth.create_at) } } pub fn make_special_depth(label: String, depth_asks: &mut Vec, depth_bids: &mut Vec, t: Decimal, create_at: i64) -> SpecialDepth { depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal)); depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal)); // TODO 不排序的话,有4us可以省下来。 let mp = (depth_asks[0].price + depth_bids[0].price) * dec!(0.5); let step = (public_params::EFF_RANGE * mp / Decimal::from_usize(public_params::LEVEL).unwrap()).round_dp(mp.scale()); let mut ap = Vec::new(); let mut bp = Vec::new(); let mut av: Vec = Vec::new(); let mut bv: Vec = Vec::new(); for i in 0..public_params::LEVEL { let price = (depth_asks[0].price + step * Decimal::from_f64(i as f64).unwrap()).round_dp(depth_asks[0].price.scale()); ap.push(price); } for i in 0..public_params::LEVEL { let price = (depth_bids[0].price - step * Decimal::from_f64(i as f64).unwrap()).round_dp(depth_bids[0].price.scale()); bp.push(price); } let mut ap_price_tag = depth_asks[0].price + step; let mut ap_index = 0; for item in depth_asks.iter() { let price = item.price; let amount = item.amount; if av.get(ap_index).is_none() { av.push(Decimal::ZERO) }; if price < ap_price_tag { av[ap_index] += amount; } else { ap_price_tag += step; ap_index += 1; if ap_index == public_params::LEVEL { break; } av[ap_index] += amount } } let mut bp_price_tag = depth_bids[0].price - step; let mut bp_index = 0; for item in depth_bids.iter() { let price = item.price; let amount = item.amount; if bv.get(bp_index).is_none() { bv.push(Decimal::ZERO) }; if price > bp_price_tag { bv[bp_index] += amount; } else { bp_price_tag -= step; bp_index += 1; if bp_index == public_params::LEVEL { break; } bv[bp_index] += amount } } let ticker_info = SpecialTicker { sell: depth_asks[0].price, buy: depth_bids[0].price, mid_price: mp, t, create_at }; let depth_info = bp.iter().cloned().chain(bv.iter().cloned()).chain(ap.iter().cloned()).chain(av.iter().cloned()).collect(); SpecialDepth { name: label, depth: depth_info, ticker: ticker_info, t, create_at, } } pub fn format_depth(exchange: ExchangeEnum, res_data: &ResponseData) -> DepthParam { let depth_asks: Vec; let depth_bids: Vec; let t: Decimal; let create_at: i64; match exchange { // ExchangeEnum::BinanceSpot => { // depth_asks = binance_swap_handle::format_depth_items(res_data_json["asks"].clone()); // depth_bids = binance_swap_handle::format_depth_items(res_data_json["bids"].clone()); // t = Decimal::from_str(&res_data_json["lastUpdateId"].to_string()).unwrap(); // create_at = 0; // } ExchangeEnum::BinanceSwap => { depth_asks = binance_swap_handle::format_depth_items(res_data.data["a"].clone()); depth_bids = binance_swap_handle::format_depth_items(res_data.data["b"].clone()); t = Decimal::from_str(&res_data.data["u"].to_string()).unwrap(); create_at = res_data.data["E"].as_i64().unwrap() * 1000; } ExchangeEnum::GateSwap => { depth_asks = gate_swap_handle::format_depth_items(&res_data.data["asks"]); depth_bids = gate_swap_handle::format_depth_items(&res_data.data["bids"]); // todo! 有id可以取 保证与py一致 t = Decimal::from_str(&res_data.data["t"].to_string()).unwrap(); create_at = res_data.data["t"].as_i64().unwrap() * 1000; } ExchangeEnum::KucoinSwap => { depth_asks = kucoin_handle::format_depth_items(res_data.data["asks"].clone()); depth_bids = kucoin_handle::format_depth_items(res_data.data["bids"].clone()); t = Decimal::from_str(&res_data.data["sequence"].to_string()).unwrap(); create_at = res_data.data["ts"].as_i64().unwrap() * 1000; } // ExchangeEnum::KucoinSpot => { // depth_asks = kucoin_spot_handle::format_depth_items(res_data_json["asks"].clone()); // depth_bids = kucoin_spot_handle::format_depth_items(res_data_json["bids"].clone()); // t = Decimal::from_str(&res_data_json["timestamp"].to_string()).unwrap(); // create_at = res_data_json["timestamp"].as_i64().unwrap() * 1000; // } // ExchangeEnum::OkxSwap => { // depth_asks = okx_handle::format_depth_items(res_data_json[0]["asks"].clone()); // depth_bids = okx_handle::format_depth_items(res_data_json[0]["bids"].clone()); // t = Decimal::from_str(&res_data_json[0]["seqId"].to_string()).unwrap(); // create_at = res_data_json[0]["ts"].as_str().unwrap().parse::().unwrap() * 1000; // } // ExchangeEnum::BitgetSpot => { // depth_asks = bitget_spot_handle::format_depth_items(res_data_json[0]["asks"].clone()); // depth_bids = bitget_spot_handle::format_depth_items(res_data_json[0]["bids"].clone()); // t = Decimal::from_str(res_data_json[0]["ts"].as_str().unwrap()).unwrap(); // create_at = res_data_json[0]["ts"].as_str().unwrap().parse::().unwrap() * 1000; // } ExchangeEnum::BitgetSwap => { depth_asks = bitget_swap_handle::format_depth_items(res_data.data[0]["asks"].clone()); depth_bids = bitget_swap_handle::format_depth_items(res_data.data[0]["bids"].clone()); t = Decimal::from_str(res_data.data[0]["ts"].as_str().unwrap()).unwrap(); create_at = res_data.data[0]["ts"].as_str().unwrap().parse::().unwrap() * 1000; } ExchangeEnum::BybitSwap => { depth_asks = bybit_swap_handle::format_depth_items(res_data.data["a"].clone()); depth_bids = bybit_swap_handle::format_depth_items(res_data.data["b"].clone()); t = Decimal::from_i64(res_data.reach_time).unwrap(); create_at = res_data.reach_time * 1000; } } DepthParam { depth_asks, depth_bids, t, create_at } }