|
|
@@ -1,23 +1,25 @@
|
|
|
-use std::cmp::Ordering;
|
|
|
use rust_decimal::Decimal;
|
|
|
-use rust_decimal::prelude::FromPrimitive;
|
|
|
use rust_decimal_macros::dec;
|
|
|
-use serde_json::json;
|
|
|
use exchanges::response_base::ResponseData;
|
|
|
-use global::public_params;
|
|
|
use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker};
|
|
|
+use crate::exchange::ExchangeEnum;
|
|
|
+use crate::handle_info::HandleSwapInfo;
|
|
|
|
|
|
+// 处理账号信息
|
|
|
pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Account {
|
|
|
+ let res_data_str = res_data.data;
|
|
|
+ let res_data_json: serde_json::Value = serde_json::from_str(&res_data_str).unwrap();
|
|
|
+ format_account_info(res_data_json, symbol)
|
|
|
+}
|
|
|
+
|
|
|
+pub fn format_account_info(data: serde_json::Value, symbol: String) -> Account {
|
|
|
let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
- let res_data_str = &res_data.data;
|
|
|
- let default_info = json!({"subject": "","data": {"availableBalance": 0, "holdBalance": 0, "currency":""}});
|
|
|
- let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap_or(default_info);
|
|
|
let mut available_balance = dec!(0);
|
|
|
let mut frozen_balance = dec!(0);
|
|
|
let mut balance = dec!(0);
|
|
|
- if res_data_json["data"]["currency"].as_str().unwrap() == symbol_array[1].to_string() && res_data_json["subject"].as_str().unwrap() == "availableBalance.change" {
|
|
|
- available_balance = res_data_json["data"]["availableBalance"].to_string().parse().unwrap_or(dec!(0));
|
|
|
- frozen_balance = res_data_json["data"]["holdBalance"].to_string().parse().unwrap_or(dec!(0));
|
|
|
+ if data["data"]["currency"].as_str().unwrap() == symbol_array[1].to_string() && data["subject"].as_str().unwrap() == "availableBalance.change" {
|
|
|
+ available_balance = data["data"]["availableBalance"].to_string().parse().unwrap_or(dec!(0));
|
|
|
+ frozen_balance = data["data"]["holdBalance"].to_string().parse().unwrap_or(dec!(0));
|
|
|
balance = available_balance + frozen_balance;
|
|
|
}
|
|
|
Account {
|
|
|
@@ -30,15 +32,38 @@ pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Account {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 处理特殊Ticket信息
|
|
|
+pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth {
|
|
|
+ let res_data_str = res_data.data;
|
|
|
+ let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
|
|
|
+ format_special_ticker(res_data_json, res_data.lable)
|
|
|
+}
|
|
|
+
|
|
|
+pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialDepth {
|
|
|
+ let bp = data["bestBidPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
+ let bq = data["bestBidSize"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
+ let ap = data["bestAskPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
+ let aq = data["bestAskSize"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
+ let mp = (bp + ap) * dec!(0.5);
|
|
|
+
|
|
|
+ let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp };
|
|
|
+ let depth_info = vec![bp, bq, ap, aq];
|
|
|
+ SpecialDepth {
|
|
|
+ name: label,
|
|
|
+ depth: depth_info,
|
|
|
+ ticker: ticker_info,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 处理position信息
|
|
|
pub fn handle_position(res_data: ResponseData, amount_size: Decimal) -> Vec<Position> {
|
|
|
let res_data_str = res_data.data;
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&res_data_str).unwrap();
|
|
|
- let result = res_data_json.iter().map(|item| { parse_position_item(item, amount_size) }).collect();
|
|
|
+ let result = res_data_json.iter().map(|item| { format_position_item(item, amount_size) }).collect();
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-fn parse_position_item(position: &serde_json::Value, amount_size: Decimal) -> Position {
|
|
|
+pub fn format_position_item(position: &serde_json::Value, amount_size: Decimal) -> Position {
|
|
|
let symbol = position["symbol"].as_str().unwrap_or("");
|
|
|
let currency = position["settleCurrency"].as_str().unwrap_or("");
|
|
|
let coin = &symbol[..symbol.find(currency).unwrap_or(0)];
|
|
|
@@ -64,127 +89,43 @@ pub fn handle_order(res_data: ResponseData, amount_size: Decimal) -> SpecialOrde
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
|
|
|
let mut order_info = Vec::new();
|
|
|
for item in res_data_json.iter() {
|
|
|
- let id = item["id"].as_str().unwrap_or("").parse().unwrap();
|
|
|
- let custom_id = item["clientOid"].as_str().unwrap_or("").parse().unwrap();
|
|
|
- let price = item["price"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
- let status = item["type"].as_str().unwrap_or("");
|
|
|
- let size = item["size"].to_string().parse().unwrap_or(dec!(0));
|
|
|
- let order_type = item["orderType"].as_str().unwrap_or("0").parse().unwrap_or("".to_string());
|
|
|
- let filled_size = item["filledSize"].to_string().parse().unwrap_or(dec!(0));
|
|
|
- let match_price = item["matchPrice"].to_string().parse().unwrap_or(dec!(0));
|
|
|
-
|
|
|
- let amount = size * amount_size;
|
|
|
- let deal_amount = filled_size * amount_size;
|
|
|
- let avg_price = if status == "match" { match_price } else { price };
|
|
|
- let custom_status = if ["done", "match"].contains(&status) { "REMOVE".to_string() } else if status == "open" { "NEW".to_string() } else { "OTHER".to_string() };
|
|
|
- let order = Order {
|
|
|
- id,
|
|
|
- custom_id,
|
|
|
- price,
|
|
|
- amount,
|
|
|
- deal_amount,
|
|
|
- avg_price,
|
|
|
- status: custom_status,
|
|
|
- order_type,
|
|
|
- };
|
|
|
- order_info.push(order);
|
|
|
+ order_info.push(format_order_item(item.clone(), amount_size));
|
|
|
}
|
|
|
-
|
|
|
SpecialOrder {
|
|
|
name: res_data.lable,
|
|
|
order: order_info,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 处理特殊Ticket信息
|
|
|
-pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth {
|
|
|
- let res_data_str = res_data.data;
|
|
|
- let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
|
|
|
- let bp = res_data_json["bestBidPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
- let bq = res_data_json["bestBidSize"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
- let ap = res_data_json["bestAskPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
- let aq = res_data_json["bestAskSize"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
- let mp = (bp + ap) * dec!(0.5);
|
|
|
+pub fn format_order_item(order: serde_json::Value, amount_size: Decimal) -> Order {
|
|
|
+ let price = order["price"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
+ let size = order["size"].to_string().parse().unwrap_or(dec!(0));
|
|
|
+ let status = order["status"].as_str().unwrap_or("");
|
|
|
+ let filled_size = order["filledSize"].to_string().parse().unwrap_or(dec!(0));
|
|
|
+ let match_price = order["matchPrice"].to_string().parse().unwrap_or(dec!(0));
|
|
|
|
|
|
- let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp };
|
|
|
- let depth_info = vec![bp, bq, ap, aq];
|
|
|
- let result = SpecialDepth {
|
|
|
- name: res_data.lable,
|
|
|
- depth: depth_info,
|
|
|
- ticker: ticker_info,
|
|
|
- };
|
|
|
- return result;
|
|
|
+ let amount = size * amount_size;
|
|
|
+ let deal_amount = filled_size * amount_size;
|
|
|
+ let avg_price = if status == "match" { match_price } else { price };
|
|
|
+ let custom_status = if ["done", "match"].contains(&status) { "REMOVE".to_string() } else if status == "open" { "NEW".to_string() } else { "OTHER".to_string() };
|
|
|
+ Order {
|
|
|
+ id: order["id"].as_str().unwrap_or("").parse().unwrap(),
|
|
|
+ custom_id: order["clientOid"].as_str().unwrap_or("").parse().unwrap(),
|
|
|
+ price,
|
|
|
+ amount,
|
|
|
+ deal_amount,
|
|
|
+ avg_price,
|
|
|
+ status: custom_status,
|
|
|
+ order_type: order["type"].as_str().unwrap_or("").parse().unwrap(),
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 处理特殊深度数据
|
|
|
pub fn handle_special_depth(res_data: ResponseData) -> SpecialDepth {
|
|
|
- let res_data_str = res_data.data;
|
|
|
- let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
|
|
|
- let mut depth_asks: Vec<MarketOrder> = parse_depth_items(&res_data_json["asks"]);
|
|
|
- let mut depth_bids: Vec<MarketOrder> = parse_depth_items(&res_data_json["bids"]);
|
|
|
- depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
|
|
|
- depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
|
|
|
- let mp = (depth_asks[0].price + depth_bids[0].price) * dec!(0.5);
|
|
|
- let step = (public_params::EFF_RANGE * mp / Decimal::from_usize(public_params::LEVEL).unwrap()).round_dp(mp.scale());
|
|
|
- let mut ap = Vec::new();
|
|
|
- let mut bp = Vec::new();
|
|
|
- let mut av: Vec<Decimal> = Vec::new();
|
|
|
- let mut bv: Vec<Decimal> = Vec::new();
|
|
|
- for i in 0..public_params::LEVEL {
|
|
|
- let price = (depth_asks[0].price + step * Decimal::from_f64(i as f64).unwrap()).round_dp(depth_asks[0].price.scale());
|
|
|
- ap.push(price);
|
|
|
- }
|
|
|
- for i in 0..public_params::LEVEL {
|
|
|
- let price = (depth_bids[0].price - step * Decimal::from_f64(i as f64).unwrap()).round_dp(depth_bids[0].price.scale());
|
|
|
- bp.push(price);
|
|
|
- }
|
|
|
- let mut ap_price_tag = depth_asks[0].price + step;
|
|
|
- let mut ap_index = 0;
|
|
|
- for item in depth_asks.iter() {
|
|
|
- let price = item.price;
|
|
|
- let amount = item.amount;
|
|
|
- if av.get(ap_index).is_none() { av.push(dec!(0)) };
|
|
|
- if price < ap_price_tag {
|
|
|
- av[ap_index] += amount;
|
|
|
- } else {
|
|
|
- ap_price_tag += step;
|
|
|
- ap_index += 1;
|
|
|
- if ap_index == public_params::LEVEL {
|
|
|
- break;
|
|
|
- }
|
|
|
- av[ap_index] += amount
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let mut bp_price_tag = depth_bids[0].price - step;
|
|
|
- let mut bp_index = 0;
|
|
|
- for item in depth_bids.iter() {
|
|
|
- let price = item.price;
|
|
|
- let amount = item.amount;
|
|
|
- if bv.get(bp_index).is_none() { bv.push(dec!(0)) };
|
|
|
- if price > bp_price_tag {
|
|
|
- bv[bp_index] += amount;
|
|
|
- } else {
|
|
|
- bp_price_tag -= step;
|
|
|
- bp_index += 1;
|
|
|
- if bp_index == public_params::LEVEL {
|
|
|
- break;
|
|
|
- }
|
|
|
- bv[bp_index] += amount
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let ticker_info = SpecialTicker { sell: depth_asks[0].price, buy: depth_bids[0].price, mid_price: mp };
|
|
|
- let depth_info = bp.iter().cloned().chain(bv.iter().cloned()).chain(ap.iter().cloned()).chain(av.iter().cloned()).collect();
|
|
|
- let result = SpecialDepth {
|
|
|
- name: res_data.lable,
|
|
|
- depth: depth_info,
|
|
|
- ticker: ticker_info,
|
|
|
- };
|
|
|
- return result;
|
|
|
+ HandleSwapInfo::handle_special_depth(ExchangeEnum::KucoinSwap, res_data)
|
|
|
}
|
|
|
|
|
|
-fn parse_depth_items(value: &serde_json::Value) -> Vec<MarketOrder> {
|
|
|
+pub fn format_depth_items(value: serde_json::Value) -> Vec<MarketOrder> {
|
|
|
let mut depth_items: Vec<MarketOrder> = vec![];
|
|
|
for value in value.as_array().unwrap() {
|
|
|
depth_items.push(MarketOrder {
|