bot.cpp | ●●●●● patch | view | raw | blame | history | |
json.cpp | ●●●●● patch | view | raw | blame | history | |
json.hpp | ●●●●● patch | view | raw | blame | history | |
protocol.cpp | ●●●●● patch | view | raw | blame | history | |
protocol.hpp | ●●●●● patch | view | raw | blame | history | |
strat.cpp | ●●●●● patch | view | raw | blame | history | |
strat.hpp | ●●●●● patch | view | raw | blame | history |
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(); } 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 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); 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) 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); 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 strat.hpp
@@ -1,9 +1,8 @@ #pragma once #include "book.hpp" #include <string> #include <unordered_map> namespace strat { void initialise(); void destroy(); void mainLoop(); }