Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <parsing/markets/lbank_spot/api.hpp>
- #include <parsing/markets/lbank_spot/errors.hpp>
- using namespace mira;
- const int _aux_lbank_spot = ParserBuilder::add_parser<lbank_spot_api>("LBANK_SPOT");
- lbank_spot_api::lbank_spot_api(const account_name_t& name) : basic_api(name) {
- core_.init(HOST_URL);
- ws_mutex_ = core_.create_mutex();
- market = "LBANK_SPOT";
- auto exchange_info = get_exchange_info({}).wait();
- for (const ticker_t& ticker : exchange_info.value()) {
- members_.symbols[ticker.symbol] = ticker;
- }
- }
- lbank_spot_api::lbank_spot_api(const account_name_t& name, const std::unordered_map<std::string, std::string>& args) : basic_api(name) {
- if (args.count("api") && args.count("secret")) {
- api_ = args.at("api");
- secret_ = args.at("secret");
- }
- core_.init(HOST_URL);
- ws_mutex_ = core_.create_mutex();
- if (!api_.empty()) {
- members_.authorized = true;
- }
- market = "LBANK_SPOT";
- auto exchange_info = get_exchange_info({}).wait();
- for (const ticker_t& ticker : exchange_info.value()) {
- members_.symbols[ticker.symbol] = ticker;
- }
- start_balance_indicator(args);
- }
- webcore::headers_t lbank_spot_api::gen_headers(char* buf, const field_t& signed_query) {
- webcore::headers_t res;
- res.size = signed_query.empty() ? 1 : 4;
- res.names = new const char*[res.size];
- res.values = new const char*[res.size];
- int ptr = 0;
- res.names[0] = header_names_[0];
- res.values[0] = buf + ptr;
- ptr += sprintf(buf + ptr, "zh-CN") + 1;
- // ptr += sprintf(buf + ptr, "application/json") + 1;
- if (!signed_query.empty()) {
- res.names[1] = header_names_[1];
- res.values[1] = buf + ptr;
- ptr += sprintf(buf + ptr, "%s", signed_query.at("timestamp").s().c_str()) + 1;
- res.names[2] = header_names_[2];
- res.values[2] = buf + ptr;
- ptr += sprintf(buf + ptr, "%s", signed_query.at("signature_method").s().c_str()) + 1;
- res.names[3] = header_names_[3];
- res.values[3] = buf + ptr;
- ptr += sprintf(buf + ptr, "%s", signed_query.at("echostr").s().c_str());
- }
- return res;
- }
- field_t lbank_spot_api::form_signed_query(field_t params) {
- std::string echostr = "";
- for (int i = 0; i < 35; ++i) {
- echostr += letters_[std::rand() % 62];
- }
- params["api_key"] = api_;
- params["echostr"] = "FA37jNCchRYdSBZAYY4CbwdXs22jJZHmAIr"; // echostr;
- params["signature_method"] = "HmacSHA256";
- params["timestamp"] = std::to_string(get_timestamp());
- std::vector<std::string> keys;
- for (const auto& [key, _] : params.m()) {
- keys.push_back(key);
- }
- std::sort(keys.begin(), keys.end());
- std::string sorted_params_str = keys[0] + "=" + params[keys[0]].s();
- for (size_t i = 1; i < keys.size(); ++i) {
- sorted_params_str += ("&" + keys[i] + "=" + params[keys[i]].s());
- }
- // std::string sorted_params_str = std::accumulate(keys.begin(), keys.end(), std::string(),
- // [](const std::string& acc, const std::string& val) {
- // return acc.empty() ? val : acc + "&" + val;
- // }
- // );
- params["sign"] = calc_hmac_sha256(md5_upper(sorted_params_str), secret_);
- return params;
- }
- FutureHandle<std::string> lbank_spot_api::get_exchange_info_wrapper::execute(std::string_view request) {
- return api_->core_.get_unsigned("/v2/accuracy.do", request, "", webcore::headers_t{});
- }
- std::string lbank_spot_api::get_exchange_info_wrapper::request_filler(std::optional<std::string> symbol) {
- UNUSED(symbol);
- return "";
- }
- std::vector<ticker_t> lbank_spot_api::get_exchange_info_wrapper::response_filler(field_t&& response) {
- response = response["data"];
- std::vector<ticker_t> res(response.size());
- for (size_t i = 0; i < response.size(); ++i) {
- res[i].symbol = response[i].get("symbol").ms();
- size_t pos = res[i].symbol.find("_");
- res[i].quote = res[i].symbol.substr(0, pos);
- res[i].base = res[i].symbol.substr(pos);
- res[i].market_quantity_precision = res[i].quantity_precision = std::stoi(response[i].get("quantityAccuracy").s());
- res[i].market_amount_precision = res[i].price_precision = std::stoi(response[i].get("priceAccuracy").s());
- res[i].price_step = precised_float::from_scaled(1, res[i].price_precision);
- res[i].quantity_step = precised_float::from_scaled(1, res[i].quantity_precision);
- res[i].min_notional = std::stod(response[i].get("minTranQua").s());
- res[i].max_notional = 1e9;
- res[i].api = api_;
- }
- return res;
- }
- FutureHandle<result_t<std::vector<ticker_t>, market_error>> lbank_spot_api::get_exchange_info(std::optional<std::string> symbol) {
- UNUSED(symbol);
- return _get_exchange_info(symbol);
- }
- FutureHandle<std::string> lbank_spot_api::get_depth_wrapper::execute(std::string_view request) {
- std::cout << request << '\n';
- return api_->core_.get_unsigned("/v2/depth.do", request, "", webcore::headers_t{});
- }
- std::string lbank_spot_api::get_depth_wrapper::request_filler(const ticker_t* symbol, std::optional<size_t> limit) {
- field_t request;
- symbol_ = symbol;
- request["symbol"] = symbol->symbol;
- request["size"] = *limit;
- return request.to_query();
- }
- depth_t lbank_spot_api::get_depth_wrapper::response_filler(field_t&& response) {
- depth_t res_depth;
- std::cout << response.serialize() << std::endl;
- response = response["data"];
- res_depth.version = 0;
- res_depth.symbol = symbol_;
- res_depth.update_time = response.get("timestamp").i();
- res_depth.asks.resize(response["asks"].size());
- res_depth.bids.resize(response["bids"].size());
- for (size_t i = 0; i < response["asks"].size(); ++i) {
- res_depth.asks[i].price = symbol_->make_price(response["asks"][i][0].f());
- res_depth.asks[i].quantity = symbol_->make_quantity(response["asks"][i][1].f());
- }
- for (size_t i = 0; i < response["bids"].size(); ++i) {
- res_depth.bids[i].price = symbol_->make_price(response["bids"][i][0].f());
- res_depth.bids[i].quantity = symbol_->make_quantity(response["bids"][i][1].f());
- }
- return res_depth;
- }
- FutureHandle<result_t<depth_t, market_error>> lbank_spot_api::get_depth(const ticker_t* symbol, std::optional<size_t> limit) {
- return _get_depth(symbol, limit);
- }
- FutureHandle<std::string> lbank_spot_api::get_account_wrapper::execute(std::string_view request) {
- std::cerr << request << '\n';
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- std::cerr << signed_query.serialize() << '\n';
- std::cerr << "query 1: " << query.serialize() << '\n';
- query["sign"] = signed_query["sign"];
- query["api_key"] = signed_query["api_key"];
- std::cerr << "query 2: " << query.serialize() << '\n';
- std::cout << query.to_query() << '\n';
- return api_->core_.post_signed("/v2/supplement/user_info_account.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
- }
- std::string lbank_spot_api::get_account_wrapper::request_filler() {
- return field_t().serialize();
- }
- account_t lbank_spot_api::get_account_wrapper::response_filler(field_t&& response) {
- account_t res;
- std::cerr << response.serialize() << '\n';
- response = response["data"];
- res.account_type = e_account_type::SPOT;
- for (const auto& bal : response.get("balances").v()) {
- balance_t balance;
- balance.asset = lower(bal.at("asset").s());;
- balance.free = bal.at("free").f();
- balance.locked = bal.at("locked").f();
- res.balances[balance.asset] = balance;
- }
- return res;
- }
- FutureHandle<result_t<account_t, market_error>> lbank_spot_api::get_account() {
- return _get_account();
- }
- void lbank_spot_api::_run_ws() {
- field_t subscription = std::vector<field_t>(members_.channels.size());
- for (size_t i = 0; i < members_.channels.size(); ++i) {
- field_t channel_subscription;
- channel_subscription["action"] = "subscribe";
- switch (members_.channels[i].stream) {
- case e_stream::TRADE:
- channel_subscription["subscribe"] = "trade";
- channel_subscription["pair"] = lower(members_.channels[i].args.at("symbol"));
- break;
- case e_stream::PART_DEPTH:
- break;
- case e_stream::ACCOUNT_ORDER:
- break;
- case e_stream::ACCOUNT_BALANCE:
- break;
- case e_stream::TICK:
- break;
- }
- subscription[i] = channel_subscription;
- }
- std::string websocket_url = "wss://www.lbkex.net/ws/V2/";
- ws_callback_ = new webcore::str_callback([this] (const char* res) {
- members_.ws_event_handler(res);
- });
- ws_client_ = core_.ws_init(ws_callback_, websocket_url);
- auto reconnect = std::make_shared<std::function<void(std::string&&)>>();
- *reconnect = [reconnect, subscription, websocket_url, this] (std::string&& res) {
- field_t response = field_t::deserialize(std::move(res));
- std::cerr << response.serialize() << '\n';
- if (response.count("_LE")) {
- 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';
- members_.ws_event_handler("{\"_LE\":3}");
- ws_client_ = core_.ws_init(ws_callback_, websocket_url); // нужно ли???
- core_.ws_connect(ws_client_).async_wait(*reconnect);
- return;
- }
- core_.ws_start(ws_client_, ws_mutex_).async_wait(*reconnect);
- for (const auto& subscription_channel : subscription.v()) {
- core_.ws_send_without_handle(ws_client_, subscription_channel.serialize());
- }
- };
- core_.ws_connect(ws_client_).async_wait(*reconnect);
- std::thread { [this] () {
- while (true) {
- std::this_thread::sleep_for(std::chrono::seconds(15));
- field_t ping_request;
- ping_request["action"] = "ping";
- ping_request["ping"] = "0ca8f854-7ba7-4341-9d86-d3327e52804e";
- std::cerr << get_timestamp() << " volunerable ping: " << ping_request.serialize() << '\n';
- core_.ws_send_without_handle(ws_client_, ping_request.serialize());
- }
- }}.detach();
- }
- result_t<std::vector<ws_event>, e_stream_error> lbank_spot_api::_feed_process(const char* feed_ptr) {
- 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';
- result_t<std::vector<ws_event>, e_stream_error> res;
- field_t data = field_t::deserialize(feed_ptr);
- if (data.is_map() && data.count("pong")) {
- 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';
- }
- if (data.is_map() && data.count("ping")) {
- 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';
- field_t pong_response;
- pong_response["action"] = "pong";
- pong_response["pong"] = data["ping"];
- std::cerr << "pong: " << pong_response.serialize() << '\n';
- core_.ws_send_without_handle(ws_client_, pong_response.serialize());
- res.set_error(e_stream_error::NO_STREAM);
- return res;
- }
- return res;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement