kucoin_spot.rs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. use std::collections::{BTreeMap, HashMap};
  2. use std::io::{Error, ErrorKind};
  3. use std::str::FromStr;
  4. use tokio::sync::mpsc::Sender;
  5. use async_trait::async_trait;
  6. use futures::stream::FuturesUnordered;
  7. use futures::TryStreamExt;
  8. use rust_decimal::Decimal;
  9. use rust_decimal::prelude::FromPrimitive;
  10. use serde::{Deserialize, Serialize};
  11. use serde_json::json;
  12. use tracing::error;
  13. use exchanges::kucoin_spot_rest::KucoinSpotRest;
  14. use global::trace_stack::TraceStack;
  15. use crate::exchange::ExchangeEnum;
  16. use crate::{Account, Market, Order, OrderCommand, Platform, Position, Ticker, utils};
  17. /// Kucoin交易所账户信息请求数据结构
  18. /// 接口`"/api/v1/accounts"`;
  19. ///
  20. /// struct SpotAccount
  21. /// - `id`: String, accountId
  22. /// - `currency`: String, 币种
  23. /// - `account_type`: String, 账户类型,资金(main)账户,现货交易(trade)账户,现货高频交易(trade_hf)账户,杠杆(margin)账户
  24. /// - `balance`: Decimal, 资金总额
  25. /// - `available`: Decimal, 可用余额
  26. /// - `holds`: Decimal, 冻结金额
  27. #[derive(Debug, Deserialize, Serialize)]
  28. #[serde(rename_all = "camelCase")]
  29. struct SpotAccount {
  30. id: String,
  31. currency: String,
  32. account_type: String,
  33. balance: Decimal,
  34. available: Decimal,
  35. holds: Decimal,
  36. }
  37. impl SpotAccount {
  38. fn new() -> SpotAccount {
  39. SpotAccount {
  40. id: "".to_string(),
  41. currency: "".to_string(),
  42. account_type: "".to_string(),
  43. balance: Default::default(),
  44. available: Default::default(),
  45. holds: Default::default(),
  46. }
  47. }
  48. }
  49. /// Kucoin交易所Ticker信息请求数据结构
  50. /// 接口`"/api/v1/market/orderbook/level1"`;
  51. ///
  52. /// struct SpotTicker
  53. /// - `sequence`: String, 序列号
  54. /// - `price`: Decimal, 最新成交价格
  55. /// - `size`: Decimal, 最新成交数量
  56. /// - `best_ask`: Decimal, 最佳卖一价
  57. /// - `best_ask_size`: Decimal, 最佳卖一数量
  58. /// - `best_bid`: Decimal, 最佳买一价
  59. /// - `best_bid_size`: Decimal, 最佳买一数量
  60. /// - `time`: i64, 时间戳
  61. #[derive(Debug, Deserialize, Serialize)]
  62. #[serde(rename_all = "camelCase")]
  63. struct SpotTicker {
  64. sequence: String,
  65. price: Decimal,
  66. size: Decimal,
  67. best_ask: Decimal,
  68. best_ask_size: Decimal,
  69. best_bid: Decimal,
  70. best_bid_size: Decimal,
  71. time: i64,
  72. }
  73. /// Kucoin交易所Market信息请求数据结构
  74. /// 接口`"/api/v2/symbols"`;
  75. ///
  76. /// struct SpotTicker
  77. /// - `symbol: String, 交易对唯一标识码
  78. /// - `name: String, 交易对名称
  79. /// - `base_currency: String, 商品货币
  80. /// - `quote_currency: String, 计价币种
  81. /// - `fee_currency: String, 交易计算手续费的币种
  82. /// - `market: String, 交易市场
  83. /// - `base_min_size: Decimal, 下单时size的最小值
  84. /// - `quote_min_size: Decimal, 下市价单,funds的最小值
  85. /// - `base_max_size: Decimal, 下单,size的最大值
  86. /// - `quote_max_size: Decimal, 下市价单,funds的最大值
  87. /// - `base_increment: Decimal, 数量增量,下单的size必须为数量增量的正整数倍
  88. /// - `quote_increment: Decimal, 市价单:资金增量,下单的funds必须为资金增量的正整数倍
  89. /// - `price_increment: Decimal, 限价单:价格增量,下单的price必须为价格增量的正整数倍
  90. /// - `price_limit_rate: Decimal, 价格保护阈值
  91. /// - `min_funds: Option<Decimal>, 最小交易金额
  92. /// - `is_margin_enabled: bool, 是否支持杠杆
  93. /// - `enable_trading: bool, 是否可以用于交易
  94. #[derive(Debug, Deserialize, Serialize)]
  95. #[serde(rename_all = "camelCase")]
  96. struct SpotMarket {
  97. symbol: String,
  98. name: String,
  99. base_currency: String,
  100. quote_currency: String,
  101. fee_currency: String,
  102. market: String,
  103. base_min_size: Decimal,
  104. quote_min_size: Decimal,
  105. base_max_size: Decimal,
  106. quote_max_size: Decimal,
  107. base_increment: Decimal,
  108. quote_increment: Decimal,
  109. price_increment: Decimal,
  110. price_limit_rate: Decimal,
  111. min_funds: Option<Decimal>,
  112. is_margin_enabled: bool,
  113. enable_trading: bool,
  114. }
  115. /// Kucoin交易所Order信息请求数据结构
  116. /// 接口`"/api/v1/orders/{orderId}"`;
  117. ///
  118. /// struct SpotOrder
  119. /// - `id`: String,
  120. /// - `symbol`: String,
  121. /// - `op_type`: String,
  122. /// - `order_type`: String,
  123. /// - `side`: String,
  124. /// - `price`: Decimal,
  125. /// - `size`: Decimal,
  126. /// - `funds`: Decimal,
  127. /// - `deal_funds`: Decimal,
  128. /// - `deal_size`: Decimal,
  129. /// - `fee`: Decimal,
  130. /// - `fee_currency`: String,
  131. /// - `stp`: String,
  132. /// - `stop`: String,
  133. /// - `stop_triggered`: bool,
  134. /// - `stop_price`: Decimal,
  135. /// - `time_in_force`: String,
  136. /// - `post_only`: bool,
  137. /// - `hidden`: bool,
  138. /// - `iceberg`: bool,
  139. /// - `visible_size`: Decimal,
  140. /// - `cancel_after`: i64,
  141. /// - `channel`: String,
  142. /// - `client_oid`: String,
  143. /// - `remark`: String,
  144. /// - `tags`: String,
  145. /// - `is_active`: bool,
  146. /// - `cancel_exist`: bool,
  147. /// - `created_at`: i64,
  148. /// - `trade_type`: String,
  149. #[derive(Debug, Deserialize, Serialize)]
  150. #[serde(rename_all = "camelCase")]
  151. struct SpotOrder {
  152. id: String,
  153. symbol: String,
  154. op_type: String,
  155. #[serde(rename = "type")]
  156. order_type: String,
  157. side: String,
  158. price: Decimal,
  159. size: Decimal,
  160. funds: Decimal,
  161. deal_funds: Decimal,
  162. deal_size: Decimal,
  163. fee: Decimal,
  164. fee_currency: String,
  165. stp: String,
  166. stop: String,
  167. stop_triggered: bool,
  168. stop_price: Decimal,
  169. time_in_force: String,
  170. post_only: bool,
  171. hidden: bool,
  172. iceberg: bool,
  173. visible_size: Decimal,
  174. cancel_after: i64,
  175. channel: String,
  176. client_oid: String,
  177. remark: String,
  178. tags: String,
  179. is_active: bool,
  180. cancel_exist: bool,
  181. created_at: i64,
  182. trade_type: String,
  183. }
  184. #[allow(dead_code)]
  185. #[derive(Clone)]
  186. pub struct KucoinSpot {
  187. exchange: ExchangeEnum,
  188. symbol: String,
  189. is_colo: bool,
  190. params: BTreeMap<String, String>,
  191. request: KucoinSpotRest,
  192. market: Market,
  193. order_sender: Sender<Order>,
  194. error_sender: Sender<Error>,
  195. }
  196. impl KucoinSpot {
  197. pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> KucoinSpot {
  198. let market = Market::new();
  199. let mut kucoin_spot = KucoinSpot {
  200. exchange: ExchangeEnum::KucoinSpot,
  201. symbol: symbol.to_uppercase(),
  202. is_colo,
  203. params: params.clone(),
  204. request: KucoinSpotRest::new(is_colo, params.clone()),
  205. market,
  206. order_sender,
  207. error_sender,
  208. };
  209. kucoin_spot.market = KucoinSpot::get_market(&mut kucoin_spot).await.unwrap_or(kucoin_spot.market);
  210. return kucoin_spot;
  211. }
  212. }
  213. #[async_trait]
  214. impl Platform for KucoinSpot {
  215. // 克隆方法
  216. fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
  217. fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::KucoinSpot }
  218. // 获取交易对
  219. fn get_self_symbol(&self) -> String { self.symbol.clone() }
  220. // 获取是否使用高速通道
  221. fn get_self_is_colo(&self) -> bool {
  222. self.is_colo
  223. }
  224. // 获取params信息
  225. fn get_self_params(&self) -> BTreeMap<String, String> {
  226. self.params.clone()
  227. }
  228. // 获取market信息
  229. fn get_self_market(&self) -> Market { self.market.clone() }
  230. // 获取请求时间
  231. fn get_request_delays(&self) -> Vec<i64> { self.request.get_delays() }
  232. // 获取请求平均时间
  233. fn get_request_avg_delay(&self) -> Decimal { self.request.get_avg_delay() }
  234. // 获取请求最大时间
  235. fn get_request_max_delay(&self) -> i64 { self.request.get_max_delay() }
  236. // 获取服务器时间
  237. async fn get_server_time(&mut self) -> Result<String, Error> {
  238. let res_data = self.request.get_server_time().await;
  239. if res_data.code == "200" {
  240. let res_data_str = &res_data.data;
  241. let result = res_data_str.clone();
  242. Ok(result)
  243. } else {
  244. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  245. }
  246. }
  247. async fn get_account(&mut self) -> Result<Account, Error> {
  248. let coin_array: Vec<&str> = self.symbol.split("_").collect();
  249. let res_data = self.request.get_accounts(coin_array[1].to_string()).await;
  250. if res_data.code == "200" {
  251. let res_data_str = &res_data.data;
  252. let balance_info_list: Vec<SpotAccount> = serde_json::from_str(res_data_str).unwrap();
  253. let mut balance_info_default = SpotAccount::new();
  254. balance_info_default.currency = coin_array[1].to_string();
  255. let balance_info = balance_info_list.iter().find(|&item| item.currency == coin_array[1].to_string()).unwrap_or(&balance_info_default);
  256. let mut stocks_info_default = SpotAccount::new();
  257. stocks_info_default.currency = coin_array[0].to_string();
  258. let stocks_info = balance_info_list.iter().find(|&item| item.currency == coin_array[0].to_string()).unwrap_or(&balance_info_default);
  259. let result = Account {
  260. coin: format!("{}_{}", balance_info.currency, stocks_info.currency),
  261. balance: balance_info.available + balance_info.holds,
  262. available_balance: balance_info.available,
  263. frozen_balance: balance_info.holds,
  264. stocks: stocks_info.available + stocks_info.holds,
  265. available_stocks: stocks_info.available,
  266. frozen_stocks: stocks_info.holds,
  267. };
  268. Ok(result)
  269. } else {
  270. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  271. }
  272. }
  273. async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
  274. let res_data = self.request.get_accounts("".to_string()).await;
  275. if res_data.code == "200" {
  276. let res_data_str = &res_data.data;
  277. let balance_info_list: Vec<SpotAccount> = serde_json::from_str(res_data_str).unwrap();
  278. let result = balance_info_list.iter().map(|item| {
  279. Account {
  280. coin: item.currency.to_string(),
  281. balance: item.available + item.holds,
  282. available_balance: item.available,
  283. frozen_balance: item.holds,
  284. stocks: Decimal::ZERO,
  285. available_stocks: Decimal::ZERO,
  286. frozen_stocks: Decimal::ZERO,
  287. }
  288. }).collect();
  289. Ok(result)
  290. } else {
  291. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  292. }
  293. }
  294. async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
  295. Err(Error::new(ErrorKind::NotFound, "kucoin_spot:该交易所方法未实现".to_string()))
  296. }
  297. async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
  298. Err(Error::new(ErrorKind::NotFound, "kucoin_spot:该交易所方法未实现".to_string()))
  299. }
  300. async fn get_ticker(&mut self) -> Result<Ticker, Error> {
  301. let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
  302. let res_data = self.request.get_level1(symbol_format).await;
  303. if res_data.code == "200" {
  304. let res_data_str = &res_data.data;
  305. let ticker_info: SpotTicker = serde_json::from_str(res_data_str).unwrap();
  306. let result = Ticker {
  307. time: ticker_info.time,
  308. high: ticker_info.best_ask,
  309. low: ticker_info.best_bid,
  310. sell: ticker_info.best_ask,
  311. buy: ticker_info.best_bid,
  312. last: ticker_info.price,
  313. volume: ticker_info.size,
  314. };
  315. Ok(result)
  316. } else {
  317. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  318. }
  319. }
  320. async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
  321. let symbol_format = utils::format_symbol(symbol.clone(), "-");
  322. let res_data = self.request.get_level1(symbol_format).await;
  323. if res_data.code == "200" {
  324. let res_data_str = &res_data.data;
  325. let ticker_info: SpotTicker = serde_json::from_str(res_data_str).unwrap();
  326. let result = Ticker {
  327. time: ticker_info.time,
  328. high: ticker_info.best_ask,
  329. low: ticker_info.best_bid,
  330. sell: ticker_info.best_ask,
  331. buy: ticker_info.best_bid,
  332. last: ticker_info.price,
  333. volume: ticker_info.size,
  334. };
  335. Ok(result)
  336. } else {
  337. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  338. }
  339. }
  340. async fn get_market(&mut self) -> Result<Market, Error> {
  341. let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
  342. let res_data = self.request.get_symbols().await;
  343. if res_data.code == "200" {
  344. let res_data_str = &res_data.data;
  345. let market_info_list: Vec<SpotMarket> = serde_json::from_str(res_data_str).unwrap();
  346. let market_info = market_info_list.iter().find(|&item| item.symbol == symbol_format).unwrap();
  347. let result = Market {
  348. symbol: market_info.symbol.replace("-", "_"),
  349. base_asset: market_info.base_currency.clone(),
  350. quote_asset: market_info.quote_currency.clone(),
  351. tick_size: market_info.price_increment,
  352. amount_size: market_info.base_increment,
  353. price_precision: Decimal::from_u32(market_info.price_increment.scale()).unwrap(),
  354. amount_precision: Decimal::from_u32(market_info.base_increment.scale()).unwrap(),
  355. min_qty: market_info.base_min_size,
  356. max_qty: market_info.base_max_size,
  357. min_notional: market_info.price_increment * market_info.base_min_size,
  358. max_notional: market_info.price_increment * market_info.base_max_size,
  359. ct_val: Decimal::ONE,
  360. };
  361. Ok(result)
  362. } else {
  363. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  364. }
  365. }
  366. async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
  367. let symbol_format = utils::format_symbol(symbol.clone(), "-");
  368. let res_data = self.request.get_symbols().await;
  369. if res_data.code == "200" {
  370. let res_data_str = &res_data.data;
  371. let market_info_list: Vec<SpotMarket> = serde_json::from_str(res_data_str).unwrap();
  372. let market_info = market_info_list.iter().find(|&item| item.symbol == symbol_format).unwrap();
  373. let result = Market {
  374. symbol: market_info.symbol.replace("-", "_"),
  375. base_asset: market_info.base_currency.clone(),
  376. quote_asset: market_info.quote_currency.clone(),
  377. tick_size: market_info.price_increment,
  378. amount_size: market_info.base_increment,
  379. price_precision: Decimal::from_u32(market_info.price_increment.scale()).unwrap(),
  380. amount_precision: Decimal::from_u32(market_info.base_increment.scale()).unwrap(),
  381. min_qty: market_info.base_min_size,
  382. max_qty: market_info.base_max_size,
  383. min_notional: market_info.price_increment * market_info.base_min_size,
  384. max_notional: market_info.price_increment * market_info.base_max_size,
  385. ct_val: Decimal::ONE,
  386. };
  387. Ok(result)
  388. } else {
  389. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  390. }
  391. }
  392. async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
  393. let res_data = if order_id != "" { self.request.get_order_by_order_id(order_id.to_string()).await } else { self.request.get_order_by_client_id(custom_id.to_string()).await };
  394. if res_data.code == "200" {
  395. let res_data_str = &res_data.data;
  396. let result = format_order_item(res_data_str.clone());
  397. Ok(result)
  398. } else {
  399. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  400. }
  401. }
  402. async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
  403. let res_data = self.request.get_order().await;
  404. if res_data.code == "200" {
  405. let res_data_str = &res_data.data;
  406. let order_info_list: Vec<String> = serde_json::from_str(res_data_str).unwrap();
  407. let result = order_info_list.iter().map(|item| format_order_item(item.clone())).collect();
  408. Ok(result)
  409. } else {
  410. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  411. }
  412. }
  413. async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
  414. let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
  415. let mut params = json!({
  416. "symbol": symbol_format.to_string(),
  417. "clientOid": custom_id,
  418. "price": price.to_string(),
  419. "size": amount.to_string()
  420. });
  421. if price.eq(&Decimal::ZERO) {
  422. params["type"] = json!("market");
  423. } else {
  424. params["type"] = json!("limit");
  425. };
  426. match origin_side {
  427. "kd" => {
  428. params["side"] = json!("buy");
  429. }
  430. "pd" => {
  431. params["side"] = json!("sell");
  432. }
  433. "kk" => {
  434. params["side"] = json!("sell");
  435. }
  436. "pk" => {
  437. params["side"] = json!("buy");
  438. }
  439. _ => { error!("下单参数错误"); }
  440. };
  441. let res_data = self.request.spot_order(params).await;
  442. if res_data.code == "200" {
  443. let res_data_str = &res_data.data;
  444. let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
  445. let result = Order {
  446. id: res_data_json["orderId"].as_str().unwrap().to_string(),
  447. custom_id: custom_id.to_string(),
  448. price: Decimal::ZERO,
  449. amount: Decimal::ZERO,
  450. deal_amount: Decimal::ZERO,
  451. avg_price: Decimal::ZERO,
  452. status: "NEW".to_string(),
  453. order_type: "".to_string(),
  454. trace_stack: TraceStack::default().on_special("550 kucoin_spot".to_string()),
  455. };
  456. Ok(result)
  457. } else {
  458. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  459. }
  460. }
  461. async fn take_order_symbol(&mut self, symbol: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
  462. let symbol_format = utils::format_symbol(symbol.clone(), "-");
  463. let mut params = json!({
  464. "symbol": symbol_format.to_string(),
  465. "clientOid": custom_id,
  466. "price": price.to_string(),
  467. "size": amount * ct_val,
  468. });
  469. if price.eq(&Decimal::ZERO) {
  470. params["type"] = json!("market");
  471. } else {
  472. params["type"] = json!("limit");
  473. };
  474. match origin_side {
  475. "kd" => {
  476. params["side"] = json!("buy");
  477. }
  478. "pd" => {
  479. params["side"] = json!("sell");
  480. }
  481. "kk" => {
  482. params["side"] = json!("sell");
  483. }
  484. "pk" => {
  485. params["side"] = json!("buy");
  486. }
  487. _ => { error!("下单参数错误"); }
  488. };
  489. let res_data = self.request.spot_order(params).await;
  490. if res_data.code == "200" {
  491. let res_data_str = &res_data.data;
  492. let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
  493. let result = Order {
  494. id: res_data_json["orderId"].as_str().unwrap().to_string(),
  495. custom_id: custom_id.to_string(),
  496. price: Decimal::ZERO,
  497. amount: Decimal::ZERO,
  498. deal_amount: Decimal::ZERO,
  499. avg_price: Decimal::ZERO,
  500. status: "NEW".to_string(),
  501. order_type: "".to_string(),
  502. trace_stack: TraceStack::default().on_special("599 kucoin_spot".to_string()),
  503. };
  504. Ok(result)
  505. } else {
  506. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  507. }
  508. }
  509. async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
  510. let res_data = if order_id != "" { self.request.cancel_order_by_order_id(order_id.to_string()).await } else { self.request.cancel_order_by_client_id(custom_id.to_string()).await };
  511. if res_data.code == "200" {
  512. let res_data_str = &res_data.data;
  513. let order_info: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
  514. let id = if order_id != "" { order_info["cancelledOrderIds"][0].as_str().unwrap().to_string() } else { order_info["cancelledOrderId"].as_str().unwrap().to_string() };
  515. let custom_id = if order_id != "" { "".to_string() } else { order_info["clientOid"].as_str().unwrap().to_string() };
  516. let result = Order {
  517. id,
  518. custom_id,
  519. price: Decimal::ZERO,
  520. amount: Decimal::ZERO,
  521. deal_amount: Decimal::ZERO,
  522. avg_price: Decimal::ZERO,
  523. status: "REMOVE".to_string(),
  524. order_type: "".to_string(),
  525. trace_stack: TraceStack::default().on_special("623 kucoin_spot".to_string()),
  526. };
  527. Ok(result)
  528. } else {
  529. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  530. }
  531. }
  532. async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
  533. let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
  534. let res_data = self.request.cancel_order_all(symbol_format).await;
  535. if res_data.code == "200" {
  536. let res_data_str = &res_data.data;
  537. let order_info: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
  538. let id_list = order_info["cancelledOrderIds"].as_array().unwrap();
  539. let result = id_list.iter().map(|item| Order {
  540. id: item["id"].as_str().unwrap().to_string(),
  541. custom_id: "".to_string(),
  542. price: Decimal::ZERO,
  543. amount: Decimal::ZERO,
  544. deal_amount: Decimal::ZERO,
  545. avg_price: Decimal::ZERO,
  546. status: "REMOVE".to_string(),
  547. order_type: "".to_string(),
  548. trace_stack: TraceStack::default().on_special("647 kucoin_spot".to_string()),
  549. }).collect();
  550. Ok(result)
  551. } else {
  552. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  553. }
  554. }
  555. async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
  556. let res_data = self.request.cancel_order_all("".to_string()).await;
  557. if res_data.code == "200" {
  558. let res_data_str = &res_data.data;
  559. let order_info: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
  560. let id_list = order_info["cancelledOrderIds"].as_array().unwrap();
  561. let result = id_list.iter().map(|item| Order {
  562. id: item["id"].as_str().unwrap().to_string(),
  563. custom_id: "".to_string(),
  564. price: Decimal::ZERO,
  565. amount: Decimal::ZERO,
  566. deal_amount: Decimal::ZERO,
  567. avg_price: Decimal::ZERO,
  568. status: "REMOVE".to_string(),
  569. order_type: "".to_string(),
  570. trace_stack: TraceStack::default().on_special("670 kucoin_spot".to_string()),
  571. }).collect();
  572. Ok(result)
  573. } else {
  574. Err(Error::new(ErrorKind::Other, res_data.to_string()))
  575. }
  576. }
  577. async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
  578. Err(Error::new(ErrorKind::NotFound, "kucoin_spot:该交易所方法未实现".to_string()))
  579. }
  580. async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
  581. Err(Error::new(ErrorKind::NotFound, "kucoin_spot:该交易所方法未实现".to_string()))
  582. }
  583. async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> {
  584. Err(Error::new(ErrorKind::NotFound, "kucoin_spot:该交易所方法未实现".to_string()))
  585. }
  586. async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
  587. Err(Error::new(ErrorKind::NotFound, "kucoin_spot:该交易所方法未实现".to_string()))
  588. }
  589. async fn command_order(&mut self, order_command: OrderCommand, trace_stack: TraceStack) {
  590. let mut handles = vec![];
  591. // 撤销订单
  592. let cancel = order_command.cancel;
  593. for item in cancel.keys() {
  594. let mut self_clone = self.clone();
  595. let cancel_clone = cancel.clone();
  596. let item_clone = item.clone();
  597. let order_id = cancel_clone[&item_clone].get(1).unwrap_or(&"".to_string()).clone();
  598. let custom_id = cancel_clone[&item_clone].get(0).unwrap_or(&"".to_string()).clone();
  599. let result_sd = self.order_sender.clone();
  600. let err_sd = self.error_sender.clone();
  601. let handle = tokio::spawn(async move {
  602. let result = self_clone.cancel_order(&order_id, &custom_id).await;
  603. match result {
  604. Ok(_) => {
  605. // result_sd.send(result).await.unwrap();
  606. }
  607. Err(error) => {
  608. // 取消失败去查订单。
  609. let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
  610. match query_rst {
  611. Ok(order) => {
  612. result_sd.send(order).await.unwrap();
  613. }
  614. Err(_query_err) => {
  615. // error!(?_query_err);
  616. // error!("撤单失败,而且查单也失败了,bitget_spot,oid={}, cid={}。", order_id.clone(), custom_id.clone());
  617. }
  618. }
  619. err_sd.send(error).await.unwrap();
  620. }
  621. }
  622. });
  623. handles.push(handle)
  624. }
  625. // 下单指令
  626. let mut limits = HashMap::new();
  627. limits.extend(order_command.limits_open);
  628. limits.extend(order_command.limits_close);
  629. for item in limits.keys() {
  630. let mut self_clone = self.clone();
  631. let limits_clone = limits.clone();
  632. let item_clone = item.clone();
  633. let result_sd = self.order_sender.clone();
  634. let err_sd = self.error_sender.clone();
  635. let mut ts = trace_stack.clone();
  636. let handle = tokio::spawn(async move {
  637. let value = limits_clone[&item_clone].clone();
  638. let amount = Decimal::from_str(value.get(0).unwrap_or(&"0".to_string())).unwrap();
  639. let side = value.get(1).unwrap();
  640. let price = Decimal::from_str(value.get(2).unwrap_or(&"0".to_string())).unwrap();
  641. let cid = value.get(3).unwrap();
  642. // order_name: [数量,方向,价格,c_id]
  643. let result = self_clone.take_order(cid, side, price, amount).await;
  644. match result {
  645. Ok(mut result) => {
  646. // 记录此订单完成时间
  647. ts.on_after_send();
  648. result.trace_stack = ts;
  649. result_sd.send(result).await.unwrap();
  650. }
  651. Err(error) => {
  652. let mut err_order = Order::new();
  653. err_order.custom_id = cid.clone();
  654. err_order.status = "REMOVE".to_string();
  655. result_sd.send(err_order).await.unwrap();
  656. err_sd.send(error).await.unwrap();
  657. }
  658. }
  659. });
  660. handles.push(handle)
  661. }
  662. // 检查订单指令
  663. let check = order_command.check;
  664. for item in check.keys() {
  665. let mut self_clone = self.clone();
  666. let check_clone = check.clone();
  667. let item_clone = item.clone();
  668. let order_id = check_clone[&item_clone].get(1).unwrap_or(&"".to_string()).clone();
  669. let custom_id = check_clone[&item_clone].get(0).unwrap_or(&"".to_string()).clone();
  670. let result_sd = self.order_sender.clone();
  671. let err_sd = self.error_sender.clone();
  672. let handle = tokio::spawn(async move {
  673. let result = self_clone.get_order_detail(&order_id, &custom_id).await;
  674. match result {
  675. Ok(result) => {
  676. result_sd.send(result).await.unwrap();
  677. }
  678. Err(error) => {
  679. err_sd.send(error).await.unwrap();
  680. }
  681. }
  682. });
  683. handles.push(handle)
  684. }
  685. let futures = FuturesUnordered::from_iter(handles);
  686. let _: Result<Vec<_>, _> = futures.try_collect().await;
  687. }
  688. }
  689. pub fn format_order_item(data: String) -> Order {
  690. let order_info: SpotOrder = serde_json::from_str(&data).unwrap();
  691. Order {
  692. id: order_info.id,
  693. custom_id: order_info.client_oid,
  694. price: order_info.price,
  695. amount: order_info.size,
  696. deal_amount: order_info.deal_size,
  697. avg_price: order_info.deal_funds / order_info.deal_size,
  698. status: if order_info.is_active { "NEW".to_string() } else { "REMOVE".to_string() },
  699. order_type: order_info.order_type,
  700. trace_stack: TraceStack::default().on_special("811 kucoin_spot".to_string()),
  701. }
  702. }