exchange_middle_ware.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. use std::env;
  2. use std::io::{BufRead, Error, ErrorKind};
  3. use std::future::Future;
  4. use std::sync::Arc;
  5. use serde_json::json;
  6. use tokio::sync::Mutex;
  7. use crate::{Bot};
  8. use crate::exchange_libs::{BinanceExc, OkxExc, ResponseData, SocketTool};
  9. // 深度结构体
  10. #[derive(Debug)]
  11. pub struct Depth {
  12. // 卖单数组
  13. pub asks: Vec<DepthItem>,
  14. // 买单数组
  15. pub bids: Vec<DepthItem>,
  16. }
  17. #[derive(Debug)]
  18. pub struct DepthItem {
  19. // 价格
  20. pub price: f64,
  21. // 数量
  22. pub amount: f64,
  23. }
  24. // k线数据结构体
  25. #[derive(Debug)]
  26. pub struct Record {
  27. // 时间
  28. pub time: i64,
  29. // 开盘价
  30. pub open: f64,
  31. // 最高价
  32. pub high: f64,
  33. // 最低价
  34. pub low: f64,
  35. // 收盘价
  36. pub close: f64,
  37. // 交易量
  38. pub volume: f64,
  39. }
  40. // Account信息结构体
  41. #[derive(Debug)]
  42. pub struct Account {
  43. // 可用计价币数量
  44. pub balance: f64,
  45. // Balance挂单的冻结数量
  46. pub frozen_balance: f64,
  47. // 可用交易币数量
  48. pub stocks: f64,
  49. // stocks挂单的冻结数量
  50. pub frozen_stocks: f64,
  51. }
  52. #[derive(Debug)]
  53. pub struct Order {
  54. // 交易单唯一标识
  55. pub id: String,
  56. // 下单价格
  57. pub price: f64,
  58. // 下单数量
  59. pub amount: f64,
  60. // 成交数量
  61. pub deal_amount: f64,
  62. // 成交均价
  63. pub avg_price: f64,
  64. // 订单状态
  65. pub status: String,
  66. // 订单类型
  67. pub order_type: String,
  68. }
  69. #[derive(Debug)]
  70. pub struct Market {
  71. symbol: String,
  72. base_asset: String,
  73. quote_asset: String,
  74. tick_size: f64,
  75. amount_size: f64,
  76. price_precision: f64,
  77. amount_precision: f64,
  78. min_qty: f64,
  79. max_qty: f64,
  80. min_notional: f64,
  81. max_notional: f64,
  82. ct_val: f64,
  83. }
  84. pub struct Exchange {
  85. // okx okx_access_key
  86. okx_access_key: String,
  87. // okx okx_secret_key
  88. okx_secret_key: String,
  89. // okx okx_passphrase
  90. okx_passphrase: String,
  91. // binance BinanceExc请求方法结构体
  92. binance_exc: BinanceExc,
  93. // okx OkxExc请求方法结构体
  94. okx_exc: OkxExc,
  95. // binance Binance,
  96. }
  97. impl Exchange {
  98. // new Exchange结构体
  99. // okx_access_key: okx_access_key
  100. // okx_secret_key: okx_secret_key
  101. // okx_passphrase: okx_passphrase
  102. pub fn new(okx_access_key: String, okx_secret_key: String, okx_passphrase: String) -> Exchange {
  103. let binance_exc = BinanceExc::new("".to_string(), "".to_string());
  104. let okx_exc = OkxExc::new(okx_access_key.clone(), okx_secret_key.clone(), okx_passphrase.clone());
  105. Exchange { okx_access_key, okx_secret_key, okx_passphrase, binance_exc, okx_exc }
  106. }
  107. // 处理交易对格式
  108. // symbol: 交易币对, "BTC_USDT"
  109. // str: 替换字符串, "-"
  110. pub fn get_real_symbol(&self, symbol: &String, str: String) -> String {
  111. return symbol.to_uppercase().replace("_", &*str);
  112. }
  113. // 获取币安深度信息
  114. // symbol: 交易币对, "BTC_USDT"
  115. // limit: 返回条数, 最大 5000. 可选值:[5, 10, 20, 50, 100, 500, 1000, 5000]
  116. pub async fn subscribe_binance_depth(&self, symbol: &String, limit: i32, mut bot_arc: Arc<Mutex<Bot>>) {
  117. let real_symbol = self.get_real_symbol(symbol, "".to_string());
  118. let get_res_data = move |res_data: ResponseData| {
  119. let bot_arc_clone = Arc::clone(&bot_arc);
  120. async move {
  121. if res_data.code == "0" {
  122. let res_data_str = res_data.data;
  123. let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
  124. let depth_asks: Vec<DepthItem> = parse_depth_items(&res_data_json["asks"]);
  125. let depth_bids: Vec<DepthItem> = parse_depth_items(&res_data_json["bids"]);
  126. let result = Depth {
  127. asks: depth_asks,
  128. bids: depth_bids,
  129. };
  130. {
  131. let mut bot = bot_arc_clone.lock().await;
  132. bot.depth_handler(result)
  133. }
  134. } else {
  135. panic!("get_binance_depth: {}", res_data.message);
  136. }
  137. }
  138. };
  139. SocketTool::binance_run_depth(vec![&real_symbol], limit.to_string(), get_res_data)
  140. }
  141. // 获取币安K线数据信息
  142. // symbol: 交易币对, "BTC_USDT"
  143. // interval: K线间隔, 可选值:[1s, 1m, 3m, 5m, 15m,30m,1h, 2h, 4h, 6h, 8h,12h, 1d, 3d, 1w, 1M]
  144. // limit: 返回条数, 最大 1000
  145. pub async fn get_binance_klines(&self, symbol: &String, interval: &String, limit: &i32) -> Result<Vec<Record>, Error> {
  146. let real_symbol = self.get_real_symbol(symbol, "".to_string());
  147. let res_data = self.binance_exc.binance_k(&real_symbol, interval, &limit.to_string()).await;
  148. if res_data.code == "0" {
  149. let res_data_str = res_data.data;
  150. let res_data_json: Vec<Vec<serde_json::Value>> = serde_json::from_str(&*res_data_str).unwrap();
  151. let mut result: Vec<Record> = vec![];
  152. for item in res_data_json.iter() {
  153. let record = Record {
  154. time: item[0].as_i64().unwrap_or(0),
  155. open: item[1].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  156. high: item[2].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  157. low: item[3].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  158. close: item[4].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  159. volume: item[5].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  160. };
  161. result.push(record);
  162. }
  163. Ok(result)
  164. } else {
  165. Err(Error::new(ErrorKind::Other, res_data.message))
  166. }
  167. }
  168. // 获取okx账户信息数据
  169. // symbol: 交易币对, "BTC_USDT"
  170. pub async fn get_okx_account(&self, symbol: &String) -> Result<Account, Error> {
  171. let real_symbol = self.get_real_symbol(symbol, ",".to_string());
  172. let res_data = self.okx_exc.okx_acc(&real_symbol).await;
  173. if res_data.code == "0" {
  174. let res_data_str = res_data.data;
  175. let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
  176. let symbol_array: Vec<&str> = symbol.split("_").collect();
  177. let details = res_data_json[0]["details"].as_array().unwrap();
  178. let default_info = json!({"availBal":"0","fixedBal":"0"});
  179. let stocks_info = details.iter().find(|item| item["ccy"].as_str().unwrap() == symbol_array[0].to_string()).unwrap_or(&default_info);
  180. let balance_info = details.iter().find(|item| item["ccy"].as_str().unwrap() == symbol_array[1].to_string()).unwrap_or(&default_info);
  181. let result = Account {
  182. balance: balance_info["availBal"].as_str().unwrap().parse().unwrap_or(0.0),
  183. frozen_balance: balance_info["fixedBal"].as_str().unwrap().parse().unwrap_or(0.0),
  184. stocks: stocks_info["availBal"].as_str().unwrap().parse().unwrap_or(0.0),
  185. frozen_stocks: stocks_info["fixedBal"].as_str().unwrap().parse().unwrap_or(0.0),
  186. };
  187. Ok(result)
  188. } else {
  189. Err(Error::new(ErrorKind::Other, res_data.message))
  190. }
  191. }
  192. // OKX下单
  193. // symbol: 交易币对, "BTC_USDT"
  194. // side: 订单方向, buy:买,sell:卖
  195. // order_type: 订单类型, market:市价单, limit:限价单等 具体文档查看 https://www.okx.com/docs-v5/zh/#order-book-trading-trade-post-place-order
  196. // price: 委托价格
  197. // amount: 委托数量
  198. pub async fn place_okx_order(&self, symbol: &String, side: &String, order_type: &String, price: &String, amount: &String) -> Result<String, Error> {
  199. let real_symbol = self.get_real_symbol(symbol, "-".to_string());
  200. let res_data = self.okx_exc.okx_order(&real_symbol, "cash", side, order_type, price, amount).await;
  201. if res_data.code == "0" {
  202. let res_data_str = res_data.data;
  203. let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
  204. let result = res_data_json[0]["ordId"].as_str().unwrap().parse().unwrap();
  205. Ok(result)
  206. } else {
  207. Err(Error::new(ErrorKind::Other, res_data.message))
  208. }
  209. }
  210. // OKX查询订单
  211. // symbol: 交易币对, "BTC_USDT"
  212. // order_id: 订单ID, "590910403358593111"
  213. pub async fn get_okx_order(&self, symbol: &String, order_id: &String) -> Result<Order, Error> {
  214. let real_symbol = self.get_real_symbol(symbol, "-".to_string());
  215. let res_data = self.okx_exc.okx_get_order(&real_symbol, order_id).await;
  216. if res_data.code == "0" {
  217. let res_data_str = res_data.data;
  218. let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
  219. let result = parse_order_info(res_data_json[0].clone());
  220. Ok(result)
  221. } else {
  222. Err(Error::new(ErrorKind::Other, res_data.message))
  223. }
  224. }
  225. // OKX订阅订单
  226. // symbol: 交易币对, "BTC_USDT"
  227. pub async fn subscribe_okx_order(&self, symbol: &String, mut bot_arc: Arc<Mutex<Bot>>) {
  228. let real_symbol = self.get_real_symbol(symbol, "-".to_string());
  229. let get_res_data = move |res_data: ResponseData| {
  230. let bot_arc_clone = Arc::clone(&bot_arc);
  231. async move {
  232. if res_data.code == "0" {
  233. let res_data_str = res_data.data;
  234. let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
  235. let order_info_arr: serde_json::Value = res_data_json["data"].clone();
  236. let result = parse_order_info(order_info_arr[0].clone());
  237. print!("{:?}", result);
  238. {
  239. let mut bot = bot_arc_clone.lock().await;
  240. bot.order_change_response(result).await;
  241. }
  242. } else {
  243. panic!("subscribe_okx_order: {}", res_data.message);
  244. }
  245. }
  246. };
  247. let okx_access_key = env::var("okx_access_key").unwrap();
  248. let okx_secret_key = env::var("okx_secret_key").unwrap();
  249. let okx_passphrase = env::var("okx_passphrase").unwrap();
  250. SocketTool::okx_pr_run_orders(vec![&real_symbol], okx_access_key, okx_secret_key, okx_passphrase, get_res_data);
  251. }
  252. // OKX撤销订单
  253. // symbol: 交易币对, "BTC_USDT"
  254. // order_id: 订单ID, "590910403358593111"
  255. pub async fn cancel_okx_order(&self, symbol: &String, order_id: &String) -> Result<bool, Error> {
  256. let real_symbol = self.get_real_symbol(symbol, "-".to_string());
  257. let res_data = self.okx_exc.okx_revocation_order(&real_symbol, order_id).await;
  258. if res_data.code == "0" {
  259. let res_data_str = res_data.data;
  260. let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
  261. let order_info = res_data_json[0]["sCode"].as_str().unwrap();
  262. let result = if order_info == "0" { true } else { false };
  263. Ok(result)
  264. } else {
  265. Err(Error::new(ErrorKind::Other, res_data.message))
  266. }
  267. }
  268. // OKX撤销订单
  269. // symbol: 交易币对, "BTC_USDT"
  270. // order_id: 订单ID, "590910403358593111"
  271. pub async fn get_okx_instruments(&self, symbol: &String) {
  272. // let real_symbol = self.get_real_symbol(symbol, "-".to_string());
  273. // let mut btree_map: BTreeMap<&str, &str> = BTreeMap::new();
  274. // btree_map.insert("instType", "SPOT");
  275. // let result = self.okx_exc.get_v("/api/v5/public/instruments".to_string(), btree_map).await;
  276. // match result {
  277. // Ok(res_data) => {
  278. // let symbol_array: Vec<&str> = symbol.split("_").collect();
  279. // let res_data_str = res_data.data;
  280. // let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
  281. // let order_info = res_data_json["data"].as_array().unwrap();
  282. // let info = order_info.iter().find(|item| item["baseCcy"].as_str().unwrap() == symbol_array[0] && item["quoteCcy"].as_str().unwrap() == symbol_array[1]).unwrap();
  283. // println!("\n\n{:?}", info);
  284. //
  285. // let min_qty = info["minSz"].as_str().unwrap_or("0").parse().unwrap_or(0.0);
  286. // let amount_size = info["lotSz"].as_str().unwrap_or("0").parse().unwrap_or(0.0);
  287. // let result = Market {
  288. // symbol: info["instId"].as_str().unwrap().parse().unwrap(),
  289. // base_asset: info["baseCcy"].as_str().unwrap().parse().unwrap(),
  290. // quote_asset: info["quoteCcy"].as_str().unwrap().parse().unwrap(),
  291. // tick_size: info["tickSz"].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  292. // amount_size,
  293. // price_precision: info["tickSz"].as_str().unwrap().parse().to_string().split(".").collect()[1],
  294. // amount_precision:info["lotSz"].as_str().unwrap().parse().to_string().split(".").collect()[1],
  295. // min_qty,
  296. // max_qty: info["minSz"].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  297. // min_notional: amount_size * min_qty,
  298. // max_notional: 0.01,
  299. // ct_val: info["ctVal"].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  300. // };
  301. // println!("\n\n{:?}", result);
  302. // // let order_info = res_data_json;
  303. // }
  304. // Err(err) => {}
  305. // }
  306. // let real_symbol = self.get_real_symbol(symbol, "-".to_string());
  307. // let res_data = self.okx_exc.get_v("/api/v5/public/instruments", order_id).await;
  308. // if res_data.code == "0" {
  309. // let res_data_str = res_data.data;
  310. // let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
  311. // let order_info = res_data_json[0]["sCode"].as_str().unwrap();
  312. // let result = if order_info == "0" { true } else { false };
  313. // Ok(result)
  314. // } else {
  315. // Err(Error::new(ErrorKind::Other, res_data.message))
  316. // }
  317. }
  318. }
  319. fn parse_order_info(res_data_json: serde_json::Value) -> Order {
  320. let order = Order {
  321. id: res_data_json["ordId"].as_str().unwrap().parse().unwrap(),
  322. price: res_data_json["px"].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  323. amount: res_data_json["sz"].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  324. deal_amount: res_data_json["accFillSz"].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  325. avg_price: res_data_json["avgPx"].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  326. status: res_data_json["state"].as_str().unwrap().parse().unwrap(),
  327. order_type: res_data_json["instType"].as_str().unwrap().parse().unwrap(),
  328. };
  329. return order;
  330. }
  331. // 深度信息买单/卖单处理
  332. fn parse_depth_items(value: &serde_json::Value) -> Vec<DepthItem> {
  333. let mut depth_items: Vec<DepthItem> = vec![];
  334. for value in value.as_array().unwrap() {
  335. depth_items.push(DepthItem {
  336. price: value[0].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  337. amount: value[1].as_str().unwrap_or("0").parse().unwrap_or(0.0),
  338. })
  339. }
  340. return depth_items;
  341. }
  342. // 单元测试集
  343. #[cfg(test)]
  344. mod tests {
  345. use std::env;
  346. use std::io::{self, Write};
  347. use crate::exchange_middle_ware::{Exchange};
  348. use crate::exchange_libs::{ResponseData, SocketTool, http_enable_proxy};
  349. // new Exchange
  350. fn new_exchange() -> Exchange {
  351. let okx_access_key = env::var("okx_access_key").unwrap();
  352. let okx_secret_key = env::var("okx_secret_key").unwrap();
  353. let okx_passphrase = env::var("okx_passphrase").unwrap();
  354. Exchange::new(okx_access_key, okx_secret_key, okx_passphrase)
  355. }
  356. // 测试new Exchange
  357. #[tokio::test]
  358. async fn test_new_exchange() {
  359. http_enable_proxy();
  360. let exchange = new_exchange();
  361. println!("test_new_exchange:okx_access_key:{},okx_secret_key:{},okx_passphrase:{}", exchange.okx_access_key, exchange.okx_secret_key, exchange.okx_passphrase);
  362. }
  363. // 测试交易对处理
  364. #[tokio::test]
  365. async fn test_get_real_symbol() {
  366. http_enable_proxy();
  367. let exchange = new_exchange();
  368. let real_symbol = exchange.get_real_symbol(&"BTC_USDT".to_string(), "".to_string());
  369. println!("test_get_real_symbol:{}", real_symbol);
  370. }
  371. // 测试binance获取深度信息
  372. #[tokio::test]
  373. async fn test_get_binance_depth() {
  374. let exchange = new_exchange();
  375. let get_res_data = move |res_data: ResponseData| {
  376. async move {
  377. let mut stdout = io::stdout();
  378. writeln!(stdout, "test_get_binance_depth: {:?}", res_data).expect("TODO: panic message");
  379. }
  380. };
  381. SocketTool::binance_run_depth(vec![&"BTCUSDT"], "10".to_string(), get_res_data)
  382. }
  383. // 测试binance获取k线
  384. #[tokio::test]
  385. async fn test_get_binance_klines() {
  386. http_enable_proxy();
  387. let exchange = new_exchange();
  388. let klines = exchange.get_binance_klines(&"DOGE_USDT".to_string(), &"5m".to_string(), &10).await;
  389. println!("test_get_binance_klines:{:?}", klines);
  390. }
  391. // 测试okx查询账户信息
  392. #[tokio::test]
  393. async fn test_get_okx_account() {
  394. http_enable_proxy();
  395. let exchange = new_exchange();
  396. let account = exchange.get_okx_account(&"BTC_USDT".to_string()).await;
  397. println!("test_get_okx_account:{:?}", account);
  398. }
  399. // 测试okx下订单
  400. #[tokio::test]
  401. async fn test_place_okx_order() {
  402. http_enable_proxy();
  403. let exchange = new_exchange();
  404. let order_id = exchange.place_okx_order(&"BTC_USDT".to_string(), &"buy".to_string(), &"limit".to_string(), &"20000".to_string(), &"0.0001".to_string()).await;
  405. println!("test_place_okx_order:{:?}", order_id);
  406. }
  407. // 测试okx查询订单
  408. #[tokio::test]
  409. async fn test_get_okx_order() {
  410. http_enable_proxy();
  411. let exchange = new_exchange();
  412. let get_res_data = move |res_data: ResponseData| {
  413. writeln!(io::stdout(), "Current number: {:?}", res_data).expect("TODO: panic message");
  414. async move {}
  415. };
  416. SocketTool::okx_pr_run_orders(vec![&"BTC-USDT"], exchange.okx_access_key, exchange.okx_secret_key, exchange.okx_passphrase, get_res_data);
  417. }
  418. // 测试okx撤单
  419. #[tokio::test]
  420. async fn test_cancel_okx_order() {
  421. http_enable_proxy();
  422. let exchange = new_exchange();
  423. let is_success = exchange.cancel_okx_order(&"BTC_USDT".to_string(), &"612034971737800726".to_string()).await;
  424. println!("test_cancel_okx_order:{:?}", is_success);
  425. }
  426. // 测试okx撤单
  427. #[tokio::test]
  428. async fn test_get_okx_instruments() {
  429. http_enable_proxy();
  430. let exchange = new_exchange();
  431. let is_success = exchange.get_okx_instruments(&"BTC_USDT".to_string()).await;
  432. println!("test_cancel_okx_order:{:?}", is_success);
  433. }
  434. }