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