coinex_swap_handle.rs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. use std::str::FromStr;
  2. use rust_decimal::Decimal;
  3. use rust_decimal::prelude::FromPrimitive;
  4. use rust_decimal_macros::dec;
  5. use serde_json::Value;
  6. use tokio::time::Instant;
  7. use tracing::{error, info};
  8. use tracing_subscriber::fmt::format;
  9. use exchanges::response_base::ResponseData;
  10. use global::trace_stack::TraceStack;
  11. use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker};
  12. // 处理账号信息
  13. pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
  14. let res_data_json = res_data.data["balance_list"].as_array().unwrap();
  15. format_account_info(res_data_json, symbol)
  16. }
  17. pub fn format_account_info(data: &Vec<Value>, symbol: &String) -> Account {
  18. let symbol_upper = symbol.to_uppercase();
  19. let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
  20. let balance_info = data.iter().find(|&item| item["ccy"].as_str().unwrap().contains(symbol_array[1]));
  21. match balance_info {
  22. None => {
  23. error!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data);
  24. panic!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data)
  25. }
  26. Some(value) => {
  27. let frozen_balance= Decimal::from_str(&value["frozen"].as_str().unwrap()).unwrap();
  28. let available_balance = Decimal::from_str(&value["available"].as_str().unwrap()).unwrap();
  29. let margin = Decimal::from_str(&value["margin"].as_str().unwrap()).unwrap();
  30. let profit_unreal = Decimal::from_str(&value["unrealized_pnl"].as_str().unwrap()).unwrap();
  31. let balance = frozen_balance + available_balance + margin + profit_unreal;
  32. Account {
  33. coin: symbol_array[1].to_string(),
  34. balance,
  35. available_balance: Decimal::ZERO,
  36. frozen_balance: Decimal::ZERO,
  37. stocks: Decimal::ZERO,
  38. available_stocks: Decimal::ZERO,
  39. frozen_stocks: Decimal::ZERO,
  40. }
  41. }
  42. }
  43. }
  44. // 处理position信息
  45. pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
  46. let res_data_json = &res_data.data["position"];
  47. let position = format_position_item(res_data_json, ct_val);
  48. vec![position]
  49. }
  50. pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
  51. let mut position_mode = match position["side"].as_str().unwrap_or("") {
  52. "long" => PositionModeEnum::Long,
  53. "short" => PositionModeEnum::Short,
  54. _ => {
  55. error!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
  56. panic!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
  57. }
  58. };
  59. let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
  60. let amount = size * ct_val;
  61. Position {
  62. symbol: position["market"].as_str().unwrap().to_string(),
  63. margin_level: Decimal::from_str(&position["leverage"].as_str().unwrap()).unwrap(),
  64. amount,
  65. frozen_amount: Decimal::ZERO,
  66. price: Decimal::from_str(&position["avg_entry_price"].as_str().unwrap()).unwrap(),
  67. profit: Decimal::from_str(&position["unrealized_pnl"].as_str().unwrap()).unwrap(),
  68. position_mode,
  69. margin: Decimal::from_str(&position["ath_margin_size"].as_str().unwrap()).unwrap(),
  70. }
  71. }
  72. // 处理order信息
  73. pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
  74. let status = res_data.data["event"].as_str().unwrap();
  75. let res_data_json = &res_data.data["order"];
  76. let order_info = format_order_item(res_data_json, ct_val, status);
  77. SpecialOrder {
  78. name: res_data.label,
  79. order: vec![order_info],
  80. }
  81. }
  82. pub fn format_order_item(order: &Value, ct_val: Decimal, status: &str) -> Order {
  83. let text = order["client_id"].as_str().unwrap_or("");
  84. let size = Decimal::from_str(order["amount"].as_str().unwrap()).unwrap();
  85. let left = Decimal::from_str(order["unfilled_amount"].as_str().unwrap()).unwrap();
  86. // 成交量
  87. let filled_amount = Decimal::from_str(order["filled_amount"].as_str().unwrap_or("0")).unwrap();
  88. // 成交额
  89. let filled_value = Decimal::from_str(order["filled_value"].as_str().unwrap()).unwrap();
  90. // 成交均价
  91. let mut avg_price = Decimal::ZERO;
  92. if filled_amount != Decimal::ZERO{
  93. avg_price = filled_value/filled_amount;
  94. }
  95. let amount = size * ct_val;
  96. let deal_amount = (size - left) * ct_val;
  97. let custom_status = if status == "finish" { "REMOVE".to_string() } else if status == "put" { "NEW".to_string() } else {
  98. "NULL".to_string()
  99. };
  100. let rst_order = Order {
  101. id: order["order_id"].to_string(),
  102. custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
  103. price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
  104. amount,
  105. deal_amount,
  106. avg_price,
  107. status: custom_status,
  108. order_type: "limit".to_string(),
  109. trace_stack: TraceStack::new(0, Instant::now()).on_special("120 Coinex_handle".to_string()),
  110. };
  111. return rst_order;
  112. }
  113. // 处理特殊Ticket信息
  114. pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
  115. let depth = &res_data.data["depth"];
  116. let bp = Decimal::from_str(depth["bids"][0][0].as_str().unwrap()).unwrap();
  117. let bq = Decimal::from_str(depth["bids"][0][1].as_str().unwrap()).unwrap();
  118. let ap = Decimal::from_str((depth["asks"][0][0].as_str().unwrap())).unwrap();
  119. let aq = Decimal::from_str(depth["asks"][0][1].as_str().unwrap()).unwrap();
  120. let mp = (bp + ap) * dec!(0.5);
  121. let t = Decimal::from_i64(depth.get("checksum").unwrap().as_i64().unwrap_or(0i64)).unwrap();
  122. let create_at = depth.get("updated_at").unwrap().as_i64().unwrap() * 1000;
  123. let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
  124. let depth_info = vec![bp, bq, ap, aq];
  125. SpecialDepth {
  126. name: (*res_data).label.clone(),
  127. depth: depth_info,
  128. ticker: ticker_info,
  129. t,
  130. create_at,
  131. }
  132. }
  133. pub fn format_depth_items(value: &Value) -> Vec<MarketOrder> {
  134. if value.is_null() {
  135. return vec![];
  136. }
  137. let mut depth_items: Vec<MarketOrder> = vec![];
  138. for value in value.as_array().unwrap() {
  139. let values = value.as_array().unwrap();
  140. depth_items.push(MarketOrder {
  141. price: Decimal::from_str(values[0].as_str().unwrap()).unwrap(),
  142. amount: Decimal::from_str(values[1].as_str().unwrap()).unwrap(),
  143. })
  144. }
  145. return depth_items;
  146. }