#include "json.hpp" #include "book.hpp" #include "protocol.hpp" #include "rapidjson/include/rapidjson/document.h" #include "rapidjson/include/rapidjson/rapidjson.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace json { static std::unordered_map mapTypes; static std::unordered_map mapAnnounce; static std::unordered_map mapOrder; static std::unordered_map mapTrade; static std::unordered_map mapOrderSide; static std::unordered_map mapAStr; static std::unordered_map mapTTStr; void initialise() { mapTypes = {{"FUTURE", FUTURE_TYPE}, {"SPREAD", SPREAD_TYPE}, {"CALL", CALL_TYPE}, {"PUT", PUT_TYPE}, {"SETTLEMENT", SETTLEMENT}, {"ADDED", ADDED}, {"DELETED", DELETED}, {"TRADE", TRADE}, {"BROKER_REQUEST", BROKER_REQUEST}, {"BROKER_ACK", BROKER_ACK}, {"BROKER_CONFIRM", BROKER_CONFIRM}}; mapAnnounce = {{FUTURE_TYPE, book::FUTURE}, {SPREAD_TYPE, book::SPREAD}, {CALL_TYPE, book::CALL}, {PUT_TYPE, book::PUT}}; mapOrder = {{"BUY", book::Buy}, {"SELL", book::Sell}}; mapTrade = {{"BUY_AGGRESSOR", BUY_AGGRESSOR}, {"SELL_AGGRESSOR", SELL_AGGRESSOR}, {"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); AnnounceMessage* announce(rapidjson::Value& d); SettleMessage* settle(rapidjson::Value& d); AddedMessage* added(rapidjson::Value& d); DeletedMessage* deleted(rapidjson::Value& d); RejectMessage* reject(rapidjson::Value& d); TradeMessage* trade(rapidjson::Value& d); BrokerRequest* brokerReq(rapidjson::Value& d); BrokerAck* brokerAck(rapidjson::Value& d); BrokerConfirm* brokerCon(rapidjson::Value& d); ErrorMessage* error(rapidjson::Value& d); std::chrono::seconds parseTime(std::string& s); std::queue parse(std::string& str) { std::queue out; rapidjson::Document d; d.Parse(str.c_str()); if (d.IsArray()) { for (rapidjson::SizeType i = 0; i < d.Size(); i++) { out.push(parseSingle(d[i])); } } else { out.push(parseSingle(d)); } return out; } Message* parseSingle(rapidjson::Value& d) { if (mapTypes.empty()) { initialise(); } if (d.HasMember("error")) return error(d); Message* out; switch (mapTypes[d["type"].GetString()]) { case FUTURE_TYPE: case SPREAD_TYPE: case CALL_TYPE: case PUT_TYPE: out = announce(d); break; case SETTLEMENT: out = settle(d); break; case ADDED: out = added(d); break; case DELETED: out = deleted(d); break; case REJECT: out = reject(d); break; case TRADE: out = trade(d); break; case BROKER_REQUEST: out = brokerReq(d); break; case BROKER_ACK: out = brokerAck(d); break; case BROKER_CONFIRM: out = brokerCon(d); break; default: out = new Message(NONE, ""); break; } return out; } std::chrono::seconds parseTime(std::string& s) { return std::chrono::hours{std::stoi(s.substr(0, 4)) * 24 * 30 * 12} + std::chrono::hours{std::stoi(s.substr(5, 2)) * 24 * 30} + std::chrono::hours{std::stoi(s.substr(8, 2)) * 24} + std::chrono::hours{std::stoi(s.substr(11, 2))} + std::chrono::minutes{std::stoi(s.substr(14, 2))} + std::chrono::hours{std::stoi(s.substr(16, 5))}; } AnnounceMessage* announce(rapidjson::Value& d) { std::string es = d["expiry"].GetString(); std::chrono::nanoseconds exp_time(0); exp_time = parseTime(es); return new AnnounceMessage( mapTypes[d["type"].GetString()], d["product"].GetString(), d["stationId"].GetInt(), d["stationName"].GetString(), d["unit"].GetString(), exp_time, d["aggressiveFee"].GetDouble(), d["passiveFee"].GetDouble(), d["brokerFee"].GetDouble(), d["sequence"].GetInt(), d["timestamp"].GetDouble()); } SettleMessage* settle(rapidjson::Value& d) { std::chrono::nanoseconds exp_time(0); 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(), d["sequence"].GetInt(), d["timestamp"].GetDouble()); } 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["owner"].GetString(), d["sequence"].GetInt(), d["timestamp"].GetDouble()); } DeletedMessage* deleted(rapidjson::Value& d) { return new DeletedMessage( mapTypes[d["type"].GetString()], d["product"].GetString(), d["id"].GetString(), mapOrder[d["side"].GetString()], d["sequence"].GetInt(), d["timestamp"].GetDouble()); } RejectMessage* reject(rapidjson::Value& d) { return new RejectMessage(mapTypes[d["type"].GetString()], "", d["error"].GetString(), uint64_t(0), double(0)); } TradeMessage* trade(rapidjson::Value& d) { return new TradeMessage( mapTypes[d["type"].GetString()], d["product"].GetString(), d["price"].GetDouble(), d["volume"].GetInt(), d["buyer"].GetString(), d["seller"].GetString(), mapTrade[d["tradeType"].GetString()], d["passiveOrder"].GetString(), d["passiveOrderRemaining"].GetInt(), d["sequence"].GetInt(), d["timestamp"].GetDouble()); } BrokerRequest* brokerReq(rapidjson::Value& d) { return new BrokerRequest( mapTypes[d["type"].GetString()], d["product"].GetString(), d["price"].GetDouble(), mapOrder[d["side"].GetString()], d["volume"].GetInt(), d["counterparty"].GetString()); } BrokerAck* brokerAck(rapidjson::Value& d) { return new BrokerAck(mapTypes[d["type"].GetString()], d["product"].GetString(), d["price"].GetDouble(), mapOrder[d["side"].GetString()], d["volume"].GetInt(), d["counterparty"].GetString(), d["id"].GetString(), d["brokerTradeStatus"].GetString(), d["owner"].GetString()); } BrokerConfirm* brokerCon(rapidjson::Value& d) { return new BrokerConfirm( mapTypes[d["type"].GetString()], d["product"].GetString(), d["price"].GetDouble(), mapOrder[d["side"].GetString()], d["volume"].GetInt(), d["counterparty"].GetString(), d["id"].GetString()); } ErrorMessage* error(rapidjson::Value& d) { return new ErrorMessage(d["error"].GetString()); } Message::Message() : type(NONE), product("error") {} Message::Message(MessageTypes types, std::string product) : type(types), product(product) { } ErrorMessage::ErrorMessage(std::string message) : Message(ERROR, ""), message(message) { } std::string ErrorMessage::as_string() { return "{\"error\": \"" + this->message + "\"}"; } FromExchange::FromExchange(MessageTypes type, std::string product, uint64_t sequence, double timestamp) : Message(type, product), sequence(sequence), timestamp(timestamp) { } ToExchange::ToExchange(MessageTypes type, std::string product) : Message(type, product){}; Broker::Broker(MessageTypes type, std::string product, double price, book::OrderSideEnum side, uint64_t volume, std::string counterparty) : Message(type, product), price(price), side(side), volume(volume), counterparty(counterparty) { } AnnounceMessage::AnnounceMessage(MessageTypes type, std::string product, int stationId, std::string stationName, std::string unit, std::chrono::nanoseconds expiry, double aggFee, double pasFee, double broFee, uint64_t sequence, double timestamp) : FromExchange(type, product, sequence, timestamp), stationId(stationId), stationName(stationName), unit(unit), expiry(expiry), aggFee(aggFee), pasFee(pasFee), broFee(broFee) { } 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, uint64_t sequence, double timestamp) : 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, book::OrderSideEnum side, uint64_t volume) : ToExchange(type, product), price(price), side(side), volume(volume) { } std::string AddMessage::as_string() { if (mapOrderSide.empty()) initialise(); return "{\"type\": \"ADD\", \"product\": \"" + this->product + "\", \"price\": " + std::to_string(this->price) + ", \"side\": \"" + mapOrderSide[this->side] + "\", \"volume\": " + std::to_string(this->volume) + "}"; } AddedMessage::AddedMessage(MessageTypes type, std::string product, std::string id, book::OrderSideEnum side, double price, uint64_t filled, uint64_t resting, std::string owner, uint64_t sequence, double timestamp) : FromExchange(type, product, sequence, timestamp), id(id), side(side), price(price), filled(filled), resting(resting), owner(owner) { } std::string AddedMessage::as_string() { return "{\"type\": \"ADDED\", \"product\": \"" + this->product + "\", \"product\": \"" + this->id + "\", \"side\": \"" + mapOrderSide[this->side] + "\", \"price\": " + std::to_string(this->price) + ", \"filled\": " + std::to_string(this->filled) + ", \"resting\": " + std::to_string(this->resting) + ", \"owner\": \"" + this->owner + "\", \"sequence\": " + std::to_string(this->sequence) + ", \"timestamp\": " + std::to_string(this->timestamp) + "}"; } DeleteMessage::DeleteMessage(MessageTypes type, std::string product, std::string id) : ToExchange(type, product), id(id) { } std::string DeleteMessage::as_string() { if (mapOrderSide.empty()) initialise(); return "{\"type\": \"DELETE\", \"product\": \"" + this->product + "\", \"id\": \"" + this->id + "\"}"; } DeletedMessage::DeletedMessage(MessageTypes type, std::string product, std::string id, book::OrderSideEnum side, uint64_t sequence, double timestamp) : FromExchange(type, product, sequence, timestamp), id(id), side(side) { } std::string DeletedMessage::as_string() { return "{\"type\": \"DELETED\", \"product\": \"" + this->product + "\", \"product\": \"" + this->id + "\", \"side\": \"" + mapOrderSide[this->side] + ", \"sequence\": " + std::to_string(this->sequence) + ", \"timestamp\": " + std::to_string(this->timestamp) + "}"; } RejectMessage::RejectMessage(MessageTypes type, std::string product, std::string error, uint64_t sequence, double timestamp) : FromExchange(type, product, sequence, timestamp), error(error) { } std::string RejectMessage::as_string() { return "{\"type\": \"REJECT\", \"product\": \"" + this->product + "\", \"error\": \"" + this->error + "\", \"sequence\": " + std::to_string(this->sequence) + ", \"timestamp\": " + std::to_string(this->timestamp) + "}"; } TradeMessage::TradeMessage(MessageTypes type, std::string product, double price, uint64_t volume, std::string buyer, std::string seller, TradeTypeEnum tradeType, std::string passiveOrder, uint64_t passiveOrderRemaining, uint64_t sequence, double timestamp) : FromExchange(type, product, sequence, timestamp), price(price), volume(volume), buyer(buyer), seller(seller), tradeType(tradeType), passiveOrder(passiveOrder), passiveOrderRemaining(passiveOrderRemaining) { } 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, book::OrderSideEnum side, uint64_t volume, std::string counterparty, std::string id, std::string brokerTradeStatus, std::string owner) : Broker(type, product, price, side, volume, counterparty), id(id), brokerTradeStatus(brokerTradeStatus), owner(owner) { } 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, std::string id) : 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