gate_swap_handle.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. use std::cmp::Ordering;
  2. use std::str::FromStr;
  3. use rust_decimal::{Decimal};
  4. use rust_decimal::prelude::FromPrimitive;
  5. use serde_json::Value;
  6. use tokio::time::Instant;
  7. use tracing::{error};
  8. use crate::public_params;
  9. use crate::model::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker};
  10. use crate::response_base::ResponseData;
  11. use crate::trace_stack::TraceStack;
  12. #[derive(Debug, Clone, PartialEq, Eq)]
  13. pub struct DepthParam {
  14. pub depth_asks: Vec<MarketOrder>,
  15. pub depth_bids: Vec<MarketOrder>,
  16. pub t: Decimal,
  17. pub create_at: i64
  18. }
  19. // 处理账号信息
  20. pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
  21. let res_data_json = res_data.data.as_array().unwrap();
  22. format_account_info(res_data_json, symbol)
  23. }
  24. pub fn format_account_info(data: &Vec<Value>, symbol: &String) -> Account {
  25. let symbol_upper = symbol.to_uppercase();
  26. let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
  27. let balance_info = data.iter().find(|&item| item["text"].as_str().unwrap().contains(&symbol_upper));
  28. match balance_info {
  29. None => {
  30. error!("Gate:格式化账号信息错误!\nformat_account_info: data={:?}", data);
  31. panic!("Gate:格式化账号信息错误!\nformat_account_info: data={:?}", data)
  32. }
  33. Some(value) => {
  34. let balance = Decimal::from_str(&value["balance"].as_f64().unwrap().to_string()).unwrap();
  35. Account {
  36. coin: symbol_array[1].to_string(),
  37. balance,
  38. available_balance: Decimal::ZERO,
  39. frozen_balance: Decimal::ZERO,
  40. stocks: Decimal::ZERO,
  41. available_stocks: Decimal::ZERO,
  42. frozen_stocks: Decimal::ZERO,
  43. }
  44. }
  45. }
  46. }
  47. // 处理position信息
  48. pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
  49. let res_data_json = res_data.data.as_array().unwrap();
  50. res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect()
  51. }
  52. pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
  53. let mut position_mode = match position["mode"].as_str().unwrap_or("") {
  54. "single" => PositionModeEnum::Both,
  55. "dual_long" => PositionModeEnum::Long,
  56. "dual_short" => PositionModeEnum::Short,
  57. _ => {
  58. error!("Gate:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
  59. panic!("Gate:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
  60. }
  61. };
  62. let size = Decimal::from_str(&position["size"].as_f64().unwrap().to_string()).unwrap();
  63. let amount = size * ct_val;
  64. match position_mode {
  65. PositionModeEnum::Both => {
  66. position_mode = match amount {
  67. amount if amount > Decimal::ZERO => PositionModeEnum::Long,
  68. amount if amount < Decimal::ZERO => PositionModeEnum::Short,
  69. _ => { PositionModeEnum::Both }
  70. }
  71. }
  72. _ => {}
  73. }
  74. Position {
  75. symbol: position["contract"].as_str().unwrap().to_string(),
  76. margin_level: Decimal::from_str(&position["leverage"].as_f64().unwrap().to_string()).unwrap(),
  77. amount,
  78. frozen_amount: Decimal::ZERO,
  79. price: Decimal::from_str(&position["entry_price"].as_f64().unwrap().to_string()).unwrap(),
  80. profit: Decimal::from_str(&position["realised_pnl"].as_f64().unwrap().to_string()).unwrap(),
  81. position_mode,
  82. margin: Decimal::from_str(&position["margin"].as_f64().unwrap().to_string()).unwrap(),
  83. }
  84. }
  85. // 处理order信息
  86. pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
  87. let res_data_json = res_data.data.as_array().unwrap();
  88. let mut order_info = Vec::new();
  89. for item in res_data_json.iter() {
  90. order_info.push(format_order_item(item.clone(), ct_val));
  91. };
  92. SpecialOrder {
  93. name: res_data.label,
  94. order: order_info,
  95. }
  96. }
  97. pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
  98. let status = order["status"].as_str().unwrap_or("");
  99. let text = order["text"].as_str().unwrap_or("");
  100. let size = Decimal::from_f64(order["size"].as_f64().unwrap()).unwrap();
  101. let left = Decimal::from_f64(order["left"].as_f64().unwrap()).unwrap();
  102. let amount = size * ct_val;
  103. let deal_amount = (size - left) * ct_val;
  104. let custom_status = if status == "finished" { "REMOVE".to_string() } else if status == "open" { "NEW".to_string() } else {
  105. error!("Gate:格式化订单状态错误!\nformat_order_item:order={:?}", order);
  106. panic!("Gate:格式化订单状态错误!\nformat_order_item:order={:?}", order)
  107. };
  108. let rst_order = Order {
  109. id: order["id"].to_string(),
  110. custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
  111. price: Decimal::from_f64(order["price"].as_f64().unwrap()).unwrap(),
  112. amount,
  113. deal_amount,
  114. avg_price: Decimal::from_f64(order["fill_price"].as_f64().unwrap()).unwrap(),
  115. status: custom_status,
  116. order_type: "limit".to_string(),
  117. trace_stack: TraceStack::new(0, Instant::now()).on_special("120 gate_handle".to_string()),
  118. };
  119. return rst_order;
  120. }
  121. // 处理特殊Ticket信息
  122. pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
  123. let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap_or("0")).unwrap_or(Decimal::ZERO);
  124. let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
  125. let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap_or("0")).unwrap_or(Decimal::ZERO);
  126. let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
  127. let mp = (bp + ap) * Decimal::from_str("0.5").unwrap();
  128. let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
  129. let create_at = (*res_data).data["t"].as_i64().unwrap() * 1000;
  130. let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
  131. // 最佳买方的价格, 最佳买方的数量, 最佳卖方的价格, 最佳卖方的数量
  132. let depth_info = vec![bp, bq, ap, aq];
  133. SpecialDepth {
  134. name: (*res_data).label.clone(),
  135. depth: depth_info,
  136. ticker: ticker_info,
  137. t,
  138. create_at,
  139. }
  140. }
  141. pub fn format_depth_items(value: &Value) -> Vec<MarketOrder> {
  142. let mut depth_items: Vec<MarketOrder> = vec![];
  143. for value in value.as_array().unwrap() {
  144. depth_items.push(MarketOrder {
  145. price: Decimal::from_str(value["p"].as_str().unwrap()).unwrap(),
  146. amount: Decimal::from_f64(value["s"].as_f64().unwrap()).unwrap(),
  147. })
  148. }
  149. depth_items
  150. }
  151. // 处理深度信息
  152. pub fn handle_special_depth(res_data: &ResponseData) -> SpecialDepth {
  153. let label = res_data.label.clone();
  154. // 格式化
  155. let mut format_depth = format_depth(res_data);
  156. // 运算、组装
  157. make_special_depth(label, &mut format_depth.depth_asks, &mut format_depth.depth_bids, format_depth.t, format_depth.create_at)
  158. }
  159. pub fn format_depth(res_data: &ResponseData) -> DepthParam {
  160. let depth_asks: Vec<MarketOrder> = format_depth_items(&res_data.data["asks"]);
  161. let depth_bids: Vec<MarketOrder> = format_depth_items(&res_data.data["bids"]);
  162. // todo! 有id可以取 保证与py一致
  163. let t: Decimal = Decimal::from_str(&res_data.data["t"].to_string()).unwrap();
  164. let create_at: i64 = res_data.data["t"].as_i64().unwrap() * 1000;
  165. DepthParam {
  166. depth_asks,
  167. depth_bids,
  168. t,
  169. create_at
  170. }
  171. }
  172. pub fn make_special_depth(label: String, depth_asks: &mut Vec<MarketOrder>, depth_bids: &mut Vec<MarketOrder>, t: Decimal, create_at: i64) -> SpecialDepth {
  173. depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
  174. depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
  175. // TODO 不排序的话,有4us可以省下来。
  176. let mp = (depth_asks[0].price + depth_bids[0].price) * Decimal::from_str("0.5").unwrap();
  177. // 每1权重需要多少价格距离,0.001代表0.1%,每0.1%代表1权重 0.001
  178. let step = (Decimal::new(1, 3) * mp / Decimal::from_usize(public_params::LEVEL).unwrap()).round_dp(mp.scale());
  179. let mut ap = Vec::new();
  180. let mut bp = Vec::new();
  181. let mut av: Vec<Decimal> = Vec::new();
  182. let mut bv: Vec<Decimal> = Vec::new();
  183. for i in 0..public_params::LEVEL {
  184. let price = (depth_asks[0].price + step * Decimal::from_f64(i as f64).unwrap()).round_dp(depth_asks[0].price.scale());
  185. ap.push(price);
  186. }
  187. for i in 0..public_params::LEVEL {
  188. let price = (depth_bids[0].price - step * Decimal::from_f64(i as f64).unwrap()).round_dp(depth_bids[0].price.scale());
  189. bp.push(price);
  190. }
  191. let mut ap_price_tag = depth_asks[0].price + step;
  192. let mut ap_index = 0;
  193. for item in depth_asks.iter() {
  194. let price = item.price;
  195. let amount = item.amount;
  196. if av.get(ap_index).is_none() { av.push(Decimal::ZERO) };
  197. if price < ap_price_tag {
  198. av[ap_index] += amount;
  199. } else {
  200. ap_price_tag += step;
  201. ap_index += 1;
  202. if ap_index == public_params::LEVEL {
  203. break;
  204. }
  205. av[ap_index] += amount
  206. }
  207. }
  208. let mut bp_price_tag = depth_bids[0].price - step;
  209. let mut bp_index = 0;
  210. for item in depth_bids.iter() {
  211. let price = item.price;
  212. let amount = item.amount;
  213. if bv.get(bp_index).is_none() { bv.push(Decimal::ZERO) };
  214. if price > bp_price_tag {
  215. bv[bp_index] += amount;
  216. } else {
  217. bp_price_tag -= step;
  218. bp_index += 1;
  219. if bp_index == public_params::LEVEL {
  220. break;
  221. }
  222. bv[bp_index] += amount
  223. }
  224. }
  225. let ticker_info = SpecialTicker { sell: depth_asks[0].price, buy: depth_bids[0].price, mid_price: mp, t, create_at };
  226. let depth_info = bp.iter().cloned().chain(bv.iter().cloned()).chain(ap.iter().cloned()).chain(av.iter().cloned()).collect();
  227. SpecialDepth {
  228. name: label,
  229. depth: depth_info,
  230. ticker: ticker_info,
  231. t,
  232. create_at,
  233. }
  234. }