From 0b7aa02704f6ece97d17fbb118519c5cc62caaba Mon Sep 17 00:00:00 2001
From: Joel Grunbaum <joelgrun@gmail.com>
Date: Wed, 19 Jan 2022 07:45:21 +0000
Subject: [PATCH] Bot prints exchange feed

---
 strat.cpp    |  115 +++++++++++++++++++
 json.hpp     |    9 +
 strat.hpp    |    7 
 bot.cpp      |   22 +++
 json.cpp     |  118 +++++++++++++++++--
 protocol.cpp |   57 +++++---
 protocol.hpp |    5 
 7 files changed, 289 insertions(+), 44 deletions(-)

diff --git a/bot.cpp b/bot.cpp
index 2b2d6f7..0a25597 100644
--- a/bot.cpp
+++ b/bot.cpp
@@ -1,3 +1,23 @@
 #include "strat.hpp"
+#include <csignal>
+#include <cstdlib>
+#include <iostream>
 
-int main(void) {}
+void signalHandler(int signum)
+{
+    strat::destroy();
+    std::exit(0);
+}
+
+void no(int signum)
+{
+    std::cout << "no." << std::endl;
+}
+
+int main(void)
+{
+    signal(SIGINT, signalHandler);
+    // signal(SIGTERM, no);
+    strat::initialise();
+    strat::mainLoop();
+}
diff --git a/json.cpp b/json.cpp
index a8b2397..d486ddc 100644
--- a/json.cpp
+++ b/json.cpp
@@ -24,6 +24,8 @@
 static std::unordered_map<std::string, book::OrderSideEnum> mapOrder;
 static std::unordered_map<std::string, TradeTypeEnum> mapTrade;
 static std::unordered_map<book::OrderSideEnum, std::string> mapOrderSide;
+static std::unordered_map<MessageTypes, std::string> mapAStr;
+static std::unordered_map<TradeTypeEnum, std::string> mapTTStr;
 
 void initialise()
 {
@@ -51,6 +53,15 @@
 	            {"BROKER_TRADE", BROKER_TRADE}};
 
 	mapOrderSide = {{book::Buy, "BUY"}, {book::Sell, "SELL"}};
+
+	mapAStr = {{FUTURE_TYPE, "FUTURE"},
+	           {SPREAD_TYPE, "SPREAD"},
+	           {CALL_TYPE, "CALL"},
+	           {PUT_TYPE, "PUT"}};
+
+	mapTTStr = {{BUY_AGGRESSOR, "BUY_AGGRESSOR"},
+	            {SELL_AGGRESSOR, "SELL_AGGRESSOR"},
+	            {BROKER_TRADE, "BROKER_TRADE"}};
 }
 
 Message* parseSingle(rapidjson::Value& d);
@@ -153,8 +164,8 @@
 SettleMessage* settle(rapidjson::Value& d)
 {
 	std::chrono::nanoseconds exp_time(0);
-    std::string es = d["expiry"].GetString();
-    exp_time = parseTime(es);
+	std::string es = d["expiry"].GetString();
+	exp_time = parseTime(es);
 	return new SettleMessage(
 		mapTypes[d["type"].GetString()], d["product"].GetString(),
 		d["stationName"].GetString(), exp_time, d["price"].GetDouble(),
@@ -163,11 +174,12 @@
 
 AddedMessage* added(rapidjson::Value& d)
 {
-	return new AddedMessage(
-		mapTypes[d["type"].GetString()], d["product"].GetString(),
-		d["id"].GetString(), mapOrder[d["side"].GetString()],
-		d["price"].GetDouble(), d["filled"].GetInt(), d["resting"].GetInt(),
-		d["sequence"].GetInt(), d["timestamp"].GetDouble());
+	return new AddedMessage(mapTypes[d["type"].GetString()],
+	                        d["product"].GetString(), d["id"].GetString(),
+	                        mapOrder[d["side"].GetString()],
+	                        d["price"].GetDouble(), d["filled"].GetInt(),
+	                        d["resting"].GetInt(), d["owner"].GetString(),
+	                        d["sequence"].GetInt(), d["timestamp"].GetDouble());
 }
 
 DeletedMessage* deleted(rapidjson::Value& d)
@@ -270,6 +282,20 @@
 {
 }
 
+std::string AnnounceMessage::as_string()
+{
+	return "{\"type\": \"" + mapAStr[this->type] =
+	           "\", \"product\": \"" + this->product +
+	           "\", \"stationId\": " + std::to_string(this->stationId) +
+	           "\", \"stationName\": \"" + this->stationName +
+	           "\", \"unit\": \"" + this->unit +
+	           "\", \"expiry\": " + std::to_string(this->expiry.count()) +
+	           ", \"aggressiveFee\": " + std::to_string(this->aggFee) +
+	           ", \"passiveFee\": " + std::to_string(this->pasFee) +
+	           ", \"sequence\": " + std::to_string(this->sequence) +
+	           ", \"timestamp\": " + std::to_string(this->timestamp) + "}";
+}
+
 SettleMessage::SettleMessage(MessageTypes type, std::string product,
                              std::string stationName,
                              std::chrono::nanoseconds expiry, double price,
@@ -277,6 +303,17 @@
 	: FromExchange(type, product, sequence, timestamp),
 	  stationName(stationName), expiry(expiry), price(price)
 {
+}
+
+std::string SettleMessage::as_string()
+{
+	return "{\"type\": \"" + mapAStr[this->type] =
+	           "\", \"product\": \"" + this->product +
+	           "\", \"stationName\": \"" + this->stationName +
+	           "\", \"expiry\": " + std::to_string(this->expiry.count()) +
+	           ", \"price\": " + std::to_string(this->price) +
+	           ", \"sequence\": " + std::to_string(this->sequence) +
+	           ", \"timestamp\": " + std::to_string(this->timestamp) + "}";
 }
 
 AddMessage::AddMessage(MessageTypes type, std::string product, double price,
@@ -297,22 +334,24 @@
 AddedMessage::AddedMessage(MessageTypes type, std::string product,
                            std::string id, book::OrderSideEnum side,
                            double price, uint64_t filled, uint64_t resting,
-                           uint64_t sequence, double timestamp)
+                           std::string owner, uint64_t sequence,
+                           double timestamp)
 	: FromExchange(type, product, sequence, timestamp), id(id), side(side),
-	  price(price), filled(filled), resting(resting)
+	  price(price), filled(filled), resting(resting), owner(owner)
 {
 }
 
 std::string AddedMessage::as_string()
 {
 	return "{\"type\": \"ADDED\", \"product\": \"" + this->product +
-	       "\", \"product\": \"" + this->id + "\" \"side\": \"" +
+	       "\", \"product\": \"" + this->id + "\", \"side\": \"" +
 	       mapOrderSide[this->side] +
 	       "\", \"price\": " + std::to_string(this->price) +
-	       "\"filled\": " + std::to_string(this->filled) +
+	       ", \"filled\": " + std::to_string(this->filled) +
 	       ", \"resting\": " + std::to_string(this->resting) +
-	       ", \"sequence\": " + std::to_string(this->sequence) +
-	       ", \"timestamp\":" + std::to_string(this->timestamp) + "}";
+	       ", \"owner\": \"" + this->owner +
+	       "\", \"sequence\": " + std::to_string(this->sequence) +
+	       ", \"timestamp\": " + std::to_string(this->timestamp) + "}";
 }
 
 DeleteMessage::DeleteMessage(MessageTypes type, std::string product,
@@ -338,10 +377,10 @@
 std::string DeletedMessage::as_string()
 {
 	return "{\"type\": \"DELETED\", \"product\": \"" + this->product +
-	       "\", \"product\": \"" + this->id + "\" \"side\": \"" +
+	       "\", \"product\": \"" + this->id + "\", \"side\": \"" +
 	       mapOrderSide[this->side] +
 	       ", \"sequence\": " + std::to_string(this->sequence) +
-	       ", \"timestamp\":" + std::to_string(this->timestamp) + "}";
+	       ", \"timestamp\": " + std::to_string(this->timestamp) + "}";
 }
 
 RejectMessage::RejectMessage(MessageTypes type, std::string product,
@@ -371,11 +410,35 @@
 {
 }
 
+std::string TradeMessage::as_string()
+{
+	return "{\"type\": \"TRADE\", \"product\": \"" + this->product +
+	       "\", \"price\": " + std::to_string(this->price) +
+	       ", \"volume\": " + std::to_string(this->volume) + ", \"buyer\": \"" +
+	       this->buyer + "\", \"seller\": \"" + this->seller +
+	       "\", \"tradeType\": \"" + mapTTStr[this->tradeType] +
+	       "\", \"passiveOrder\": \"" + this->passiveOrder +
+	       "\", \"passoveOrderRemaining\": " +
+	       std::to_string(this->passiveOrderRemaining) +
+	       "\", \"sequence\": " + std::to_string(this->sequence) +
+	       ", \"timestamp\": " + std::to_string(this->timestamp) + "}";
+}
+
 BrokerRequest::BrokerRequest(MessageTypes type, std::string product,
                              double price, book::OrderSideEnum side,
                              uint64_t volume, std::string counterparty)
 	: Broker(type, product, price, side, volume, counterparty)
 {
+}
+
+std::string BrokerRequest::as_string()
+{
+	return "{\"type\": \"" + mapAStr[this->type] =
+	           "\", \"product\": \"" + this->product +
+	           "\", \"price\": " + std::to_string(this->price) +
+	           ", \"side\": " + mapOrderSide[this->side] +
+	           ", \"volume\": " + std::to_string(this->volume) +
+	           ", \"counterparty\": \"" + this->counterparty + "\"}";
 }
 
 BrokerAck::BrokerAck(MessageTypes type, std::string product, double price,
@@ -387,6 +450,19 @@
 {
 }
 
+std::string BrokerAck::as_string()
+{
+	return "{\"type\": \"" + mapAStr[this->type] =
+	           "\", \"product\": \"" + this->product +
+	           "\", \"price\": " + std::to_string(this->price) +
+	           ", \"side\": " + mapOrderSide[this->side] +
+	           ", \"volume\": " + std::to_string(this->volume) +
+	           ", \"counterparty\": \"" + this->counterparty + +"\", \"id\"" +
+	           this->id +
+	           "\", \"brokerTradeStatus\": " + this->brokerTradeStatus +
+	           "\", \"owner\": \"" + this->owner + "\"}";
+}
+
 BrokerConfirm::BrokerConfirm(MessageTypes type, std::string product,
                              double price, book::OrderSideEnum side,
                              uint64_t volume, std::string counterparty,
@@ -394,4 +470,16 @@
 	: Broker(type, product, price, side, volume, counterparty), id(id)
 {
 }
+
+std::string BrokerConfirm::as_string()
+{
+	return "{\"type\": \"" + mapAStr[this->type] =
+	           "\", \"product\": \"" + this->product +
+	           "\", \"price\": " + std::to_string(this->price) +
+	           ", \"side\": " + mapOrderSide[this->side] +
+	           ", \"volume\": " + std::to_string(this->volume) +
+	           ", \"counterparty\": \"" + this->counterparty +
+	           "\", \"id\": " + this->id + "\"}";
+}
+
 } // namespace json
diff --git a/json.hpp b/json.hpp
index 45bf855..bfe2c50 100644
--- a/json.hpp
+++ b/json.hpp
@@ -82,6 +82,7 @@
 	                std::chrono::nanoseconds expiry, double aggFee,
 	                double pasFee, double broFee, uint64_t sequence,
 	                double timestamp);
+    std::string as_string();
 };
 
 struct SettleMessage : public FromExchange {
@@ -91,6 +92,7 @@
 	SettleMessage(MessageTypes type, std::string product,
 	              std::string stationName, std::chrono::nanoseconds expiry,
 	              double price, uint64_t sequence, double timestamp);
+    std::string as_string();
 };
 
 struct AddMessage : public ToExchange {
@@ -108,9 +110,10 @@
 	double price;
 	uint64_t filled;
 	uint64_t resting;
+    std::string owner;
 	AddedMessage(MessageTypes type, std::string product, std::string id,
 	             book::OrderSideEnum side, double price, uint64_t filled,
-	             uint64_t resting, uint64_t sequence, double timestamp);
+	             uint64_t resting, std::string owner, uint64_t sequence, double timestamp);
 	std::string as_string();
 };
 
@@ -149,12 +152,14 @@
 	             TradeTypeEnum tradeType, std::string passiveOrder,
 	             uint64_t passiveOrderRemaining, uint64_t sequence,
 	             double timestamp);
+	std::string as_string();
 };
 
 struct BrokerRequest : public Broker {
 	BrokerRequest(MessageTypes type, std::string product, double price,
 	              book::OrderSideEnum side, uint64_t volume,
 	              std::string counterparty);
+	std::string as_string();
 };
 
 struct BrokerAck : public Broker {
@@ -165,6 +170,7 @@
 	          book::OrderSideEnum side, uint64_t volume,
 	          std::string counterparty, std::string id,
 	          std::string brokerTradeStatus, std::string owner);
+	std::string as_string();
 };
 
 struct BrokerConfirm : public Broker {
@@ -172,6 +178,7 @@
 	BrokerConfirm(MessageTypes type, std::string product, double price,
 	              book::OrderSideEnum side, uint64_t volume,
 	              std::string counterparty, std::string id);
+	std::string as_string();
 };
 
 std::queue<Message*> parse(std::string& str);
diff --git a/protocol.cpp b/protocol.cpp
index 0492374..a4b8475 100644
--- a/protocol.cpp
+++ b/protocol.cpp
@@ -22,6 +22,7 @@
 	mapAnnounce;
 std::string server = std::string(HOST) + ":" + std::string(PORT);
 httplib::Client cli("http://" + server);
+std::unique_ptr<easywsclient::WebSocket> ws;
 
 double lastime = 0;
 
@@ -57,32 +58,44 @@
 	return bs;
 }
 
-void catchUp(std::unordered_map<std::string, book::Book>& bs)
+void createWebSocket()
 {
-	static std::unique_ptr<easywsclient::WebSocket> ws(
-		easywsclient::WebSocket::from_url("ws://" + server + "/information"));
-	std::string feed;
-	bool gotMessage = false;
+	ws = std::unique_ptr<easywsclient::WebSocket>(
+		easywsclient::WebSocket::pointer(easywsclient::WebSocket::from_url(
+			"ws://" + server + "/information")));
 	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;
+}
+
+std::deque<json::Message*>
+catchUp(std::unordered_map<std::string, book::Book>& bs)
+{
+	std::string feed;
+	bool gotMessage;
+	std::deque<json::Message*> out;
+	do {
+		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());
+				out.push_back(a.front());
+				a.pop();
 			}
-			protocol::handleMessage(bs, a.front());
-			delete a.front();
-			a.pop();
 		}
-	}
+	} while (gotMessage);
+	return out;
 }
 
 json::Message* addOrder(json::AddMessage& order)
diff --git a/protocol.hpp b/protocol.hpp
index 386d6af..a1a371d 100644
--- a/protocol.hpp
+++ b/protocol.hpp
@@ -3,6 +3,7 @@
 #include "book.hpp"
 #include "json.hpp"
 
+#include <deque>
 #include <string>
 #include <unordered_map>
 
@@ -12,7 +13,9 @@
 
 // Catchup utilities
 std::unordered_map<std::string, book::Book> recoverBook();
-void catchUp(std::unordered_map<std::string, book::Book>& bs);
+void createWebSocket();
+std::deque<json::Message*>
+catchUp(std::unordered_map<std::string, book::Book>& bs);
 
 // Outgoing messages
 json::Message* addOrder(json::AddMessage& order);
diff --git a/strat.cpp b/strat.cpp
index fdd367d..2856c1a 100644
--- a/strat.cpp
+++ b/strat.cpp
@@ -1,6 +1,121 @@
 #include "strat.hpp"
 
+#include "bom.hpp"
+#include "book.hpp"
+#include "json.hpp"
+#include "secrets.hpp"
+
+#include "protocol.hpp"
+#include <deque>
+#include <unordered_map>
+
 namespace strat
 {
+std::unordered_map<std::string, json::Message*> orders;
 
+void deleteOrder(json::AddedMessage* m);
+void freeMessages(std::deque<json::Message*>& m);
+void printFeed(std::deque<json::Message*>& m);
+void dumbHit(std::deque<json::Message*>& m);
+
+void initialise()
+{
+	bom::initialise();
+	protocol::createWebSocket();
 }
+
+void destroy()
+{
+	bom::destroy();
+	for (auto& i : orders) {
+		switch (i.second->type) {
+		case json::FUTURE_TYPE:
+		case json::SPREAD_TYPE:
+		case json::CALL_TYPE:
+		case json::PUT_TYPE:
+			deleteOrder((json::AddedMessage*)i.second);
+		default:;
+		}
+		delete i.second;
+	}
+}
+
+void mainLoop()
+{
+	auto bs = protocol::recoverBook();
+	while (true) {
+		auto messages = protocol::catchUp(bs);
+		// bom::updateBom(bs);
+		printFeed(messages);
+		freeMessages(messages);
+	}
+}
+
+void deleteOrder(json::AddedMessage* m)
+{
+	json::DeleteMessage a(json::DELETE, m->product, m->id);
+	delete protocol::deleteOrder(a);
+}
+
+void printFeed(std::deque<json::Message*>& m)
+{
+	for (auto& i : m) {
+		switch (i->type) {
+		case json::FUTURE_TYPE:
+		case json::SPREAD_TYPE:
+		case json::CALL_TYPE:
+		case json::PUT_TYPE:
+			std::cout << ((json::AnnounceMessage*)i)->as_string() << std::endl;
+			break;
+		case json::SETTLEMENT:
+			std::cout << ((json::SettleMessage*)i)->as_string() << std::endl;
+			break;
+		case json::ADDED:
+			std::cout << ((json::AddedMessage*)i)->as_string() << std::endl;
+			break;
+		case json::DELETED:
+			std::cout << ((json::DeletedMessage*)i)->as_string() << std::endl;
+			break;
+		case json::TRADE:
+			std::cout << ((json::TradeMessage*)i)->as_string() << std::endl;
+			break;
+		case json::BROKER_REQUEST:
+			std::cout << ((json::BrokerRequest*)i)->as_string() << std::endl;
+			break;
+		case json::BROKER_ACK:
+			std::cout << ((json::BrokerAck*)i)->as_string() << std::endl;
+			break;
+		case json::BROKER_CONFIRM:
+			std::cout << ((json::BrokerConfirm*)i)->as_string() << std::endl;
+			break;
+		default:;
+		}
+	}
+}
+
+void freeMessages(std::deque<json::Message*>& m)
+{
+	for (auto i : m) {
+		delete i;
+	}
+}
+
+void dumbHit(std::deque<json::Message*>& m)
+{
+    for (auto& i : m) {
+        if (i->type == json::ADDED) {
+            json::AddedMessage* j = (json::AddedMessage*) i;
+            if (j->owner == "nseow") {
+                book::OrderSideEnum s = j->side == book::Buy ? book::Sell : book::Buy;
+                json::AddMessage a(json::ADD, j->product, j->price, s, j->resting);
+                auto b = protocol::addOrder(a);
+                if (b->type == json::ADDED) {
+                    json::DeleteMessage d(json::DELETE, j->product, ((json::AddedMessage*) b)->id);
+                    delete protocol::deleteOrder(d);
+                }
+                delete b;
+            }
+        }
+    }
+}
+} // namespace strat
diff --git a/strat.hpp b/strat.hpp
index 836984b..dd02bf5 100644
--- a/strat.hpp
+++ b/strat.hpp
@@ -1,9 +1,8 @@
 #pragma once
 
-#include "book.hpp"
-#include <string>
-#include <unordered_map>
-
 namespace strat
 {
+    void initialise();
+    void destroy();
+    void mainLoop();
 }

--
Gitblit v1.9.3