Advertisement
den4ik2003

Untitled

Jan 21st, 2025
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.17 KB | None | 0 0
  1. #include <parsing/markets/lbank_spot/api.hpp>
  2. #include <parsing/markets/lbank_spot/errors.hpp>
  3.  
  4. using namespace mira;
  5.  
  6. const int _aux_lbank_spot = ParserBuilder::add_parser<lbank_spot_api>("LBANK_SPOT");
  7.  
  8. webcore::headers_t lbank_spot_api::gen_headers(char* buf, const field_t& signed_query) {
  9. webcore::headers_t res;
  10. res.size = signed_query.empty() ? 1 : 4;
  11. res.names = new const char*[res.size];
  12. res.values = new const char*[res.size];
  13. int ptr = 0;
  14.  
  15. res.names[0] = header_names_[0];
  16. res.values[0] = buf + ptr;
  17. ptr += sprintf(buf + ptr, "zh-CN") + 1;
  18.  
  19. if (!signed_query.empty()) {
  20. res.names[1] = header_names_[1];
  21. res.values[1] = buf + ptr;
  22. ptr += sprintf(buf + ptr, "%s", signed_query.at("timestamp").s().c_str()) + 1;
  23.  
  24. res.names[2] = header_names_[2];
  25. res.values[2] = buf + ptr;
  26. ptr += sprintf(buf + ptr, "%s", signed_query.at("signature_method").s().c_str()) + 1;
  27.  
  28. res.names[3] = header_names_[3];
  29. res.values[3] = buf + ptr;
  30. ptr += sprintf(buf + ptr, "%s", signed_query.at("echostr").s().c_str());
  31. }
  32.  
  33. return res;
  34. }
  35.  
  36. field_t lbank_spot_api::form_signed_query(field_t params) {
  37. std::cerr << "form_signed_query params: " << params.serialize() << '\n';
  38. std::string echostr = "P3LHfw6tUIYWc8R2VQNy0ilKmdg5pjhbxC7";
  39. // for (int i = 0; i < 35; ++i) {
  40. // echostr += letters_[std::rand() % 62];
  41. // }
  42.  
  43. params["api_key"] = api_;
  44. params["echostr"] = echostr;
  45. params["signature_method"] = "HmacSHA256";
  46. params["timestamp"] = get_timestamp();
  47.  
  48. std::vector<std::string> keys;
  49. for (const auto& [key, _] : params.m()) {
  50. keys.push_back(key);
  51. }
  52. std::sort(keys.begin(), keys.end());
  53.  
  54. std::string sorted_params_str = keys[0] + "=" + params[keys[0]].s();
  55. for (size_t i = 1; i < keys.size(); ++i) {
  56. sorted_params_str += ("&" + keys[i] + "=" + params[keys[i]].s());
  57. }
  58.  
  59. // std::string sorted_params_str = std::accumulate(keys.begin(), keys.end(), std::string(),
  60. // [](const std::string& acc, const std::string& val) {
  61. // return acc.empty() ? val : acc + "&" + val;
  62. // }
  63. // );
  64.  
  65. params["sign"] = calc_hmac_sha256(md5_upper(sorted_params_str), secret_);
  66.  
  67. return params;
  68. }
  69.  
  70.  
  71. lbank_spot_api::lbank_spot_api(const account_name_t& name) : basic_api(name) {
  72. core_.init(HOST_URL);
  73. ws_mutex_ = core_.create_mutex();
  74. market = "LBANK_SPOT";
  75. auto exchange_info = get_exchange_info({}).wait();
  76. for (const ticker_t& ticker : exchange_info.value()) {
  77. members_.symbols[ticker.symbol] = ticker;
  78. }
  79. }
  80.  
  81. lbank_spot_api::lbank_spot_api(const account_name_t& name, const std::unordered_map<std::string, std::string>& args) : basic_api(name) {
  82. if (args.count("api") && args.count("secret")) {
  83. api_ = args.at("api");
  84. secret_ = args.at("secret");
  85. }
  86. core_.init(HOST_URL);
  87. ws_mutex_ = core_.create_mutex();
  88. if (!api_.empty()) {
  89. members_.authorized = true;
  90. }
  91. market = "LBANK_SPOT";
  92. auto exchange_info = get_exchange_info({}).wait();
  93. for (const ticker_t& ticker : exchange_info.value()) {
  94. members_.symbols[ticker.symbol] = ticker;
  95. }
  96. start_balance_indicator(args);
  97. }
  98.  
  99. FutureHandle<std::string> lbank_spot_api::get_exchange_info_wrapper::execute(std::string_view request) {
  100. return api_->core_.get_unsigned("/v2/accuracy.do", request, "", webcore::headers_t{});
  101. }
  102.  
  103. std::string lbank_spot_api::get_exchange_info_wrapper::request_filler(std::optional<std::string> symbol) {
  104. UNUSED(symbol);
  105. return "";
  106. }
  107.  
  108. std::vector<ticker_t> lbank_spot_api::get_exchange_info_wrapper::response_filler(field_t&& response) {
  109. response = response["data"];
  110. std::vector<ticker_t> res(response.size());
  111. for (size_t i = 0; i < response.size(); ++i) {
  112. res[i].symbol = response[i].get("symbol").ms();
  113. size_t pos = res[i].symbol.find("_");
  114. res[i].quote = res[i].symbol.substr(0, pos);
  115. res[i].base = res[i].symbol.substr(pos);
  116. res[i].market_quantity_precision = res[i].quantity_precision = std::stoi(response[i].get("quantityAccuracy").s());
  117. res[i].market_amount_precision = res[i].price_precision = std::stoi(response[i].get("priceAccuracy").s());
  118. res[i].price_step = precised_float::from_scaled(1, res[i].price_precision);
  119. res[i].quantity_step = precised_float::from_scaled(1, res[i].quantity_precision);
  120. res[i].min_notional = std::stod(response[i].get("minTranQua").s());
  121. res[i].max_notional = 1e9;
  122. res[i].api = api_;
  123. }
  124. return res;
  125. }
  126.  
  127. FutureHandle<result_t<std::vector<ticker_t>, market_error>> lbank_spot_api::get_exchange_info(std::optional<std::string> symbol) {
  128. UNUSED(symbol);
  129. return _get_exchange_info(symbol);
  130. }
  131.  
  132. FutureHandle<std::string> lbank_spot_api::get_depth_wrapper::execute(std::string_view request) {
  133. return api_->core_.get_unsigned("/v2/depth.do", request, "", webcore::headers_t{});
  134. }
  135.  
  136. std::string lbank_spot_api::get_depth_wrapper::request_filler(const ticker_t* symbol, std::optional<size_t> limit) {
  137. field_t request;
  138. symbol_ = symbol;
  139. request["symbol"] = symbol->symbol;
  140. request["size"] = *limit;
  141. return request.to_query();
  142. }
  143.  
  144. depth_t lbank_spot_api::get_depth_wrapper::response_filler(field_t&& response) {
  145. depth_t res_depth;
  146. response = response["data"];
  147. res_depth.version = 0;
  148. res_depth.symbol = symbol_;
  149. res_depth.update_time = response.get("timestamp").i();
  150. res_depth.asks.resize(response["asks"].size());
  151. res_depth.bids.resize(response["bids"].size());
  152. for (size_t i = 0; i < response["asks"].size(); ++i) {
  153. res_depth.asks[i].price = symbol_->make_price(response["asks"][i][0].f());
  154. res_depth.asks[i].quantity = symbol_->make_quantity(response["asks"][i][1].f());
  155. }
  156. for (size_t i = 0; i < response["bids"].size(); ++i) {
  157. res_depth.bids[i].price = symbol_->make_price(response["bids"][i][0].f());
  158. res_depth.bids[i].quantity = symbol_->make_quantity(response["bids"][i][1].f());
  159. }
  160. return res_depth;
  161. }
  162.  
  163. FutureHandle<result_t<depth_t, market_error>> lbank_spot_api::get_depth(const ticker_t* symbol, std::optional<size_t> limit) {
  164. return _get_depth(symbol, limit);
  165. }
  166.  
  167. FutureHandle<std::string> lbank_spot_api::get_account_wrapper::execute(std::string_view request) {
  168. char header_buf[256];
  169. field_t query = field_t::deserialize(request);
  170. field_t signed_query = api_->form_signed_query(query.copy());
  171. query["api_key"] = signed_query["api_key"];
  172. query["sign"] = signed_query["sign"];
  173.  
  174. return api_->core_.post_signed("/v2/supplement/user_info_account.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  175. }
  176.  
  177. std::string lbank_spot_api::get_account_wrapper::request_filler() {
  178. return field_t().serialize();
  179. }
  180.  
  181. account_t lbank_spot_api::get_account_wrapper::response_filler(field_t&& response) {
  182. account_t res;
  183. response = response["data"];
  184. res.account_type = e_account_type::SPOT;
  185. for (const auto& bal : response.get("balances").v()) {
  186. balance_t balance;
  187. balance.asset = lower(bal.at("asset").s());;
  188. balance.free = bal.at("free").f();
  189. balance.locked = bal.at("locked").f();
  190. if (balance.free != 0 || balance.locked != 0) {
  191. res.balances[balance.asset] = balance;
  192. }
  193. }
  194. return res;
  195. }
  196.  
  197. FutureHandle<result_t<account_t, market_error>> lbank_spot_api::get_account() {
  198. return _get_account();
  199. }
  200.  
  201. FutureHandle<std::string> lbank_spot_api::listen_key_manager::new_listen_key_wrapper::execute(std::string_view request) {
  202. char header_buf[256];
  203. field_t query = field_t::deserialize(request);
  204. field_t signed_query = api_->form_signed_query(query.copy());
  205. query["api_key"] = signed_query["api_key"];
  206. query["sign"] = signed_query["sign"];
  207.  
  208. return api_->core_.post_signed("/v2/subscribe/get_key.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  209. }
  210.  
  211. std::string lbank_spot_api::listen_key_manager::new_listen_key_wrapper::request_filler() {
  212. return field_t().serialize();
  213. }
  214.  
  215. std::string lbank_spot_api::listen_key_manager::new_listen_key_wrapper::response_filler(field_t&& response) {
  216. manager_->current_listen_key_ = response["data"]["key"].s();
  217. return manager_->current_listen_key_;
  218. }
  219.  
  220. FutureHandle<std::string> lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrapper::execute(std::string_view request) {
  221. char header_buf[256];
  222. field_t query = field_t::deserialize(request);
  223. field_t signed_query = api_->form_signed_query(query.copy());
  224. query["api_key"] = signed_query["api_key"];
  225. query["sign"] = signed_query["sign"];
  226.  
  227. return api_->core_.post_signed("/v2/subscribe/refresh_key.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  228. }
  229.  
  230. std::string lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrapper::request_filler() {
  231. field_t request;
  232. if (manager_->current_listen_key_.empty()) {
  233. std::cerr << "lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrappertry::request_filler() try to keep alive connection with empty listen key";
  234. abort();
  235. }
  236. request["subscribeKey"] = manager_->current_listen_key_;
  237. return request.serialize_nospace();
  238. }
  239.  
  240. std::string lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrapper::response_filler(field_t&& response) {
  241. UNUSED(response);
  242. return "";
  243. }
  244.  
  245. FutureHandle<std::string> lbank_spot_api::new_order_wrapper::execute(std::string_view request) {
  246. char header_buf[256];
  247. field_t query = field_t::deserialize(request);
  248. field_t signed_query = api_->form_signed_query(query.copy());
  249. query["api_key"] = signed_query["api_key"];
  250. query["sign"] = signed_query["sign"];
  251.  
  252. return api_->core_.post_signed("/v2/supplement/create_order.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  253. }
  254.  
  255. std::string lbank_spot_api::new_order_wrapper::request_filler(const order_request_t& order) {
  256. field_t request;
  257. request["symbol"] = order.symbol->symbol;
  258.  
  259. std::string order_type = lower(to_c_string(order.side));
  260. if (order.type == e_order_type::LIMIT && order.post_only) {
  261. order_type += "_maker";
  262. }
  263. if (order.type == e_order_type::MARKET) {
  264. order_type += "_market";
  265. }
  266. request["type"] = order_type;
  267.  
  268. if (order.type == e_order_type::LIMIT) {
  269. request["price"] = (*order.price).to_string();
  270. request["amount"] = (*order.quantity).to_string();
  271. }
  272. if (order.type == e_order_type::MARKET) {
  273. request["price"] = (*order.price).to_string();
  274. if (order.quantity) {
  275. request["amount"] = (*order.quantity).to_string();
  276. } else {
  277. std::cerr << "lbank_spot_api::new_order_wrapper::request_filler: market orders should have quantity parameter\n";
  278. abort();
  279. }
  280. // if (order.amount) {
  281. // request["amount"] = std::to_string(*order.amount);
  282. // }
  283. }
  284.  
  285. if (order.client_order_id) {
  286. request["custom_id"] = std::to_string(*order.client_order_id);
  287. }
  288. request["window"] = 5000;
  289.  
  290. std::cerr << request.serialize() << '\n';
  291.  
  292. return request.serialize_nospace();
  293. }
  294.  
  295. order_t lbank_spot_api::new_order_wrapper::response_filler(field_t&& response) {
  296. std::cerr << "new_order_wrapper: " << response.serialize() << std::endl;
  297.  
  298. order_t res;
  299. response = response["data"];
  300. res.symbol = &api_->members_.symbols[response.get("symbol").s()];
  301. res.client_order_id = response.get("custom_id").i();
  302. res.order_id = response.get("order_id").ms();
  303. return res;
  304. }
  305.  
  306. FutureHandle<result_t<order_t, market_error>> lbank_spot_api::new_order(const order_request_t& order) {
  307. return _new_order(order); // TODO: через transform?
  308. }
  309.  
  310. FutureHandle<std::string> lbank_spot_api::cancel_order_wrapper::execute(std::string_view request) {
  311. char header_buf[256];
  312. field_t query = field_t::deserialize(request);
  313. field_t signed_query = api_->form_signed_query(query.copy());
  314. query["api_key"] = signed_query["api_key"];
  315. query["sign"] = signed_query["sign"];
  316.  
  317. return api_->core_.post_signed("/v2/supplement/cancel_order.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  318. }
  319.  
  320. std::string lbank_spot_api::cancel_order_wrapper::request_filler(const ticker_t* symbol, const order_identifier_t& id) {
  321. field_t request;
  322. request["symbol"] = symbol->symbol;
  323. symbol_ = symbol;
  324. if (id.client_order_id) {
  325. request["origClientOrderId"] = std::to_string(id.client_order_id);
  326. }
  327. if (id.order_id) {
  328. request["orderId"] = *id.order_id;
  329. }
  330. return request.serialize_nospace();
  331. }
  332.  
  333. order_t lbank_spot_api::cancel_order_wrapper::response_filler(field_t&& response) {
  334. std::cerr << "cancel_order_wrapper: " << response.serialize() << '\n';
  335.  
  336. order_t res;
  337. response = response["data"];
  338. if (response.count("symbol")) {
  339. res.symbol = &api_->members_.symbols[response.get("symbol").s()];
  340. } else {
  341. res.symbol = symbol_;
  342. }
  343. res.client_order_id = std::stoll(response.get("origClientOrderId").s());
  344. if (response.count("orderId")) {
  345. res.order_id = response.get("orderId").ms();
  346. }
  347. res.price = res.symbol->make_price(response.get("price").s());
  348. res.quantity = res.symbol->make_quantity(response.get("origQty").s());
  349. res.filled_quantity = res.symbol->make_quantity(response.get("executedQty").s());
  350. res.status = _e_order_status_from_str(response.get("status").s());
  351. res.side = (response.get("tradeType").s()[0] == 'b' ? e_side::BUY : e_side::SELL); // TODO: почему не order_type??
  352. res.type = _e_order_type_from_str(response.get("tradeType").s());
  353.  
  354. return res;
  355. }
  356.  
  357. FutureHandle<result_t<order_t, market_error>> lbank_spot_api::cancel_order(const cancel_request_t& request) {
  358. return _cancel_order(request.symbol, request.id);
  359. }
  360.  
  361. FutureHandle<std::string> lbank_spot_api::cancel_open_orders_wrapper::execute(std::string_view request) {
  362. char header_buf[256];
  363. field_t query = field_t::deserialize(request);
  364. field_t signed_query = api_->form_signed_query(query.copy());
  365. query["api_key"] = signed_query["api_key"];
  366. query["sign"] = signed_query["sign"];
  367.  
  368. return api_->core_.post_signed("/v2/supplement/cancel_order_by_symbol.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  369. }
  370.  
  371. std::string lbank_spot_api::cancel_open_orders_wrapper::request_filler(const ticker_t* symbol) {
  372. field_t request;
  373. request["symbol"] = symbol->symbol;
  374. symbol_ = symbol;
  375. return request.serialize_nospace();
  376. }
  377.  
  378. std::vector<order_t> lbank_spot_api::cancel_open_orders_wrapper::response_filler(field_t&& response) {
  379. std::cerr << "cancel_open_orders_wrapper: " << response.serialize() << '\n'; std::vector<order_t> res;
  380.  
  381. response = response["data"];
  382. res.resize(response.size());
  383. for (size_t i = 0; i < response.size(); ++i) {
  384. res[i].symbol = symbol_; // &api_->members_.symbols[response[i].get("symbol").s()];
  385. res[i].client_order_id = std::stoll(response[i].get("origClientOrderId").s());
  386. res[i].order_id = response[i].get("orderId").ms();
  387. res[i].price = res[i].symbol->make_price(response[i].get("price").s());
  388. res[i].quantity = res[i].symbol->make_quantity(response[i].get("origQty").s());
  389. res[i].filled_quantity = res[i].symbol->make_quantity(response[i].get("executedQty").s());
  390. res[i].status = _e_order_status_from_str(response[i].get("status").s());
  391. res[i].side = (response[i].get("tradeType").s()[0] == 'b' ? e_side::BUY : e_side::SELL);
  392. res[i].type = _e_order_type_from_str(response[i].get("tradeType").s());
  393. }
  394. return res;
  395. }
  396.  
  397. FutureHandle<result_t<std::vector<order_t>, market_error>> lbank_spot_api::cancel_open_orders(const ticker_t* symbol, std::optional<e_order_group> order_group) {
  398. UNUSED(order_group);
  399. return _cancel_open_orders(symbol);
  400. }
  401.  
  402. FutureHandle<std::string> lbank_spot_api::get_open_orders_wrapper::execute(std::string_view request) {
  403. char header_buf[256];
  404. field_t query = field_t::deserialize(request);
  405. field_t signed_query = api_->form_signed_query(query.copy());
  406. query["api_key"] = signed_query["api_key"];
  407. query["sign"] = signed_query["sign"];
  408.  
  409. return api_->core_.post_signed("/v2/supplement/orders_info_no_deal.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  410. }
  411.  
  412. std::string lbank_spot_api::get_open_orders_wrapper::request_filler(const ticker_t* symbol) {
  413. field_t request;
  414. request["symbol"] = symbol->symbol;
  415. request["current_page"] = "1";
  416. request["page_length"] = "100";
  417. return request.serialize_nospace();
  418. }
  419.  
  420. std::vector<order_t> lbank_spot_api::get_open_orders_wrapper::response_filler(field_t&& response) {
  421. std::cerr << response.serialize() << std::endl;
  422.  
  423. std::vector<order_t> res;
  424. response = response["data"]["orders"];
  425. res.resize(response.size());
  426. for (size_t i = 0; i < response.size(); ++i) {
  427. res[i].symbol = &api_->members_.symbols[response[i].get("symbol").s()];
  428. res[i].client_order_id = std::stoll(response[i].get("clientOrderId").s());
  429. res[i].order_id = response[i].get("orderId").ms();
  430. res[i].price = res[i].symbol->make_price(response[i].get("price").s());
  431. res[i].quantity = res[i].symbol->make_quantity(response[i].get("origQty").s());
  432. res[i].filled_quantity = res[i].symbol->make_quantity(response[i].get("executedQty").s());
  433. res[i].status = _e_order_status_from_str(response[i].get("status").s());
  434. res[i].side = (response[i].get("type").s()[0] == 'b' ? e_side::BUY : e_side::SELL);
  435. res[i].type = _e_order_type_from_str(response[i].get("type").s());
  436. res[i].update_time = response[i].get("updateTime").i();
  437. }
  438. return res;
  439. }
  440.  
  441. FutureHandle<result_t<std::vector<order_t>, market_error>> lbank_spot_api::get_open_orders(const ticker_t* symbol) {
  442. return _get_open_orders(symbol);
  443. }
  444.  
  445. void lbank_spot_api::_run_ws() {
  446. field_t subscription = std::vector<field_t>(members_.channels.size());
  447. bool is_private_exist = false;
  448.  
  449. for (size_t i = 0; i < members_.channels.size(); ++i) {
  450. field_t channel_subscription;
  451. channel_subscription["action"] = "subscribe";
  452. switch (members_.channels[i].stream) {
  453. case e_stream::TRADE:
  454. channel_subscription["subscribe"] = "trade";
  455. channel_subscription["pair"] = lower(members_.channels[i].args.at("symbol"));
  456. break;
  457. case e_stream::PART_DEPTH:
  458. channel_subscription["subscribe"] = "depth";
  459. channel_subscription["pair"] = lower(members_.channels[i].args.at("symbol"));
  460. channel_subscription["depth"] = members_.channels[i].args.at("limit");
  461. break;
  462. case e_stream::ACCOUNT_ORDER:
  463. is_private_exist = true;
  464. channel_subscription["subscribe"] = "orderUpdate";
  465. if (members_.channels[i].args.count("symbol")) {
  466. channel_subscription["pair"] = lower(members_.channels[i].args.at("symbol"));
  467. } else {
  468. channel_subscription["pair"] = "all";
  469. }
  470. break;
  471. case e_stream::ACCOUNT_BALANCE:
  472. is_private_exist = true;
  473. channel_subscription["subscribe"] = "assetUpdate";
  474. break;
  475. case e_stream::BOOK:
  476. break;
  477. case e_stream::DIFF_DEPTH:
  478. break;
  479. case e_stream::KLINE:
  480. break;
  481. case e_stream::TICK:
  482. break;
  483. default:
  484. std::cerr << "mira::lbank_spot::api::_run_ws: unknown stream: " + std::string(ENUM_TO_STR(members_.channels_[i].stream)) << std::endl;
  485. abort();
  486. }
  487. subscription[i] = channel_subscription;
  488. }
  489.  
  490. if (is_private_exist) {
  491. result_t<std::string, market_error> listen_key = _listen_key_manager._new_listen_key().wait();
  492. int retry_attempts = 0;
  493. while (!listen_key) {
  494. if (++retry_attempts > 5) {
  495. std::cerr << "api::subscribe_multiple_streams: couldn't create listenKey. Retry attemps were exceeded..." << std::endl;
  496. abort();
  497. }
  498. std::cerr << "api::subscribe_multiple_streams: couldn't create listenKey. Sleep..." << std::endl;
  499. std::this_thread::sleep_for(std::chrono::milliseconds(300));
  500. listen_key = _listen_key_manager._new_listen_key().wait();
  501. }
  502. listen_key_ = listen_key.value();
  503.  
  504. for (auto& sub : subscription.v()) {
  505. if (sub.get("subscribe").s() == "orderUpdate" || sub.get("subscribe").s() == "assetUpdate") {
  506. sub["subscribeKey"] = listen_key_;
  507. }
  508. }
  509.  
  510. std::thread { [this] () {
  511. while (true) {
  512. std::this_thread::sleep_for(std::chrono::minutes(15));
  513. _listen_key_manager._keep_alive_listen_key();
  514. }
  515. }}.detach();
  516. }
  517.  
  518. std::string websocket_url = "wss://www.lbkex.net/ws/V2/";
  519.  
  520. ws_callback_ = new webcore::str_callback([this] (const char* res) {
  521. members_.ws_event_handler(res);
  522. });
  523. ws_client_ = core_.ws_init(ws_callback_, websocket_url);
  524.  
  525. auto reconnect = std::make_shared<std::function<void(std::string&&)>>();
  526.  
  527. *reconnect = [reconnect, subscription, websocket_url, this] (std::string&& res) {
  528. field_t response = field_t::deserialize(std::move(res));
  529. std::cerr << response.serialize() << '\n';
  530. if (response.count("_LE")) {
  531. std::cerr << "Error private: " << response.serialize() << '\n';
  532. members_.ws_event_handler("{\"_LE\":3}");
  533. ws_client_ = core_.ws_init(ws_callback_, websocket_url); // нужно ли???
  534. core_.ws_connect(ws_client_).async_wait(*reconnect);
  535. return;
  536. }
  537. core_.ws_start(ws_client_, ws_mutex_).async_wait(*reconnect);
  538. for (const auto& subscription_channel : subscription.v()) {
  539. core_.ws_send_without_handle(ws_client_, subscription_channel.serialize());
  540. }
  541. };
  542. core_.ws_connect(ws_client_).async_wait(*reconnect);
  543.  
  544. std::thread { [this] () {
  545. while (true) {
  546. std::this_thread::sleep_for(std::chrono::seconds(15));
  547. field_t ping_request;
  548. ping_request["action"] = "ping";
  549. ping_request["ping"] = "0ca8f854-7ba7-4341-9d86-d3327e52804e";
  550. std::cerr << get_timestamp() << " volunerable ping: " << ping_request.serialize() << '\n';
  551. core_.ws_send_without_handle(ws_client_, ping_request.serialize());
  552. }
  553. }}.detach();
  554. }
  555.  
  556. ws_trade_event lbank_spot_api::_trade_filler(field_t&& feed) {
  557. ws_trade_event res;
  558. res.type = e_stream::TRADE;
  559. res.trade.symbol = &members_.symbols[feed.at("pair").s()];
  560. res.trade.price = res.trade.symbol->make_price(feed.at("price").f());
  561. res.trade.quantity = res.trade.symbol->make_quantity(feed.at("volume").f());
  562. res.trade.trade_side = e_side_from_str(upper(feed.at("direction").s()));
  563. res.trade.trade_time = from_date(feed.get("TS").ms());
  564. res.symbol = res.trade.symbol;
  565. res.event_time = from_date(feed.get("event_time").s());
  566. return res;
  567. }
  568.  
  569. ws_part_depth_event lbank_spot_api::_part_depth_filler(field_t&& feed) {
  570. ws_part_depth_event res;
  571. res.type = e_stream::PART_DEPTH;
  572. res.depth.symbol = &members_.symbols[feed.at("pair").s()];
  573. res.depth.version = 0; // TODO: ???
  574. res.depth.asks.resize(feed.at("asks").size());
  575. res.depth.bids.resize(feed.at("bids").size());
  576. for (size_t i = 0; i < feed["asks"].size(); ++i) {
  577. res.depth.asks[i].price = res.depth.symbol->make_price(feed["asks"][i][0].f());
  578. res.depth.asks[i].quantity = res.depth.symbol->make_quantity(feed["asks"][i][1].f());
  579. }
  580. for (size_t i = 0; i < feed["bids"].size(); ++i) {
  581. res.depth.bids[i].price = res.depth.symbol->make_price(feed["bids"][i][0].f());
  582. res.depth.bids[i].quantity = res.depth.symbol->make_quantity(feed["bids"][i][1].f());
  583. }
  584. res.symbol = res.depth.symbol;
  585. res.event_time = from_date(feed.get("event_time").ms());
  586. return res;
  587. }
  588.  
  589. ws_account_order_event lbank_spot_api::_account_order_filler(field_t&& feed) {
  590. ws_account_order_event res;
  591. res.type = e_stream::ACCOUNT_ORDER;
  592. res.symbol = &members_.symbols[feed.get("symbol").s()];
  593. res.order.symbol = res.symbol;
  594. res.order.status = _e_order_status_from_str(feed.get("orderStatus").s());
  595. res.order.side = (feed.get("type").s()[0] == 'b' ? e_side::BUY : e_side::SELL);
  596. res.order.type = _e_order_type_from_str(feed.get("type").s());
  597. if (res.order.type == e_order_type::MARKET) {
  598. res.order.price = res.symbol->make_price(feed.get("price").s());
  599. } else {
  600. res.order.price = res.symbol->make_price(feed.get("orderPrice").s());
  601. }
  602. res.order.quantity = res.symbol->make_quantity(feed.get("amount").s()); // TODO: amount или quantity все-таки?
  603. res.order.filled_quantity = res.order.quantity - res.symbol->make_quantity(feed.get("remainAmt").s());
  604. res.order.update_time = feed.get("updateTime").i();
  605. res.event_time = res.order.update_time;
  606. res.order.client_order_id = 0; // TODO
  607. return res;
  608. }
  609.  
  610. ws_account_balance_event lbank_spot_api::_account_balance_filler(field_t&& feed) {
  611. ws_account_balance_event res;
  612. res.type = e_stream::ACCOUNT_BALANCE;
  613. res.event_time = feed.get("time").i();
  614. res.balance.update_time = res.event_time;
  615. res.balance.asset = feed.at("assetCode").s();
  616. res.balance.free = std::stod(feed.at("free").s());
  617. res.balance.locked = std::stod(feed.at("l").s());
  618. return res;
  619. }
  620.  
  621. result_t<std::vector<ws_event>, e_stream_error> lbank_spot_api::_feed_process(const char* feed_ptr) {
  622. std::cerr << "_feed_process: " << std::string(feed_ptr) << '\n';
  623.  
  624. result_t<std::vector<ws_event>, e_stream_error> res;
  625.  
  626. field_t data = field_t::deserialize(feed_ptr);
  627.  
  628. if (data.is_map() && data.count("ping")) {
  629. field_t pong_response;
  630. pong_response["action"] = "pong";
  631. pong_response["pong"] = data["ping"];
  632. core_.ws_send_without_handle(ws_client_, pong_response.serialize());
  633. res.set_error(e_stream_error::NO_STREAM);
  634. return res;
  635. }
  636.  
  637. std::string type = data["type"].s();
  638. if (type != "assetUpdate") {
  639. data[type]["pair"] = data["pair"];
  640. data[type]["event_time"] = data["TS"];
  641. data = data[type];
  642. } else {
  643. data = data["data"];
  644. }
  645.  
  646. if (type == "trade") {
  647. res.value().resize(1);
  648. res.value()[0].type = e_stream::TRADE;
  649. auto new_event = _trade_filler(std::move(data));
  650. res.value()[0].set_symbol(new_event.symbol);
  651. res.value()[0].set(std::move(new_event));
  652. return res;
  653. } else if (type == "depth") {
  654. res.value().resize(1);
  655. res.value()[0].type = e_stream::PART_DEPTH;
  656. auto new_event = _part_depth_filler(std::move(data));
  657. res.value()[0].set_symbol(new_event.symbol);
  658. res.value()[0].set(std::move(new_event));
  659. return res;
  660. } else if (type == "orderUpdate") {
  661. res.value().resize(1);
  662. res.value()[0].type = e_stream::ACCOUNT_ORDER;
  663. auto new_event = _account_order_filler(std::move(data));
  664. res.value()[0].set_symbol(new_event.symbol);
  665. res.value()[0].set(std::move(new_event));
  666. return res;
  667. } else if (type == "assetUpdate") {
  668. res.value().resize(1);
  669. res.value()[0].type = e_stream::ACCOUNT_BALANCE;
  670. auto new_event = _account_balance_filler(std::move(data));
  671. res.value()[0].set_symbol(new_event.symbol);
  672. res.value()[0].set(std::move(new_event));
  673. return res;
  674. }
  675.  
  676. std::cerr << "_feed_process unknown stream: " << type << '\n';
  677. res.set_error(e_stream_error::NO_STREAM);
  678. return res;
  679. }
  680.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement