#include "json.hpp"
|
#include "book.hpp"
|
#include "protocol.hpp"
|
#include "rapidjson/include/rapidjson/document.h"
|
#include "rapidjson/include/rapidjson/rapidjson.h"
|
#include <chrono>
|
#include <cstddef>
|
#include <cstdint>
|
#include <cstring>
|
#include <deque>
|
#include <iomanip>
|
#include <netdb.h>
|
#include <numeric>
|
#include <queue>
|
#include <sstream>
|
#include <string>
|
#include <unordered_map>
|
#include <utility>
|
|
namespace json
|
{
|
static std::unordered_map<std::string, MessageTypes> mapTypes;
|
static std::unordered_map<MessageTypes, book::ProductTypeEnum> mapAnnounce;
|
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;
|
|
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"}};
|
}
|
|
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<Message*> parse(std::string& str)
|
{
|
std::queue<Message*> 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["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)
|
{
|
}
|
|
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)
|
{
|
}
|
|
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,
|
uint64_t sequence, double timestamp)
|
: FromExchange(type, product, sequence, timestamp), id(id), side(side),
|
price(price), filled(filled), resting(resting)
|
{
|
}
|
|
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) +
|
", \"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)
|
{
|
}
|
|
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)
|
{
|
}
|
|
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)
|
{
|
}
|
|
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)
|
{
|
}
|
} // namespace json
|