| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- use std::str::FromStr;
- use std::time::SystemTime;
- use rust_decimal::Decimal;
- use serde_json::{from_value, Value};
- use tracing::{error};
- use exchanges::response_base::ResponseData;
- use rust_decimal::prelude::FromPrimitive;
- use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder, Record, Trade};
- // 处理账号信息
- pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
- format_account_info(res_data.data.as_array().unwrap().clone(), symbol)
- }
- pub fn format_account_info(data: Vec<Value>, symbol: &String) -> Account {
- let account = data.iter().find(|&item| item["accountType"] == "UNIFIED");
- match account {
- None => {
- error!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data);
- panic!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data)
- }
- Some(val) => {
- let arr: Vec<Value> = from_value(val["coin"].clone()).unwrap();
- let upper_str = symbol.to_uppercase();
- let symbol_array: Vec<&str> = upper_str.split("_").collect();
- let balance_info = arr.iter().find(|&item| item["coin"].as_str().unwrap() == symbol_array[1]);
- match balance_info {
- None => {
- error!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info);
- panic!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info)
- }
- Some(value) => {
- let balance = Decimal::from_str(&value["walletBalance"].as_str().unwrap().to_string()).unwrap();
- Account {
- coin: symbol_array[1].to_string(),
- balance,
- available_balance: Decimal::ZERO,
- frozen_balance: Decimal::ZERO,
- stocks: Decimal::ZERO,
- available_stocks: Decimal::ZERO,
- frozen_stocks: Decimal::ZERO,
- }
- }
- }
- }
- }
- }
- // 处理position信息
- pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
- res_data.data.as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect()
- }
- pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
- let position_idx: String = position["positionIdx"].to_string();
- let mut position_mode = match position_idx.as_str() {
- "0" => PositionModeEnum::Both,
- "1" => PositionModeEnum::Long,
- "2" => PositionModeEnum::Short,
- _ => {
- error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
- panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
- }
- };
- let symbol_mapper = position["symbol"].as_str().unwrap().to_string();
- let currency = "USDT";
- let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
- let size_str: String = from_value(position["size"].clone()).unwrap();
- let size = Decimal::from_str(size_str.as_str()).unwrap();
- let amount = size * ct_val;
- match position_mode {
- PositionModeEnum::Both => {
- position_mode = match amount {
- amount if amount > Decimal::ZERO => PositionModeEnum::Long,
- amount if amount < Decimal::ZERO => PositionModeEnum::Short,
- _ => { PositionModeEnum::Both }
- }
- }
- _ => {}
- }
- Position {
- symbol: format! {"{}_{}", coin, currency},
- margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
- amount,
- frozen_amount: Decimal::ZERO,
- price: Decimal::from_str(position["entryPrice"].as_str().unwrap()).unwrap(),
- profit: Decimal::from_str(position["unrealisedPnl"].as_str().unwrap()).unwrap(),
- position_mode,
- margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
- }
- }
- // 处理order信息
- pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
- let res_data_json: Vec<Value> = res_data.data.as_array().unwrap().clone();
- let mut order_info = Vec::new();
- for item in res_data_json.iter() {
- order_info.push(format_order_item(item.clone(), ct_val));
- };
- SpecialOrder {
- name: res_data.tag.clone(),
- order: order_info,
- }
- }
- pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
- let status = order["orderStatus"].as_str().unwrap_or("");
- let text = order["orderLinkId"].as_str().unwrap_or("");
- let size = Decimal::from_str(order["qty"].as_str().unwrap()).unwrap();
- let right = Decimal::from_str(order["cumExecQty"].as_str().unwrap()).unwrap();
- let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
- let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
- let amount = size * ct_val;
- let mut avg_price = Decimal::ZERO;
- if right != Decimal::ZERO {
- avg_price = right_val / right;
- }
- let deal_amount = right * ct_val;
- let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
- "NULL".to_string()
- };
- let rst_order = Order {
- id: format!("{}", order["orderId"].as_str().unwrap()),
- custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
- price,
- amount,
- deal_amount,
- avg_price,
- status: custom_status,
- order_type: "limit".to_string(),
- };
- return rst_order;
- }
- // 处理特殊Ticket信息
- // pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
- // let ap = Decimal::from_str(res_data.data["ask1Price"].as_str().unwrap()).unwrap();
- // let bp = Decimal::from_str(res_data.data["bid1Price"].as_str().unwrap()).unwrap();
- // let aq = Decimal::from_str(res_data.data["ask1Size"].as_str().unwrap()).unwrap();
- // let bq = Decimal::from_str(res_data.data["bid1Size"].as_str().unwrap()).unwrap();
- // let mp = (bp + ap) * dec!(0.5);
- //
- // let t = Decimal::from_i64(res_data.data["ts"].as_i64().unwrap()).unwrap();
- // let create_at = t.to_i64().unwrap();
- //
- // let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at: 0 };
- // let depth_info = vec![bp, bq, ap, aq];
- // SpecialDepth {
- // name: res_data.tag.clone(),
- // depth: depth_info,
- // ticker: ticker_info,
- // t,
- // create_at,
- // }
- // }
- pub fn format_depth_items(value: serde_json::Value) -> Vec<OrderBook> {
- let mut depth_items: Vec<OrderBook> = vec![];
- for val in value.as_array().unwrap() {
- let arr = val.as_array().unwrap();
- depth_items.push(OrderBook {
- price: Decimal::from_str(arr[0].as_str().unwrap()).unwrap(),
- amount: Decimal::from_str(arr[1].as_str().unwrap()).unwrap(),
- })
- }
- return depth_items;
- }
- pub fn handle_records(value: &Value) -> Vec<Record> {
- let mut records = vec![];
- let s = value["topic"].as_str().unwrap().to_string();
- let s_split: Vec<String> = s.split(".").map(|s| s.to_string()).collect();
- let symbol = s_split[2].replace("USDT", "_USDT");
- let data = value["data"].clone();
- for record_value in data.as_array().unwrap() {
- records.push(Record {
- time: Decimal::from_i64(record_value["timestamp"].as_i64().unwrap()).unwrap(),
- open: Decimal::from_str(record_value["open"].as_str().unwrap()).unwrap(),
- high: Decimal::from_str(record_value["high"].as_str().unwrap()).unwrap(),
- low: Decimal::from_str(record_value["low"].as_str().unwrap()).unwrap(),
- close: Decimal::from_str(record_value["close"].as_str().unwrap()).unwrap(),
- volume: Decimal::from_str(record_value["volume"].as_str().unwrap()).unwrap(),
- symbol: symbol.clone(),
- });
- }
- return records;
- }
- pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
- let result = res_data.data["data"].as_array().unwrap();
- let mut trades = vec![];
- for item in result {
- let side = item["S"].as_str().unwrap();
- let size = Decimal::from_str(item["v"].as_str().unwrap()).unwrap();
- let id = SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("Time went backwards").as_nanos().to_string();
- trades.push(Trade {
- id: id.clone(),
- time: Decimal::from_i64(item["T"].as_i64().unwrap()).unwrap(),
- size: if side == "Buy" { size } else { -size },
- price: Decimal::from_str(item["p"].as_str().unwrap()).unwrap(),
- symbol: item["s"].as_str().unwrap().replace("USDT", "_USDT"),
- })
- }
- return trades;
- }
|