Advertisement
den4ik2003

Untitled

Nov 5th, 2024
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.46 KB | None | 0 0
  1. #include <algo/volume/volume_strategy.hpp>
  2.  
  3. using namespace mira;
  4.  
  5. const int volume::VolumeBot::aux_ = StrategyBuilder::add_strategy<VolumeBot>("VOLUME_BOT");
  6.  
  7. volume::VolumeBot::VolumeBot(const strategy_config_t& config) : SingleStrategy(config) {
  8.     *static_cast<strategy_config_t*>(&config_) = config;
  9.  
  10.     using conv_fn = std::function<void(const std::string&)>;
  11.     std::unordered_map<std::string, conv_fn> cnv = {
  12.         {"volume",                     [this](const auto& v) { config_.volume = std::stod(v); }},
  13.         {"min_order_size",             [this](const auto& v) { config_.min_order_size = std::stod(v); }},
  14.         {"symbol",                     [this](const auto& v) { config_.symbol_str = v; }},
  15.         {"sigma",                      [this](const auto& v) { config_.sigma = std::stod(v); }},
  16.         {"volume_sigma",               [this](const auto& v) { config_.volume_sigma = std::stod(v); }},
  17.         {"path_to_price_file",         [this](const auto& v) { config_.path_to_price_file = v; }},
  18.         {"narrow_spread_trading",      [this](const auto& v) { config_.narrow_spread_trading = std::stoi(v); }},
  19.         {"time_frequency",
  20.             [this](const auto& v) {
  21.                 config_.cooldown = std::stoi(v);
  22.                 config_.sleep_time = config_.cooldown;
  23.             }
  24.         },
  25.     };
  26.  
  27.     for (const auto &[key, fn] : cnv) {
  28.         try {
  29.             if (config_.args.count(key)) {
  30.                 fn(config_.args[key].s());
  31.             }
  32.         } catch (const std::exception& e) {
  33.             config_.logger->log("Error for key " + key + ": " + e.what());
  34.             std::exit(EXIT_FAILURE);
  35.         }
  36.     }
  37.  
  38.     config_.time_distribution = std::normal_distribution{static_cast<double>(config_.cooldown), config_.cooldown * 0.1};
  39.     config_.volume_distribution = std::normal_distribution{static_cast<double>(config_.volume), config_.volume * config_.volume_sigma};
  40.  
  41.     auto bid_and_ask = config_.shared_state->get_data_getter(config_.symbols.back()).get_best_book();
  42.     std::cout << "order book " << bid_and_ask << '\n';
  43.     auto market_mid_price = (bid_and_ask.ask_price + bid_and_ask.bid_price) / 2;
  44.  
  45.     if (config_.path_to_price_file == "") {
  46.         config_.logger->log("no volume price file");
  47.         config_.previous_price = market_mid_price;
  48.     } else {
  49.         config_.logger->log("opening volume price file: " + config_.path_to_price_file);
  50.         config_.price_file.open(config_.path_to_price_file, std::ios::app);
  51.         if (!config_.price_file.is_open()) {
  52.             config_.logger->log("can't open volume price file!");
  53.             exit(EXIT_FAILURE);
  54.         }
  55.         if (std::filesystem::file_size(config_.path_to_price_file) == 0) {
  56.             config_.logger->log("volume price file is empty -> writing price = " + std::to_string(market_mid_price));
  57.             config_.price_file << "{\"market_price\": \"" + std::to_string(market_mid_price) + "\"}" << std::flush;
  58.         }
  59.         std::string all_string = "", buf;
  60.         std::ifstream config(config_.path_to_price_file);
  61.         while (config >> buf) {
  62.             all_string += buf;
  63.         }
  64.         config_.logger->log("initial price from file: " + all_string);
  65.         config_.previous_price = field_t::deserialize(all_string).at("market_price").f();
  66.  
  67.         if (config_.previous_price >= bid_and_ask.ask_price || config_.previous_price <= bid_and_ask.bid_price) {
  68.             config_.logger->log("config_.previous_price >= bid_and_ask.ask_price || config_.previous_price <= bid_and_ask.bid_price");
  69.             config_.previous_price = market_mid_price;
  70.         }
  71.     }
  72. }
  73.  
  74. order_event volume::VolumeBot::_process_single(const market_event& event) {
  75.     order_event res;
  76.  
  77.     if (get_millis() - config_.upd_time < config_.sleep_time) { // 0-момент сюда не попадёт
  78.         return res;
  79.     }
  80.  
  81.     if (event.type == e_market_event::ORDER_BOOK) {
  82.         auto orderbook_event = event.get<market_order_book_event>();
  83.         config_.upd_time = get_millis();
  84.         auto best_book = config_.shared_state->get_data_getter(event.symbol).get_best_book();
  85.         return calculate_trade_event(event, best_book);
  86.     } else if (event.type == e_market_event::TICK) {
  87.         auto best_book = config_.shared_state->get_data_getter(event.symbol).get_best_book();
  88.         config_.upd_time = get_millis();
  89.         return calculate_trade_event(event, best_book);
  90.     }
  91.  
  92.     return res;
  93. }
  94.  
  95. double volume::VolumeBot::calculate_deviated_value(std::normal_distribution<double>& distribution, double lower_bound, double upper_bound) {
  96.     auto sampled_value = distribution(config_.gen);
  97.     return std::max(std::min(sampled_value, upper_bound), lower_bound);
  98. }
  99.  
  100. double volume::VolumeBot::calculate_normal_distributed_price(double current_price, precised_float precised_lower_bound, precised_float precised_upper_bound) {
  101.     /* the probability of being in the [p * (1 - sigma), p * (1 + sigma)] is about 96% (= erf(sqrt(2)))*/
  102.     double lower_bound = precised_lower_bound.to_double();
  103.     double upper_bound = precised_upper_bound.to_double();
  104.     double min_step = config_.symbols.back()->price_step.to_double();
  105.     std::normal_distribution<double> price_distr(current_price, current_price * config_.sigma / 2);
  106.     double new_price = calculate_deviated_value(price_distr, current_price * (1 - config_.sigma), current_price * (1 + config_.sigma));
  107.  
  108.     config_.logger->log("calculate deviated price (new) = " + std::to_string(new_price) + " current price = " + std::to_string(current_price));
  109.     double delta = new_price - current_price;
  110.     if (delta == 0) {
  111.         config_.logger->log("delta == 0");
  112.         delta = min_step;
  113.     }
  114.     config_.logger->log("delta = " + std::to_string(delta));
  115.  
  116.     if (new_price > upper_bound) { // здесь delta > 0
  117.         config_.logger->log("new_price > upper_bound");
  118.         if (current_price - std::abs(delta) < lower_bound) { // reflected price
  119.             delta = min_step;
  120.             config_.logger->log("change delta");
  121.         }
  122.         new_price = std::min(std::max(current_price - std::abs(delta), lower_bound), upper_bound);
  123.         if (new_price == current_price) {
  124.             config_.logger->log("new_price == current_price");
  125.             new_price = std::min(new_price + min_step, upper_bound);
  126.         }
  127.     } else if (new_price < lower_bound) { // здесь delta < 0 будет
  128.         config_.logger->log("new_price < lower_bound");
  129.         if (current_price + std::abs(delta) > upper_bound) { // reflected price
  130.             delta = min_step;
  131.             config_.logger->log("change delta");
  132.         }
  133.         new_price = std::max(std::min(current_price + std::abs(delta), upper_bound), lower_bound);
  134.         if (new_price == current_price) {
  135.             config_.logger->log("new_price == current_price");
  136.             new_price = std::max(new_price - min_step, lower_bound);
  137.         }
  138.     }
  139.  
  140.     config_.logger->log("new price after = " + std::to_string(new_price));
  141.     return new_price;
  142. }
  143.  
  144. order_event volume::VolumeBot::calculate_trade_event(const market_event& event, const float_book_t& best_book) {
  145.     order_event res;
  146.  
  147.     auto ask_price = event.symbol->make_price(best_book.ask_price);
  148.     auto bid_price = event.symbol->make_price(best_book.bid_price);
  149.  
  150.     config_.sleep_time = calculate_deviated_value(config_.time_distribution, 0.8 * config_.cooldown, 1.2 * config_.cooldown);
  151.     config_.logger->log("sleep time = " + std::to_string(config_.sleep_time));
  152.  
  153.     if (!ask_price.initialized() || !bid_price.initialized()) {
  154.         config_.logger->log("No ask or bid");
  155.         return res;
  156.     }
  157.     size_t spread_ticks = (ask_price - bid_price).to_scaled();
  158.  
  159.     config_.logger->log("ask price " + ask_price.to_string() + " bid price: " + bid_price.to_string());
  160.  
  161.     if (spread_ticks == event.symbol->price_step.to_scaled()) { // норм ли сравниваются precised_float?
  162.         config_.logger->log("Narrow spread");
  163.         if (config_.narrow_spread_trading) {
  164.             config_.logger->log("dealing with narrow spread");
  165.  
  166.             double current_volume = calculate_deviated_value(config_.volume_distribution, 0.8 * config_.volume, 1.2 * config_.volume);
  167.             double ask_trade_quantity = std::min(current_volume / (2 * ask_price.to_double()), best_book.ask_quantity);
  168.             double bid_trade_quantity = std::min(current_volume / (2 * bid_price.to_double()), best_book.bid_quantity);
  169.  
  170.             limit_order_request_t buy_limit_req;
  171.             buy_limit_req.level.price = ask_price.to_double();
  172.             buy_limit_req.level.quantity = ask_trade_quantity;
  173.             buy_limit_req.repeat_config = repeated_request_config_t{0, 3, 100};
  174.  
  175.             limit_order_request_t sell_limit_req;
  176.             sell_limit_req.level.price = bid_price.to_double();
  177.             sell_limit_req.level.quantity = bid_trade_quantity;
  178.             sell_limit_req.repeat_config = repeated_request_config_t{0, 3, 100};
  179.  
  180.             res.set(
  181.                 order_limit_grid_event(
  182.                     std::vector<limit_order_request_t>{sell_limit_req},
  183.                     std::vector<limit_order_request_t>{buy_limit_req}
  184.                 )
  185.             );
  186.             res.set_symbol(event.symbol);
  187.             config_.logger->log(res, e_severity_level::INFO, "dealing with narrow spread result");
  188.             return res;
  189.         }
  190.         return res;
  191.     }
  192.  
  193.     double current_volume = calculate_deviated_value(config_.volume_distribution, 0.8 * config_.volume, 1.2 * config_.volume);
  194.     config_.logger->log("current_volume: " + std::to_string(current_volume) + " previous price = " + std::to_string(config_.previous_price));
  195.     config_.logger->log("start calculating new normal distributed price");
  196.  
  197.     double current_price = calculate_normal_distributed_price(config_.previous_price, bid_price + 1, ask_price - 1);
  198.     double quantity = current_volume / current_price;
  199.  
  200.     config_.previous_price = current_price;
  201.     if (config_.price_file.is_open()) {
  202.         config_.logger->log("writing to volume price file");
  203.         std::filesystem::resize_file(config_.path_to_price_file, 0);
  204.         config_.price_file.seekp(0);
  205.         config_.price_file << "{\"market_price\": \"" + std::to_string(current_price) + "\"}" << std::flush;
  206.     }
  207.  
  208.     config_.logger->log("price: " + std::to_string(current_price) + "\nquantity: " + std::to_string(quantity));
  209.  
  210.     res.set(order_self_trade_event(current_price, quantity));
  211.     res.set_symbol(event.symbol);
  212.  
  213.     return res;
  214. }
  215.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement