bybit_swap_handle.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. use std::str::FromStr;
  2. use std::sync::Arc;
  3. use chrono::Utc;
  4. use lazy_static::lazy_static;
  5. use rust_decimal::{Decimal};
  6. use rust_decimal::prelude::FromPrimitive;
  7. use serde_json::{from_value, Value};
  8. use tokio::sync::Mutex;
  9. use tokio::time::Instant;
  10. use tracing::{error};
  11. use exchanges::response_base::ResponseData;
  12. use global::trace_stack::TraceStack;
  13. use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder, Depth, Trade, Ticker, Record};
  14. // 处理账号信息
  15. pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
  16. format_account_info(res_data.data.as_array().unwrap().clone(), symbol)
  17. }
  18. pub fn format_account_info(data: Vec<Value>, symbol: &String) -> Account {
  19. let account = data.iter().find(| &item | item["accountType"] == "UNIFIED");
  20. match account {
  21. None => {
  22. error!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data);
  23. panic!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data)
  24. }
  25. Some(val) =>{
  26. let arr: Vec<Value> = from_value(val["coin"].clone()).unwrap();
  27. let upper_str = symbol.to_uppercase();
  28. let symbol_array: Vec<&str> = upper_str.split("_").collect();
  29. let balance_info = arr.iter().find(|&item| item["coin"].as_str().unwrap() == symbol_array[1]);
  30. match balance_info {
  31. None => {
  32. error!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info);
  33. panic!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info)
  34. }
  35. Some(value) => {
  36. let balance = Decimal::from_str(&value["walletBalance"].as_str().unwrap().to_string()).unwrap();
  37. Account {
  38. coin: symbol_array[1].to_string(),
  39. balance,
  40. available_balance: Decimal::ZERO,
  41. frozen_balance: Decimal::ZERO,
  42. stocks: Decimal::ZERO,
  43. available_stocks: Decimal::ZERO,
  44. frozen_stocks: Decimal::ZERO,
  45. }
  46. }
  47. }
  48. }
  49. }
  50. }
  51. // 处理position信息
  52. pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
  53. res_data.data.as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect()
  54. }
  55. pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
  56. let position_idx: String = position["positionIdx"].to_string();
  57. let mut position_mode = match position_idx.as_str() {
  58. "0" => PositionModeEnum::Both,
  59. "1" => PositionModeEnum::Long,
  60. "2" => PositionModeEnum::Short,
  61. _ => {
  62. error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
  63. panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
  64. }
  65. };
  66. let symbol_mapper = position["symbol"].as_str().unwrap().to_string();
  67. let currency = "USDT";
  68. let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
  69. let size_str: String = from_value(position["size"].clone()).unwrap();
  70. let size = Decimal::from_str(size_str.as_str()).unwrap();
  71. let amount = size * ct_val;
  72. let side = position["side"].as_str().unwrap().to_string();
  73. let mut profit = Decimal::ZERO;
  74. let profit_str = position["unrealisedPnl"].as_str().unwrap_or("0");
  75. if profit_str != "" {
  76. profit = Decimal::from_str(profit_str).unwrap();
  77. }
  78. let update_time = Decimal::from_str(position["updatedTime"].as_str().unwrap()).unwrap();
  79. match position_mode {
  80. PositionModeEnum::Both => {
  81. position_mode = match side.as_str() {
  82. "Buy" => PositionModeEnum::Long,
  83. "Sell" => PositionModeEnum::Short,
  84. _ => { PositionModeEnum::Both }
  85. }
  86. }
  87. _ => {}
  88. }
  89. Position {
  90. symbol: format!{"{}_{}", coin, currency},
  91. margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
  92. amount,
  93. frozen_amount: Decimal::ZERO,
  94. price: Decimal::from_str(position["entryPrice"].as_str().unwrap()).unwrap(),
  95. profit,
  96. position_mode,
  97. margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
  98. update_time
  99. }
  100. }
  101. // 处理order信息
  102. pub fn handle_order(res_data: &ResponseData, ct_val: &Decimal) -> SpecialOrder {
  103. let res_data_json: Vec<Value> = res_data.data.as_array().unwrap().clone();
  104. let mut order_info = Vec::new();
  105. for item in res_data_json.iter() {
  106. order_info.push(format_order_item(item.clone(), ct_val));
  107. };
  108. SpecialOrder {
  109. name: res_data.label.clone(),
  110. order: order_info,
  111. }
  112. }
  113. pub fn format_order_item(order: Value, ct_val: &Decimal) -> Order {
  114. let status = order["orderStatus"].as_str().unwrap_or("");
  115. let text = order["orderLinkId"].as_str().unwrap_or("");
  116. let size = Decimal::from_str(order["qty"].as_str().unwrap()).unwrap();
  117. let right = Decimal::from_str(order["cumExecQty"].as_str().unwrap()).unwrap();
  118. let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
  119. let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
  120. let amount = size * ct_val;
  121. let mut avg_price = Decimal::ZERO;
  122. if right != Decimal::ZERO {
  123. avg_price = right_val / right;
  124. }
  125. let deal_amount = right * ct_val;
  126. let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
  127. "NULL".to_string()
  128. };
  129. let rst_order = Order {
  130. id: format!("{}", order["orderId"].as_str().unwrap()),
  131. custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
  132. price,
  133. amount,
  134. deal_amount,
  135. avg_price,
  136. status: custom_status,
  137. order_type: "limit".to_string(),
  138. trace_stack: TraceStack::new(0, Instant::now()).on_special("132 bybit_swap_handle".to_string()),
  139. };
  140. rst_order
  141. }
  142. pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
  143. let result = response.data.as_array().unwrap();
  144. let mut trades = vec![];
  145. for item in result {
  146. // 因为gate的量都是张数,所以要进行真实交易量处理
  147. let mut size = Decimal::from_str(item["v"].as_str().unwrap()).unwrap();
  148. let price = Decimal::from_str(item["p"].as_str().unwrap().to_string().as_str()).unwrap();
  149. let side = item["S"].as_str().unwrap().to_string();
  150. size = match side.as_str() {
  151. "Buy" => {
  152. size
  153. }
  154. "Sell" => {
  155. -size
  156. }
  157. _ => {
  158. error!("{}", item.to_string());
  159. panic!("Bybit trade error side(bybit_swap_handle_156)")
  160. }
  161. };
  162. let value = (size * price).abs();
  163. trades.push(Trade {
  164. id: item["i"].as_str().unwrap().to_string(),
  165. time: Decimal::from_i64(item["T"].as_i64().unwrap()).unwrap(),
  166. size,
  167. price,
  168. value,
  169. symbol: item["s"].as_str().unwrap().to_string(),
  170. })
  171. }
  172. return trades
  173. }
  174. pub fn handle_book_ticker(res_data: &ResponseData, mul: &Decimal) -> Depth {
  175. let asks = format_depth_items(res_data.data["a"].clone(), mul);
  176. let bids = format_depth_items(res_data.data["b"].clone(), mul);
  177. let t = Decimal::from_i64(res_data.reach_time).unwrap();
  178. let s = res_data.data["s"].as_str().unwrap().replace("USDT", "_USDT");
  179. Depth {
  180. time: t,
  181. symbol: s.to_string(),
  182. asks,
  183. bids,
  184. }
  185. }
  186. lazy_static! {
  187. static ref TICKER: Arc<Mutex<Ticker>> = Arc::new(Mutex::new(Ticker::new()));
  188. }
  189. pub async fn handle_ticker(res_data: &ResponseData) -> Ticker {
  190. let mut ticker = TICKER.lock().await;
  191. ticker.time = Decimal::from_i64(Utc::now().timestamp_millis()).unwrap();
  192. ticker.high = match res_data.data["highPrice24h"].as_str() {
  193. Some(str) => { Decimal::from_str(str).unwrap() }
  194. None => { ticker.high }
  195. };
  196. ticker.low = match res_data.data["lowPrice24h"].as_str() {
  197. Some(str) => { Decimal::from_str(str).unwrap() }
  198. None => { ticker.low }
  199. };
  200. ticker.sell = match res_data.data["ask1Price"].as_str() {
  201. Some(str) => { Decimal::from_str(str).unwrap() }
  202. None => { ticker.sell }
  203. };
  204. ticker.buy = match res_data.data["bid1Price"].as_str() {
  205. Some(str) => { Decimal::from_str(str).unwrap() }
  206. None => { ticker.buy }
  207. };
  208. ticker.last = match res_data.data["lastPrice"].as_str() {
  209. Some(str) => { Decimal::from_str(str).unwrap() }
  210. None => { ticker.last }
  211. };
  212. ticker.volume = match res_data.data["volume24h"].as_str() {
  213. Some(str) => { Decimal::from_str(str).unwrap() }
  214. None => { ticker.volume }
  215. };
  216. ticker.open_interest = match res_data.data["openInterest"].as_str() {
  217. Some(str) => { Decimal::from_str(str).unwrap() }
  218. None => { ticker.open_interest }
  219. };
  220. // let s = res_data.data["symbol"].as_str().unwrap().replace("USDT", "_USDT");
  221. ticker.clone()
  222. }
  223. pub fn format_depth_items(value: Value, mul: &Decimal) -> Vec<OrderBook> {
  224. let mut depth_items: Vec<OrderBook> = vec![];
  225. for val in value.as_array().unwrap() {
  226. let arr = val.as_array().unwrap();
  227. let price = Decimal::from_str(arr[0].as_str().unwrap()).unwrap();
  228. let size = Decimal::from_str(arr[1].as_str().unwrap()).unwrap();
  229. if size.is_zero() {
  230. continue
  231. }
  232. depth_items.push(OrderBook {
  233. price,
  234. size,
  235. value: price * size * mul,
  236. })
  237. }
  238. depth_items
  239. }
  240. pub fn handle_records(value: &Value) -> Vec<Record> {
  241. let mut records = vec![];
  242. for record_value in value.as_array().unwrap() {
  243. records.push(Record {
  244. time: Decimal::from_i64(record_value["start"].as_i64().unwrap()).unwrap(),
  245. open: Decimal::from_str(record_value["open"].as_str().unwrap()).unwrap(),
  246. high: Decimal::from_str(record_value["high"].as_str().unwrap()).unwrap(),
  247. low: Decimal::from_str(record_value["low"].as_str().unwrap()).unwrap(),
  248. close: Decimal::from_str(record_value["close"].as_str().unwrap()).unwrap(),
  249. volume: Decimal::from_str(record_value["volume"].as_str().unwrap()).unwrap(),
  250. symbol: "".to_string(),
  251. });
  252. }
  253. return records;
  254. }