Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <strategy/market_making/mexc_spot/mm_strategy.hpp>
- namespace mira {
- namespace marketmaking {
- MexcSpotMarketMaking::MexcSpotMarketMaking(strategy_config_t config) : Strategy(config) {
- using conv_fn = std::function<void(const std::string&)>;
- *reinterpret_cast<strategy_config_t*>(&config_) = config; // init parent part
- std::unordered_map<std::string, conv_fn> cnv = {
- {"api", [this](const auto& v) { config_.api_key = v; }},
- {"secret", [this](const auto& v) { config_.secret_key = v; }},
- {"available_base_balance_to_total", [this](const auto& v) { config_.available_base_balance_to_total = std::stod(v); }},
- {"available_quote_balance_to_total", [this](const auto& v) { config_.available_quote_balance_to_total = std::stod(v); }},
- {"cancel_on_signal_event", [this](const auto& v) { config_.cancel_on_signal_event = std::stoi(v); }},
- {"min_order_size", [this](const auto& v) { config_.min_order_size = std::stod(v); }},
- {"n_base", [this](const auto& v) { config_.n_base = std::stoi(v); }},
- {"n_lvl", [this](const auto& v) { config_.n_lvl = std::stoi(v); }},
- {"price_step", [this](const auto& v) { config_.price_step = std::stoi(v); }},
- {"cooldown", [this](const auto& v) { config_.cooldown = std::stoi(v); }},
- {"spread_size", [this](const auto& v) { config_.spread_size = std::stod(v); }},
- {"symbol", [this](const auto& v) { config_.symbol_str = v; }},
- {"target_price", [this](const auto& v) { config_.target.price = std::stod(v); }},
- {"debug", [this](const auto& v) { config_.debug = std::stoi(v); }},
- {"target_type",
- [this](const auto& v) {
- if (v == "up") {
- config_.target.type = target::targetType::Up;
- } else if (v == "down") {
- config_.target.type = target::targetType::Down;
- } else if (v == "stable") {
- config_.target.type = target::targetType::Stable;
- }
- }
- },
- };
- for (const auto &[key, fn] : cnv) {
- try {
- if (config_.init_args.count(key)) {
- fn(config_.init_args[key].s());
- }
- } catch (const std::exception& e) {
- config_.logger->log("Error for key " + key + ": " + e.what());
- std::exit(EXIT_FAILURE);
- }
- }
- // Validate some parameters
- if (config_.target.type == target::targetType::Stable && !config_.target.price.has_value()) {
- config_.logger->log("Wrong target type: \"Stable\", but no targetPrice specified.");
- exit(EXIT_FAILURE);
- }
- // if (!config_.debug) {
- // std::string fname = "/mnt/logs/" + config_.symbol_str + "-" + get_date(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) + ".log";
- // std::cout << "***\n"
- // << fname << "\n***\n";
- // std::freopen(fname.c_str(), "w", stderr);
- // }
- }
- order_event MexcSpotMarketMaking::_process(const market_event& event) {
- order_event res;
- if (event.type == e_market_event::ORDER_BOOK) {
- auto orderbook_event = event.get<market_order_book_event>();
- _update_mid_price(orderbook_event);
- if (config_hidden_.previous_mid_price == config_hidden_.mid_price) {
- return res;
- }
- int spread_ticks = std::max(
- (config_hidden_.mid_price * config_.spread_size).to_scaled(), INT_64_ONE
- );
- auto [asks, bids] = calculate_orders(config_hidden_.mid_price, spread_ticks);
- auto limit_event = order_limit_grid_event(asks, bids);
- res.set(std::move(limit_event));
- res.set_symbol(config_.symbol);
- // config_.logger->log(res, e_severity_level::DEBUG);
- }
- return res;
- }
- MexcSpotMarketMaking::asks_and_bids MexcSpotMarketMaking::calculate_orders(precised_float mid_price, int spread_ticks) // TODO залогировать
- {
- // config_.logger->log("start orders calculating");
- auto& balance_getter = config_.shared_state.get()->get_balance_getter(config_.market, config_.init_args.at("account_name").s());
- auto base_balance_res = balance_getter.get_balance(config_.symbol->base);
- auto quote_balance_res = balance_getter.get_balance(config_.symbol->quote);
- // config_.logger->log(base_balance_res, e_severity_level::DEBUG, "base balance");
- // config_.logger->log(quote_balance_res, e_severity_level::DEBUG, "quote balance");
- auto base_balance = (base_balance_res.free + base_balance_res.locked) * config_.available_base_balance_to_total;
- auto quote_balance = (quote_balance_res.free + quote_balance_res.locked) * config_.available_quote_balance_to_total;
- // if (quote_balance / config_.available_quote_balance_to_total < 250) {
- // std::cerr << "hardcode low balance indicator im gonna die: " << (quote_balance_res.free + quote_balance_res.locked);
- // exit(EXIT_FAILURE);
- // }
- const auto& bid_and_asks_levels = config_.shared_state->get_data_getter(config_.symbol).get_order_book()[0]; // TODO: это же не факт, что органика
- auto ask_price = std::max(mid_price, config_.symbol->make_price(bid_and_asks_levels.bid_price) + 1) + (spread_ticks + 1) / 2;
- auto bid_price = std::min(mid_price, config_.symbol->make_price(bid_and_asks_levels.ask_price) - 1) - spread_ticks / 2;
- double base_amount_per_level = base_balance / config_.n_base;
- double quote_amount_per_level = quote_balance / config_.n_base;
- std::vector<std::pair<double, double>> asks, bids;
- for (int i = 0; i < config_.n_lvl; ++i) {
- // SELL orders
- auto sell_price = (ask_price + i * config_.price_step).to_double();
- asks.push_back(std::make_pair(sell_price, base_amount_per_level));
- // BUY orders
- auto buy_price = (bid_price - i * config_.price_step).to_double();
- bids.push_back(std::make_pair(buy_price, quote_amount_per_level / buy_price));
- }
- // config_.logger->log("calculating completed");
- return std::make_pair(std::move(asks), std::move(bids));
- }
- // Обновляет мидпрайс и время её последнего изменения
- void MexcSpotMarketMaking::_update_mid_price(const market_order_book_event& event) {
- config_.logger.get()->log(event, e_severity_level::INFO, "_update_mid_price: ");
- if (!config_hidden_.mid_price.initialized()) {
- config_hidden_.mid_price = config_.symbol->make_price(0);
- }
- if (config_.target.price.has_value()) {
- // ветка для таргетированной цены:
- config_hidden_.mid_price = config_.symbol->make_price(config_.target.price.value());
- } else {
- const auto& bid_and_asks_levels = event.order_book[0];
- double mid_price;
- if (bid_and_asks_levels.ask_price && bid_and_asks_levels.bid_price) { // в стакане есть и бид и аск
- mid_price = (bid_and_asks_levels.ask_price + bid_and_asks_levels.bid_price) / 2;
- } else if (bid_and_asks_levels.ask_price + bid_and_asks_levels.bid_price != 0) { // в стакане есть либо бид, либо аск
- if (bid_and_asks_levels.ask_price) { // есть аск
- mid_price = bid_and_asks_levels.ask_price * (1 - config_.spread_size / 2);
- } else { // есть бид
- mid_price = bid_and_asks_levels.bid_price * (1 + config_.spread_size / 2);
- }
- } else { // пустой стакан
- mid_price = 1;
- }
- config_hidden_.previous_mid_price = config_hidden_.mid_price;
- config_hidden_.mid_price = config_.symbol->make_price(mid_price);
- }
- // config_.logger->log("new mid price: " + config_hidden_.mid_price.to_string());
- }
- } // namespace marketmaking
- } // namespace mira
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement