Added json parsing, protocol comprehension and began executables for algs
7 files modified
1 files deleted
12 files added
| | |
| | | AllowShortIfStatementsOnASingleLine: true |
| | | BreakBeforeBraces: Linux |
| | | IndentCaseLabels: false |
| | | --- |
| | | PointerAlignment: Left |
| | | AllowShortIfStatementsOnASingleLine: true |
| | | IndentCaseBlocks: true |
| | | IndentCaseLabels: false |
| | | SortUsingDeclarations: true |
New file |
| | |
| | | [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 |
New file |
| | |
| | | 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) |
| | |
| | | #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) |
| | | Level::Level(Order& order) |
| | | : price{order.price}, volume(order.remaining_volume), side{order.side}, |
| | | timestamp{order.timestamp}, id{order.id} {} |
| | | |
| | | 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())) |
| | | return true; |
| | | else |
| | | return false; |
| | | timestamp{order.timestamp}, id{order.id} |
| | | { |
| | | } |
| | | |
| | | 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())) |
| | | return true; |
| | | else |
| | | return false; |
| | | bool operator<(const Level& a, const Level& b) |
| | | { |
| | | if (a.price < b.price) |
| | | return true; |
| | | 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) |
| | | return true; |
| | | else if (a.price == b.price && (a.timestamp.count() >= b.timestamp.count())) |
| | | return true; |
| | | else |
| | | return false; |
| | | bool operator>(const Level& a, const Level& b) |
| | | { |
| | | if (a.price > b.price) |
| | | return true; |
| | | 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) |
| | | return true; |
| | | else if (a.price == b.price && (a.timestamp.count() >= b.timestamp.count())) |
| | | return true; |
| | | else |
| | | return false; |
| | | bool operator<=(const Level& a, const Level& b) |
| | | { |
| | | if (a.price <= b.price) |
| | | return true; |
| | | 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())) |
| | | return true; |
| | | else |
| | | return false; |
| | | bool operator>=(const Level& a, const Level& b) |
| | | { |
| | | if (a.price >= b.price) |
| | | return true; |
| | | 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 == b.timestamp)) |
| | | return true; |
| | | else |
| | | return false; |
| | | } |
| | | |
| | | 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, |
| | |
| | | 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; |
| | | order.filled_volume += temp; |
| | | this->bidSide.topRemoveVolume(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(); |
| | | 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.front().volume -= order.remaining_volume; |
| | | order.remaining_volume -= temp; |
| | | break; |
| | | } else { |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | 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; |
| | | order.filled_volume += temp; |
| | | this->askSide.topRemoveVolume(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(); |
| | | if (order.remaining_volume > 0) { |
| | | this->askSide.emplace(this->askSide.begin(), order); |
| | | std::make_heap(this->askSide.begin(), this->askSide.end(), |
| | | std::greater<Level>()); |
| | | } |
| | | } |
| | | if (order.remaining_volume > 0) { |
| | | this->bidSide.emplace(order); |
| | | } |
| | | } |
| | | |
| | | void Book::printBook(std::size_t numOrders) { |
| | | std::cout << "Sell side: " << this->askSide.size() << std::endl; |
| | | this->askSide.printTop(numOrders); |
| | | std::cout << "Buy side: " << this->bidSide.size() << std::endl; |
| | | this->bidSide.printTop(numOrders); |
| | | 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.front().volume -= order.remaining_volume; |
| | | order.remaining_volume -= temp; |
| | | break; |
| | | } else { |
| | | 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(this->bidSide.begin(), order); |
| | | std::make_heap(this->bidSide.begin(), this->bidSide.end(), |
| | | std::less<Level>()); |
| | | } |
| | | } |
| | | |
| | | Book testBook(int orders, bool printBook) { |
| | | Book b = Book(); |
| | | std::chrono::nanoseconds time(1); |
| | | for (int i = 1; i < orders; i++) { |
| | | Order t(i, Buy, 10, time++, "a"); |
| | | b.bid(t); |
| | | } |
| | | for (int i = orders + 1; i < 2 * orders; i++) { |
| | | Order t(i, Sell, 10, time++, "b"); |
| | | b.ask(t); |
| | | } |
| | | if (printBook) |
| | | b.printBook(orders - 1); |
| | | return b; |
| | | void Book::printBook(std::size_t numOrders) |
| | | { |
| | | std::cout << "Sell side: " << this->askSide.size() << std::endl; |
| | | 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; |
| | | 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 b = Book(); |
| | | double time(1); |
| | | for (int i = 1; i < orders; i++) { |
| | | Order t(i, Buy, 10, time++, "a"); |
| | | b.bid(t); |
| | | } |
| | | for (int i = orders + 1; i < 2 * orders; i++) { |
| | | Order t(i, Sell, 10, time++, "b"); |
| | | b.ask(t); |
| | | } |
| | | if (printBook) b.printBook(orders - 1); |
| | | return b; |
| | | } |
| | | } // namespace book |
| | |
| | | #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 }; |
| | | |
| | | struct Order { |
| | | double price; |
| | | OrderSideEnum side; |
| | | int remaining_volume; |
| | | int filled_volume; |
| | | std::chrono::nanoseconds timestamp; |
| | | std::string id; |
| | | Order(double price, OrderSideEnum side, int volume, |
| | | std::chrono::nanoseconds timestamp, std::string id); |
| | | double price; |
| | | OrderSideEnum side; |
| | | int remaining_volume; |
| | | int filled_volume; |
| | | double 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; |
| | | std::string id; |
| | | double price; |
| | | int volume; |
| | | OrderSideEnum side; |
| | | double timestamp; |
| | | std::string id; |
| | | |
| | | Level(Order &order); |
| | | Level(Order& order); |
| | | }; |
| | | |
| | | bool operator>(const Level &a, const Level &b); |
| | | bool operator<(const Level &a, const Level &b); |
| | | bool operator>=(const Level &a, const Level &b); |
| | | bool operator<=(const Level &a, const Level &b); |
| | | bool operator==(const Level &a, const Level &b); |
| | | bool operator>(const Level& a, const Level& b); |
| | | bool operator<(const Level& a, const Level& b); |
| | | bool operator>=(const Level& a, const Level& b); |
| | | bool operator<=(const Level& a, const Level& b); |
| | | 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; |
| | | ProductTypeEnum productType; |
| | | std::string product; |
| | | std::string stationId; |
| | | std::string unit; |
| | | std::chrono::nanoseconds expiry; |
| | | double aggFee; |
| | | double pasFee; |
| | | double broFee; |
| | | std::vector<Level> bidSide; |
| | | std::vector<Level> askSide; |
| | | ProductTypeEnum productType; |
| | | std::string product; |
| | | std::string stationId; |
| | | std::string unit; |
| | | std::chrono::nanoseconds expiry; |
| | | double aggFee; |
| | | double pasFee; |
| | | 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); |
| | | void ask(Order &order); |
| | | void bid(Order &order); |
| | | Book(); |
| | | 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 |
New file |
| | |
| | | #include "strat.hpp" |
| | | |
| | | int main(void) |
| | | { |
| | | |
| | | } |
New file |
| | |
| | | #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:; |
| | | } |
| | | } |
New file |
| | |
| | | Subproject commit 11e02e901cb9078f814903493359281ad4064ed5 |
New file |
| | |
| | | Subproject commit 655b249b8f463f690c53a19d6b4110297699e3c5 |
New file |
| | |
| | | #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 |
New file |
| | |
| | | #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 |
| | |
| | | #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(); |
| | | } |
| | | } |
New file |
| | |
| | | #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 |
New file |
| | |
| | | #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 |
| | |
| | | #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"; |
New file |
| | |
| | | #include "strat.hpp" |
| | | |
| | | namespace strat { |
| | | |
| | | } |
| | |
| | | #pragma once |
| | | |
| | | #include "book.hpp" |
| | | #include "secrets.hpp" |
| | | #include <unordered_map> |
| | | #include <string> |
| | | |
| | | Book recoverBook() |
| | | { |
| | | |
| | | namespace strat { |
| | | } |
New file |
| | |
| | | #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(); |
| | | } |
| | | } |