Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <execution/execution.hpp>
- using namespace mira;
- void execution_config_t::init_additional(const field_t& args) {
- if (args.count("calculate_init_position")) {
- std::string val = args.at("calculate_init_position").s();
- this->calculate_init_position = (val == "true" || std::stoi(val));
- }
- if (args.count("cancel_on_start")) {
- std::string val = args.at("cancel_on_start").s();
- if (val == "true" || std::stoi(val)) {
- this->cancel_on_start = "true";
- if (args.count("cancel_group")) {
- this->cancel_group = e_order_group_from_str(args.at("cancel_group").s());
- }
- }
- this->calculate_init_position = (val == "true" || std::stoi(val));
- }
- if (args.count("delay_between_cancel_and_new")) {
- this->delay_between_cancel_and_new = args.at("delay_between_cancel_and_new").i();
- }
- if (args.count("orders_update_cooldown")) {
- this->orders_update_cooldown = args.at("orders_update_cooldown").i();
- }
- if (args.count("path_to_position_file")) {
- this->path_to_position_file = args.at("path_to_position_file").s();
- }
- if (args.count("print_ws_events")) {
- std::string val = args.at("print_ws_events").s();
- this->print_ws_events = (val == "true" || std::stoi(val));
- }
- if (args.count("use_tp_market")) {
- std::string val = args.at("use_tp_market").s();
- this->use_tp_market = (val == "true" || std::stoi(val));
- }
- if (args.count("close_pos_on_cd")) {
- this->close_pos_on_cd = args.at("close_pos_on_cd").i();
- }
- }
- void Execution::_order_storage_updater() {
- auto update_routine = [this] () {
- auto orders = config_.api->get_open_orders(config_.symbol);
- std::lock_guard<std::mutex> locker(orders_.locker);
- orders_.limit_orders.clear();
- orders_.market_orders.clear();
- orders_.algo_orders.clear();
- for (auto order : orders.value()) {
- if (order.type == e_order_type::LIMIT) {
- orders_.limit_orders[order.client_order_id].order = order;
- } else if (order.type != e_order_type::MARKET) {
- orders_.algo_orders[order.client_order_id].order = order;
- }
- }
- };
- update_routine();
- std::thread {[this, update_routine] () {
- std::this_thread::sleep_for(std::chrono::seconds(config_.orders_update_cooldown));
- update_routine();
- }}.detach();
- }
- Execution::Execution(const execution_config_t& config, const field_t& trader_args) : config_(config) {
- if (trader_args.count("execution")) {
- config_.init_additional(trader_args.at("execution"));
- }
- config_.shared_state->add_execution_getter(this, config_.symbol);
- stream_description_t description;
- description.stream = e_stream::ACCOUNT_ORDER;
- config_.api->subscribe(description, this, config_.symbol);
- description.stream = e_stream::ACCOUNT_TRADE;
- config_.api->subscribe(description, this, config_.symbol);
- position_info_.position_order.symbol = position_info_.position_trade.symbol = config_.symbol; // TODO внести в конструктор
- if (config_.path_to_position_file != "") {
- if (config_.calculate_init_position) {
- _init_position();
- }
- }
- if (e_market_account_type(config_.symbol->api->market) == e_account_type::FUTURES) {
- description.stream = e_stream::ACCOUNT_POSITION;
- config_.api->subscribe(description, this, config_.symbol);
- position_info_.reset_position(config_.api->get_position(config_.symbol).value());
- }
- if (config_.cancel_on_start) {
- config_.api->cancel_open_orders(config_.symbol, config_.cancel_group);
- }
- _order_storage_updater();
- }
- void Execution::_init_position() {
- position_info_.position_file.open(config_.path_to_position_file, std::ios::app);
- if (!position_info_.position_file.is_open()) {
- config_.logger->log("can't open position file!");
- exit(EXIT_FAILURE);
- }
- if (std::filesystem::file_size(config_.path_to_position_file) == 0) {
- config_.logger->log("position file file is empty");
- } else {
- std::string all_string = "", buf;
- std::ifstream config(config_.path_to_position_file);
- while (config >> buf) {
- all_string += buf;
- }
- config_.logger->log("initial position file content: " + all_string);
- std::cout << "initial position file content: " + all_string << '\n';
- auto position_file_content = field_t::deserialize(all_string);
- // std::ostringstream position_stream;
- // position_stream << position_info_.position_file.rdbuf();
- // auto prev_position = field_t::deserialize(position_stream.str());
- position_info_.position_order = position_info_.position_trade = position_t {
- .base_quantity = position_file_content.at("baseQuantity").f(),
- .entry_price = position_file_content.at("entryPrice").f(),
- .position_quote = position_file_content.at("quotePosition").f(),
- .symbol = config_.symbol
- };
- auto previous_trades = trade_t {
- .price = config_.symbol->make_price(position_file_content.at("entryPrice").f()),
- .quantity = config_.symbol->make_quantity(std::abs(position_file_content.at("baseQuantity").f())),
- .symbol = config_.symbol,
- .trade_side = position_file_content.at("baseQuantity").f() > 0 ? e_side::BUY : e_side::SELL,
- .trade_time = get_timestamp()
- };
- auto prev_base_qty = position_file_content.at("baseBalance").f();
- auto prev_quote_amount = position_file_content.at("quoteBalance").f();
- auto res_cur_base_qty = config_.api->get_account().value().balances.at(config_.symbol->base);
- auto res_cur_quote_amount = config_.api->get_account().value().balances.at(config_.symbol->quote);
- auto cur_base_qty = res_cur_base_qty.free + res_cur_base_qty.locked;
- auto cur_quote_amount = res_cur_quote_amount.free + res_cur_quote_amount.locked;
- position_info_.open_position(previous_trades, 0);
- position_info_.open_position(previous_trades, 1);
- if (prev_base_qty != cur_base_qty) { // TODO: случай когда они равны, но трейды были
- config_.logger->log("there were trades when we shutdown");
- double shutdown_average_price = std::abs((cur_quote_amount - prev_quote_amount) / (prev_base_qty - cur_base_qty)); // вроде abs не нужен, но на всякий случай
- auto shutdown_trade = trade_t {
- .price = config_.symbol->make_price(shutdown_average_price),
- .quantity = config_.symbol->make_quantity(std::abs(prev_base_qty - cur_base_qty)),
- .symbol = config_.symbol,
- .trade_side = (prev_base_qty - cur_base_qty) > 0 ? e_side::SELL : e_side::BUY,
- .trade_time = get_timestamp()
- };
- position_info_.open_position(shutdown_trade, 0);
- position_info_.open_position(shutdown_trade, 1);
- }
- }
- }
- void Execution::_process_self_trade(const order_self_trade_event& event) {
- order_request_t req;
- req.symbol = event.symbol;
- req.price = req.symbol->make_price(event.price);
- req.quantity = req.symbol->make_quantity(event.quantity);
- req.type = e_order_type::LIMIT;
- req.post_only = false;
- req.side = e_side::BUY;
- _safe_new_order(req);
- req.side = e_side::SELL;
- _safe_new_order(req);
- }
- void Execution::_process_limit_grid(const order_limit_grid_event& event) {
- std::unordered_map<int64_t, int64_t> requests;
- std::unordered_map<int64_t, order_appendix_t> appendices;
- for (auto req : event.asks) {
- config_.logger->log(req.price, e_severity_level::DEBUG, "in _process_limit_grid");
- config_.logger->log(req.quantity, e_severity_level::DEBUG, "in _process_limit_grid");
- requests[config_.symbol->make_price(req.price).to_scaled()] += config_.symbol->make_quantity(req.quantity).to_scaled();
- appendices[config_.symbol->make_price(req.price).to_scaled()] = req.appendix;
- }
- for (auto req : event.bids) {
- config_.logger->log(req.price, e_severity_level::DEBUG, "in _process_limit_grid");
- config_.logger->log(req.quantity, e_severity_level::DEBUG, "in _process_limit_grid");
- // config_.logger->log("before req price " + std::to_string(req.price));
- // config_.logger->log("precised " + config_.symbol->make_price(req.price));
- // config_.logger->log("scaled " + config_.symbol->make_price(req.price).to_scaled());
- requests[config_.symbol->make_price(req.price).to_scaled()] -= config_.symbol->make_quantity(req.quantity).to_scaled();
- appendices[config_.symbol->make_price(req.price).to_scaled()] = req.appendix;
- }
- std::vector<std::pair<order_request_t, order_appendix_t>> create_requests;
- std::vector<size_t> to_cancel;
- {
- std::lock_guard<std::mutex> lock(orders_.locker);
- for (const auto& [id, extended_order] : orders_.limit_orders) {
- int64_t cq = (extended_order.order.side == e_side::BUY ? -1 : 1) * extended_order.order.quantity.to_scaled();
- auto it = requests.find(extended_order.order.price.to_scaled());
- if (it == requests.end() || it->second != cq) {
- to_cancel.push_back(id);
- } else {
- requests.erase(it);
- }
- }
- for (auto [p, q] : requests) {
- if (std::fabs(q) * p < config_.symbol->min_notional) {
- continue;
- }
- order_request_t req;
- req.symbol = config_.symbol;
- req.type = e_order_type::LIMIT;
- req.side = (q < 0 ? e_side::BUY : e_side::SELL);
- req.price = config_.symbol->make_price_from_scaled(p);
- req.quantity = config_.symbol->make_quantity_from_scaled(std::fabs(q));
- req.post_only = true;
- config_.logger->log(req, e_severity_level::DEBUG, "@#*&* ");
- create_requests.push_back({req, appendices[p]});
- }
- }
- config_.logger->log("csize: " + std::to_string(to_cancel.size()));
- for (auto id : to_cancel) {
- _safe_cancel_order(id, {}, e_order_type::LIMIT);
- }
- if (config_.delay_between_cancel_and_new) {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- }
- for (auto& [req, app] : create_requests) {
- _safe_new_order(req, app);
- }
- }
- void Execution::_process_taker_buy(const order_taker_buy_event& event) {
- order_request_t req;
- req.symbol = event.symbol;
- req.type = e_order_type::MARKET;
- req.side = e_side::BUY;
- req.reduce_only = event.reduce_only;
- if (event.quantity) {
- req.quantity = config_.symbol->make_quantity(event.quantity);
- } else {
- req.amount = event.amount;
- }
- _safe_new_order(req);
- }
- void Execution::_process_taker_sell(const order_taker_sell_event& event) {
- order_request_t req;
- req.symbol = event.symbol;
- req.type = e_order_type::MARKET;
- req.side = e_side::SELL;
- req.reduce_only = event.reduce_only;
- req.quantity = config_.symbol->make_quantity(event.quantity);
- _safe_new_order(req);
- }
- void Execution::_process(const order_event& event) {
- config_.logger->log(event, e_severity_level::INFO);
- if (event.type == e_order_event::SELF_TRADE) {
- _process_self_trade(event.get<order_self_trade_event>());
- } else if (event.type == e_order_event::LIMIT_GRID) {
- config_.logger->log("LIMIT GRID");
- _process_limit_grid(event.get<order_limit_grid_event>());
- } else if (event.type == e_order_event::TAKER_BUY) {
- _process_taker_buy(event.get<order_taker_buy_event>());
- } else if (event.type == e_order_event::TAKER_SELL) {
- _process_taker_sell(event.get<order_taker_sell_event>());
- }
- }
- fill_order_event Execution::_process_account_order(const ws_account_order_event& event) {
- if (event.order.type == e_order_type::LIMIT || event.order.type == e_order_type::MARKET) {
- orders_.locker.lock();
- auto& cur_storage = (event.order.type == e_order_type::LIMIT ? orders_.limit_orders : orders_.market_orders);
- if (event.order.type == e_order_type::LIMIT) {
- config_.logger->log("limit");
- } else {
- config_.logger->log("market");
- }
- auto old_it = cur_storage.find(event.order.client_order_id);
- config_.logger->log(event.order, e_severity_level::DEBUG, "Event order: ");
- if (old_it != cur_storage.end()) { // такой ордер уже был
- order_t& old_order = old_it->second.order;
- config_.logger->log(old_order, e_severity_level::DEBUG, "old order: ");
- if (!old_order.filled_quantity.initialized()) {
- old_order.filled_quantity = old_order.symbol->make_quantity(0);
- }
- precised_float piece = event.order.filled_quantity - old_order.filled_quantity;
- auto debug1 = event.order.filled_quantity.to_double();
- auto debug2 = event.order.price.to_double();
- auto debug3 = old_order.filled_quantity.to_double();
- auto debug4 = old_order.price.to_double();
- double quote_piece = event.order.filled_quantity.to_double() * event.order.price.to_double() - old_order.filled_quantity.to_double() * old_order.price.to_double();
- if (quote_piece) {
- trade_t trade{
- .price = event.order.price,
- .quantity = piece,
- .symbol = event.symbol,
- .trade_side = event.order.side,
- .trade_time = event.order.update_time
- };
- position_info_.open_position(trade, 1);
- }
- if (order_cycle_ended(event.order.status)) {
- config_.logger->log("erase");
- cur_storage.erase(old_it);
- } else {
- old_order = event.order;
- }
- std::vector<std::pair<size_t, e_order_type>> to_cancel;
- for (auto& [id, ext_ord] : orders_.algo_orders) {
- auto& ord = ext_ord.order;
- bool side = (ord.side == e_side::BUY) ^ (ord.type == e_order_type::STOP_LOSS);
- if ((side && (position_info_.get_position().base_quantity < 0)) ||
- (!side && (position_info_.get_position().base_quantity > 0))) {
- continue;
- }
- to_cancel.push_back({id, ord.type});
- }
- std::vector<std::pair<std::string, e_order_type>> to_cancel_order_id;
- for (auto& [id, ext_ord] : orders_.order_id_algo_orders) {
- auto& ord = ext_ord.order;
- bool side = (ord.side == e_side::BUY) ^ (ord.type == e_order_type::STOP_LOSS);
- if ((side && (position_info_.get_position().base_quantity < 0)) ||
- (!side && (position_info_.get_position().base_quantity > 0))) {
- continue;
- }
- to_cancel_order_id.push_back({id, ord.type});
- }
- orders_.locker.unlock();
- for (auto [id, type] : to_cancel) {
- _safe_cancel_order(id, {}, type);
- }
- for (auto [id, type] : to_cancel_order_id) {
- _safe_cancel_order(0, id, type);
- }
- return fill_order_event(piece.to_double(), quote_piece, position_info_.get_position(), event.order);
- }
- orders_.locker.unlock();
- } else if (event.order.type == e_order_type::STOP_LOSS ||
- event.order.type == e_order_type::TAKE_PROFIT) {
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (event.order.client_order_id) {
- auto old_it = orders_.algo_orders.find(event.order.client_order_id);
- if (old_it != orders_.algo_orders.end()) {
- order_t& old_order = old_it->second.order;
- if (order_cycle_ended(old_order.status)) {
- orders_.algo_orders.erase(old_it);
- } else {
- old_order = event.order;
- }
- return fill_order_event(0, 0, position_info_.get_position(), event.order);
- }
- } else {
- auto old_it = orders_.order_id_algo_orders.find(event.order.order_id);
- if (old_it != orders_.order_id_algo_orders.end()) {
- order_t& old_order = old_it->second.order;
- if (order_cycle_ended(old_order.status)) {
- orders_.order_id_algo_orders.erase(old_it);
- } else {
- old_order = event.order;
- }
- return fill_order_event(0, 0, position_info_.get_position(), event.order);
- } else {
- orders_.order_id_algo_orders[event.order.order_id].order = event.order;
- }
- }
- }
- return fill_order_event(event.order.filled_quantity.to_double(), event.order.filled_quantity.to_double() * event.order.price.to_double(), position_info_.get_position(), event.order);
- }
- fill_order_event Execution::_process_account_trade(const ws_account_trade_event& event) {
- orders_.locker.lock();
- double piece = event.trade.quantity.to_double();
- double quote_piece = event.trade.price.to_double();
- trade_t trade = event.trade;
- trade.trade_side = (trade.trade_side == e_side::BUY ? e_side::SELL : e_side::BUY);
- position_info_.open_position(trade, 0);
- std::vector<std::pair<size_t, e_order_type>> to_cancel;
- for (auto& [id, ext_ord] : orders_.algo_orders) {
- auto& ord = ext_ord.order;
- bool side = (ord.side == e_side::BUY) ^ (ord.type == e_order_type::STOP_LOSS);
- if ((side && (position_info_.get_position().base_quantity < 0)) ||
- (!side && (position_info_.get_position().base_quantity > 0))) {
- continue;
- }
- to_cancel.push_back({id, ord.type});
- }
- std::vector<std::pair<std::string, e_order_type>> to_cancel_order_id;
- for (auto& [id, ext_ord] : orders_.order_id_algo_orders) {
- auto& ord = ext_ord.order;
- bool side = (ord.side == e_side::BUY) ^ (ord.type == e_order_type::STOP_LOSS);
- if ((side && (position_info_.get_position().base_quantity < 0)) ||
- (!side && (position_info_.get_position().base_quantity > 0))) {
- continue;
- }
- to_cancel_order_id.push_back({id, ord.type});
- }
- orders_.locker.unlock();
- for (auto [id, type] : to_cancel) {
- _safe_cancel_order(id, {}, type);
- }
- for (auto [id, type] : to_cancel_order_id) {
- _safe_cancel_order(0, id, type);
- }
- return fill_order_event(piece, quote_piece, position_info_.get_position(), {});
- }
- fill_order_event Execution::_process_account_position(const ws_account_position_event& event) {
- orders_.locker.lock();
- position_info_.reset_position(event.position);
- if (std::fabs(event.position.base_quantity) < 1e-6) {
- position_info_.not_null_time = 0;
- } else if (!position_info_.not_null_time) {
- position_info_.not_null_time = event.position.update_time;
- }
- std::vector<std::pair<size_t, e_order_type>> to_cancel;
- for (auto& [id, ext_ord] : orders_.algo_orders) {
- auto& ord = ext_ord.order;
- bool side = (ord.side == e_side::BUY) ^ (ord.type == e_order_type::STOP_LOSS);
- if ((side && (position_info_.get_position().base_quantity < 0)) ||
- (!side && (position_info_.get_position().base_quantity > 0))) {
- continue;
- }
- to_cancel.push_back({id, ord.type});
- }
- std::vector<std::pair<std::string, e_order_type>> to_cancel_order_id;
- for (auto& [id, ext_ord] : orders_.order_id_algo_orders) {
- auto& ord = ext_ord.order;
- bool side = (ord.side == e_side::BUY) ^ (ord.type == e_order_type::STOP_LOSS);
- if ((side && (position_info_.get_position().base_quantity < 0)) ||
- (!side && (position_info_.get_position().base_quantity > 0))) {
- continue;
- }
- to_cancel_order_id.push_back({id, ord.type});
- }
- orders_.locker.unlock();
- for (auto [id, type] : to_cancel) {
- _safe_cancel_order(id, {}, type);
- }
- for (auto [id, type] : to_cancel_order_id) {
- _safe_cancel_order(0, id, type);
- }
- return fill_order_event(0, 0, position_info_.get_position(), {}, event.rpnl);
- }
- fill_event Execution::_process(const ws_event& event) {
- if (config_.print_ws_events) {
- std::cout << event << '\n';
- }
- config_.logger->log(event, e_severity_level::INFO);
- fill_event res;
- if (event.type == e_stream::ACCOUNT_ORDER) {
- auto account_order_event = event.get<ws_account_order_event>();
- res.set(_process_account_order(account_order_event));
- } else if (event.type == e_stream::ACCOUNT_TRADE) {
- auto account_trade_event = event.get<ws_account_trade_event>();
- res.set(_process_account_trade(account_trade_event));
- } else if (event.type == e_stream::ACCOUNT_POSITION) {
- auto account_position_event = event.get<ws_account_position_event>();
- res.set(_process_account_position(account_position_event));
- } else if (event.type == e_stream::TICK) {
- res.type = e_fill_event::TICK;
- }
- res.set_symbol(event.symbol);
- if (config_.close_pos_on_cd && position_info_.not_null_time && position_info_.not_null_time + config_.close_pos_on_cd < get_timestamp()) {
- position_t cur_pos = position_info_.get_position();
- if (cur_pos.base_quantity) {
- order_request_t req;
- req.symbol = cur_pos.symbol;
- req.quantity = req.symbol->make_quantity(cur_pos.base_quantity);
- req.amount = cur_pos.position_quote;
- req.side = (cur_pos.base_quantity > 0 ? e_side::SELL : e_side::BUY);
- req.type = e_order_type::MARKET;
- req.reduce_only = true;
- position_info_.not_null_time = get_timestamp();
- _safe_new_order(req);
- }
- }
- return res;
- }
- void Execution::_safe_new_order(order_request_t req, order_appendix_t app) {
- req.client_order_id = _gen_client_order_id();
- order_t new_ord;
- new_ord.symbol = req.symbol;
- new_ord.type = req.type;
- new_ord.side = req.side;
- new_ord.client_order_id = *req.client_order_id;
- if (req.price.has_value()) {
- new_ord.price = *req.price;
- }
- if (req.quantity.has_value()) {
- new_ord.quantity = *req.quantity;
- }
- if (req.stop_price.has_value()) {
- new_ord.stop_price = *req.stop_price;
- }
- new_ord.post_only = req.post_only;
- new_ord.reduce_only = req.reduce_only;
- new_ord.status = e_order_status::PENDING;
- if (req.symbol->api->market == e_market::BYBIT_FUTURES && app.tp_bips) {
- double bips = *app.tp_bips * 1e-4;
- double stop_price = req.price->to_double() * (1 + (req.side == e_side::BUY ? 1 : -1) * bips);
- req.stop_price = req.symbol->make_price(stop_price);
- req.algo_limit = !config_.use_tp_market;
- }
- {
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (req.type == e_order_type::LIMIT) {
- orders_.limit_orders[*req.client_order_id] = {new_ord, app};
- } else if (req.type == e_order_type::MARKET) {
- orders_.market_orders[*req.client_order_id] = {new_ord, app};
- } else {
- orders_.algo_orders[*req.client_order_id] = {new_ord, app};
- }
- }
- std::thread {[req, this] () {
- config_.logger->log(req, e_severity_level::DEBUG, "! new");
- auto res = config_.api->new_order(req);
- config_.logger->log(res, e_severity_level::DEBUG, "? new");
- if (!res) {
- config_.logger->log(res, e_severity_level::ERROR, "new order error: request=" + to_string(req));
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (req.type == e_order_type::LIMIT) {
- orders_.limit_orders.erase(*req.client_order_id);
- } else if (req.type == e_order_type::MARKET) {
- orders_.market_orders.erase(*req.client_order_id);
- } else{
- orders_.algo_orders.erase(*req.client_order_id);
- }
- }
- }}.detach();
- }
- void Execution::_safe_cancel_order(size_t client_order_id, std::optional<std::string> order_id, e_order_type type) {
- extended_order_t prev_ord;
- {
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (type == e_order_type::LIMIT) {
- auto it = orders_.limit_orders.find(client_order_id);
- if (it == orders_.limit_orders.end()) {
- return;
- }
- prev_ord = it->second;
- } else {
- if (!order_id) {
- auto it = orders_.algo_orders.find(client_order_id);
- if (it == orders_.algo_orders.end()) {
- return;
- }
- prev_ord = it->second;
- } else {
- auto it = orders_.order_id_algo_orders.find(*order_id);
- if (it == orders_.order_id_algo_orders.end()) {
- return;
- }
- prev_ord = it->second;
- orders_.order_id_algo_orders.erase(it);
- }
- }
- }
- std::thread {[client_order_id, order_id, prev_ord, this] () {
- config_.logger->log(prev_ord.order, e_severity_level::DEBUG, "! cancel");
- auto res = config_.api->cancel_order(prev_ord.order.symbol, (order_id ? std::optional<size_t>() : prev_ord.order.client_order_id), order_id);
- config_.logger->log(res, e_severity_level::DEBUG, "? cancel");
- if (!res) {
- config_.logger->log(res, e_severity_level::ERROR, "cancel order error");
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (prev_ord.order.type == e_order_type::LIMIT) {
- orders_.limit_orders[client_order_id] = prev_ord;
- } else {
- if (!order_id) {
- orders_.algo_orders[client_order_id] = prev_ord;
- } else {
- orders_.order_id_algo_orders[*order_id] = prev_ord;
- }
- }
- }
- }}.detach();
- }
- result_t<order_t, e_execution_error> ExecutionGetter::get_order(size_t client_order_id) const {
- result_t<order_t, e_execution_error> res;
- auto& orders_storage = exec_->orders_;
- std::lock_guard<std::mutex> locker(orders_storage.locker);
- auto it = orders_storage.limit_orders.find(client_order_id);
- if (it != orders_storage.limit_orders.end()) {
- res.set_value(it->second.order);
- return res;
- }
- it = orders_storage.algo_orders.find(client_order_id);
- if (it != orders_storage.algo_orders.end()) {
- res.set_value(it->second.order);
- return res;
- }
- res.set_error(e_execution_error::ORDER_NOT_FOUND);
- return res;
- }
- float_limit_grid_t ExecutionGetter::get_limit_grid() const {
- float_limit_grid_t res;
- auto& orders_storage = exec_->orders_;
- std::lock_guard<std::mutex> locker(orders_storage.locker);
- for (auto& [id, ext_ord] : orders_storage.limit_orders) {
- auto& ord = ext_ord.order;
- if (ord.side == e_side::BUY) {
- res.bid_orders[ord.price.to_double()] = (ord.quantity - ord.filled_quantity).to_double();
- } else {
- res.ask_orders[ord.price.to_double()] = (ord.quantity - ord.filled_quantity).to_double();
- }
- }
- return res;
- }
- void Execution::_position_info_t::open_position(const trade_t& trade, bool is_order) {
- std::lock_guard lock(locker);
- std::cerr << "$$$ " << trade << '\n';
- exec->config_.logger->log(trade, e_severity_level::INFO, "Open position: ");
- position_t position = (is_order ? position_order : position_trade);
- int prev_pos_sgn = (position.base_quantity > 0);
- if (trade.trade_side == e_side::BUY) {
- position.position_quote += trade.price.to_double() * trade.quantity.to_double();
- position.base_quantity += trade.quantity.to_double();
- }
- if (trade.trade_side == e_side::SELL) {
- position.position_quote -= trade.price.to_double() * trade.quantity.to_double();
- position.base_quantity -= trade.quantity.to_double();
- }
- int cur_pos_sgn = (position.base_quantity > 0);
- if (position.base_quantity == 0) {
- position.position_quote = 0;
- position.entry_price = 0;
- } else {
- if (position.position_quote != 0) { // Пример: BUY (p1, q1) = (1, 1) -> SELL (p2, q2) = (1.25, 0.8) -> q_remain = 0.2 but position = 0
- if (prev_pos_sgn == cur_pos_sgn) { // случай, когда мы усредняемся по цене
- position.entry_price = std::abs(position.position_quote / position.base_quantity);
- } else { // случай, когда наша позиция сменила сторону (например, с SELL на BUY)
- position.entry_price = trade.price.to_double();
- }
- }
- }
- position.update_time = trade.trade_time;
- if (is_order) {
- position_order = position;
- } else {
- position_trade = position;
- }
- exec->config_.logger->log(position, e_severity_level::INFO, "new position");
- if (exec->config_.path_to_position_file != "") {
- if (exec->position_info_.position_file.is_open()) {
- exec->config_.logger->log("writing to volume price file");
- const auto& balances = exec->config_.api->get_account().value().balances;
- auto base_balance = balances.at(exec->config_.symbol->base);
- auto quote_balance = balances.at(exec->config_.symbol->quote);
- std::filesystem::resize_file(exec->config_.path_to_position_file, 0);
- exec->position_info_.position_file.seekp(0);
- // std::cout << "{\"baseQuantity\": \"" + std::to_string(position.base_quantity) + "\",\n" +
- // "\"entryPrice\": \"" + std::to_string(position.entry_price) + "\",\n" +
- // "\"quotePosition\": \"" + std::to_string(position.position_quote) + "\",\n" +
- // "\"baseBalance\": \"" + std::to_string(base_balance.locked + base_balance.free) + "\",\n" +
- // "\"quoteBalance\": \"" + std::to_string(quote_balance.locked + quote_balance.free) + "\",\n" + "}";
- exec->position_info_.position_file <<
- "{\"baseQuantity\": \"" + std::to_string(position.base_quantity) + "\",\n" <<
- "\"entryPrice\": \"" + std::to_string(position.entry_price) + "\",\n" <<
- "\"quotePosition\": \"" + std::to_string(position.position_quote) + "\",\n" <<
- "\"baseBalance\": \"" + std::to_string(base_balance.locked + base_balance.free) + "\",\n" <<
- "\"quoteBalance\": \"" + std::to_string(quote_balance.locked + quote_balance.free) + "\",\n" << "}" << std::flush;
- } else {
- exec->config_.logger->log("execution position file is not open but has non zero path");
- }
- }
- }
- void Execution::_position_info_t::reset_position(const position_t& position) {
- std::lock_guard lock(locker);
- position_order = position;
- position_trade = position;
- exec->config_.logger->log(position, e_severity_level::INFO, "new position");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement