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");
- 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;
- 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::cerr << "form_signed_query params: " << params.serialize() << '\n';
- std::string echostr = "P3LHfw6tUIYWc8R2VQNy0ilKmdg5pjhbxC7";
- // for (int i = 0; i < 35; ++i) {
- // echostr += letters_[std::rand() % 62];
- // }
- params["api_key"] = api_;
- params["echostr"] = echostr;
- params["signature_method"] = "HmacSHA256";
- params["timestamp"] = 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;
- }
- 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);
- }
- 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) {
- 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;
- 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) {
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- query["api_key"] = signed_query["api_key"];
- query["sign"] = signed_query["sign"];
- 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;
- 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();
- if (balance.free != 0 || balance.locked != 0) {
- res.balances[balance.asset] = balance;
- }
- }
- return res;
- }
- FutureHandle<result_t<account_t, market_error>> lbank_spot_api::get_account() {
- return _get_account();
- }
- FutureHandle<std::string> lbank_spot_api::listen_key_manager::new_listen_key_wrapper::execute(std::string_view request) {
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- query["api_key"] = signed_query["api_key"];
- query["sign"] = signed_query["sign"];
- return api_->core_.post_signed("/v2/subscribe/get_key.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
- }
- std::string lbank_spot_api::listen_key_manager::new_listen_key_wrapper::request_filler() {
- return field_t().serialize();
- }
- std::string lbank_spot_api::listen_key_manager::new_listen_key_wrapper::response_filler(field_t&& response) {
- manager_->current_listen_key_ = response["data"]["key"].s();
- return manager_->current_listen_key_;
- }
- FutureHandle<std::string> lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrapper::execute(std::string_view request) {
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- query["api_key"] = signed_query["api_key"];
- query["sign"] = signed_query["sign"];
- return api_->core_.post_signed("/v2/subscribe/refresh_key.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
- }
- std::string lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrapper::request_filler() {
- field_t request;
- if (manager_->current_listen_key_.empty()) {
- std::cerr << "lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrappertry::request_filler() try to keep alive connection with empty listen key";
- abort();
- }
- request["subscribeKey"] = manager_->current_listen_key_;
- return request.serialize_nospace();
- }
- std::string lbank_spot_api::listen_key_manager::keep_alive_listen_key_wrapper::response_filler(field_t&& response) {
- UNUSED(response);
- return "";
- }
- FutureHandle<std::string> lbank_spot_api::new_order_wrapper::execute(std::string_view request) {
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- query["api_key"] = signed_query["api_key"];
- query["sign"] = signed_query["sign"];
- return api_->core_.post_signed("/v2/supplement/create_order.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
- }
- std::string lbank_spot_api::new_order_wrapper::request_filler(const order_request_t& order) {
- field_t request;
- request["symbol"] = order.symbol->symbol;
- std::string order_type = lower(to_c_string(order.side));
- if (order.type == e_order_type::LIMIT && order.post_only) {
- order_type += "_maker";
- }
- if (order.type == e_order_type::MARKET) {
- order_type += "_market";
- }
- request["type"] = order_type;
- if (order.type == e_order_type::LIMIT) {
- request["price"] = (*order.price).to_string();
- request["amount"] = (*order.quantity).to_string();
- }
- if (order.type == e_order_type::MARKET) {
- request["price"] = (*order.price).to_string();
- if (order.quantity) {
- request["amount"] = (*order.quantity).to_string();
- } else {
- std::cerr << "lbank_spot_api::new_order_wrapper::request_filler: market orders should have quantity parameter\n";
- abort();
- }
- // if (order.amount) {
- // request["amount"] = std::to_string(*order.amount);
- // }
- }
- if (order.client_order_id) {
- request["custom_id"] = std::to_string(*order.client_order_id);
- }
- request["window"] = 5000;
- std::cerr << request.serialize() << '\n';
- return request.serialize_nospace();
- }
- order_t lbank_spot_api::new_order_wrapper::response_filler(field_t&& response) {
- std::cerr << "new_order_wrapper: " << response.serialize() << std::endl;
- order_t res;
- response = response["data"];
- res.symbol = &api_->members_.symbols[response.get("symbol").s()];
- res.client_order_id = response.get("custom_id").i();
- res.order_id = response.get("order_id").ms();
- return res;
- }
- FutureHandle<result_t<order_t, market_error>> lbank_spot_api::new_order(const order_request_t& order) {
- return _new_order(order); // TODO: через transform?
- }
- FutureHandle<std::string> lbank_spot_api::cancel_order_wrapper::execute(std::string_view request) {
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- query["api_key"] = signed_query["api_key"];
- query["sign"] = signed_query["sign"];
- return api_->core_.post_signed("/v2/supplement/cancel_order.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
- }
- std::string lbank_spot_api::cancel_order_wrapper::request_filler(const ticker_t* symbol, const order_identifier_t& id) {
- field_t request;
- request["symbol"] = symbol->symbol;
- symbol_ = symbol;
- if (id.client_order_id) {
- request["origClientOrderId"] = std::to_string(id.client_order_id);
- }
- if (id.order_id) {
- request["orderId"] = *id.order_id;
- }
- return request.serialize_nospace();
- }
- order_t lbank_spot_api::cancel_order_wrapper::response_filler(field_t&& response) {
- std::cerr << "cancel_order_wrapper: " << response.serialize() << '\n';
- order_t res;
- response = response["data"];
- if (response.count("symbol")) {
- res.symbol = &api_->members_.symbols[response.get("symbol").s()];
- } else {
- res.symbol = symbol_;
- }
- res.client_order_id = std::stoll(response.get("origClientOrderId").s());
- if (response.count("orderId")) {
- res.order_id = response.get("orderId").ms();
- }
- res.price = res.symbol->make_price(response.get("price").s());
- res.quantity = res.symbol->make_quantity(response.get("origQty").s());
- res.filled_quantity = res.symbol->make_quantity(response.get("executedQty").s());
- res.status = _e_order_status_from_str(response.get("status").s());
- res.side = (response.get("tradeType").s()[0] == 'b' ? e_side::BUY : e_side::SELL); // TODO: почему не order_type??
- res.type = _e_order_type_from_str(response.get("tradeType").s());
- return res;
- }
- FutureHandle<result_t<order_t, market_error>> lbank_spot_api::cancel_order(const cancel_request_t& request) {
- return _cancel_order(request.symbol, request.id);
- }
- FutureHandle<std::string> lbank_spot_api::cancel_open_orders_wrapper::execute(std::string_view request) {
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- query["api_key"] = signed_query["api_key"];
- query["sign"] = signed_query["sign"];
- return api_->core_.post_signed("/v2/supplement/cancel_order_by_symbol.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
- }
- std::string lbank_spot_api::cancel_open_orders_wrapper::request_filler(const ticker_t* symbol) {
- field_t request;
- request["symbol"] = symbol->symbol;
- symbol_ = symbol;
- return request.serialize_nospace();
- }
- std::vector<order_t> lbank_spot_api::cancel_open_orders_wrapper::response_filler(field_t&& response) {
- std::cerr << "cancel_open_orders_wrapper: " << response.serialize() << '\n'; std::vector<order_t> res;
- response = response["data"];
- res.resize(response.size());
- for (size_t i = 0; i < response.size(); ++i) {
- res[i].symbol = symbol_; // &api_->members_.symbols[response[i].get("symbol").s()];
- res[i].client_order_id = std::stoll(response[i].get("origClientOrderId").s());
- res[i].order_id = response[i].get("orderId").ms();
- res[i].price = res[i].symbol->make_price(response[i].get("price").s());
- res[i].quantity = res[i].symbol->make_quantity(response[i].get("origQty").s());
- res[i].filled_quantity = res[i].symbol->make_quantity(response[i].get("executedQty").s());
- res[i].status = _e_order_status_from_str(response[i].get("status").s());
- res[i].side = (response[i].get("tradeType").s()[0] == 'b' ? e_side::BUY : e_side::SELL);
- res[i].type = _e_order_type_from_str(response[i].get("tradeType").s());
- }
- return res;
- }
- 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) {
- UNUSED(order_group);
- return _cancel_open_orders(symbol);
- }
- FutureHandle<std::string> lbank_spot_api::get_open_orders_wrapper::execute(std::string_view request) {
- char header_buf[256];
- field_t query = field_t::deserialize(request);
- field_t signed_query = api_->form_signed_query(query.copy());
- query["api_key"] = signed_query["api_key"];
- query["sign"] = signed_query["sign"];
- return api_->core_.post_signed("/v2/supplement/orders_info_no_deal.do", query.to_query(), "", api_->gen_headers(header_buf, signed_query));
- }
- std::string lbank_spot_api::get_open_orders_wrapper::request_filler(const ticker_t* symbol) {
- field_t request;
- request["symbol"] = symbol->symbol;
- request["current_page"] = "1";
- request["page_length"] = "100";
- return request.serialize_nospace();
- }
- std::vector<order_t> lbank_spot_api::get_open_orders_wrapper::response_filler(field_t&& response) {
- std::cerr << response.serialize() << std::endl;
- std::vector<order_t> res;
- response = response["data"]["orders"];
- res.resize(response.size());
- for (size_t i = 0; i < response.size(); ++i) {
- res[i].symbol = &api_->members_.symbols[response[i].get("symbol").s()];
- res[i].client_order_id = std::stoll(response[i].get("clientOrderId").s());
- res[i].order_id = response[i].get("orderId").ms();
- res[i].price = res[i].symbol->make_price(response[i].get("price").s());
- res[i].quantity = res[i].symbol->make_quantity(response[i].get("origQty").s());
- res[i].filled_quantity = res[i].symbol->make_quantity(response[i].get("executedQty").s());
- res[i].status = _e_order_status_from_str(response[i].get("status").s());
- res[i].side = (response[i].get("type").s()[0] == 'b' ? e_side::BUY : e_side::SELL);
- res[i].type = _e_order_type_from_str(response[i].get("type").s());
- res[i].update_time = response[i].get("updateTime").i();
- }
- return res;
- }
- FutureHandle<result_t<std::vector<order_t>, market_error>> lbank_spot_api::get_open_orders(const ticker_t* symbol) {
- return _get_open_orders(symbol);
- }
- void lbank_spot_api::_run_ws() {
- field_t subscription = std::vector<field_t>(members_.channels.size());
- bool is_private_exist = false;
- 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:
- channel_subscription["subscribe"] = "depth";
- channel_subscription["pair"] = lower(members_.channels[i].args.at("symbol"));
- channel_subscription["depth"] = members_.channels[i].args.at("limit");
- break;
- case e_stream::ACCOUNT_ORDER:
- is_private_exist = true;
- channel_subscription["subscribe"] = "orderUpdate";
- if (members_.channels[i].args.count("symbol")) {
- channel_subscription["pair"] = lower(members_.channels[i].args.at("symbol"));
- } else {
- channel_subscription["pair"] = "all";
- }
- break;
- case e_stream::ACCOUNT_BALANCE:
- is_private_exist = true;
- channel_subscription["subscribe"] = "assetUpdate";
- break;
- case e_stream::BOOK:
- break;
- case e_stream::DIFF_DEPTH:
- break;
- case e_stream::KLINE:
- break;
- case e_stream::TICK:
- break;
- default:
- std::cerr << "mira::lbank_spot::api::_run_ws: unknown stream: " + std::string(ENUM_TO_STR(members_.channels_[i].stream)) << std::endl;
- abort();
- }
- subscription[i] = channel_subscription;
- }
- if (is_private_exist) {
- result_t<std::string, market_error> listen_key = _listen_key_manager._new_listen_key().wait();
- int retry_attempts = 0;
- while (!listen_key) {
- if (++retry_attempts > 5) {
- std::cerr << "api::subscribe_multiple_streams: couldn't create listenKey. Retry attemps were exceeded..." << std::endl;
- abort();
- }
- std::cerr << "api::subscribe_multiple_streams: couldn't create listenKey. Sleep..." << std::endl;
- std::this_thread::sleep_for(std::chrono::milliseconds(300));
- listen_key = _listen_key_manager._new_listen_key().wait();
- }
- listen_key_ = listen_key.value();
- for (auto& sub : subscription.v()) {
- if (sub.get("subscribe").s() == "orderUpdate" || sub.get("subscribe").s() == "assetUpdate") {
- sub["subscribeKey"] = listen_key_;
- }
- }
- std::thread { [this] () {
- while (true) {
- std::this_thread::sleep_for(std::chrono::minutes(15));
- _listen_key_manager._keep_alive_listen_key();
- }
- }}.detach();
- }
- 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: " << 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();
- }
- ws_trade_event lbank_spot_api::_trade_filler(field_t&& feed) {
- ws_trade_event res;
- res.type = e_stream::TRADE;
- res.trade.symbol = &members_.symbols[feed.at("pair").s()];
- res.trade.price = res.trade.symbol->make_price(feed.at("price").f());
- res.trade.quantity = res.trade.symbol->make_quantity(feed.at("volume").f());
- res.trade.trade_side = e_side_from_str(upper(feed.at("direction").s()));
- res.trade.trade_time = from_date(feed.get("TS").ms());
- res.symbol = res.trade.symbol;
- res.event_time = from_date(feed.get("event_time").s());
- return res;
- }
- ws_part_depth_event lbank_spot_api::_part_depth_filler(field_t&& feed) {
- ws_part_depth_event res;
- res.type = e_stream::PART_DEPTH;
- res.depth.symbol = &members_.symbols[feed.at("pair").s()];
- res.depth.version = 0; // TODO: ???
- res.depth.asks.resize(feed.at("asks").size());
- res.depth.bids.resize(feed.at("bids").size());
- for (size_t i = 0; i < feed["asks"].size(); ++i) {
- res.depth.asks[i].price = res.depth.symbol->make_price(feed["asks"][i][0].f());
- res.depth.asks[i].quantity = res.depth.symbol->make_quantity(feed["asks"][i][1].f());
- }
- for (size_t i = 0; i < feed["bids"].size(); ++i) {
- res.depth.bids[i].price = res.depth.symbol->make_price(feed["bids"][i][0].f());
- res.depth.bids[i].quantity = res.depth.symbol->make_quantity(feed["bids"][i][1].f());
- }
- res.symbol = res.depth.symbol;
- res.event_time = from_date(feed.get("event_time").ms());
- return res;
- }
- ws_account_order_event lbank_spot_api::_account_order_filler(field_t&& feed) {
- ws_account_order_event res;
- res.type = e_stream::ACCOUNT_ORDER;
- res.symbol = &members_.symbols[feed.get("symbol").s()];
- res.order.symbol = res.symbol;
- res.order.status = _e_order_status_from_str(feed.get("orderStatus").s());
- res.order.side = (feed.get("type").s()[0] == 'b' ? e_side::BUY : e_side::SELL);
- res.order.type = _e_order_type_from_str(feed.get("type").s());
- if (res.order.type == e_order_type::MARKET) {
- res.order.price = res.symbol->make_price(feed.get("price").s());
- } else {
- res.order.price = res.symbol->make_price(feed.get("orderPrice").s());
- }
- res.order.quantity = res.symbol->make_quantity(feed.get("amount").s()); // TODO: amount или quantity все-таки?
- res.order.filled_quantity = res.order.quantity - res.symbol->make_quantity(feed.get("remainAmt").s());
- res.order.update_time = feed.get("updateTime").i();
- res.event_time = res.order.update_time;
- res.order.client_order_id = 0; // TODO
- return res;
- }
- ws_account_balance_event lbank_spot_api::_account_balance_filler(field_t&& feed) {
- ws_account_balance_event res;
- res.type = e_stream::ACCOUNT_BALANCE;
- res.event_time = feed.get("time").i();
- res.balance.update_time = res.event_time;
- res.balance.asset = feed.at("assetCode").s();
- res.balance.free = std::stod(feed.at("free").s());
- res.balance.locked = std::stod(feed.at("l").s());
- return res;
- }
- result_t<std::vector<ws_event>, e_stream_error> lbank_spot_api::_feed_process(const char* feed_ptr) {
- std::cerr << "_feed_process: " << 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("ping")) {
- field_t pong_response;
- pong_response["action"] = "pong";
- pong_response["pong"] = data["ping"];
- core_.ws_send_without_handle(ws_client_, pong_response.serialize());
- res.set_error(e_stream_error::NO_STREAM);
- return res;
- }
- std::string type = data["type"].s();
- if (type != "assetUpdate") {
- data[type]["pair"] = data["pair"];
- data[type]["event_time"] = data["TS"];
- data = data[type];
- } else {
- data = data["data"];
- }
- if (type == "trade") {
- res.value().resize(1);
- res.value()[0].type = e_stream::TRADE;
- auto new_event = _trade_filler(std::move(data));
- res.value()[0].set_symbol(new_event.symbol);
- res.value()[0].set(std::move(new_event));
- return res;
- } else if (type == "depth") {
- res.value().resize(1);
- res.value()[0].type = e_stream::PART_DEPTH;
- auto new_event = _part_depth_filler(std::move(data));
- res.value()[0].set_symbol(new_event.symbol);
- res.value()[0].set(std::move(new_event));
- return res;
- } else if (type == "orderUpdate") {
- res.value().resize(1);
- res.value()[0].type = e_stream::ACCOUNT_ORDER;
- auto new_event = _account_order_filler(std::move(data));
- res.value()[0].set_symbol(new_event.symbol);
- res.value()[0].set(std::move(new_event));
- return res;
- } else if (type == "assetUpdate") {
- res.value().resize(1);
- res.value()[0].type = e_stream::ACCOUNT_BALANCE;
- auto new_event = _account_balance_filler(std::move(data));
- res.value()[0].set_symbol(new_event.symbol);
- res.value()[0].set(std::move(new_event));
- return res;
- }
- std::cerr << "_feed_process unknown stream: " << type << '\n';
- res.set_error(e_stream_error::NO_STREAM);
- return res;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement