Advertisement
den4ik2003

Untitled

May 10th, 2024
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.63 KB | None | 0 0
  1. #include <strategy/market_making/mexc_spot/mm_strategy.hpp>
  2.  
  3. namespace mira {
  4.  
  5. namespace marketmaking {
  6.  
  7. MexcSpotMarketMaking::MexcSpotMarketMaking(strategy_config_t config) : Strategy(config) {
  8. using conv_fn = std::function<void(const std::string&)>;
  9.  
  10. config_.symbol = Strategy::config_.symbol;
  11. config_.execution = Strategy::config_.execution;
  12. config_.data = Strategy::config_.data;
  13.  
  14. std::unordered_map<std::string, conv_fn> cnv = {
  15. {"api", [this](const auto& v) { config_.api_key = v; }},
  16. {"secret", [this](const auto& v) { config_.secret_key = v; }},
  17. {"available_base_balance_to_total", [this](const auto& v) { config_.available_base_balance_to_total = std::stod(v); }},
  18. {"available_quote_balance_to_total", [this](const auto& v) { config_.available_quote_balance_to_total = std::stod(v); }},
  19. {"base_size_to_total", [this](const auto& v) { config_.base_size_to_total = std::stod(v); }},
  20. {"cancel_on_signal_event", [this](const auto& v) { config_.cancel_on_signal_event = std::stoi(v); }},
  21. {"first_order_size", [this](const auto& v) { config_.first_order_size = std::stod(v); }},
  22. {"min_order_size", [this](const auto& v) { config_.min_order_size = std::stod(v); }},
  23. {"n_base", [this](const auto& v) { config_.n_base = std::stoi(v); }},
  24. {"n_lvl", [this](const auto& v) { config_.n_lvl = std::stoi(v); }},
  25. {"price_step", [this](const auto& v) { config_.price_step = std::stoi(v); }},
  26. {"react_on_trade", [this](const auto& v) { config_.react_on_trade = std::stoi(v); }},
  27. {"spread_size", [this](const auto& v) { config_.spread_size = std::stod(v); }},
  28. {"symbol", [this](const auto& v) { config_.symbol_str = v; }},
  29. {"target_price", [this](const auto& v) { config_.target.price = std::stod(v); }},
  30. {"use_grid", [this](const auto& v) { config_.use_grid = std::stoi(v); }},
  31. {"debug", [this](const auto& v) { config_.debug = std::stoi(v); }},
  32. {"enable_batch_orders", [this](const auto& v) { config_.enable_batch_orders = std::stoi(v); }},
  33. {"target_type",
  34. [this](const auto& v) {
  35. if (v == "up") {
  36. config_.target.type = target::targetType::Up;
  37. } else if (v == "down") {
  38. config_.target.type = target::targetType::Down;
  39. } else if (v == "stable") {
  40. config_.target.type = target::targetType::Stable;
  41. }
  42. }
  43. },
  44. };
  45.  
  46. for (const auto &[key, fn] : cnv) {
  47. try {
  48. if (config_.init_args.count(key)) {
  49. fn(config_.init_args[key]);
  50. }
  51. } catch (const std::exception& e) {
  52. std::cerr << "Error for key " << key << ": " << e.what() << '\n';
  53. std::exit(EXIT_FAILURE);
  54. }
  55. }
  56.  
  57. // Validate some parameters
  58. if (config_.target.type == target::targetType::Stable && !config_.target.price.has_value()) {
  59. std::cerr << "Wrong target type: \"Stable\", but no targetPrice specified.";
  60. exit(EXIT_FAILURE);
  61. }
  62.  
  63. if (!config_.debug) {
  64. 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";
  65. std::cout << "***\n"
  66. << fname << "\n***\n";
  67. std::freopen(fname.c_str(), "w", stderr);
  68. }
  69. }
  70.  
  71. order_event MexcSpotMarketMaking::__process(const market_event& event) {
  72. order_event res;
  73. if (event.type == e_market_event::ORDER_BOOK) {
  74. auto orderbook_event = event.get<market_order_book_event>();
  75. if (orderbook_event.event_time - config_hidden_.upd_time < 1000) { // 0-момент по-идее сюда не попадёт
  76. return res;
  77. }
  78.  
  79. __update_mid_price(orderbook_event);
  80.  
  81. int spread_ticks = std::max(
  82. (config_hidden_.mid_price * config_.spread_size).to_scaled(), SIZE_T_ONE
  83. );
  84.  
  85. auto [asks, bids] = calculate_orders(config_hidden_.mid_price, spread_ticks);
  86.  
  87. res.set(order_limit_grid_event(std::move(asks), std::move(bids)));
  88. res.symbol = config_.symbol;
  89. }
  90.  
  91. return res;
  92. }
  93.  
  94. void MexcSpotMarketMaking::__fill_order_preprocessing(const fill_order_event& event) {
  95. // config_.logger.get()->log(event, e_severity_level::INFO);
  96. std::cerr << "Fill event:\n" << event << "\n";
  97.  
  98. order_t order = event.order;
  99. double filled_qty = event.filled_quantity_piece;
  100.  
  101. // Note: Позиция уже обновлена в execution, тепер ММ не берёт обязанности риск-чекера
  102. if (event.order.status == e_order_status::FILLED) { // т.е. когда снесли уровень полностью, иначе нам неитересно реагировать
  103.  
  104. if (config_.target.type == target::targetType::Stable) { // thought: case_1
  105. return;
  106. }
  107.  
  108. int trade_sgn = (event.order.side == e_side::SELL ? 1 : -1);
  109. int target_sgn;
  110. switch (config_.target.type) {
  111. case target::targetType::Up:
  112. target_sgn = 1;
  113. break;
  114. case target::targetType::Down:
  115. target_sgn = -1;
  116. break;
  117. default:
  118. target_sgn = 0;
  119. break;
  120. }
  121.  
  122. if (trade_sgn != target_sgn) {
  123. if (config_.react_on_trade) {
  124. if (!target_sgn) {
  125. config_.target.type = target::targetType::Adaptive;
  126. } else {
  127. config_.target.type = (target_sgn == 1 ? target::targetType::Down : target::targetType::Up);
  128. }
  129. }
  130. }
  131. }
  132. }
  133.  
  134. order_event MexcSpotMarketMaking::__process_fill_order(const fill_order_event& event) {
  135. __fill_order_preprocessing(event); // режим работы пересчитываем
  136.  
  137. return order_event(); // mock
  138. }
  139.  
  140. order_event MexcSpotMarketMaking::__process(const fill_event& event) { // get it from execution
  141. order_event res;
  142. switch(event.type) {
  143. case e_fill_event::ORDER: {
  144. auto fill_event = event.get<fill_order_event>();
  145. res.set(__process_fill_order(fill_event));
  146. res.symbol = config_.symbol;
  147. break;
  148. }
  149. case e_fill_event::NONE:
  150. break;
  151. default:
  152. throw std::runtime_error("unknown e_fill_event type");
  153. }
  154. return res;
  155. }
  156.  
  157. std::pair<MexcSpotMarketMaking::grids, MexcSpotMarketMaking::grids> MexcSpotMarketMaking::calculate_orders(precised_float mid_price, int spread_ticks) // TODO залогировать
  158. {
  159. auto& balance_getter = config_.shared_state.get()->get_balance_getter(config_.market);
  160.  
  161. auto base_balance_res = balance_getter.get_balance(config_.symbol->base);
  162. auto quote_balance_res = balance_getter.get_balance(config_.symbol->quote);
  163. auto base_balance = (base_balance_res.free + base_balance_res.locked) * config_.available_base_balance_to_total;
  164. auto quote_balance = (quote_balance_res.free + quote_balance_res.locked) * config_.available_quote_balance_to_total;
  165.  
  166. const auto& bid_and_asks_levels = config_.shared_state->get_data_getter(config_.symbol).get_order_book()[0]; // TODO: это же не факт, что органика
  167. auto ask_price = std::max(mid_price, config_.symbol->make_price(bid_and_asks_levels.bid_price) + 1) + (spread_ticks + 1) / 2;
  168. auto bid_price = std::min(mid_price, config_.symbol->make_price(bid_and_asks_levels.ask_price) - 1) - spread_ticks / 2;
  169.  
  170. double base_amount_per_level = base_balance / config_.n_base;
  171. double quote_amount_per_level = quote_balance / config_.n_base;
  172.  
  173. grids asks, bids;
  174.  
  175. for (int i = 0; i < config_.n_lvl; ++i) {
  176. // SELL orders
  177. auto sell_price = ask_price + i * config_.price_step;
  178. asks[sell_price] = config_.symbol->make_quantity(base_amount_per_level / sell_price.to_double());
  179.  
  180. // BUY orders
  181. auto buy_price = bid_price - i * config_.price_step;
  182. bids[buy_price] = config_.symbol->make_quantity(quote_amount_per_level / buy_price.to_double());
  183. }
  184. return std::make_pair(std::move(asks), std::move(bids));
  185. }
  186.  
  187. // Обновляет мидпрайс и время её последнего изменения
  188. void MexcSpotMarketMaking::__update_mid_price(const market_order_book_event& event) {
  189. // config_.logger.get()->log(event, e_severity_level::INFO);
  190. std::cerr << "Order book event:\n" << event << "\n";
  191.  
  192. if (config_.target.price.has_value()) {
  193. // ветка для таргетированной цены:
  194. config_hidden_.mid_price = config_.symbol->make_price(config_.target.price.value());
  195. } else {
  196. const auto& bid_and_asks_levels = event.order_book[0];
  197.  
  198. double mid_price;
  199. if (bid_and_asks_levels.ask_price && bid_and_asks_levels.bid_price) { // в стакане есть и бид и аск
  200. mid_price = (bid_and_asks_levels.ask_price + bid_and_asks_levels.bid_price) / 2;
  201. } else if (bid_and_asks_levels.ask_price + bid_and_asks_levels.bid_price != 0) { // в стакане есть либо бид, либо аск
  202.  
  203. if (bid_and_asks_levels.ask_price) { // есть аск
  204. mid_price = bid_and_asks_levels.ask_price * (1 - config_.spread_size / 2);
  205. } else { // есть бид
  206. mid_price = bid_and_asks_levels.bid_price * (1 + config_.spread_size / 2);
  207. }
  208.  
  209. } else { // пустой стакан
  210. mid_price = 1;
  211. }
  212. config_hidden_.mid_price = config_.symbol->make_price(mid_price);
  213. }
  214. config_hidden_.upd_time = event.event_time;
  215. }
  216.  
  217. } // namespace marketmaking
  218.  
  219.  
  220. } // namespace mira
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement