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>
@@ -19,6 +23,8 @@
std::string server = std::string(HOST) + ":" + std::string(PORT);
httplib::Client cli("http://" + server);
+double lastime = 0;
+
void initialise()
{
mapAnnounce = {{json::FUTURE_TYPE, book::FUTURE},
@@ -40,13 +46,45 @@
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)
{
std::string message = order.as_string();
@@ -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.10.0