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