Joel Grunbaum
2022-01-08 16b655e7c8cfb2e32e6bb839373f30ad63506f9a
Added json parsing, protocol comprehension and began executables for algs
7 files modified
1 files deleted
12 files added
1243 ■■■■■ changed files
.clang-format 6 ●●●● patch | view | raw | blame | history
.gitignore 1 ●●●● patch | view | raw | blame | history
.gitmodules 6 ●●●●● patch | view | raw | blame | history
CMakeLists.txt 18 ●●●●● patch | view | raw | blame | history
Makefile 16 ●●●●● patch | view | raw | blame | history
book.cpp 149 ●●●● patch | view | raw | blame | history
book.hpp 35 ●●●●● patch | view | raw | blame | history
bot.cpp 6 ●●●●● patch | view | raw | blame | history
click.cpp 77 ●●●●● patch | view | raw | blame | history
cpp-httplib @ 11e02e 1 ●●●● patch | view | raw | blame | history
date @ 655b24 1 ●●●● patch | view | raw | blame | history
json.cpp 493 ●●●●● patch | view | raw | blame | history
json.hpp 169 ●●●●● patch | view | raw | blame | history
main.cpp 10 ●●●●● patch | view | raw | blame | history
protocol.cpp 177 ●●●●● patch | view | raw | blame | history
protocol.hpp 37 ●●●●● patch | view | raw | blame | history
secrets.hpp 14 ●●●●● patch | view | raw | blame | history
strat.cpp 5 ●●●●● patch | view | raw | blame | history
strat.hpp 7 ●●●●● patch | view | raw | blame | history
test.cpp 15 ●●●●● patch | view | raw | blame | history
.clang-format
@@ -5,4 +5,8 @@
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Linux
IndentCaseLabels: false
---
PointerAlignment: Left
AllowShortIfStatementsOnASingleLine: true
IndentCaseBlocks: true
IndentCaseLabels: false
SortUsingDeclarations: true
.gitignore
@@ -7,3 +7,4 @@
bid
ask
oneshot
build
.gitmodules
New file
@@ -0,0 +1,6 @@
[submodule "cpp-httplib"]
    path = cpp-httplib
    url = https://github.com/yhirose/cpp-httplib.git
[submodule "date"]
    path = date
    url = https://github.com/HowardHinnant/date.git
CMakeLists.txt
New file
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.10)
project(bomex)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_subdirectory(date)
add_library(MAIN json.cpp date protocol.cpp book.cpp)
add_executable(test test.cpp strat.cpp)
add_executable(bot bot.cpp strat.cpp)
add_executable(click click.cpp)
target_link_libraries(test PUBLIC MAIN)
target_link_libraries(bot PUBLIC MAIN)
target_link_libraries(click PUBLIC MAIN)
Makefile
File was deleted
book.cpp
@@ -1,55 +1,67 @@
#include "book.hpp"
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <iostream>
Order::Order(double price, OrderSideEnum side, int volume,
             std::chrono::nanoseconds timestamp, std::string id)
namespace book
{
Order::Order(double price, OrderSideEnum side, int volume, double timestamp,
             std::string id)
    : price{price}, side{side}, remaining_volume{volume},
      filled_volume(0), timestamp{timestamp}, id{id} {}
      filled_volume(0), timestamp{timestamp}, id{id}
{
}
Level::Level(Order &order)
    : price{order.price}, volume(order.remaining_volume), side{order.side},
      timestamp{order.timestamp}, id{order.id} {}
      timestamp{order.timestamp}, id{order.id}
{
}
bool operator<(const Level &a, const Level &b) {
bool operator<(const Level& a, const Level& b)
{
  if (a.price < b.price)
    return true;
  else if (a.price == b.price && (a.timestamp.count() > b.timestamp.count()))
    else if (a.price == b.price && (a.timestamp > b.timestamp))
    return true;
  else
    return false;
}
bool operator>(const Level &a, const Level &b) {
bool operator>(const Level& a, const Level& b)
{
  if (a.price > b.price)
    return true;
  else if (a.price == b.price && (a.timestamp.count() > b.timestamp.count()))
    else if (a.price == b.price && (a.timestamp > b.timestamp))
    return true;
  else
    return false;
}
bool operator<=(const Level &a, const Level &b) {
bool operator<=(const Level& a, const Level& b)
{
  if (a.price <= b.price)
    return true;
  else if (a.price == b.price && (a.timestamp.count() >= b.timestamp.count()))
    else if (a.price == b.price && (a.timestamp >= b.timestamp))
    return true;
  else
    return false;
}
bool operator>=(const Level &a, const Level &b) {
bool operator>=(const Level& a, const Level& b)
{
  if (a.price >= b.price)
    return true;
  else if (a.price == b.price && (a.timestamp.count() >= b.timestamp.count()))
    else if (a.price == b.price && (a.timestamp >= b.timestamp))
    return true;
  else
    return false;
}
bool operator==(const Level &a, const Level &b) {
    if (a.price == b.price && (a.timestamp.count() == b.timestamp.count()))
bool operator==(const Level& a, const Level& b)
{
    if (a.price == b.price && (a.timestamp == b.timestamp))
    return true;
  else
    return false;
@@ -57,39 +69,16 @@
std::ostream& operator<<(std::ostream& out, const Level& a)
{
    return out << "Price: " << a.price << ", volume: " << a.volume << ", time: " << a.timestamp.count() << ", id: " << a.id;
}
template<class T>
void Side<T>::deleteLevel(std::string orderId)
{
    for (auto i = this->c.begin(); i != this->c.end();) {
        if (*i.id == orderId) {
            this->c.erase(i);
            std::make_heap(this->c.begin(), this->c.end(), this->comp);
        }
    }
}
template<class T>
void Side<T>::topRemoveVolume(int volume) { this->c[0].volume -= volume; }
template<class T>
void Side<T>::printTop(std::size_t num)
{
    std::vector<Level> copy(this->c);
    std::sort(copy.begin(), copy.end(), this->comp);
    if (copy.size() && copy[0].side == Buy)
        std::reverse(copy.begin(), copy.end());
    for (std::size_t i = 0; i < copy.size() &&  i < num; i++) {
        std::cout << copy[i] << std::endl;
    }
    return out << "Price: " << a.price << ", volume: " << a.volume
               << ", time: " << a.timestamp << ", id: " << a.id;
}
Book::Book()
    : bidSide(), askSide(), productType(TEST), product("a"), stationId("b"),
      unit("c"), expiry(std::chrono::nanoseconds(0)), aggFee(1), pasFee(-1),
      broFee(2) {}
      broFee(2)
{
}
Book::Book(ProductTypeEnum productType, std::string product,
           std::string stationId, std::string unit,
@@ -97,56 +86,80 @@
           double broFee)
    : bidSide{}, askSide{}, productType{productType}, product(product),
      stationId(stationId), unit(unit), expiry(expiry), aggFee(aggFee),
      pasFee(pasFee), broFee(broFee) {}
      pasFee(pasFee), broFee(broFee)
{
}
void Book::ask(Order &order) {
  while (this->bidSide.size() && this->bidSide.top().price >= order.price) {
    if (this->bidSide.top().volume > order.remaining_volume) {
      int temp = this->bidSide.top().volume;
void Book::ask(Order& order)
{
    while (this->bidSide.size() && this->bidSide[0].price >= order.price) {
    if (this->bidSide[0].volume > order.remaining_volume) {
        int temp = this->bidSide[0].volume;
      order.filled_volume += temp;
      this->bidSide.topRemoveVolume(order.remaining_volume);
        this->bidSide.front().volume -= order.remaining_volume;
      order.remaining_volume -= temp;
      break;
    } else {
      order.remaining_volume -= this->bidSide.top().volume;
      order.filled_volume += this->bidSide.top().volume;
      this->bidSide.pop();
        order.remaining_volume -= this->bidSide[0].volume;
        order.filled_volume += this->bidSide[0].volume;
        this->bidSide.erase(this->bidSide.begin());
        std::make_heap(this->bidSide.begin(), this->bidSide.end(),
                       std::less<Level>());
    }
  }
  if (order.remaining_volume > 0) {
    this->askSide.emplace(order);
    this->askSide.emplace(this->askSide.begin(), order);
    std::make_heap(this->askSide.begin(), this->askSide.end(),
                   std::greater<Level>());
  }
}
void Book::bid(Order &order) {
  while (this->askSide.size() && this->askSide.top().price <= order.price) {
    if (this->askSide.top().volume > order.remaining_volume) {
      int temp = this->askSide.top().volume;
void Book::bid(Order& order)
{
    while (this->askSide.size() && this->askSide[0].price <= order.price) {
    if (this->askSide[0].volume > order.remaining_volume) {
        int temp = this->askSide.front().volume;
      order.filled_volume += temp;
      this->askSide.topRemoveVolume(order.remaining_volume);
        this->askSide.front().volume -= order.remaining_volume;
      order.remaining_volume -= temp;
      break;
    } else {
      order.remaining_volume -= this->askSide.top().volume;
      order.filled_volume += this->askSide.top().volume;
      this->askSide.pop();
        order.remaining_volume -= this->askSide[0].volume;
        order.filled_volume += this->askSide[0].volume;
        this->askSide.erase(this->askSide.begin());
        std::make_heap(this->askSide.begin(), this->askSide.end(),
                       std::greater<Level>());
    }
  }
  if (order.remaining_volume > 0) {
    this->bidSide.emplace(order);
    this->bidSide.emplace(this->bidSide.begin(), order);
    std::make_heap(this->bidSide.begin(), this->bidSide.end(),
                   std::less<Level>());
  }
}
void Book::printBook(std::size_t numOrders) {
void Book::printBook(std::size_t numOrders)
{
  std::cout << "Sell side: " << this->askSide.size() << std::endl;
  this->askSide.printTop(numOrders);
    std::vector<Level> askCopy(this->askSide);
    int count = 0;
    std::sort(askCopy.begin(), askCopy.end());
    for (auto i = askCopy.rbegin(); i != askCopy.rend() && count < numOrders; i++, count++) {
        std::cout << *i << std::endl;
    }
  std::cout << "Buy side: " << this->bidSide.size() << std::endl;
  this->bidSide.printTop(numOrders);
    std::vector<Level> bidCopy(this->bidSide);
    count = 0;
    std::sort(bidCopy.begin(), bidCopy.end());
    for (auto i = bidCopy.rbegin(); i != bidCopy.rend() && count < numOrders; i++, count++) {
        std::cout << *i << std::endl;
    }
}
Book testBook(int orders, bool printBook) {
Book testBook(int orders, bool printBook)
{
  Book b = Book();
  std::chrono::nanoseconds time(1);
    double time(1);
  for (int i = 1; i < orders; i++) {
    Order t(i, Buy, 10, time++, "a");
    b.bid(t);
@@ -155,7 +168,7 @@
    Order t(i, Sell, 10, time++, "b");
    b.ask(t);
  }
  if (printBook)
    b.printBook(orders - 1);
    if (printBook) b.printBook(orders - 1);
  return b;
}
} // namespace book
book.hpp
@@ -1,13 +1,15 @@
#pragma once
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
#include <algorithm>
namespace book
{
enum OrderSideEnum { Buy, Sell };
enum ProductTypeEnum { TEST, FUTURE, SPREAD, CALL, PUT };
@@ -16,17 +18,17 @@
  OrderSideEnum side;
  int remaining_volume;
  int filled_volume;
  std::chrono::nanoseconds timestamp;
    double timestamp;
  std::string id;
  Order(double price, OrderSideEnum side, int volume,
        std::chrono::nanoseconds timestamp, std::string id);
    Order(double price, OrderSideEnum side, int volume, double timestamp,
          std::string id);
};
struct Level {
  double price;
  int volume;
  OrderSideEnum side;
  std::chrono::nanoseconds timestamp;
    double timestamp;
  std::string id;
  Level(Order &order);
@@ -39,20 +41,9 @@
bool operator==(const Level &a, const Level &b);
std::ostream& operator<<(std::ostream& out, const Level& a);
template <class T>
struct Side : public std::priority_queue<Level, std::vector<Level>, T> {
public:
    void deleteLevel(std::string orderId);
    void topRemoveVolume(int volume);
    void printTop(std::size_t num = 5);
};
using AskSide = Side<std::greater<Level>>;
using BidSide = Side<std::less<Level>>;
struct Book {
  BidSide bidSide;
  AskSide askSide;
    std::vector<Level> bidSide;
    std::vector<Level> askSide;
  ProductTypeEnum productType;
  std::string product;
  std::string stationId;
@@ -63,12 +54,14 @@
  double broFee;
  Book();
  Book(ProductTypeEnum productType, std::string product, std::string stationId,
       std::string unit, std::chrono::nanoseconds expiry, double aggFee,
       double pasFee, double broFee);
    Book(ProductTypeEnum productType, std::string product,
         std::string stationId, std::string unit,
         std::chrono::nanoseconds expiry, double aggFee, double pasFee,
         double broFee);
  void ask(Order &order);
  void bid(Order &order);
    void printBook(std::size_t numOrders = 10);
};
Book testBook(int orders = 10, bool printBook = true);
} // namespace book
bot.cpp
New file
@@ -0,0 +1,6 @@
#include "strat.hpp"
int main(void)
{
}
click.cpp
New file
@@ -0,0 +1,77 @@
#include "book.hpp"
#include "json.hpp"
#include "protocol.hpp"
#include <cstdlib>
#include <getopt.h>
#include <iostream>
#include <unordered_map>
enum clickType { Buy, Sell, Flash };
static std::unordered_map<std::string, clickType> mapClick;
void initialise()
{
    mapClick = {{"BUY", Buy}, {"SELL", Sell}, {"FLASH", Flash},
                {"b", Buy},   {"s", Sell},    {"f", Flash},
                {"B", Buy},   {"S", Sell},    {"F", Flash}};
}
void usage()
{
    std::cout << "DESCRIPTION" << std::endl
          << "Click trader using same algs" << std::endl
          << std::endl
          << "USAGE" << std::endl
          << "\t-a product" << std::endl
          << "\t-t click type (buy, sell, flash)" << std::endl
          << "\t-p price" << std::endl
          << "\t-v volume" << std::endl
          << "\t-i id" << std::endl
          << "Always need product, need side, price and volume for "
         "adding/flash, need id for deleting"
          << std::endl;
}
int main(int argc, char** argv)
{
    int c;
    int index;
    std::string product, id;
    double price;
    clickType click;
    uint64_t volume;
    initialise();
    if (argc == 1) {
    usage(), exit(0);
    }
    while ((c = getopt(argc, argv, "a::t::p::v::i::")) != -1) {
    switch (c) {
    case 'a':
        product = std::string(optarg);
        break;
    case 's':
        click = mapClick[optarg];
        break;
    case 'p':
        price = std::stod(optarg);
        break;
    case 'v':
        volume = std::stoll(optarg);
        break;
    case 'i':
        id = std::string(optarg);
        break;
    case '?':
    default:
        usage();
        exit(0);
    }
    }
    switch (click) {
    case Buy:
    case Sell:
    case Flash:;
    }
}
cpp-httplib
New file
@@ -0,0 +1 @@
Subproject commit 11e02e901cb9078f814903493359281ad4064ed5
date
New file
@@ -0,0 +1 @@
Subproject commit 655b249b8f463f690c53a19d6b4110297699e3c5
json.cpp
New file
@@ -0,0 +1,493 @@
#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
json.hpp
New file
@@ -0,0 +1,169 @@
#pragma once
#include "book.hpp"
#include <chrono>
#include <cstdint>
#include <ostream>
#include <queue>
#include <unordered_map>
namespace json
{
enum MessageTypes {
    FUTURE_TYPE,
    SPREAD_TYPE,
    CALL_TYPE,
    PUT_TYPE,
    SETTLEMENT,
    ADD,
    ADDED,
    DELETE,
    DELETED,
    REJECT,
    TRADE,
    BROKER_REQUEST,
    BROKER_ACK,
    BROKER_CONFIRM,
    NONE
};
enum TradeTypeEnum { BUY_AGGRESSOR, SELL_AGGRESSOR };
struct Message {
    MessageTypes type;
    std::string product;
    Message(MessageTypes type, std::string product);
    Message();
    virtual ~Message() = default;
};
struct FromExchange : public Message {
    uint64_t sequence;
    double timestamp;
    FromExchange(MessageTypes type, std::string product, uint64_t sequence,
                 double timestamp);
    virtual ~FromExchange() = default;
};
struct ToExchange : public Message {
    ToExchange(MessageTypes type, std::string product);
    virtual ~ToExchange() = default;
};
struct Broker : public Message {
    double price;
    book::OrderSideEnum side;
    uint64_t volume;
    std::string counterparty;
    Broker(MessageTypes type, std::string product, double price,
           book::OrderSideEnum side, uint64_t volume, std::string counterparty);
    virtual ~Broker() = default;
};
struct AnnounceMessage : public FromExchange {
    std::string stationId;
    std::string stationName;
    std::string unit;
    std::chrono::nanoseconds expiry;
    double aggFee;
    double pasFee;
    double broFee;
    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);
};
struct SettleMessage : public FromExchange {
    std::string stationName;
    std::chrono::nanoseconds expiry;
    double price;
    SettleMessage(MessageTypes type, std::string product,
                  std::string stationName, std::chrono::nanoseconds expiry,
                  double price, uint64_t sequence, double timestamp);
};
struct AddMessage : public ToExchange {
    double price;
    book::OrderSideEnum side;
    uint64_t volume;
    AddMessage(MessageTypes type, std::string product, double price,
               book::OrderSideEnum side, uint64_t volume);
    std::string as_string();
};
struct AddedMessage : public FromExchange {
    std::string id;
    book::OrderSideEnum side;
    double price;
    uint64_t filled;
    uint64_t resting;
    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);
};
struct DeleteMessage : public ToExchange {
    std::string id;
    DeleteMessage(MessageTypes type, std::string product, std::string id);
    std::string as_string();
};
struct DeletedMessage : public FromExchange {
    std::string id;
    book::OrderSideEnum side;
    DeletedMessage(MessageTypes type, std::string product, std::string id,
                   book::OrderSideEnum side, uint64_t sequence,
                   double timestamp);
};
struct RejectMessage : public FromExchange {
    std::string error;
    RejectMessage(MessageTypes type, std::string product, std::string error,
                  uint64_t sequence, double timestamp);
};
struct TradeMessage : public FromExchange {
    double price;
    uint64_t volume;
    std::string buyer;
    std::string seller;
    TradeTypeEnum tradeType;
    std::string passiveOrder;
    uint64_t passiveOrderRemaining;
    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);
};
struct BrokerRequest : public Broker {
    BrokerRequest(MessageTypes type, std::string product, double price,
                  book::OrderSideEnum side, uint64_t volume,
                  std::string counterparty);
};
struct BrokerAck : public Broker {
    std::string id;
    std::string brokerTradeStatus;
    std::string owner;
    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);
};
struct BrokerConfirm : public Broker {
    std::string id;
    BrokerConfirm(MessageTypes type, std::string product, double price,
                  book::OrderSideEnum side, uint64_t volume,
                  std::string counterparty, std::string id);
};
Message* parseSingle(std::string& str);
std::queue<Message*> parseMany(std::string& str);
} // namespace json
main.cpp
@@ -1,7 +1,15 @@
#include "book.hpp"
#include "json.hpp"
#include "protocol.hpp"
#include <chrono>
int main(void)
{
    Book b = testBook(10, true);
    book::Book b = book::testBook(10, true);
    auto bs = protocol::recoverBook();
    std::cout << bs.size() << std::endl;
    for (auto i : bs) {
        std::cout << i.first << std::endl;
        i.second.printBook();
    }
}
protocol.cpp
New file
@@ -0,0 +1,177 @@
#include "protocol.hpp"
#include "book.hpp"
#include "cpp-httplib/httplib.h"
#include "json.hpp"
#include "secrets.hpp"
#include <chrono>
#include <iostream>
#include <queue>
#include <sstream>
#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);
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("../rec.log");
    std::stringstream ss;
    ss << sampleFile.rdbuf();
    // httplib::Client cli("http://" + server);
    // auto res = cli.Get("/recover");
    std::string l;
    l = ss.str();
    std::queue<json::Message*> a(json::parseMany(l));
    while (!a.empty()) {
    protocol::handleMessage(bs, a.front());
    delete a.front();
    a.pop();
    }
    return bs;
}
void addOrder(json::AddMessage& order)
{
    std::string message = "{\"message\": " + order.as_string() + ", " +
                          "\"username\": \"" + std::string(USER) +
                          "\", \"password\": \"" + std::string(PASS) + "\"}";
    send(message);
}
void deleteOrder(json::DeleteMessage& order)
{
    std::string message = "{\"message\": " + order.as_string() +
                          ", \"username\": \"" + std::string(USER) +
                          "\", \"password\": \"" + std::string(PASS) + "\"}";
    send(message);
}
void handleMessage(std::unordered_map<std::string, book::Book>& bs,
                   json::Message* message)
{
    if (mapAnnounce.empty()) initialise();
    json::AnnounceMessage* a = dynamic_cast<json::AnnounceMessage*>(message);
    json::SettleMessage* b = dynamic_cast<json::SettleMessage*>(message);
    json::AddedMessage* c = dynamic_cast<json::AddedMessage*>(message);
    json::DeletedMessage* d = dynamic_cast<json::DeletedMessage*>(message);
    json::TradeMessage* e = dynamic_cast<json::TradeMessage*>(message);
    json::Broker* f = dynamic_cast<json::Broker*>(message);
    switch (message->type) {
    case json::FUTURE_TYPE:
    case json::SPREAD_TYPE:
    case json::CALL_TYPE:
    case json::PUT_TYPE:
    announce(bs, a);
    break;
    case json::SETTLEMENT:
    settle(bs, dynamic_cast<json::SettleMessage*>(message));
    break;
    case json::ADDED:
    addedOrder(bs, dynamic_cast<json::AddedMessage*>(message));
    break;
    case json::DELETED:
    deletedOrder(bs, dynamic_cast<json::DeletedMessage*>(message));
    break;
    case json::TRADE:
    tradeOrder(bs, dynamic_cast<json::TradeMessage*>(message));
    break;
    case json::BROKER_REQUEST:
    case json::BROKER_ACK:
    case json::BROKER_CONFIRM:
    broker(bs, dynamic_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) {
    book::Order t(message->price, book::Buy, message->resting,
                  message->timestamp, message->id);
    bs[message->product].bid(t);
    } else {
    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) {
    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);
        std::make_heap(bs[message->product].bidSide.begin(),
                       bs[message->product].bidSide.end(),
                       std::less<book::Level>());
        }
    }
    } else {
    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);
        std::make_heap(bs[message->product].askSide.begin(),
                       bs[message->product].askSide.end(),
                       std::greater<book::Level>());
        }
    }
    }
}
void tradeOrder(std::unordered_map<std::string, book::Book>& bs,
                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);
    }
}
void broker(std::unordered_map<std::string, book::Book>& bs,
            json::Broker* message)
{
}
void send(std::string& message)
{
    cli.Post("/execution", message, "text/plain");
}
} // namespace protocol
protocol.hpp
New file
@@ -0,0 +1,37 @@
#pragma once
#include "book.hpp"
#include "json.hpp"
#include <string>
#include <unordered_map>
namespace protocol
{
enum OrderEnum { ADD, DELETE, BROKER_REQUEST, BROKER_CONFIRM };
    // Catchup utilities
std::unordered_map<std::string, book::Book> recoverBook();
    // Outgoing messages
    void addOrder(json::AddMessage& order);
    void deleteOrder(json::DeleteMessage& order);
// Incoming messages
void handleMessage(std::unordered_map<std::string, book::Book>& bs,
                   json::Message* message);
void announce(std::unordered_map<std::string, book::Book>& bs,
              json::AnnounceMessage* message);
void settle(std::unordered_map<std::string, book::Book>& bs,
            json::SettleMessage* message);
void addedOrder(std::unordered_map<std::string, book::Book>& bs,
              json::AddedMessage* message);
void deletedOrder(std::unordered_map<std::string, book::Book>& bs,
                 json::DeletedMessage* message);
void tradeOrder(std::unordered_map<std::string, book::Book>& bs,
                json::TradeMessage* message);
void broker(std::unordered_map<std::string, book::Book>& bs,
            json::Broker* message);
    void send(std::string& message);
} // namespace protocol
secrets.hpp
@@ -1,11 +1,15 @@
#pragma once
#define HOST "sytev070"
#include <string>
#define TEST
constexpr const char* HOST="sytev070";
#ifdef TEST
#define PORT "9005"
constexpr const char* PORT="9005";
#else
#define PORT "9000"
constexpr const char* PORT="9000";
#endif
#define USER "jgrunbau"
#define PASS "b7d630945a0854581d9f86ba147f34a5"
constexpr const char* USER="jgrunbau";
constexpr const char* PASS="b7d630945a0854581d9f86ba147f34a5";
strat.cpp
New file
@@ -0,0 +1,5 @@
#include "strat.hpp"
namespace strat {
}
strat.hpp
@@ -1,9 +1,8 @@
#pragma once
#include "book.hpp"
#include "secrets.hpp"
#include <unordered_map>
#include <string>
Book recoverBook()
{
namespace strat {
}
test.cpp
New file
@@ -0,0 +1,15 @@
#include "book.hpp"
#include "json.hpp"
#include "protocol.hpp"
#include <chrono>
int main(void)
{
    book::Book b = book::testBook(10, true);
    auto bs = protocol::recoverBook();
    std::cout << bs.size() << std::endl;
    for (auto i : bs) {
        std::cout << i.first << std::endl;
        i.second.printBook();
    }
}