#ifndef COINBASE_ORDERBOOK_H #define COINBASE_ORDERBOOK_H #include #include struct OrderBook { // price qty using BidBook = std::map>; using AskBook = std::map>; BidBook m_bids; AskBook m_asks; int64_t getTime(const std::string& eventTime) { // 2023-01-17T16:53:49.212563Z size_t pos = eventTime.find_first_of('.'); std::string YMD_HMS = eventTime.substr(0, pos); std::string microsStr = eventTime.substr(pos + 1); microsStr.erase(microsStr.size() - 1); int64_t micros = atol(microsStr.c_str()); std::tm t = {}; std::istringstream ss(YMD_HMS); ss >> std::get_time(&t, "%Y-%m-%dT%H:%M:%S"); if (ss.fail()) std::cerr << "Parse failed " << eventTime << std::endl; time_t secondsSinceEpoch = mktime(&t); int64_t nanos = micros * 1000; int64_t secondsInNanos = secondsSinceEpoch * 1E9; int64_t nanosSinceEpoch = secondsInNanos + nanos; return nanosSinceEpoch; } template void insert(Book& book, const Json::Value& price, const Json::Value& quantity, const Json::Value& eventTime) { double px = atof(price.asString().c_str()); double qty = atof(quantity.asString().c_str()); [[maybe_unused]] int64_t time = getTime(eventTime.asString()); auto iter = book.find(px); if ( iter != book.end()) { if (qty == 0.0) { book.erase(iter); } else iter->second = qty; } else { if (qty != 0.0) { book.insert(std::make_pair(px, qty)); } } } void dump(size_t count = UINT_MAX) { std::cout << "************* ORDER BOOK DUMP ***************\n"; std::cout << std::fixed; std::cout << "Asks size: " << m_asks.size() << std::endl; std::cout << "Bids size: " << m_bids.size() << std::endl; std::cout << std::setw(10) << "price (USD)" << std::setw(20) << "qty (BTC)" << std::endl; std::cout << std::setfill('-') << std::setw(10) << "-" << std::setfill(' ') << std::setw(10) << " " << std::setfill('-') << std::setw(10) << "-" << std::setfill(' ') << std::endl; auto iter = m_asks.rbegin(); if (m_asks.size() > count) std::advance(iter, m_asks.size() - count); while (iter != m_asks.rend()) { std::cout << std::setprecision(2) << std::setw(10) << iter->first << std::setw(20) << std::setprecision(8) << iter->second << " ASK\n"; iter++; } std::cout << std::endl; size_t num = 1; for (auto iter: m_bids) { std::cout << std::setprecision(2) << std::setw(10) << iter.first << std::setw(20) << std::setprecision(8) << iter.second << " BID\n"; if (num++ == count) break; } } void topOfBook() { std::cout << "************* TOP OF BOOK ***************\n"; std::cout << std::setw(10) << "price (USD)" << std::setw(20) << "qty (BTC)" << std::endl; std::cout << std::setfill('-') << std::setw(10) << "-" << std::setfill(' ') << std::setw(10) << " " << std::setfill('-') << std::setw(10) << "-" << std::setfill(' ') << std::endl; auto bid = m_bids.begin(); auto ask = m_asks.begin(); std::cout << std::setprecision(2) << std::setw(10) << ask->first << std::setw(20) << std::setprecision(8) << ask->second << " ASK\n"; std::cout << std::setprecision(2) << std::setw(10) << bid->first << std::setw(20) << std::setprecision(8) << bid->second << " BID\n"; } }; #endif