Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algo/volume/volume_strategy.hpp>
- using namespace mira;
- const int volume::VolumeBot::aux_ = StrategyBuilder::add_strategy<VolumeBot>("VOLUME_BOT");
- volume::VolumeBot::VolumeBot(const strategy_config_t& config) : SingleStrategy(config) {
- *static_cast<strategy_config_t*>(&config_) = config;
- using conv_fn = std::function<void(const std::string&)>;
- std::unordered_map<std::string, conv_fn> cnv = {
- {"volume", [this](const auto& v) { config_.volume = std::stod(v); }},
- {"min_order_size", [this](const auto& v) { config_.min_order_size = std::stod(v); }},
- {"symbol", [this](const auto& v) { config_.symbol_str = v; }},
- {"sigma", [this](const auto& v) { config_.sigma = std::stod(v); }},
- {"volume_sigma", [this](const auto& v) { config_.volume_sigma = std::stod(v); }},
- {"path_to_price_file", [this](const auto& v) { config_.path_to_price_file = v; }},
- {"narrow_spread_trading", [this](const auto& v) { config_.narrow_spread_trading = std::stoi(v); }},
- {"time_frequency",
- [this](const auto& v) {
- config_.cooldown = std::stoi(v);
- config_.sleep_time = config_.cooldown;
- }
- },
- };
- for (const auto &[key, fn] : cnv) {
- try {
- if (config_.args.count(key)) {
- fn(config_.args[key].s());
- }
- } catch (const std::exception& e) {
- config_.logger->log("Error for key " + key + ": " + e.what());
- std::exit(EXIT_FAILURE);
- }
- }
- config_.time_distribution = std::normal_distribution{static_cast<double>(config_.cooldown), config_.cooldown * 0.1};
- config_.volume_distribution = std::normal_distribution{static_cast<double>(config_.volume), config_.volume * config_.volume_sigma};
- auto bid_and_ask = config_.shared_state->get_data_getter(config_.symbols.back()).get_best_book();
- std::cout << "order book " << bid_and_ask << '\n';
- auto market_mid_price = (bid_and_ask.ask_price + bid_and_ask.bid_price) / 2;
- if (config_.path_to_price_file == "") {
- config_.logger->log("no volume price file");
- config_.previous_price = market_mid_price;
- } else {
- config_.logger->log("opening volume price file: " + config_.path_to_price_file);
- config_.price_file.open(config_.path_to_price_file, std::ios::app);
- if (!config_.price_file.is_open()) {
- config_.logger->log("can't open volume price file!");
- exit(EXIT_FAILURE);
- }
- if (std::filesystem::file_size(config_.path_to_price_file) == 0) {
- config_.logger->log("volume price file is empty -> writing price = " + std::to_string(market_mid_price));
- config_.price_file << "{\"market_price\": \"" + std::to_string(market_mid_price) + "\"}" << std::flush;
- }
- std::string all_string = "", buf;
- std::ifstream config(config_.path_to_price_file);
- while (config >> buf) {
- all_string += buf;
- }
- config_.logger->log("initial price from file: " + all_string);
- config_.previous_price = field_t::deserialize(all_string).at("market_price").f();
- if (config_.previous_price >= bid_and_ask.ask_price || config_.previous_price <= bid_and_ask.bid_price) {
- config_.logger->log("config_.previous_price >= bid_and_ask.ask_price || config_.previous_price <= bid_and_ask.bid_price");
- config_.previous_price = market_mid_price;
- }
- }
- }
- order_event volume::VolumeBot::_process_single(const market_event& event) {
- order_event res;
- if (get_millis() - config_.upd_time < config_.sleep_time) { // 0-момент сюда не попадёт
- return res;
- }
- if (event.type == e_market_event::ORDER_BOOK) {
- auto orderbook_event = event.get<market_order_book_event>();
- config_.upd_time = get_millis();
- auto best_book = config_.shared_state->get_data_getter(event.symbol).get_best_book();
- return calculate_trade_event(event, best_book);
- } else if (event.type == e_market_event::TICK) {
- auto best_book = config_.shared_state->get_data_getter(event.symbol).get_best_book();
- config_.upd_time = get_millis();
- return calculate_trade_event(event, best_book);
- }
- return res;
- }
- double volume::VolumeBot::calculate_deviated_value(std::normal_distribution<double>& distribution, double lower_bound, double upper_bound) {
- auto sampled_value = distribution(config_.gen);
- return std::max(std::min(sampled_value, upper_bound), lower_bound);
- }
- double volume::VolumeBot::calculate_normal_distributed_price(double current_price, precised_float precised_lower_bound, precised_float precised_upper_bound) {
- /* the probability of being in the [p * (1 - sigma), p * (1 + sigma)] is about 96% (= erf(sqrt(2)))*/
- double lower_bound = precised_lower_bound.to_double();
- double upper_bound = precised_upper_bound.to_double();
- double min_step = config_.symbols.back()->price_step.to_double();
- std::normal_distribution<double> price_distr(current_price, current_price * config_.sigma / 2);
- double new_price = calculate_deviated_value(price_distr, current_price * (1 - config_.sigma), current_price * (1 + config_.sigma));
- config_.logger->log("calculate deviated price (new) = " + std::to_string(new_price) + " current price = " + std::to_string(current_price));
- double delta = new_price - current_price;
- if (delta == 0) {
- config_.logger->log("delta == 0");
- delta = min_step;
- }
- config_.logger->log("delta = " + std::to_string(delta));
- if (new_price > upper_bound) { // здесь delta > 0
- config_.logger->log("new_price > upper_bound");
- if (current_price - std::abs(delta) < lower_bound) { // reflected price
- delta = min_step;
- config_.logger->log("change delta");
- }
- new_price = std::min(std::max(current_price - std::abs(delta), lower_bound), upper_bound);
- if (new_price == current_price) {
- config_.logger->log("new_price == current_price");
- new_price = std::min(new_price + min_step, upper_bound);
- }
- } else if (new_price < lower_bound) { // здесь delta < 0 будет
- config_.logger->log("new_price < lower_bound");
- if (current_price + std::abs(delta) > upper_bound) { // reflected price
- delta = min_step;
- config_.logger->log("change delta");
- }
- new_price = std::max(std::min(current_price + std::abs(delta), upper_bound), lower_bound);
- if (new_price == current_price) {
- config_.logger->log("new_price == current_price");
- new_price = std::max(new_price - min_step, lower_bound);
- }
- }
- config_.logger->log("new price after = " + std::to_string(new_price));
- return new_price;
- }
- order_event volume::VolumeBot::calculate_trade_event(const market_event& event, const float_book_t& best_book) {
- order_event res;
- auto ask_price = event.symbol->make_price(best_book.ask_price);
- auto bid_price = event.symbol->make_price(best_book.bid_price);
- config_.sleep_time = calculate_deviated_value(config_.time_distribution, 0.8 * config_.cooldown, 1.2 * config_.cooldown);
- config_.logger->log("sleep time = " + std::to_string(config_.sleep_time));
- if (!ask_price.initialized() || !bid_price.initialized()) {
- config_.logger->log("No ask or bid");
- return res;
- }
- size_t spread_ticks = (ask_price - bid_price).to_scaled();
- config_.logger->log("ask price " + ask_price.to_string() + " bid price: " + bid_price.to_string());
- if (spread_ticks == event.symbol->price_step.to_scaled()) { // норм ли сравниваются precised_float?
- config_.logger->log("Narrow spread");
- if (config_.narrow_spread_trading) {
- config_.logger->log("dealing with narrow spread");
- double current_volume = calculate_deviated_value(config_.volume_distribution, 0.8 * config_.volume, 1.2 * config_.volume);
- double ask_trade_quantity = std::min(current_volume / (2 * ask_price.to_double()), best_book.ask_quantity);
- double bid_trade_quantity = std::min(current_volume / (2 * bid_price.to_double()), best_book.bid_quantity);
- limit_order_request_t buy_limit_req;
- buy_limit_req.level.price = ask_price.to_double();
- buy_limit_req.level.quantity = ask_trade_quantity;
- buy_limit_req.repeat_config = repeated_request_config_t{0, 3, 100};
- limit_order_request_t sell_limit_req;
- sell_limit_req.level.price = bid_price.to_double();
- sell_limit_req.level.quantity = bid_trade_quantity;
- sell_limit_req.repeat_config = repeated_request_config_t{0, 3, 100};
- res.set(
- order_limit_grid_event(
- std::vector<limit_order_request_t>{sell_limit_req},
- std::vector<limit_order_request_t>{buy_limit_req}
- )
- );
- res.set_symbol(event.symbol);
- config_.logger->log(res, e_severity_level::INFO, "dealing with narrow spread result");
- return res;
- }
- return res;
- }
- double current_volume = calculate_deviated_value(config_.volume_distribution, 0.8 * config_.volume, 1.2 * config_.volume);
- config_.logger->log("current_volume: " + std::to_string(current_volume) + " previous price = " + std::to_string(config_.previous_price));
- config_.logger->log("start calculating new normal distributed price");
- double current_price = calculate_normal_distributed_price(config_.previous_price, bid_price + 1, ask_price - 1);
- double quantity = current_volume / current_price;
- config_.previous_price = current_price;
- if (config_.price_file.is_open()) {
- config_.logger->log("writing to volume price file");
- std::filesystem::resize_file(config_.path_to_price_file, 0);
- config_.price_file.seekp(0);
- config_.price_file << "{\"market_price\": \"" + std::to_string(current_price) + "\"}" << std::flush;
- }
- config_.logger->log("price: " + std::to_string(current_price) + "\nquantity: " + std::to_string(quantity));
- res.set(order_self_trade_event(current_price, quantity));
- res.set_symbol(event.symbol);
- return res;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement