use std::str::FromStr; use rust_decimal::Decimal; use rust_decimal::prelude::FromPrimitive; use serde_json::Value; use tokio::time::Instant; use tracing::error; use exchanges::response_base::ResponseData; use global::trace_stack::TraceStack; use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder, Depth, Trade, Record}; // 处理账号信息 pub fn handle_account_info(response: &ResponseData, _symbol: &String) -> Account { let mut rst = Account::new(); let data_info = response.data["data"].clone(); for data in data_info.as_array().unwrap() { if data["marginCoin"].as_str().unwrap() != "USDT" { continue; } // 格式化account信息 let mut account = Account { coin: data["marginCoin"].to_string(), balance: Decimal::from_str(data["usdtEquity"].as_str().unwrap()).unwrap(), available_balance: Decimal::from_str(data["available"].as_str().unwrap()).unwrap(), frozen_balance: Decimal::from_str(data["frozen"].as_str().unwrap()).unwrap(), stocks: Default::default(), available_stocks: Default::default(), frozen_stocks: Default::default(), }; account.frozen_balance = account.balance - account.available_balance; rst = account } return rst; } // 处理order信息 pub fn handle_order(res_data: &ResponseData, multiplier: &Decimal) -> SpecialOrder { let data_info = res_data.data["data"].clone(); let res_data_json = data_info.as_array().unwrap(); let mut order_info = Vec::new(); for item in res_data_json.iter() { order_info.push(format_order_item(item.clone(), multiplier.clone())); } SpecialOrder { name: res_data.label.clone(), order: order_info, } } // 处理订单信息 pub fn format_order_item(order: Value, _multiplier: Decimal) -> Order { let price = Decimal::from_str(order["price"].as_str().unwrap().to_string().as_str()).unwrap(); let size = Decimal::from_str(order["size"].as_str().unwrap().to_string().as_str()).unwrap(); let binding = order["status"].clone().as_str().unwrap().to_string(); let status = binding.as_str(); let acc_base_volume = Decimal::from_str(order["accBaseVolume"].as_str().unwrap().to_string().as_str()).unwrap(); let avg_price = if order["priceAvg"].is_null() || order["priceAvg"].as_str().unwrap().is_empty() { Decimal::ZERO } else { Decimal::from_str(order["priceAvg"].as_str().unwrap().to_string().as_str()).unwrap() }; let c_id = if order["clientOid"].is_null() { "" } else { order["clientOid"].as_str().unwrap() }; let amount = size; let deal_amount = acc_base_volume; let custom_status = if ["filled", "canceled"].contains(&status) { "REMOVE".to_string() } else if ["init", "live", "new", "partially_filled"].contains(&status) { "NEW".to_string() } else { "NULL".to_string() }; Order { id: order["orderId"].as_str().unwrap().to_string(), custom_id: c_id.to_string(), price, amount, deal_amount, avg_price, status: custom_status, order_type: order["orderType"].as_str().unwrap().to_string(), trace_stack: TraceStack::new(0, Instant::now()).on_special("86 bitget_swap_handle".to_string()), } } // 格式化深度信息 pub fn format_depth_items(value: Value, mul: &Decimal) -> Vec { let mut depth_items: Vec = vec![]; for value in value.as_array().unwrap() { let price = Decimal::from_str(value[0].as_str().unwrap()).unwrap(); let size = Decimal::from_str(value[1].as_str().unwrap()).unwrap(); depth_items.push(OrderBook { price, size, value: price * size * mul, }) } return depth_items; } // 处理position信息 pub fn handle_position(res_data: &ResponseData, multiplier: &Decimal) -> Vec { let data_info = res_data.data["data"].clone(); let data_info_json = data_info.as_array().unwrap(); data_info_json.iter().map(|item| { format_position_item(item, multiplier) }).collect() } pub fn format_position_item(position_json: &Value, _multiplier: &Decimal) -> Position { let symbol = position_json["instId"].as_str().unwrap().to_string(); let margin_level = Decimal::from_i64(position_json["leverage"].as_i64().unwrap()).unwrap(); let amount = Decimal::from_str(position_json["total"].as_str().unwrap()).unwrap(); let frozen_amount = Decimal::from_str(position_json["frozen"].as_str().unwrap()).unwrap(); let price = Decimal::from_str(position_json["openPriceAvg"].as_str().unwrap()).unwrap(); let profit = Decimal::from_str(position_json["unrealizedPL"].as_str().unwrap()).unwrap(); let mut position_mode = match position_json["posMode"].as_str().unwrap() { "hedge_mode" => { match position_json["holdSide"].as_str().unwrap() { "short" => { PositionModeEnum::Short } "long" => { PositionModeEnum::Long } _ => { panic!("bitget_usdt_swap: 未知的持仓模式与持仓方向: {}, {}", position_json["posMode"].as_str().unwrap(), position_json["holdSide"].as_str().unwrap()) } } } "one_way_mode" => { PositionModeEnum::Both } _ => { panic!("bitget_usdt_swap: 未知的持仓模式: {}", position_json["posMode"].as_str().unwrap()) } }; let margin = Decimal::from_str(position_json["marginSize"].as_str().unwrap()).unwrap(); let update_time = Decimal::from_str(position_json["uTime"].as_str().unwrap()).unwrap(); let side = position_json["holdSide"].as_str().unwrap(); match position_mode { PositionModeEnum::Both => { position_mode = match side { "long" => PositionModeEnum::Long, "short" => PositionModeEnum::Short, _ => { PositionModeEnum::Both } } } _ => {} } Position { symbol, margin_level, amount, frozen_amount, price, profit, position_mode, margin, update_time } } pub fn format_trade_items(response: &ResponseData) -> Vec { let data_info = response.data["data"].clone(); let result = data_info.as_array().unwrap(); let mut trades = vec![]; for item in result { // 因为gate的量都是张数,所以要进行真实交易量处理 let mut size = Decimal::from_str(item["size"].as_str().unwrap()).unwrap(); let price = Decimal::from_str(item["price"].as_str().unwrap().to_string().as_str()).unwrap(); let side = item["side"].as_str().unwrap().to_string(); size = match side.as_str() { "buy" => { size } "sell" => { -size } _ => { error!("{}", item.to_string()); panic!("Bitget trade error side(bitget_swap_handle_156)") } }; let value = (size * price).abs(); trades.push(Trade { id: item["tradeId"].as_str().unwrap().to_string(), time: Decimal::from_str(item["ts"].as_str().unwrap()).unwrap(), size, price, value, symbol: response.data["arg"]["instId"].as_str().unwrap().replace("USDT", "_USDT"), }) } return trades; } pub fn handle_book_ticker(res_data: &ResponseData, mul: &Decimal) -> Depth { let data_info = res_data.data["data"].clone(); let asks = format_depth_items(data_info[0]["asks"].clone(), mul); let bids = format_depth_items(data_info[0]["bids"].clone(), mul); let t = Decimal::from_i64(res_data.reach_time).unwrap(); let s = res_data.data["arg"]["instId"].as_str().unwrap().replace("USDT", "_USDT"); Depth { time: t, symbol: s.to_string(), asks, bids, } } pub fn handle_records(value: &Value) -> Vec { let data_info = value["data"].clone(); let mut records = vec![]; for record_value in data_info.as_array().unwrap() { records.push(Record { time: Decimal::from_str(record_value[0].as_str().unwrap()).unwrap(), open: Decimal::from_str(record_value[1].as_str().unwrap()).unwrap(), high: Decimal::from_str(record_value[2].as_str().unwrap()).unwrap(), low: Decimal::from_str(record_value[3].as_str().unwrap()).unwrap(), close: Decimal::from_str(record_value[4].as_str().unwrap()).unwrap(), volume: Decimal::from_str(record_value[5].as_str().unwrap()).unwrap(), symbol: value["arg"]["instId"].as_str().unwrap().replace("USDT", "_USDT"), }); } return records; } // 处理特殊深度数据 // pub fn handle_special_depth(res_data: ResponseData) -> SpecialDepth { // HandleSwapInfo::handle_special_depth(ExchangeEnum::BitgetSwap, res_data) // } // // 处理特殊Ticker信息 // pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth { // let res_data_str = res_data.data; // let res_data_json: Vec = serde_json::from_str(&*res_data_str).unwrap(); // format_special_ticker(res_data_json[0].clone(), res_data.label) // } // // pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialDepth { // let bp = Decimal::from_str(data["bidPr"].as_str().unwrap()).unwrap(); // let bq = Decimal::from_str(data["bidSz"].as_str().unwrap()).unwrap(); // let ap = Decimal::from_str(data["askPr"].as_str().unwrap()).unwrap(); // let aq = Decimal::from_str(data["askSz"].as_str().unwrap()).unwrap(); // let mp = (bp + ap) * dec!(0.5); // let t = Decimal::from_str(data["ts"].as_str().unwrap()).unwrap(); // let create_at = data["ts"].as_str().unwrap().parse::().unwrap() * 1000; // // let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at }; // let depth_info = vec![bp, bq, ap, aq]; // SpecialDepth { // name: label, // depth: depth_info, // ticker: ticker_info, // t, // create_at, // } // }