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,
@@ -279,6 +305,17 @@
{
}
+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,
book::OrderSideEnum side, uint64_t volume)
: ToExchange(type, product), price(price), side(side), volume(volume)
@@ -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,6 +410,20 @@
{
}
+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)
@@ -378,6 +431,16 @@
{
}
+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,
book::OrderSideEnum side, uint64_t volume,
std::string counterparty, std::string id,
@@ -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.10.0