#include "protocol.hpp"
|
|
#include "book.hpp"
|
#include "cpp-httplib/httplib.h"
|
#include "easywsclient/easywsclient.hpp"
|
#include "json.hpp"
|
#include "secrets.hpp"
|
|
#include <chrono>
|
#include <cstddef>
|
#include <iostream>
|
#include <memory>
|
#include <queue>
|
#include <sstream>
|
#include <stdexcept>
|
#include <string>
|
#include <unordered_map>
|
|
namespace protocol
|
{
|
static std::unordered_map<json::MessageTypes, book::ProductTypeEnum>
|
mapAnnounce;
|
std::string server = std::string(HOST) + ":" + std::string(PORT);
|
httplib::Client cli("http://" + server);
|
|
double lastime = 0;
|
|
void initialise()
|
{
|
mapAnnounce = {{json::FUTURE_TYPE, book::FUTURE},
|
{json::SPREAD_TYPE, book::SPREAD},
|
{json::CALL_TYPE, book::CALL},
|
{json::PUT_TYPE, book::PUT}};
|
}
|
|
std::unordered_map<std::string, book::Book> recoverBook()
|
{
|
std::unordered_map<std::string, book::Book> bs;
|
// std::ifstream sampleFile("../data.test");
|
// std::stringstream ss;
|
// ss << sampleFile.rdbuf();
|
httplib::Client cli("http://" + server);
|
auto res = cli.Get("/recover");
|
std::string l;
|
// l = ss.str();
|
l = res->body;
|
std::queue<json::Message*> a(json::parse(l));
|
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());
|
}
|
delete a.front();
|
a.pop();
|
}
|
return bs;
|
}
|
|
void catchUp(std::unordered_map<std::string, book::Book>& bs)
|
{
|
static std::unique_ptr<easywsclient::WebSocket> ws(
|
easywsclient::WebSocket::from_url("ws://" + server + "/information"));
|
std::string feed;
|
bool 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());
|
delete a.front();
|
a.pop();
|
}
|
}
|
}
|
|
json::Message* addOrder(json::AddMessage& order)
|
{
|
std::string message = order.as_string();
|
return send(message);
|
}
|
|
json::Message* deleteOrder(json::DeleteMessage& order)
|
{
|
std::string message = order.as_string();
|
return send(message);
|
}
|
|
void handleMessage(std::unordered_map<std::string, book::Book>& bs,
|
json::Message* message)
|
{
|
if (mapAnnounce.empty()) initialise();
|
if (dynamic_cast<json::FromExchange*>(message) != nullptr) {
|
lastime = dynamic_cast<json::FromExchange*>(message)->timestamp;
|
}
|
switch (message->type) {
|
case json::FUTURE_TYPE:
|
case json::SPREAD_TYPE:
|
case json::CALL_TYPE:
|
case json::PUT_TYPE:
|
announce(bs, static_cast<json::AnnounceMessage*>(message));
|
break;
|
case json::SETTLEMENT:
|
settle(bs, static_cast<json::SettleMessage*>(message));
|
break;
|
case json::ADDED:
|
addedOrder(bs, static_cast<json::AddedMessage*>(message));
|
break;
|
case json::DELETED:
|
deletedOrder(bs, static_cast<json::DeletedMessage*>(message));
|
break;
|
case json::TRADE:
|
tradeOrder(bs, static_cast<json::TradeMessage*>(message));
|
break;
|
case json::BROKER_REQUEST:
|
case json::BROKER_ACK:
|
case json::BROKER_CONFIRM:
|
broker(bs, static_cast<json::Broker*>(message));
|
break;
|
default:;
|
}
|
}
|
|
void announce(std::unordered_map<std::string, book::Book>& bs,
|
json::AnnounceMessage* message)
|
{
|
bs[message->product] =
|
book::Book(mapAnnounce[message->type], message->product,
|
message->stationId, message->unit, message->expiry,
|
message->aggFee, message->pasFee, message->broFee);
|
}
|
void settle(std::unordered_map<std::string, book::Book>& bs,
|
json::SettleMessage* message)
|
{
|
bs.erase(message->product);
|
}
|
void addedOrder(std::unordered_map<std::string, book::Book>& bs,
|
json::AddedMessage* message)
|
{
|
if (message->side == book::Buy && message->resting) {
|
book::Order t(message->price, book::Buy, message->resting,
|
message->timestamp, message->id);
|
bs[message->product].bid(t);
|
} else if (message->side == book::Sell && message->resting) {
|
book::Order t(message->price, book::Sell, message->resting,
|
message->timestamp, message->id);
|
bs[message->product].ask(t);
|
}
|
}
|
void deletedOrder(std::unordered_map<std::string, book::Book>& bs,
|
json::DeletedMessage* message)
|
{
|
if (message->side == book::Buy) {
|
bs[message->product].bidSide.erase(message->id);
|
} else {
|
bs[message->product].askSide.erase(message->id);
|
}
|
}
|
void tradeOrder(std::unordered_map<std::string, book::Book>& bs,
|
json::TradeMessage* message)
|
{
|
if (bs.find(message->passiveOrder) != bs.end()) {
|
if (message->tradeType == json::BUY_AGGRESSOR) {
|
if (message->passiveOrderRemaining > 0) {
|
bs[message->product].askSide.at(message->passiveOrder).volume =
|
message->passiveOrderRemaining;
|
} else {
|
bs[message->product].askSide.erase(message->passiveOrder);
|
}
|
} else if (message->tradeType == json::SELL_AGGRESSOR) {
|
if (message->passiveOrderRemaining > 0) {
|
bs[message->product].bidSide.at(message->passiveOrder).volume =
|
message->passiveOrderRemaining;
|
} else {
|
bs[message->product].bidSide.erase(message->passiveOrder);
|
}
|
}
|
}
|
}
|
|
void broker(std::unordered_map<std::string, book::Book>& bs,
|
json::Broker* message)
|
{
|
}
|
|
json::Message* send(std::string& message)
|
{
|
httplib::MultipartFormDataItems a = {{"message", message, "", ""},
|
{"username", USER, "", ""},
|
{"password", PASS, "", ""}};
|
auto res = cli.Post("/execution", a);
|
std::string b = res->body;
|
std::queue<json::Message*> c = json::parse(b);
|
return c.front();
|
}
|
|
} // namespace protocol
|