Advertisement
den4ik2003

Untitled

Jan 20th, 2025
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.79 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. lbank_spot_api::lbank_spot_api(const account_name_t& name) : basic_api(name) {
  9. core_.init(HOST_URL);
  10. ws_mutex_ = core_.create_mutex();
  11. market = "LBANK_SPOT";
  12. auto exchange_info = get_exchange_info({}).wait();
  13. for (const ticker_t& ticker : exchange_info.value()) {
  14. members_.symbols[ticker.symbol] = ticker;
  15. }
  16. }
  17.  
  18. lbank_spot_api::lbank_spot_api(const account_name_t& name, const std::unordered_map<std::string, std::string>& args) : basic_api(name) {
  19. if (args.count("api") && args.count("secret")) {
  20. api_ = args.at("api");
  21. secret_ = args.at("secret");
  22. }
  23. core_.init(HOST_URL);
  24. ws_mutex_ = core_.create_mutex();
  25. if (!api_.empty()) {
  26. members_.authorized = true;
  27. }
  28. market = "LBANK_SPOT";
  29. auto exchange_info = get_exchange_info({}).wait();
  30. for (const ticker_t& ticker : exchange_info.value()) {
  31. members_.symbols[ticker.symbol] = ticker;
  32. }
  33. start_balance_indicator(args);
  34. }
  35.  
  36. webcore::headers_t lbank_spot_api::gen_headers(char* buf, const field_t& signed_query) {
  37. webcore::headers_t res;
  38. res.size = signed_query.empty() ? 1 : 4;
  39. res.names = new const char*[res.size];
  40. res.values = new const char*[res.size];
  41. int ptr = 0;
  42.  
  43. res.names[0] = header_names_[0];
  44. res.values[0] = buf + ptr;
  45. ptr += sprintf(buf + ptr, "zh-CN") + 1;
  46. // ptr += sprintf(buf + ptr, "application/json") + 1;
  47.  
  48. if (!signed_query.empty()) {
  49. res.names[1] = header_names_[1];
  50. res.values[1] = buf + ptr;
  51. ptr += sprintf(buf + ptr, "%s", signed_query.at("timestamp").s().c_str()) + 1;
  52.  
  53. res.names[2] = header_names_[2];
  54. res.values[2] = buf + ptr;
  55. ptr += sprintf(buf + ptr, "%s", signed_query.at("signature_method").s().c_str()) + 1;
  56.  
  57. res.names[3] = header_names_[3];
  58. res.values[3] = buf + ptr;
  59. ptr += sprintf(buf + ptr, "%s", signed_query.at("echostr").s().c_str());
  60. }
  61.  
  62. return res;
  63. }
  64.  
  65. field_t lbank_spot_api::form_signed_query(field_t params) {
  66. std::string echostr = "";
  67. for (int i = 0; i < 35; ++i) {
  68. echostr += letters_[std::rand() % 62];
  69. }
  70.  
  71. params["api_key"] = api_;
  72. params["echostr"] = "FA37jNCchRYdSBZAYY4CbwdXs22jJZHmAIr"; // echostr;
  73. params["signature_method"] = "HmacSHA256";
  74. params["timestamp"] = std::to_string(get_timestamp());
  75.  
  76. std::vector<std::string> keys;
  77. for (const auto& [key, _] : params.m()) {
  78. keys.push_back(key);
  79. }
  80. std::sort(keys.begin(), keys.end());
  81.  
  82. std::string sorted_params_str = keys[0] + "=" + params[keys[0]].s();
  83. for (size_t i = 1; i < keys.size(); ++i) {
  84. sorted_params_str += ("&" + keys[i] + "=" + params[keys[i]].s());
  85. }
  86.  
  87. // std::string sorted_params_str = std::accumulate(keys.begin(), keys.end(), std::string(),
  88. // [](const std::string& acc, const std::string& val) {
  89. // return acc.empty() ? val : acc + "&" + val;
  90. // }
  91. // );
  92. params["sign"] = calc_hmac_sha256(md5_upper(sorted_params_str), secret_);
  93.  
  94. return params;
  95. }
  96.  
  97. FutureHandle<std::string> lbank_spot_api::get_exchange_info_wrapper::execute(std::string_view request) {
  98. return api_->core_.get_unsigned("/v2/accuracy.do", request, "", webcore::headers_t{});
  99. }
  100.  
  101. std::string lbank_spot_api::get_exchange_info_wrapper::request_filler(std::optional<std::string> symbol) {
  102. UNUSED(symbol);
  103. return "";
  104. }
  105.  
  106. std::vector<ticker_t> lbank_spot_api::get_exchange_info_wrapper::response_filler(field_t&& response) {
  107. response = response["data"];
  108. std::vector<ticker_t> res(response.size());
  109. for (size_t i = 0; i < response.size(); ++i) {
  110. res[i].symbol = response[i].get("symbol").ms();
  111. size_t pos = res[i].symbol.find("_");
  112. res[i].quote = res[i].symbol.substr(0, pos);
  113. res[i].base = res[i].symbol.substr(pos);
  114. res[i].market_quantity_precision = res[i].quantity_precision = std::stoi(response[i].get("quantityAccuracy").s());
  115. res[i].market_amount_precision = res[i].price_precision = std::stoi(response[i].get("priceAccuracy").s());
  116. res[i].price_step = precised_float::from_scaled(1, res[i].price_precision);
  117. res[i].quantity_step = precised_float::from_scaled(1, res[i].quantity_precision);
  118. res[i].min_notional = std::stod(response[i].get("minTranQua").s());
  119. res[i].max_notional = 1e9;
  120. res[i].api = api_;
  121. }
  122. return res;
  123. }
  124.  
  125. FutureHandle<result_t<std::vector<ticker_t>, market_error>> lbank_spot_api::get_exchange_info(std::optional<std::string> symbol) {
  126. UNUSED(symbol);
  127. return _get_exchange_info(symbol);
  128. }
  129.  
  130.  
  131. FutureHandle<std::string> lbank_spot_api::get_depth_wrapper::execute(std::string_view request) {
  132. std::cout << request << '\n';
  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. std::cout << response.serialize() << std::endl;
  147. response = response["data"];
  148. res_depth.version = 0;
  149. res_depth.symbol = symbol_;
  150. res_depth.update_time = response.get("timestamp").i();
  151. res_depth.asks.resize(response["asks"].size());
  152. res_depth.bids.resize(response["bids"].size());
  153. for (size_t i = 0; i < response["asks"].size(); ++i) {
  154. res_depth.asks[i].price = symbol_->make_price(response["asks"][i][0].f());
  155. res_depth.asks[i].quantity = symbol_->make_quantity(response["asks"][i][1].f());
  156. }
  157. for (size_t i = 0; i < response["bids"].size(); ++i) {
  158. res_depth.bids[i].price = symbol_->make_price(response["bids"][i][0].f());
  159. res_depth.bids[i].quantity = symbol_->make_quantity(response["bids"][i][1].f());
  160. }
  161. return res_depth;
  162. }
  163.  
  164. FutureHandle<result_t<depth_t, market_error>> lbank_spot_api::get_depth(const ticker_t* symbol, std::optional<size_t> limit) {
  165. return _get_depth(symbol, limit);
  166. }
  167.  
  168. FutureHandle<std::string> lbank_spot_api::get_account_wrapper::execute(std::string_view request) {
  169. std::cerr << request << '\n';
  170.  
  171. char header_buf[256];
  172. field_t query = field_t::deserialize(request);
  173. field_t signed_query = api_->form_signed_query(query.copy());
  174.  
  175. std::cerr << signed_query.serialize() << '\n';
  176.  
  177. std::cerr << "query 1: " << query.serialize() << '\n';
  178.  
  179. query["sign"] = signed_query["sign"];
  180. query["api_key"] = signed_query["api_key"];
  181.  
  182. std::cerr << "query 2: " << query.serialize() << '\n';
  183.  
  184. std::cout << query.to_query() << '\n';
  185.  
  186. return api_->core_.post_signed("/v2/supplement/user_info_account.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
  187. }
  188.  
  189. std::string lbank_spot_api::get_account_wrapper::request_filler() {
  190. return field_t().serialize();
  191. }
  192.  
  193. account_t lbank_spot_api::get_account_wrapper::response_filler(field_t&& response) {
  194. account_t res;
  195. std::cerr << response.serialize() << '\n';
  196. response = response["data"];
  197. res.account_type = e_account_type::SPOT;
  198. for (const auto& bal : response.get("balances").v()) {
  199. balance_t balance;
  200. balance.asset = lower(bal.at("asset").s());;
  201. balance.free = bal.at("free").f();
  202. balance.locked = bal.at("locked").f();
  203. res.balances[balance.asset] = balance;
  204. }
  205. return res;
  206. }
  207.  
  208. FutureHandle<result_t<account_t, market_error>> lbank_spot_api::get_account() {
  209. return _get_account();
  210. }
  211.  
  212. void lbank_spot_api::_run_ws() {
  213. field_t subscription = std::vector<field_t>(members_.channels.size());
  214.  
  215. for (size_t i = 0; i < members_.channels.size(); ++i) {
  216. field_t channel_subscription;
  217. channel_subscription["action"] = "subscribe";
  218. switch (members_.channels[i].stream) {
  219. case e_stream::TRADE:
  220. channel_subscription["subscribe"] = "trade";
  221. channel_subscription["pair"] = lower(members_.channels[i].args.at("symbol"));
  222. break;
  223. case e_stream::PART_DEPTH:
  224. break;
  225. case e_stream::ACCOUNT_ORDER:
  226. break;
  227. case e_stream::ACCOUNT_BALANCE:
  228. break;
  229. case e_stream::TICK:
  230. break;
  231. }
  232. subscription[i] = channel_subscription;
  233. }
  234.  
  235. std::string websocket_url = "wss://www.lbkex.net/ws/V2/";
  236.  
  237. ws_callback_ = new webcore::str_callback([this] (const char* res) {
  238. members_.ws_event_handler(res);
  239. });
  240. ws_client_ = core_.ws_init(ws_callback_, websocket_url);
  241.  
  242. auto reconnect = std::make_shared<std::function<void(std::string&&)>>();
  243.  
  244. *reconnect = [reconnect, subscription, websocket_url, this] (std::string&& res) {
  245. field_t response = field_t::deserialize(std::move(res));
  246. std::cerr << response.serialize() << '\n';
  247. if (response.count("_LE")) {
  248. std::cerr << "Error private: " << get_date(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) << " " << response.serialize() << '\n';
  249. members_.ws_event_handler("{\"_LE\":3}");
  250. ws_client_ = core_.ws_init(ws_callback_, websocket_url); // нужно ли???
  251. core_.ws_connect(ws_client_).async_wait(*reconnect);
  252. return;
  253. }
  254. core_.ws_start(ws_client_, ws_mutex_).async_wait(*reconnect);
  255. for (const auto& subscription_channel : subscription.v()) {
  256. core_.ws_send_without_handle(ws_client_, subscription_channel.serialize());
  257. }
  258. };
  259. core_.ws_connect(ws_client_).async_wait(*reconnect);
  260.  
  261. std::thread { [this] () {
  262. while (true) {
  263. std::this_thread::sleep_for(std::chrono::seconds(15));
  264. field_t ping_request;
  265. ping_request["action"] = "ping";
  266. ping_request["ping"] = "0ca8f854-7ba7-4341-9d86-d3327e52804e";
  267. std::cerr << get_timestamp() << " volunerable ping: " << ping_request.serialize() << '\n';
  268. core_.ws_send_without_handle(ws_client_, ping_request.serialize());
  269. }
  270. }}.detach();
  271. }
  272.  
  273. result_t<std::vector<ws_event>, e_stream_error> lbank_spot_api::_feed_process(const char* feed_ptr) {
  274. std::cerr << get_date(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) << " " << std::string(feed_ptr) << '\n';
  275. result_t<std::vector<ws_event>, e_stream_error> res;
  276.  
  277. field_t data = field_t::deserialize(feed_ptr);
  278.  
  279. if (data.is_map() && data.count("pong")) {
  280. std::cerr << "_feed_process: " << get_date(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) << " " << std::string(feed_ptr) << '\n';
  281. }
  282.  
  283. if (data.is_map() && data.count("ping")) {
  284. std::cerr << "_feed_process Get Server Ping: " << get_date(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) << " " << std::string(feed_ptr) << '\n';
  285.  
  286. field_t pong_response;
  287. pong_response["action"] = "pong";
  288. pong_response["pong"] = data["ping"];
  289. std::cerr << "pong: " << pong_response.serialize() << '\n';
  290. core_.ws_send_without_handle(ws_client_, pong_response.serialize());
  291. res.set_error(e_stream_error::NO_STREAM);
  292. return res;
  293. }
  294.  
  295. return res;
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement