Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <atomic>
- #include <iostream>
- #include <cstdlib>
- #include <mutex>
- #include <random>
- #include <optional>
- #include <stdexcept>
- #include <exception>
- #include <python_connector.hpp>
- #include <tools.hpp>
- // Constants
- const std::string SELL = "sell";
- const std::string BUY = "buy";
- const std::string LIMIT = "limit";
- const std::string LIMIT_MAKER = "limit_maker";
- const std::string MARKET = "market";
- // thought: enum class OrderBookForm { Pyramid, Other };
- class MarketMakingManager {
- public:
- MarketMakingManager(int argc, char* argv[]) {
- args = tt::parse_args(argc, argv);
- market_ = std::make_shared<mm::python_connector>(args["keys"].c_str(), named_args["market"]);
- symbol_ = mm::ticker(args["symbol"], *market_);
- using conv_fn = std::function<void(const std::string&)>;
- std::unordered_map<std::string, conv_fn> cnv = {
- {"n_lvl", [&n_lvl_](const auto& v) { n_lvl_ = std::stoi(v); }},
- {"n_base", [&n_base_](const auto& v) { n_base_ = std::stoi(v); }},
- {"base_size_to_remain", [&base_size_to_remain_](const auto& v) { base_size_to_remain_ = std::stod(v); }},
- {"first_order_size_", [&first_order_size_](const auto& v) { first_order_size_ = std::stod(v); }},
- {"balance", [&balance_](const auto& v) { balance_ = std::stod(v); }},
- {"spread_size", [&spread_size_](const auto& v) { spread_size_ = std::stod(v); }},
- {"cooldown", [&cooldown_](const auto& v) { cooldown_ = std::stod(v); }},
- {"price_step", [&price_step_](const auto& v) { price_step_ = std::stoi(v); }},
- {"min_order_size", [&min_order_size_](const auto& v) { min_order_size_ = std::stod(v); }},
- };
- for (const auto& [k, c] : cnv) {
- try {
- if (args.count(k)) c(args[k]);
- } catch (const std::exception& e) {
- std::cerr << "Error for key " << k << ": " << e.what() << '\n';
- std::exit(EXIT_FAILURE);
- }
- }
- }
- void CalculateOrders(
- std::vector<mm::float_param_t>& ask_prices
- std::vector<mm::float_param_t>& ask_amount
- std::vector<mm::float_param_t>& bid_prices
- std::vector<mm::float_param_t>& bid_amount)
- {
- // thought: вообще, здесь мы хотим, чтобы был лок в коннекторе на операции, чтобы баланс не менялся
- double base_balance = market_->get_acc_balance(symbol_.base) * balance_;
- double quote_balance = market_->get_acc_balance(symbol_.base) * balance_;
- auto mid_price = mm::float_x((book_.a + book_.b) / 2, symbol_.price_prec);
- auto ask_price = mm::float_x(mid_price(1 + spread_size_ / 2), symbol_.price_prec);
- auto bid_price = mm::float_x(mid_price(1 - spread_size_ / 2), symbol_.price_prec);
- if (first_order_size_ * base_balance < min_order_size_) { // thought: тут можно либо упасть, либо выставлять объёмы не по параметрам указанным + лог
- std::cerr << "Bad input: first offer < minimal order size";
- exit(EXIT_FAILURE);
- }
- if (first_order_size_ * n_base_ > 1) { // thought: пока что не очень хорошая параметризация, надо к процентной перейти
- std::cerr << "Bad input: balance / n <= first offer";
- exit(EXIT_FAILURE);
- }
- auto delta_volume = 2 * base_size_to_remain_ * base_balance * (1 - first_order_size_ * n_base_) / (n_base_ * (n_base_ - 1));
- // пока только base часть, потому что формула итак неоптимальная, надо подправить
- for (int i = 0; i < n_base_; ++i) {
- volume_i = first_order_size_ * base_balance * base_size_to_remain_ + delta_volume * (i - 1);
- ask_prices.push_back(ask_price + price_step_ * symbol_.price_step * (n_base_ - 1)); // thought: тут вроде доп каст нужен, чтобы умножилось
- ask_amount.push_back(volume_i / ask_prices[i]);
- bid_prices.push_back(bid_price - price_step_ * symbol_.price_step * (n_base_ - 1));
- bid_amount.push_back(volume_i / bid_prices[i]);
- }
- }
- void BalancesPhaseCb(bool result) {
- if (!result) {
- // tought: немного странно такую пустую ситуацию ифать, мб можно красивее сделать
- // Внутри коннектора мы залогировали эту ситуацию
- return;
- }
- // thought: Нужен ли калибровочный ордер?
- std::vector<mm::float_param_t> a, b, A, B;
- CalculateOrders(a, A, b, B);
- // TODO: добавить ретраи
- market_->new_batch_order(symbol, SELL, LIMIT_MAKER, A, a, {}); // thought: склеить бы вместе количествои цену тут
- market_->new_batch_order(symbol, BUY, LIMIT_MAKER, B, b, {}); // + по-хорошему убелиться бы, что выложили
- }
- void CancelPhaseCb(bool result) {
- if (!result) {
- return;
- }
- market_->update_balances(BalancesPhaseCb);
- }
- void ManageOrdersCb(std::vector<mm::book> books) { // now we got one book
- // TODO: пока что непонятно при такой архитектуре, где cooldown использовать
- std::lock_guard<std::mutex> guard(m_);
- book_ = books.front();
- // TODO: добавить условия на то, когда перевыставляем ордера
- market_->cancel_all_orders(symbol, CancelPhaseCb);
- }
- void Start() {
- try {
- market_->open_trade_listener(symbol, {});
- market_->open_book_listener(symbol, ManageOrdersCb);
- market_->start();
- } catch (const std::exception& e) {
- std::cerr << "Main: Error" << e.what() << "\n";
- exit(EXIT_FAILURE);
- }
- /*
- // Так как пока непонятно как извне с коннектором работать, то пока закомментим
- // Хочется отделить сущность коннектора и маркет мейкингового алгоса
- std::thread{[&]() {
- try {
- market->open_trade_listener(symbol, {});
- market->open_book_listener(symbol, ManageOrdersCb);
- market->start();
- } catch (const std::exception& e) {
- std::cerr << "Main: Error" << e.what() << "\n";
- exit(EXIT_FAILURE);
- }
- }}.detach(); // thought: а что если коннектор упадёт и может ли такое быть
- while(true) {
- ManageOrders();
- std::this_thread::sleep_for(std::chrono::milliseconds(cooldown_)); // thought: далее тут можно condvar на пробуждение поставить
- }
- */
- }
- private:
- // Market
- std::make_shared<mm::python_connector> market_;
- mm::ticker ticker_;
- mm::book book_;
- // Control
- int n_lvl_ = 8;
- int n_base = 3;
- double base_size_to_remain_ = 0.15; // in percentages
- double first_order_size_ = 0.1;
- double balance_;
- double spread_size_ = 0.05; // in percentages
- int cooldown_ = 60000; // in ms
- int price_step_ = 1;
- double min_order_size_;
- // System
- std::mutex m_;
- };
- /**
- ./market_making --symbol=BTCUSDT --latency_in=20, --latency_out=3, --filename=../data/new_19502_1 --bal=5000
- ./market_making --keys=../market_making.keys --market=lbank --symbol=wei_usdt --spread_size=0.05
- * Bitmart
- ./market_making --keys=../keys/bitmart_mm.keys --market=bitmart --symbol=VAB_USDT --spread_size=0.05
- Full list:
- --keys : Key filepath
- --market : Name of market (e.g. lbank, mexc, bitmart)
- --symbol : Name of the currency pair. could be in a different format (e.g. wei_usdt, CHEELUSDT, VAB_USDT)
- --q : Quantity of account's balance that we're using for trades
- --cooldown : Timeout between orders in Ms (approximated)
- --n_lvl : Number of levels what we want to have for each side. (Inside spread. (Also same amount of orders outside spread)
- --calib_coef : How smooth the calibtaion is. Higher value - stronger calibration.
- --spread_size : Targeted spread size. Value in percentage of mid_pr
- --tagret_price : Used for price support. Algorithm will try to put orders around target_price, or come closer to it
- --ema_mid_price : EMA. System.
- --alpha : Alpha coefficient for EMA. Affects more sensetive price changing filter
- --price_change_limit : Price change limitation for EMA calculation (0.2 = 10% in two ways)
- --qty : Lower balance limit (in Base) for trade termination
- --min_order_size : Minimal order size in base currency (USDT)
- --beta : Largest order / smallest order coeffitient
- */
- int main(int argc, char* argv[]) {
- auto currentMarketMakingManager = std::make_shared<MarketMakingManager>(argc, argv);
- currentMarketMakingManager->Start();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement