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&)>;
- config_.symbol = Strategy::config_.symbol;
- config_.execution = Strategy::config_.execution;
- config_.data = Strategy::config_.data;
- 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); }},
- {"base_size_to_total", [this](const auto& v) { config_.base_size_to_total = std::stod(v); }},
- {"cancel_on_signal_event", [this](const auto& v) { config_.cancel_on_signal_event = std::stoi(v); }},
- {"first_order_size", [this](const auto& v) { config_.first_order_size = std::stod(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); }},
- {"react_on_trade", [this](const auto& v) { config_.react_on_trade = 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); }},
- {"use_grid", [this](const auto& v) { config_.use_grid = std::stoi(v); }},
- {"debug", [this](const auto& v) { config_.debug = std::stoi(v); }},
- {"enable_batch_orders", [this](const auto& v) { config_.enable_batch_orders = 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]);
- }
- } catch (const std::exception& e) {
- std::cerr << "Error for key " << key << ": " << e.what() << '\n';
- std::exit(EXIT_FAILURE);
- }
- }
- // Validate some parameters
- if (config_.target.type == target::targetType::Stable && !config_.target.price.has_value()) {
- std::cerr << "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>();
- if (orderbook_event.event_time - config_hidden_.upd_time < 1000) { // 0-момент по-идее сюда не попадёт
- return res;
- }
- __update_mid_price(orderbook_event);
- int spread_ticks = std::max(
- (config_hidden_.mid_price * config_.spread_size).to_scaled(), SIZE_T_ONE
- );
- auto [asks, bids] = calculate_orders(config_hidden_.mid_price, spread_ticks);
- res.set(order_limit_grid_event(std::move(asks), std::move(bids)));
- res.symbol = config_.symbol;
- }
- return res;
- }
- void MexcSpotMarketMaking::__fill_order_preprocessing(const fill_order_event& event) {
- // config_.logger.get()->log(event, e_severity_level::INFO);
- std::cerr << "Fill event:\n" << event << "\n";
- order_t order = event.order;
- double filled_qty = event.filled_quantity_piece;
- // Note: Позиция уже обновлена в execution, тепер ММ не берёт обязанности риск-чекера
- if (event.order.status == e_order_status::FILLED) { // т.е. когда снесли уровень полностью, иначе нам неитересно реагировать
- if (config_.target.type == target::targetType::Stable) { // thought: case_1
- return;
- }
- int trade_sgn = (event.order.side == e_side::SELL ? 1 : -1);
- int target_sgn;
- switch (config_.target.type) {
- case target::targetType::Up:
- target_sgn = 1;
- break;
- case target::targetType::Down:
- target_sgn = -1;
- break;
- default:
- target_sgn = 0;
- break;
- }
- if (trade_sgn != target_sgn) {
- if (config_.react_on_trade) {
- if (!target_sgn) {
- config_.target.type = target::targetType::Adaptive;
- } else {
- config_.target.type = (target_sgn == 1 ? target::targetType::Down : target::targetType::Up);
- }
- }
- }
- }
- }
- order_event MexcSpotMarketMaking::__process_fill_order(const fill_order_event& event) {
- __fill_order_preprocessing(event); // режим работы пересчитываем
- return order_event(); // mock
- }
- order_event MexcSpotMarketMaking::__process(const fill_event& event) { // get it from execution
- order_event res;
- switch(event.type) {
- case e_fill_event::ORDER: {
- auto fill_event = event.get<fill_order_event>();
- res.set(__process_fill_order(fill_event));
- res.symbol = config_.symbol;
- break;
- }
- case e_fill_event::NONE:
- break;
- default:
- throw std::runtime_error("unknown e_fill_event type");
- }
- return res;
- }
- std::pair<MexcSpotMarketMaking::grids, MexcSpotMarketMaking::grids> MexcSpotMarketMaking::calculate_orders(precised_float mid_price, int spread_ticks) // TODO залогировать
- {
- auto& balance_getter = config_.shared_state.get()->get_balance_getter(config_.market);
- auto base_balance_res = balance_getter.get_balance(config_.symbol->base);
- auto quote_balance_res = balance_getter.get_balance(config_.symbol->quote);
- 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;
- 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;
- grids asks, bids;
- for (int i = 0; i < config_.n_lvl; ++i) {
- // SELL orders
- auto sell_price = ask_price + i * config_.price_step;
- asks[sell_price] = config_.symbol->make_quantity(base_amount_per_level / sell_price.to_double());
- // BUY orders
- auto buy_price = bid_price - i * config_.price_step;
- bids[buy_price] = config_.symbol->make_quantity(quote_amount_per_level / buy_price.to_double());
- }
- 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);
- std::cerr << "Order book event:\n" << event << "\n";
- 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_.mid_price = config_.symbol->make_price(mid_price);
- }
- config_hidden_.upd_time = event.event_time;
- }
- } // namespace marketmaking
- } // namespace mira
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement