Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <execution/execution.hpp>
- using namespace mira;
- Execution::Execution(const execution_config_t& config) : config_(config) {
- config_.shared_state->add_execution_getter(this, config_.symbol);
- stream_description_t description;
- description.stream = e_stream::ACCOUNT_ORDER;
- description.args["symbol"] = config_.symbol->symbol;
- {
- auto orders = config_.api->get_open_orders(config_.symbol);
- std::lock_guard<std::mutex> locker(orders_.locker);
- for (auto order : orders.value()) {
- if (!order.client_order_id) {
- continue;
- }
- if (order.type == e_order_type::LIMIT) {
- orders_.limit_orders[order.client_order_id] = order;
- } else {
- orders_.algo_orders[order.client_order_id] = order;
- }
- }
- }
- config_.api->subscribe(description, this);
- __init_position();
- }
- void Execution::__update_position_with_open_orders() {
- position_info_.open_orders_file.open(config_.path_to_open_orders_file);
- if (!position_info_.open_orders_file.is_open()) {
- std::cerr << "can't open open_orders file!\n";
- exit(EXIT_FAILURE);
- }
- auto orders = config_.api->get_open_orders(config_.symbol);
- std::ostringstream orders_stream;
- orders_stream << position_info_.open_orders_file.rdbuf();
- auto prev_orders_deserialized = field_t::deserialize(orders_stream.str());
- std::vector<order_t> prev_orders;
- for (size_t i = 0; i < prev_orders_deserialized.size(); ++i) {
- prev_orders[i].client_order_id = prev_orders_deserialized[i].get("clientOrderId").i();
- prev_orders[i].price = config_.symbol->make_price(prev_orders_deserialized[i].get("price").f());
- prev_orders[i].quantity = config_.symbol->make_price(prev_orders_deserialized[i].get("origQty").f());
- prev_orders[i].filled_quantity = config_.symbol->make_price(prev_orders_deserialized[i].get("executedQty").f());
- prev_orders[i].side = prev_orders_deserialized[i].get("side").s() == "SELL" ? e_side::SELL : e_side::BUY;
- std::string status = prev_orders_deserialized[i].get("status").s();
- if (status == "NEW") {
- prev_orders[i].status = e_order_status::NEW;
- } else if (status == "PARTIALLY_FILLED") {
- prev_orders[i].status = e_order_status::PARTIALLY_FILLED;
- } else if (status == "FILLED") {
- prev_orders[i].status = e_order_status::FILLED;
- } else if (status == "CANCELED" || status == "PARTIALLY_CANCELED") {
- prev_orders[i].status = e_order_status::CANCELED;
- } else {
- throw std::runtime_error("previous order doesn't have status field");
- }
- }
- for (const auto& prev_order : prev_orders) {
- for (const auto& order : orders.value()) {
- if (prev_order.client_order_id == order.client_order_id) {
- if (prev_order.filled_quantity != order.filled_quantity) {
- trade_t trade{
- .price = prev_order.price,
- .quantity = order.filled_quantity - prev_order.filled_quantity,
- .trade_side = prev_order.side
- };
- position_info_.position.open_position(trade);
- }
- break;
- }
- }
- // т.е. ордер не найден -> исполнен был полностью
- trade_t trade{
- .price = prev_order.price,
- .quantity = prev_order.quantity - prev_order.filled_quantity,
- .trade_side = prev_order.side
- };
- position_info_.position.open_position(trade);
- }
- }
- void Execution::__init_position() {
- position_info_.position_file.open(config_.path_to_position_file);
- if (!position_info_.position_file.is_open()) {
- std::cerr << "can't open position file!\n";
- exit(EXIT_FAILURE);
- }
- std::ostringstream position_stream;
- position_stream << position_info_.position_file.rdbuf();
- auto prev_position = field_t::deserialize(position_stream.str());
- position_info_.position = position_t {
- .base_quantity = prev_position.get("baseQuantity").f(),
- .entry_price = prev_position.get("entryPrice").f(),
- .position_quote = prev_position.get("quotePosition").f(),
- .symbol = config_.symbol
- };
- auto prev_base_qty = prev_position.get("baseBalance").f();
- auto prev_quote_amount = prev_position.get("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;
- double shutdown_average_price = (cur_quote_amount - prev_quote_amount) / (prev_base_qty - cur_base_qty);
- 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)),
- .trade_side = (prev_base_qty - cur_base_qty) > 0 ? e_side::SELL : e_side::BUY
- };
- position_info_.position.open_position(shutdown_trade);
- __update_position_with_open_orders();
- }
- void Execution::__process_limit_grid(const order_limit_grid_event& event) {
- std::unordered_map<size_t, double> requests;
- for (auto [p, q] : event.asks) {
- requests[config_.symbol->make_price(p).to_scaled()] += q;
- }
- for (auto [p, q] : event.bids) {
- requests[config_.symbol->make_price(p).to_scaled()] -= q;
- }
- std::vector<order_request_t> create_requests;
- std::vector<size_t> to_cancel;
- {
- std::lock_guard<std::mutex> lock(orders_.locker);
- for (const auto& [id, order] : orders_.limit_orders) {
- double cq = (order.side == e_side::BUY ? -1 : 1) * order.quantity.to_double();
- auto it = requests.find(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(std::fabs(q));
- req.client_order_id = __gen_client_order_id();
- req.post_only = true;
- std::cerr << "@#*&* " << req << '\n';
- create_requests.push_back(req);
- }
- }
- std::cerr << "csize: " << to_cancel.size() << '\n';
- for (size_t id : to_cancel) {
- __safe_cancel_order(id, e_order_type::LIMIT);
- }
- for (auto& req : create_requests) {
- __safe_new_order(req);
- }
- }
- void Execution::__process_taker_buy(const order_taker_buy_event& event) {
- order_request_t req;
- req.symbol = config_.symbol;
- req.type = e_order_type::MARKET;
- req.side = e_side::BUY;
- *req.amount = event.amount;
- config_.api->new_order(req);
- }
- void Execution::__process_taker_sell(const order_taker_sell_event& event) {
- order_request_t req;
- req.symbol = config_.symbol;
- req.type = e_order_type::MARKET;
- req.side = e_side::SELL;
- req.quantity = config_.symbol->make_quantity(event.quantity);
- config_.api->new_order(req);
- }
- void Execution::__process(const order_event& event) {
- // logger_->log(event, e_severity_level::INFO);
- if (event.type == e_order_event::LIMIT_GRID) {
- std::cerr << "LIMIT_GRID" << '\n';
- __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) {
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (event.order.type == e_order_type::LIMIT) {
- auto old_it = orders_.limit_orders.find(event.order.client_order_id);
- if (old_it != orders_.limit_orders.end()) { // такой ордер уже был
- order_t& old_order = old_it->second;
- if (!old_order.filled_quantity.initialized()) {
- old_order.filled_quantity = old_order.symbol->make_quantity(0);
- }
- auto piece = event.order.filled_quantity - old_order.filled_quantity;
- trade_t trade{
- .price = event.order.price,
- .quantity = piece,
- .symbol = event.order.symbol,
- .trade_side = event.order.side,
- .trade_time = 0
- };
- position_info_.position.open_position(trade);
- if (order_cycle_ended(old_order.status)) {
- orders_.limit_orders.erase(old_it);
- } else {
- old_order = event.order;
- }
- return fill_order_event(event.order, piece.to_double(), position_info_.position);
- }
- } else if (event.order.type == e_order_type::STOP_LOSS ||
- event.order.type == e_order_type::TAKE_PROFIT) {
- 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;
- if (order_cycle_ended(old_order.status)) {
- orders_.algo_orders.erase(old_it);
- } else {
- old_order = event.order;
- }
- return fill_order_event(event.order, 0, position_info_.position);
- }
- } else if (event.order.type == e_order_type::MARKET) {
- trade_t trade{
- .price = event.order.price,
- .quantity = event.order.quantity,
- .symbol = event.order.symbol,
- .trade_side = event.order.side,
- .trade_time = 0
- };
- position_info_.position.open_position(trade);
- }
- return fill_order_event(event.order, event.order.filled_quantity.to_double(), position_info_.position);
- }
- fill_event Execution::__process(const ws_event& event) {
- 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>();
- // Этот if станет ненужным, когда пофиксим баг с вызовом хэндлеров для ивентов
- if (account_order_event.order.symbol == config_.symbol) { // т.к. может прийти ивент по другой монете, но с того же аккаунта
- res.set(__process_account_order(account_order_event));
- }
- }
- return res;
- }
- void Execution::__safe_new_order(const order_request_t& req) {
- 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;
- new_ord.price = *req.price;
- new_ord.quantity = *req.quantity;
- if (req.stop_price) {
- new_ord.stop_price = *req.stop_price;
- }
- new_ord.status = e_order_status::PENDING;
- {
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (req.type == e_order_type::LIMIT) {
- orders_.limit_orders[*req.client_order_id] = new_ord;
- } else {
- orders_.algo_orders[*req.client_order_id] = new_ord;
- }
- }
- std::thread {[req, this] () {
- std::cerr << req << '\n';
- auto res = config_.api->new_order(req);
- std::cerr << res << '\n';
- if (!res) {
- config_.logger->log(res, e_severity_level::ERROR, "new order error");
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (req.type == e_order_type::LIMIT) {
- orders_.limit_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, e_order_type type) {
- 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 {
- auto it = orders_.algo_orders.find(client_order_id);
- if (it == orders_.algo_orders.end()) {
- return;
- }
- prev_ord = it->second;
- }
- }
- std::thread {[prev_ord, this] () {
- std::cerr << "! cancel " << prev_ord << '\n';
- auto res = config_.api->cancel_order(prev_ord.symbol, prev_ord.client_order_id);
- std::cerr << "? " << res << '\n';
- if (!res) {
- config_.logger->log(res, e_severity_level::ERROR, "cancel order error");
- std::lock_guard<std::mutex> lock(orders_.locker);
- if (prev_ord.type == e_order_type::LIMIT) {
- orders_.limit_orders[prev_ord.client_order_id] = prev_ord;
- } else {
- orders_.algo_orders[prev_ord.client_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);
- return res;
- }
- it = orders_storage.algo_orders.find(client_order_id);
- if (it != orders_storage.algo_orders.end()) {
- res.set_value(it->second);
- return res;
- }
- res.set_error(e_execution_error::ORDER_NOT_FOUND);
- return res;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement