okx_handle.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. use std::str::FromStr;
  2. use rust_decimal::Decimal;
  3. use rust_decimal_macros::dec;
  4. use serde::{Deserialize, Serialize};
  5. use tracing::trace;
  6. use exchanges::response_base::ResponseData;
  7. use global::trace_stack::TraceStack;
  8. use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker};
  9. use crate::exchange::ExchangeEnum;
  10. use crate::handle_info::HandleSwapInfo;
  11. use crate::okx_swap::SwapPosition;
  12. #[derive(Debug, Deserialize, Serialize)]
  13. #[serde(rename_all = "camelCase")]
  14. struct SwapBalanceAndPositionSubscribe {
  15. pos_data: Vec<SwapBalanceAndPositionPosDataSubscribe>,
  16. }
  17. #[derive(Debug, Deserialize, Serialize)]
  18. #[serde(rename_all = "camelCase")]
  19. struct SwapBalanceAndPositionPosDataSubscribe {
  20. pos_id: String,
  21. trade_id: String,
  22. inst_id: String,
  23. inst_type: String,
  24. mgn_mode: String,
  25. pos_side: String,
  26. pos: Decimal,
  27. ccy: String,
  28. pos_ccy: String,
  29. avg_px: Decimal,
  30. u_time: String,
  31. }
  32. #[derive(Debug, Deserialize, Serialize)]
  33. #[serde(rename_all = "camelCase")]
  34. struct SwapPositionSubscribe {
  35. arg: SwapPositionSubscribeArg,
  36. data: Vec<SwapPosition>,
  37. }
  38. #[derive(Debug, Deserialize, Serialize)]
  39. #[serde(rename_all = "camelCase")]
  40. struct SwapPositionSubscribeArg {
  41. channel: String,
  42. uid: String,
  43. inst_type: String,
  44. }
  45. // 处理账号信息
  46. pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Account {
  47. let res_data_str = res_data.data;
  48. let res_data_json: serde_json::Value = serde_json::from_str(&res_data_str).unwrap();
  49. let account_info = res_data_json[0]["details"].clone();
  50. let details = account_info[0].clone();
  51. format_account_info(details, symbol)
  52. }
  53. pub fn format_account_info(data: serde_json::Value, symbol: String) -> Account {
  54. let symbol_upper = symbol.to_uppercase();
  55. let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
  56. Account {
  57. coin: symbol_array[1].to_string(),
  58. balance: Decimal::from_str(data["cashBal"].as_str().unwrap()).unwrap(),
  59. available_balance: Decimal::from_str(data["availBal"].as_str().unwrap()).unwrap(),
  60. frozen_balance: Decimal::from_str(data["fixedBal"].as_str().unwrap()).unwrap(),
  61. stocks: Decimal::ZERO,
  62. available_stocks: Decimal::ZERO,
  63. frozen_stocks: Decimal::ZERO,
  64. }
  65. }
  66. // 处理order信息
  67. pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
  68. let res_data_str = res_data.data;
  69. let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
  70. trace!(?res_data_json);
  71. let mut order_info = Vec::new();
  72. for item in res_data_json.iter() {
  73. order_info.push(format_order_item(item.clone(), ct_val));
  74. }
  75. trace!(?order_info);
  76. SpecialOrder {
  77. name: res_data.label,
  78. order: order_info,
  79. }
  80. }
  81. // 处理订单信息
  82. pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
  83. let price = Decimal::from_str(order["px"].as_str().unwrap()).unwrap();
  84. let size = Decimal::from_str(order["sz"].as_str().unwrap()).unwrap();
  85. let status = order["state"].as_str().unwrap_or("");
  86. let filled_size = Decimal::from_str(order["accFillSz"].as_str().unwrap()).unwrap();
  87. let avg_price = Decimal::from_str(order["avgPx"].as_str().unwrap()).unwrap();
  88. let amount = size * ct_val;
  89. let deal_amount = filled_size * ct_val;
  90. let custom_status = if ["canceled", "filled", "mmp_canceled"].contains(&status) {
  91. "REMOVE".to_string()
  92. } else if ["live", "partially_filled"].contains(&status) {
  93. "NEW".to_string()
  94. } else {
  95. "NULL".to_string()
  96. };
  97. Order {
  98. id: order["ordId"].as_str().unwrap().to_string(),
  99. custom_id: order["clOrdId"].as_str().unwrap().to_string(),
  100. price,
  101. amount,
  102. deal_amount,
  103. avg_price,
  104. status: custom_status,
  105. order_type: order["ordType"].as_str().unwrap().to_string(),
  106. trace_stack: TraceStack::default().on_special("77 okx_handle".to_string()),
  107. }
  108. }
  109. // 处理特殊深度数据
  110. pub fn handle_special_depth(res_data: ResponseData) -> SpecialDepth {
  111. HandleSwapInfo::handle_special_depth(ExchangeEnum::OkxSwap, res_data)
  112. }
  113. // 格式化深度信息
  114. pub fn format_depth_items(value: serde_json::Value) -> Vec<MarketOrder> {
  115. let mut depth_items: Vec<MarketOrder> = vec![];
  116. for value in value.as_array().unwrap() {
  117. depth_items.push(MarketOrder {
  118. price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
  119. amount: Decimal::from_str(value[1].as_str().unwrap()).unwrap(),
  120. })
  121. }
  122. return depth_items;
  123. }
  124. // 处理特殊Ticker信息
  125. pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth {
  126. let res_data_str = res_data.data;
  127. let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
  128. format_special_ticker(res_data_json[0].clone(), res_data.label)
  129. }
  130. pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialDepth {
  131. let bids = data["bids"][0].as_array().unwrap();
  132. let asks = data["asks"][0].as_array().unwrap();
  133. let bp = Decimal::from_str(bids[0].as_str().unwrap()).unwrap();
  134. let bq = Decimal::from_str(bids[1].as_str().unwrap()).unwrap();
  135. let ap = Decimal::from_str(asks[0].as_str().unwrap()).unwrap();
  136. let aq = Decimal::from_str(asks[1].as_str().unwrap()).unwrap();
  137. let mp = (bp + ap) * dec!(0.5);
  138. let t = Decimal::from_str(&data["seqId"].to_string()).unwrap();
  139. let create_at = data["ts"].as_str().unwrap().parse::<i64>().unwrap() * 1000;
  140. let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
  141. let depth_info = vec![bp, bq, ap, aq];
  142. SpecialDepth {
  143. name: label,
  144. depth: depth_info,
  145. ticker: ticker_info,
  146. t,
  147. create_at,
  148. }
  149. }
  150. // 处理position信息
  151. pub fn handle_position(res_data: ResponseData, ct_val: Decimal) -> Vec<Position> {
  152. let res_data_str = res_data.data;
  153. let data_list: SwapBalanceAndPositionSubscribe = serde_json::from_str(&res_data_str).unwrap();
  154. let position_data = data_list.pos_data;
  155. position_data.iter().map(|item| format_position_item(item, ct_val)).collect()
  156. }
  157. pub fn format_position_item(value: &SwapBalanceAndPositionPosDataSubscribe, ct_val: Decimal) -> Position {
  158. let position_mode = match value.pos_side.as_str() {
  159. "long" => { PositionModeEnum::Long }
  160. "short" => { PositionModeEnum::Short }
  161. _ => { PositionModeEnum::Both }
  162. };
  163. Position {
  164. symbol: value.inst_id.replace("-SWAP", ""),
  165. margin_level: Decimal::ZERO,
  166. amount: value.pos * ct_val,
  167. frozen_amount: Decimal::ZERO,
  168. price: value.avg_px,
  169. profit: Decimal::ZERO,
  170. position_mode,
  171. margin: Decimal::ZERO,
  172. }
  173. }