Joel Grunbaum
2022-01-19 0bef191acd5a77544852e6a3daae2df05bd34a31
protocol.cpp
@@ -2,13 +2,17 @@
#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>
@@ -18,6 +22,9 @@
   mapAnnounce;
std::string server = std::string(HOST) + ":" + std::string(PORT);
httplib::Client cli("http://" + server);
std::unique_ptr<easywsclient::WebSocket> ws;
double lastime = 0;
void initialise()
{
@@ -40,11 +47,55 @@
   l = res->body;
   std::queue<json::Message*> a(json::parse(l));
   while (!a.empty()) {
      protocol::handleMessage(bs, a.front());
      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 createWebSocket()
{
   ws = std::unique_ptr<easywsclient::WebSocket>(
      easywsclient::WebSocket::pointer(easywsclient::WebSocket::from_url(
         "ws://" + server + "/information")));
   ws->poll();
}
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();
         }
      }
   } while (gotMessage);
   return out;
}
json::Message* addOrder(json::AddMessage& order)
@@ -63,29 +114,32 @@
                   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, dynamic_cast<json::AnnounceMessage*>(message));
      announce(bs, static_cast<json::AnnounceMessage*>(message));
      break;
   case json::SETTLEMENT:
      settle(bs, dynamic_cast<json::SettleMessage*>(message));
      settle(bs, static_cast<json::SettleMessage*>(message));
      break;
   case json::ADDED:
      addedOrder(bs, dynamic_cast<json::AddedMessage*>(message));
      addedOrder(bs, static_cast<json::AddedMessage*>(message));
      break;
   case json::DELETED:
      deletedOrder(bs, dynamic_cast<json::DeletedMessage*>(message));
      deletedOrder(bs, static_cast<json::DeletedMessage*>(message));
      break;
   case json::TRADE:
      tradeOrder(bs, dynamic_cast<json::TradeMessage*>(message));
      tradeOrder(bs, static_cast<json::TradeMessage*>(message));
      break;
   case json::BROKER_REQUEST:
   case json::BROKER_ACK:
   case json::BROKER_CONFIRM:
      broker(bs, dynamic_cast<json::Broker*>(message));
      broker(bs, static_cast<json::Broker*>(message));
      break;
   default:;
   }
@@ -107,11 +161,11 @@
void addedOrder(std::unordered_map<std::string, book::Book>& bs,
                json::AddedMessage* message)
{
   if (message->side == book::Buy) {
   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 {
   } 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);
@@ -121,25 +175,19 @@
                  json::DeletedMessage* message)
{
   if (message->side == book::Buy) {
      for (std::size_t i = 0; i < bs[message->product].bidSide.size(); i++) {
         if (bs[message->product].bidSide[i].id == message->id) {
            bs[message->product].bidSide[i] =
               bs[message->product].bidSide.back();
            bs[message->product].bidSide.pop_back();
            std::make_heap(bs[message->product].bidSide.begin(),
                           bs[message->product].bidSide.end(),
                           std::less<book::Level>());
      for (auto i = bs[message->product].bidSide.begin();
           i != bs[message->product].bidSide.end(); i++) {
         if (i->id == message->id) {
            bs[message->product].bidSide.erase(i);
            break;
         }
      }
   } else {
      for (std::size_t i = 0; i < bs[message->product].askSide.size(); i++) {
         if (bs[message->product].askSide[i].id == message->id) {
            bs[message->product].askSide[i] =
               bs[message->product].askSide.back();
            bs[message->product].askSide.pop_back();
            std::make_heap(bs[message->product].askSide.begin(),
                           bs[message->product].askSide.end(),
                           std::greater<book::Level>());
      for (auto i = bs[message->product].askSide.begin();
           i != bs[message->product].askSide.end(); i++) {
         if (i->id == message->id) {
            bs[message->product].askSide.erase(i);
            break;
         }
      }
   }
@@ -148,15 +196,42 @@
                json::TradeMessage* message)
{
   if (message->tradeType == json::BUY_AGGRESSOR) {
      book::Order t(message->price, book::Buy, message->volume,
                    message->timestamp, message->passiveOrder);
      bs[message->product].bid(t);
   } else {
      book::Order t(message->price, book::Sell, message->volume,
                    message->timestamp, message->passiveOrder);
      bs[message->product].ask(t);
      if (message->passiveOrderRemaining > 0) {
         for (auto& i : bs[message->product].askSide) {
            if (i.id == message->passiveOrder) {
               i.volume = message->passiveOrderRemaining;
               break;
            }
         }
      } else {
         for (auto i = bs[message->product].askSide.begin();
              i != bs[message->product].askSide.end(); i++) {
            if (i->id == message->passiveOrder) {
               bs[message->product].askSide.erase(i);
               break;
            }
         }
      }
   } else if (message->tradeType == json::SELL_AGGRESSOR) {
      if (message->passiveOrderRemaining > 0) {
         for (auto& i : bs[message->product].bidSide) {
            if (i.id == message->passiveOrder) {
               i.volume = message->passiveOrderRemaining;
               break;
            }
         }
      } else {
         for (auto i = bs[message->product].bidSide.begin();
              i != bs[message->product].bidSide.end(); i++) {
            if (i->id == message->passiveOrder) {
               bs[message->product].bidSide.erase(i);
               break;
            }
         }
      }
   }
}
void broker(std::unordered_map<std::string, book::Book>& bs,
            json::Broker* message)
{
@@ -164,10 +239,13 @@
json::Message* send(std::string& message)
{
    httplib::MultipartFormDataItems a = {{"message", message, "", ""},
        {"username", USER, "", ""},
        {"password", PASS, "", ""}};
   auto res = cli.Post("/execution", a);
   httplib::MultipartFormDataItems a = {{"message", message, "", ""},
                                        {"username", USER, "", ""},
                                        {"password", PASS, "", ""}};
   auto res = cli.Post("/execution",
                       "message=" + message + "&username=" + USER +
                           "&password=" + PASS,
                       "application/x-www-form-urlencoded");
   std::string b = res->body;
   std::queue<json::Message*> c = json::parse(b);
   return c.front();