|
|
@@ -16,20 +16,16 @@ pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Account {
|
|
|
|
|
|
pub fn format_account_info(data: serde_json::Value, symbol: String) -> Account {
|
|
|
let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
- if data["data"]["currency"].as_str().unwrap() == symbol_array[1].to_string() && data["subject"].as_str().unwrap() == "availableBalance.change" {
|
|
|
- let available_balance = Decimal::from_str(&data["data"]["availableBalance"].to_string()).unwrap();
|
|
|
- let frozen_balance = Decimal::from_str(&data["data"]["holdBalance"].to_string()).unwrap();
|
|
|
- let balance = available_balance + frozen_balance;
|
|
|
- Account {
|
|
|
- balance,
|
|
|
- available_balance,
|
|
|
- frozen_balance,
|
|
|
- stocks: dec!(0),
|
|
|
- available_stocks: dec!(0),
|
|
|
- frozen_stocks: dec!(0),
|
|
|
- }
|
|
|
- } else {
|
|
|
- panic!("Kucoin:格式化账号信息错误!\nformat_account_info:data={:?}", data);
|
|
|
+ let available_balance = Decimal::from_str(data["availableBalance"].as_str().unwrap()).unwrap();
|
|
|
+ let frozen_balance = Decimal::from_str(data["holdBalance"].as_str().unwrap()).unwrap();
|
|
|
+ let balance = available_balance + frozen_balance;
|
|
|
+ Account {
|
|
|
+ balance,
|
|
|
+ available_balance,
|
|
|
+ frozen_balance,
|
|
|
+ stocks: dec!(0),
|
|
|
+ available_stocks: dec!(0),
|
|
|
+ frozen_stocks: dec!(0),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -59,35 +55,97 @@ pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialD
|
|
|
// 处理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| { format_position_item(item, amount_size) }).collect();
|
|
|
+ let res_data_json: serde_json::Value = serde_json::from_str(&res_data_str).unwrap();
|
|
|
+ let result = format_position_item(&res_data_json, amount_size);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-pub fn format_position_item(position: &serde_json::Value, amount_size: Decimal) -> Position {
|
|
|
+pub fn format_position_item(position: &serde_json::Value, amount_size: Decimal) -> Vec<Position> {
|
|
|
let symbol = position["symbol"].as_str().unwrap_or("");
|
|
|
+ let real_leverage = Decimal::from_str(&position["realLeverage"].to_string()).unwrap();
|
|
|
let currency = position["settleCurrency"].as_str().unwrap_or("");
|
|
|
let coin = &symbol[..symbol.find(currency).unwrap_or(0)];
|
|
|
+ let avg_entry_price = Decimal::from_str(&position["avgEntryPrice"].to_string()).unwrap();
|
|
|
+ let unrealised_pnl = Decimal::from_str(&position["unrealisedPnl"].to_string()).unwrap();
|
|
|
+ let pos_margin = Decimal::from_str(&position["posMargin"].to_string()).unwrap();
|
|
|
|
|
|
let current_qty = Decimal::from_str(&position["currentQty"].to_string()).unwrap();
|
|
|
let amount = current_qty * amount_size;
|
|
|
let position_mode = if amount > dec!(0) { PositionModeEnum::Long } else { PositionModeEnum::Short };
|
|
|
- Position {
|
|
|
- symbol: format!("{}_{}", coin, currency),
|
|
|
- margin_level: Decimal::from_str(&position["realLeverage"].to_string()).unwrap(),
|
|
|
- amount: amount.abs(),
|
|
|
- frozen_amount: dec!(0),
|
|
|
- price: Decimal::from_str(&position["avgEntryPrice"].to_string()).unwrap(),
|
|
|
- profit: Decimal::from_str(&position["unrealisedPnl"].to_string()).unwrap(),
|
|
|
- position_mode,
|
|
|
- margin: Decimal::from_str(&position["posMargin"].to_string()).unwrap(),
|
|
|
- }
|
|
|
+ let mut position_array = Vec::new();
|
|
|
+ return match position_mode {
|
|
|
+ PositionModeEnum::Long => {
|
|
|
+ position_array.push(
|
|
|
+ Position {
|
|
|
+ symbol: format!("{}_{}", coin, currency),
|
|
|
+ margin_level: real_leverage,
|
|
|
+ amount: amount.abs(),
|
|
|
+ frozen_amount: dec!(0),
|
|
|
+ price: avg_entry_price,
|
|
|
+ profit: unrealised_pnl,
|
|
|
+ position_mode: PositionModeEnum::Long,
|
|
|
+ margin: pos_margin,
|
|
|
+ }
|
|
|
+ );
|
|
|
+ position_array.push(
|
|
|
+ Position {
|
|
|
+ symbol: format!("{}_{}", coin, currency),
|
|
|
+ margin_level: real_leverage,
|
|
|
+ amount: dec!(0),
|
|
|
+ frozen_amount: dec!(0),
|
|
|
+ price: dec!(0),
|
|
|
+ profit: dec!(0),
|
|
|
+ position_mode: PositionModeEnum::Short,
|
|
|
+ margin: dec!(0),
|
|
|
+ });
|
|
|
+ position_array
|
|
|
+ }
|
|
|
+ PositionModeEnum::Short => {
|
|
|
+ position_array.push(
|
|
|
+ Position {
|
|
|
+ symbol: format!("{}_{}", coin, currency),
|
|
|
+ margin_level: real_leverage,
|
|
|
+ amount: dec!(0),
|
|
|
+ frozen_amount: dec!(0),
|
|
|
+ price: dec!(0),
|
|
|
+ profit: dec!(0),
|
|
|
+ position_mode: PositionModeEnum::Long,
|
|
|
+ margin: dec!(0),
|
|
|
+ });
|
|
|
+ position_array.push(
|
|
|
+ Position {
|
|
|
+ symbol: format!("{}_{}", coin, currency),
|
|
|
+ margin_level: real_leverage,
|
|
|
+ amount: amount.abs(),
|
|
|
+ frozen_amount: dec!(0),
|
|
|
+ price: Decimal::from_str(&position["avgEntryPrice"].to_string()).unwrap(),
|
|
|
+ profit: Decimal::from_str(&position["unrealisedPnl"].to_string()).unwrap(),
|
|
|
+ position_mode: PositionModeEnum::Short,
|
|
|
+ margin: Decimal::from_str(&position["posMargin"].to_string()).unwrap(),
|
|
|
+ });
|
|
|
+ position_array
|
|
|
+ }
|
|
|
+ _ => {
|
|
|
+ position_array.push(
|
|
|
+ Position {
|
|
|
+ symbol: format!("{}_{}", coin, currency),
|
|
|
+ margin_level: real_leverage,
|
|
|
+ amount,
|
|
|
+ frozen_amount: dec!(0),
|
|
|
+ price: Decimal::from_str(&position["avgEntryPrice"].to_string()).unwrap(),
|
|
|
+ profit: Decimal::from_str(&position["unrealisedPnl"].to_string()).unwrap(),
|
|
|
+ position_mode: PositionModeEnum::Both,
|
|
|
+ margin: Decimal::from_str(&position["posMargin"].to_string()).unwrap(),
|
|
|
+ });
|
|
|
+ position_array
|
|
|
+ }
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
// 处理order信息
|
|
|
pub fn handle_order(res_data: ResponseData, amount_size: Decimal) -> SpecialOrder {
|
|
|
let res_data_str = res_data.data;
|
|
|
- let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
|
|
|
+ let res_data_json: Vec<serde_json::Value> = vec![serde_json::from_str(&*res_data_str).unwrap()];
|
|
|
let mut order_info = Vec::new();
|
|
|
for item in res_data_json.iter() {
|
|
|
order_info.push(format_order_item(item.clone(), amount_size));
|
|
|
@@ -103,14 +161,19 @@ pub fn format_order_item(order: serde_json::Value, amount_size: Decimal) -> Orde
|
|
|
let size = Decimal::from_str(order["size"].as_str().unwrap()).unwrap();
|
|
|
let status = order["status"].as_str().unwrap_or("");
|
|
|
let filled_size = Decimal::from_str(order["filledSize"].as_str().unwrap()).unwrap();
|
|
|
- let match_price = Decimal::from_str(order["matchPrice"].as_str().unwrap()).unwrap();
|
|
|
+
|
|
|
+ let mut avg_price;
|
|
|
+ if status == "match" {
|
|
|
+ avg_price = Decimal::from_str(order["matchPrice"].as_str().unwrap_or("-1")).unwrap();
|
|
|
+ } else {
|
|
|
+ avg_price = price;
|
|
|
+ };
|
|
|
|
|
|
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 { panic!("Kucoin:格式化订单状态错误!\nformat_order_item:status={:?}", status); };
|
|
|
Order {
|
|
|
- id: order["id"].as_str().unwrap().to_string(),
|
|
|
+ id: order["orderId"].as_str().unwrap().to_string(),
|
|
|
custom_id: order["clientOid"].as_str().unwrap().to_string(),
|
|
|
price,
|
|
|
amount,
|