From 4fdb65896bb30efb30fb22342e5b44dd481250dd Mon Sep 17 00:00:00 2001 From: Joel Grunbaum <joelgrun@gmail.com> Date: Tue, 11 Jan 2022 07:04:05 +0000 Subject: [PATCH] Websocket added --- test.cpp | 5 + .gitmodules | 3 book.cpp | 73 +++++------------- json.hpp | 2 easywsclient | 1 book.hpp | 5 secrets.hpp | 2 json.cpp | 3 protocol.cpp | 100 ++++++++++++++++-------- protocol.hpp | 1 CMakeLists.txt | 4 11 files changed, 106 insertions(+), 93 deletions(-) diff --git a/.gitmodules b/.gitmodules index c935847..afeefb7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "rapidjson"] path = rapidjson url = https://github.com/Tencent/rapidjson.git +[submodule "easywsclient"] + path = easywsclient + url = https://github.com/dhbaird/easywsclient.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 94cf3a1..d607e47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,12 @@ add_subdirectory(date) # add_subdirectory(rapidjson) +add_library(WS easywsclient/easywsclient.cpp) + add_library(JSON json.cpp) add_library(MAIN date protocol.cpp book.cpp) -target_link_libraries(MAIN PUBLIC JSON) +target_link_libraries(MAIN PUBLIC JSON WS) add_executable(test test.cpp strat.cpp) add_executable(bot bot.cpp strat.cpp) diff --git a/book.cpp b/book.cpp index a450a08..7d74c6b 100644 --- a/book.cpp +++ b/book.cpp @@ -3,6 +3,7 @@ #include <chrono> #include <cstddef> #include <iostream> +#include <string> namespace book { @@ -91,73 +92,41 @@ void Book::ask(Order& order) { - while (this->bidSide.size() && this->bidSide[0].price >= order.price) { - if (this->bidSide[0].volume > order.remaining_volume) { - int temp = this->bidSide[0].volume; - order.filled_volume += temp; - this->bidSide.front().volume -= order.remaining_volume; - order.remaining_volume -= temp; - break; - } else { - order.remaining_volume -= this->bidSide[0].volume; - order.filled_volume += this->bidSide[0].volume; - this->bidSide.erase(this->bidSide.begin()); - std::make_heap(this->bidSide.begin(), this->bidSide.end(), - std::less<Level>()); - } - } - if (order.remaining_volume > 0) { - this->askSide.emplace_back(order); - std::make_heap(this->askSide.begin(), this->askSide.end(), - std::greater<Level>()); - } + auto a = + this->askSide.emplace(order.id, order); + if (!a.second) { + std::cout << order.id << "already exists" << std::endl; + } } void Book::bid(Order& order) { - while (this->askSide.size() && this->askSide[0].price <= order.price) { - if (this->askSide[0].volume > order.remaining_volume) { - int temp = this->askSide.front().volume; - order.filled_volume += temp; - this->askSide.front().volume -= order.remaining_volume; - order.remaining_volume -= temp; - break; - } else { - order.remaining_volume -= this->askSide[0].volume; - order.filled_volume += this->askSide[0].volume; - this->askSide.erase(this->askSide.begin()); - std::make_heap(this->askSide.begin(), this->askSide.end(), - std::greater<Level>()); - } - } - if (order.remaining_volume > 0) { - this->bidSide.emplace_back(order); - std::make_heap(this->bidSide.begin(), this->bidSide.end(), - std::less<Level>()); - } + auto a = + this->bidSide.emplace(order.id, order); + if (!a.second) { + std::cout << order.id << "already exists" << std::endl; + } } void Book::printBook(std::size_t numOrders) { std::cout << "Sell side: " << this->askSide.size() << std::endl; - std::vector<Level> askCopy(this->askSide); + std::vector<Level> askCopy; + for (auto i : this->askSide) askCopy.push_back(i.second); std::size_t count = 0; std::sort(askCopy.begin(), askCopy.end()); - std::reverse(askCopy.begin(), askCopy.end()); - double price = askCopy.front().price; - for (auto i : askCopy) { - std::cout << i << std::endl; + for (auto i = askCopy.rbegin(); i != askCopy.rend(); i++) { + std::cout << *i << std::endl; count++; if (count > numOrders) break; } std::cout << "Buy side: " << this->bidSide.size() << std::endl; - std::vector<Level> bidCopy(this->bidSide); + std::vector<Level> bidCopy; + for (auto i : this->bidSide) bidCopy.push_back(i.second); count = 0; std::sort(bidCopy.begin(), bidCopy.end()); - std::reverse(bidCopy.begin(), bidCopy.end()); - price = bidCopy.front().price; - for (auto i : bidCopy) { - std::cout << i << std::endl; + for (auto i = bidCopy.rbegin(); i != bidCopy.rend(); i++) { + std::cout << *i << std::endl; count++; if (count > numOrders) break; } @@ -168,11 +137,11 @@ Book b = Book(); double time(1); for (int i = 1; i < orders; i++) { - Order t(i, Buy, 10, time++, "a"); + Order t(i, Buy, 10, time++, std::to_string(i)); b.bid(t); } for (int i = orders + 1; i < 2 * orders; i++) { - Order t(i, Sell, 10, time++, "b"); + Order t(i, Sell, 10, time++, std::to_string(i)); b.ask(t); } if (printBook) b.printBook(orders - 1); diff --git a/book.hpp b/book.hpp index ae89819..04de3a7 100644 --- a/book.hpp +++ b/book.hpp @@ -6,6 +6,7 @@ #include <iostream> #include <queue> #include <string> +#include <unordered_map> #include <vector> namespace book @@ -42,8 +43,8 @@ std::ostream& operator<<(std::ostream& out, const Level& a); struct Book { - std::vector<Level> bidSide; - std::vector<Level> askSide; + std::unordered_map<std::string, Level> bidSide; + std::unordered_map<std::string, Level> askSide; ProductTypeEnum productType; std::string product; int stationId; diff --git a/easywsclient b/easywsclient new file mode 160000 index 0000000..afc1d8c --- /dev/null +++ b/easywsclient @@ -0,0 +1 @@ +Subproject commit afc1d8cfc584e0f1f4a77e8c0ce3e979d9fe7ce2 diff --git a/json.cpp b/json.cpp index ea1016a..f64f677 100644 --- a/json.cpp +++ b/json.cpp @@ -48,7 +48,8 @@ mapOrder = {{"BUY", book::Buy}, {"SELL", book::Sell}}; mapTrade = {{"BUY_AGGRESSOR", BUY_AGGRESSOR}, - {"SELL_AGGRESSOR", SELL_AGGRESSOR}}; + {"SELL_AGGRESSOR", SELL_AGGRESSOR}, + {"BROKER_TRADE", BROKER_TRADE}}; mapOrderSide = {{book::Buy, "BUY"}, {book::Sell, "SELL"}}; } diff --git a/json.hpp b/json.hpp index 9da1381..45bf855 100644 --- a/json.hpp +++ b/json.hpp @@ -29,7 +29,7 @@ NONE }; -enum TradeTypeEnum { BUY_AGGRESSOR, SELL_AGGRESSOR }; +enum TradeTypeEnum { BUY_AGGRESSOR, SELL_AGGRESSOR, BROKER_TRADE }; struct Message { MessageTypes type; diff --git a/protocol.cpp b/protocol.cpp index 0e168f5..e21a2df 100644 --- a/protocol.cpp +++ b/protocol.cpp @@ -2,13 +2,17 @@ #include "book.hpp" #include "cpp-httplib/httplib.h" +#include "easywsclient/easywsclient.hpp" #include "json.hpp" #include "secrets.hpp" #include <chrono> +#include <cstddef> #include <iostream> +#include <memory> #include <queue> #include <sstream> +#include <stdexcept> #include <string> #include <unordered_map> @@ -18,6 +22,8 @@ mapAnnounce; std::string server = std::string(HOST) + ":" + std::string(PORT); httplib::Client cli("http://" + server); + +double lastime = 0; void initialise() { @@ -40,11 +46,43 @@ l = res->body; std::queue<json::Message*> a(json::parse(l)); while (!a.empty()) { - protocol::handleMessage(bs, a.front()); + if (static_cast<json::FromExchange*>(a.front()) != nullptr || + static_cast<json::FromExchange*>(a.front())->timestamp > lastime) { + lastime = static_cast<json::FromExchange*>(a.front())->timestamp; + protocol::handleMessage(bs, a.front()); + } delete a.front(); a.pop(); } return bs; +} + +void catchUp(std::unordered_map<std::string, book::Book>& bs) +{ + static std::unique_ptr<easywsclient::WebSocket> ws( + easywsclient::WebSocket::from_url("ws://" + server + "/information")); + std::string feed; + bool gotMessage = false; + ws->poll(); + ws->dispatch([gotMessageOut = &gotMessage, messageOut = &feed, + ws = ws.get()](const std::string& message) { + *gotMessageOut = true; + *messageOut = message; + }); + if (gotMessage) { + std::queue<json::Message*> a(json::parse(feed)); + while (!a.empty()) { + if (static_cast<json::FromExchange*>(a.front()) != nullptr || + static_cast<json::FromExchange*>(a.front())->timestamp > + lastime) { + lastime = + static_cast<json::FromExchange*>(a.front())->timestamp; + } + protocol::handleMessage(bs, a.front()); + delete a.front(); + a.pop(); + } + } } json::Message* addOrder(json::AddMessage& order) @@ -63,6 +101,9 @@ json::Message* message) { if (mapAnnounce.empty()) initialise(); + if (dynamic_cast<json::FromExchange*>(message) != nullptr) { + lastime = dynamic_cast<json::FromExchange*>(message)->timestamp; + } switch (message->type) { case json::FUTURE_TYPE: case json::SPREAD_TYPE: @@ -107,11 +148,11 @@ void addedOrder(std::unordered_map<std::string, book::Book>& bs, json::AddedMessage* message) { - if (message->side == book::Buy) { + if (message->side == book::Buy && message->resting) { book::Order t(message->price, book::Buy, message->resting, message->timestamp, message->id); bs[message->product].bid(t); - } else { + } else if (message->side == book::Sell && message->resting) { book::Order t(message->price, book::Sell, message->resting, message->timestamp, message->id); bs[message->product].ask(t); @@ -121,42 +162,33 @@ json::DeletedMessage* message) { if (message->side == book::Buy) { - for (std::size_t i = 0; i < bs[message->product].bidSide.size(); i++) { - if (bs[message->product].bidSide[i].id == message->id) { - bs[message->product].bidSide[i] = - bs[message->product].bidSide.back(); - bs[message->product].bidSide.pop_back(); - std::make_heap(bs[message->product].bidSide.begin(), - bs[message->product].bidSide.end(), - std::less<book::Level>()); - } - } + bs[message->product].bidSide.erase(message->id); } else { - for (std::size_t i = 0; i < bs[message->product].askSide.size(); i++) { - if (bs[message->product].askSide[i].id == message->id) { - bs[message->product].askSide[i] = - bs[message->product].askSide.back(); - bs[message->product].askSide.pop_back(); - std::make_heap(bs[message->product].askSide.begin(), - bs[message->product].askSide.end(), - std::greater<book::Level>()); - } - } + bs[message->product].askSide.erase(message->id); } } void tradeOrder(std::unordered_map<std::string, book::Book>& bs, json::TradeMessage* message) { - if (message->tradeType == json::BUY_AGGRESSOR) { - book::Order t(message->price, book::Buy, message->volume, - message->timestamp, message->passiveOrder); - bs[message->product].bid(t); - } else { - book::Order t(message->price, book::Sell, message->volume, - message->timestamp, message->passiveOrder); - bs[message->product].ask(t); + if (bs.contains(message->passiveOrder)) { + if (message->tradeType == json::BUY_AGGRESSOR) { + if (message->passiveOrderRemaining > 0) { + bs[message->product].askSide.at(message->passiveOrder).volume = + message->passiveOrderRemaining; + } else { + bs[message->product].askSide.erase(message->passiveOrder); + } + } else if (message->tradeType == json::SELL_AGGRESSOR) { + if (message->passiveOrderRemaining > 0) { + bs[message->product].bidSide.at(message->passiveOrder).volume = + message->passiveOrderRemaining; + } else { + bs[message->product].bidSide.erase(message->passiveOrder); + } + } } } + void broker(std::unordered_map<std::string, book::Book>& bs, json::Broker* message) { @@ -164,9 +196,9 @@ json::Message* send(std::string& message) { - httplib::MultipartFormDataItems a = {{"message", message, "", ""}, - {"username", USER, "", ""}, - {"password", PASS, "", ""}}; + httplib::MultipartFormDataItems a = {{"message", message, "", ""}, + {"username", USER, "", ""}, + {"password", PASS, "", ""}}; auto res = cli.Post("/execution", a); std::string b = res->body; std::queue<json::Message*> c = json::parse(b); diff --git a/protocol.hpp b/protocol.hpp index 1893fd0..386d6af 100644 --- a/protocol.hpp +++ b/protocol.hpp @@ -12,6 +12,7 @@ // Catchup utilities std::unordered_map<std::string, book::Book> recoverBook(); +void catchUp(std::unordered_map<std::string, book::Book>& bs); // Outgoing messages json::Message* addOrder(json::AddMessage& order); diff --git a/secrets.hpp b/secrets.hpp index 24acfae..398da5c 100644 --- a/secrets.hpp +++ b/secrets.hpp @@ -2,7 +2,7 @@ #include <string> -#define TEST +// #define TEST constexpr const char* HOST = "sytev070"; #ifdef TEST diff --git a/test.cpp b/test.cpp index 843cbe3..68371ea 100644 --- a/test.cpp +++ b/test.cpp @@ -2,11 +2,14 @@ #include "json.hpp" #include "protocol.hpp" #include <chrono> +#include <unistd.h> +#include <unordered_map> int main(void) { // book::Book b = book::testBook(10, true); - auto bs = protocol::recoverBook(); + auto bs = protocol::recoverBook(); + protocol::catchUp(bs); std::cout << bs.size() << std::endl; for (auto i : bs) { std::cout << i.first << std::endl; -- Gitblit v1.9.3