#include "json.hpp"
|
#include "book.hpp"
|
#include "date/include/date/date.h"
|
#include "protocol.hpp"
|
#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}};
|
|
mapOrderSide = {{book::Buy, "BUY"}, {book::Sell, "SELL"}};
|
}
|
|
AnnounceMessage* announce(std::string& str);
|
SettleMessage* settle(std::string& str);
|
AddedMessage* added(std::string& str);
|
DeletedMessage* deleted(std::string& str);
|
TradeMessage* trade(std::string& str);
|
BrokerRequest* brokerReq(std::string& str);
|
BrokerAck* brokerAck(std::string& str);
|
BrokerConfirm* brokerCon(std::string& str);
|
|
std::queue<Message*> parseMany(std::string& str)
|
{
|
std::queue<Message*> out;
|
std::size_t startIndex = 0, endIndex = 0;
|
while (true) {
|
startIndex = str.find("{", endIndex);
|
if (startIndex == std::string::npos) break;
|
endIndex = str.find("},", startIndex);
|
std::string substr = str.substr(startIndex, endIndex - startIndex + 1);
|
// std::cout << substr << std::endl;
|
Message* a = parseSingle(substr);
|
out.push(a);
|
}
|
return out;
|
}
|
|
Message* parseSingle(std::string& str)
|
{
|
if (mapTypes.empty()) {
|
initialise();
|
}
|
std::size_t startIndex = str.find("\"type\": \"") + 9;
|
std::size_t endIndex = str.find("\"", startIndex + 1);
|
Message* out;
|
switch (mapTypes[str.substr(startIndex, endIndex - startIndex)]) {
|
case FUTURE_TYPE:
|
case SPREAD_TYPE:
|
case CALL_TYPE:
|
case PUT_TYPE:
|
out = announce(str);
|
break;
|
case SETTLEMENT:
|
out = settle(str);
|
break;
|
case ADDED:
|
out = added(str);
|
break;
|
case DELETED:
|
out = deleted(str);
|
break;
|
case TRADE:
|
out = trade(str);
|
break;
|
case BROKER_REQUEST:
|
out = brokerReq(str);
|
break;
|
case BROKER_ACK:
|
out = brokerAck(str);
|
break;
|
case BROKER_CONFIRM:
|
out = brokerCon(str);
|
break;
|
default:
|
out = new Message(NONE, "");
|
break;
|
}
|
return out;
|
}
|
|
inline std::pair<std::size_t, std::size_t>
|
find_arg(std::string str, std::string a, bool quotes, bool end = false)
|
{
|
std::size_t out[2];
|
if (quotes) {
|
out[0] = str.find("\"" + a + "\": \"") + 5 + a.size();
|
if (end) {
|
out[1] = str.find("\"}", out[0] + 1);
|
} else {
|
out[1] = str.find("\",", out[0] + 1);
|
}
|
} else {
|
out[0] = str.find("\"" + a + "\": ") + 4 + a.size();
|
if (end) {
|
out[1] = str.find("}", out[0] + 1);
|
} else {
|
out[1] = str.find(",", out[0] + 1);
|
}
|
}
|
return std::make_pair(out[0], out[1]);
|
}
|
|
AnnounceMessage* announce(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, stationId, stationName,
|
unit, expiry, aggFee, pasFee, broFee, sequence, timestamp;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
stationId = find_arg(str, "stationId", false, false);
|
stationName = find_arg(str, "stationName", true, false);
|
unit = find_arg(str, "unit", true, false);
|
expiry = find_arg(str, "expiry", true, false);
|
aggFee = find_arg(str, "aggressiveFee", false, false);
|
pasFee = find_arg(str, "passiveFee", false, false);
|
broFee = find_arg(str, "brokerFee", false, false);
|
sequence = find_arg(str, "sequence", false, false);
|
timestamp = find_arg(str, "timestamp", false, true);
|
std::stringstream expiryStream(
|
str.substr(expiry.first, expiry.second - expiry.first));
|
std::chrono::nanoseconds exp_time;
|
expiryStream >>
|
date::parse("%Y-%m-%f %H:%M%z", exp_time); // Parsing is broken
|
return new AnnounceMessage(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
str.substr(stationId.first, stationId.second - stationId.first),
|
str.substr(stationName.first, stationName.second - stationName.first),
|
str.substr(unit.first, unit.second - unit.first), exp_time,
|
std::stod(str.substr(aggFee.first, aggFee.second - aggFee.first)),
|
std::stod(str.substr(pasFee.first, pasFee.second - pasFee.first)),
|
std::stod(str.substr(broFee.first, broFee.second - broFee.first)),
|
std::stoll(
|
str.substr(sequence.first, sequence.second - sequence.first)),
|
std::stod(
|
str.substr(timestamp.first, timestamp.second - timestamp.first)));
|
}
|
|
SettleMessage* settle(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, stationName, expiry,
|
price, sequence, timestamp;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
stationName = find_arg(str, "stationName", true, false);
|
expiry = find_arg(str, "expiry", true, false);
|
price = find_arg(str, "price", false, false);
|
sequence = find_arg(str, "sequence", false, false);
|
timestamp = find_arg(str, "timestamp", false, true);
|
std::stringstream expiryStream(
|
str.substr(expiry.first, expiry.second - expiry.first));
|
std::chrono::nanoseconds exp_time;
|
expiryStream >> date::parse("%Y-%m-%d %H:%M%z", exp_time);
|
return new SettleMessage(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
str.substr(stationName.first, stationName.second - stationName.first),
|
exp_time,
|
std::stod(str.substr(price.first, price.second - price.first)),
|
std::stoll(
|
str.substr(sequence.first, sequence.second - sequence.first)),
|
std::stod(
|
str.substr(timestamp.first, timestamp.second - timestamp.first)));
|
}
|
|
AddedMessage* added(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, id, side, price, filled,
|
resting, sequence, timestamp;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
sequence = find_arg(str, "sequence", false, false);
|
timestamp = find_arg(str, "timestamp", false, true);
|
id = find_arg(str, "id", true, false);
|
side = find_arg(str, "side", true, false);
|
price = find_arg(str, "price", false, false);
|
filled = find_arg(str, "filled", false, false);
|
resting = find_arg(str, "resting", false, false);
|
return new AddedMessage(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
str.substr(id.first, id.second - id.first),
|
mapOrder[str.substr(side.first, side.second - side.first)],
|
std::stod(str.substr(price.first, price.second - price.first)),
|
std::stoll(str.substr(filled.first, filled.second - filled.first)),
|
std::stoll(str.substr(resting.first, resting.second - resting.first)),
|
std::stoll(
|
str.substr(sequence.first, sequence.second - sequence.first)),
|
std::stod(
|
str.substr(timestamp.first, timestamp.second - timestamp.first)));
|
}
|
|
DeletedMessage* deleted(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, id, side, sequence,
|
timestamp;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
sequence = find_arg(str, "sequence", false, false);
|
timestamp = find_arg(str, "timestamp", false, true);
|
id = find_arg(str, "id", true, false);
|
side = find_arg(str, "side", true, false);
|
return new DeletedMessage(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
str.substr(id.first, id.second - id.first),
|
mapOrder[str.substr(side.first, side.second - side.first)],
|
std::stoll(
|
str.substr(sequence.first, sequence.second - sequence.first)),
|
std::stod(
|
str.substr(timestamp.first, timestamp.second - timestamp.first)));
|
}
|
|
TradeMessage* trade(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, price, volume, buyer,
|
seller, tradeType, passiveOrder, passiveOrderRemaining, sequence,
|
timestamp;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
sequence = find_arg(str, "sequence", false, false);
|
timestamp = find_arg(str, "timestamp", false, true);
|
price = find_arg(str, "price", false, false);
|
volume = find_arg(str, "volume", false, false);
|
buyer = find_arg(str, "buyer", true, false);
|
seller = find_arg(str, "seller", true, false);
|
tradeType = find_arg(str, "tradeType", true, false);
|
passiveOrder = find_arg(str, "passiveOrder", true, false);
|
passiveOrderRemaining =
|
find_arg(str, "passiveOrderRemaining", false, false);
|
|
return new TradeMessage(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
std::stod(str.substr(price.first, price.second - price.first)),
|
std::stoll(str.substr(volume.first, volume.second - volume.first)),
|
str.substr(buyer.first, buyer.second - buyer.first),
|
str.substr(seller.first, seller.second - seller.first),
|
mapTrade[str.substr(tradeType.first,
|
tradeType.second - tradeType.first)],
|
str.substr(passiveOrder.first,
|
passiveOrder.second - passiveOrder.first),
|
std::stoll(str.substr(passiveOrderRemaining.first,
|
passiveOrderRemaining.second -
|
passiveOrderRemaining.first)),
|
std::stoll(
|
str.substr(sequence.first, sequence.second - sequence.first)),
|
std::stod(
|
str.substr(timestamp.first, timestamp.second - timestamp.first)));
|
}
|
|
BrokerRequest* brokerReq(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, price, side, volume,
|
counterparty;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
price = find_arg(str, "price", false, false);
|
side = find_arg(str, "side", true, false);
|
volume = find_arg(str, "volume", false, false);
|
counterparty = find_arg(str, "counterparty", true, false);
|
return new BrokerRequest(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
std::stod(str.substr(price.first, price.second - price.first)),
|
mapOrder[str.substr(side.first, side.second - side.first)],
|
std::stoll(str.substr(volume.first, volume.second - volume.first)),
|
str.substr(counterparty.first,
|
counterparty.second - counterparty.first));
|
}
|
|
BrokerAck* brokerAck(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, price, side, volume,
|
counterparty, id, brokerTradeStatus, owner;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
price = find_arg(str, "price", false, false);
|
side = find_arg(str, "side", true, false);
|
volume = find_arg(str, "volume", false, false);
|
counterparty = find_arg(str, "counterparty", true, false);
|
id = find_arg(str, "id", true, false);
|
brokerTradeStatus = find_arg(str, "brokerTradeStatus", true, false);
|
owner = find_arg(str, "owner", true, false);
|
|
return new BrokerAck(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
std::stod(str.substr(price.first, price.second - price.first)),
|
mapOrder[str.substr(side.first, side.second - side.first)],
|
std::stoll(str.substr(volume.first, volume.second - volume.first)),
|
str.substr(counterparty.first,
|
counterparty.second - counterparty.first),
|
str.substr(id.first, id.second - id.first),
|
str.substr(brokerTradeStatus.first,
|
brokerTradeStatus.second - brokerTradeStatus.first),
|
str.substr(owner.first, owner.second - owner.first));
|
}
|
BrokerConfirm* brokerCon(std::string& str)
|
{
|
std::pair<std::size_t, std::size_t> type, product, price, side, volume,
|
counterparty, id;
|
type = find_arg(str, "type", true, false);
|
product = find_arg(str, "product", true, false);
|
price = find_arg(str, "price", false, false);
|
side = find_arg(str, "side", true, false);
|
volume = find_arg(str, "volume", false, false);
|
counterparty = find_arg(str, "counterparty", true, false);
|
id = find_arg(str, "id", true, false);
|
|
return new BrokerConfirm(
|
mapTypes[str.substr(type.first, type.second - type.first)],
|
str.substr(product.first, product.second - product.first),
|
std::stod(str.substr(price.first, price.second - price.first)),
|
mapOrder[str.substr(side.first, side.second - side.first)],
|
std::stoll(str.substr(volume.first, volume.second - volume.first)),
|
str.substr(counterparty.first,
|
counterparty.second - counterparty.first),
|
str.substr(id.first, id.second - id.first));
|
}
|
|
Message::Message() : type(NONE), product("error") {}
|
|
Message::Message(MessageTypes types, std::string product)
|
: type(types), product(product)
|
{
|
}
|
|
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,
|
std::string 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)
|
{
|
}
|
|
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)
|
{
|
}
|
|
RejectMessage::RejectMessage(MessageTypes type, std::string product,
|
std::string error, uint64_t sequence,
|
double timestamp)
|
: FromExchange(type, product, sequence, timestamp), error(error)
|
{
|
}
|
|
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
|