kucoin_spot.rs 32 KB

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