.gitmodules | ●●●●● patch | view | raw | blame | history | |
CMakeLists.txt | ●●●●● patch | view | raw | blame | history | |
book.cpp | ●●●●● patch | view | raw | blame | history | |
book.hpp | ●●●●● patch | view | raw | blame | history | |
easywsclient @ afc1d8 | ●●●●● patch | view | raw | blame | history | |
json.cpp | ●●●●● patch | view | raw | blame | history | |
json.hpp | ●●●●● patch | view | raw | blame | history | |
protocol.cpp | ●●●●● patch | view | raw | blame | history | |
protocol.hpp | ●●●●● patch | view | raw | blame | history | |
secrets.hpp | ●●●●● patch | view | raw | blame | history | |
test.cpp | ●●●●● patch | view | raw | blame | history |
.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 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) 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); 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; easywsclient
New file @@ -0,0 +1 @@ Subproject commit afc1d8cfc584e0f1f4a77e8c0ce3e979d9fe7ce2 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"}}; } 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; 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); 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); secrets.hpp
@@ -2,7 +2,7 @@ #include <string> #define TEST // #define TEST constexpr const char* HOST = "sytev070"; #ifdef TEST 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;