Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
SET(SOURCES
src/lib.cpp)

ADD_EXECUTABLE(test_async tests/test_lib.cpp ${SOURCES})
ADD_EXECUTABLE(test_async tests/test_async.cpp ${SOURCES})
TARGET_LINK_LIBRARIES(test_async)

ADD_EXECUTABLE(test_lib tests/test_lib.cpp ${SOURCES})
TARGET_LINK_LIBRARIES(test_lib)

ADD_EXECUTABLE(test_parser tests/test_parser.cpp ${SOURCES})
TARGET_LINK_LIBRARIES(test_parser)

ADD_EXECUTABLE(run_app src/main.cpp ${SOURCES})
TARGET_LINK_LIBRARIES(run_app)

ENABLE_TESTING()
ADD_TEST(AsyncTests bin/test_async)
ADD_TEST(LibTests bin/test_lib)
ADD_TEST(LibTests bin/test_lib)
ADD_TEST(ParserTests bin/test_parser)
51 changes: 51 additions & 0 deletions include/exchange/concepts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef INCLUDED_EXCHANGE_CONCEPTS_HPP
#define INCLUDED_EXCHANGE_CONCEPTS_HPP

#include "util/concepts.hpp"


namespace sadhbhcraft::exchange {

template <typename T>
concept MsgParserConcept =
requires(T &x) {
util::NumberConcept<typename T::KeyType>;
util::NumberConcept<typename T::IntegerType>;
util::NumberConcept<typename T::DecimalType>;
typename T::StringType;
{
x.parse_key(
std::declval<typename T::KeyType &>())
} -> std::convertible_to<bool>;
{
x.parse_value(
std::declval<typename T::IntegerType &>())
} -> std::convertible_to<bool>;
{
x.parse_value(
std::declval<typename T::DecimalType &>())
} -> std::convertible_to<bool>;
{
x.parse_value(
std::declval<typename T::StringType &>())
} -> std::convertible_to<bool>;
{
x.parse_field(
std::declval<typename T::KeyType>(),
std::declval<typename T::IntegerType &>())
} -> std::convertible_to<bool>;
{
x.parse_field(
std::declval<typename T::KeyType>(),
std::declval<typename T::DecimalType &>())
} -> std::convertible_to<bool>;
{
x.parse_field(
std::declval<typename T::KeyType>(),
std::declval<typename T::StringType &>())
} -> std::convertible_to<bool>;
};


} // end of namespace sadhbhcraft::exchange
#endif//INCLUDED_EXCHANGE_CONCEPTS_HPP
93 changes: 93 additions & 0 deletions include/exchange/istream_msg_parser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#ifndef INCLUDED_SIMPLE_PARSER_HPP
#define INCLUDED_SIMPLE_PARSER_HPP

#include "util/concepts.hpp"

#include <istream>


namespace sadhbhcraft::exchange {

template<util::NumberConcept _KeyType>
class IStreamMsgParser
{
public:
using KeyType = _KeyType;
using StringType = std::string;
using IntegerType = int;
using DecimalType = double;

IStreamMsgParser(std::istream &is): m_is(is) {}

bool parse_key(KeyType &out_key)
{
if (m_is.eof())
{
return false;
}

m_is >> out_key;

if (auto c = m_is.get(); c != '=')
{
return false;
}

return true;
}

bool parse_value(util::NumberConcept auto &out_value)
{
if (m_is.eof())
{
return false;
}

m_is >> out_value;

if (auto c = m_is.get(); c != '\1' && !m_is.eof())
{
return false;
}

return true;
}

bool parse_value(std::string &out_value)
{
if (m_is.eof())
{
return false;
}

for (;;)
{
auto c = m_is.get();

if (c == '\1' || m_is.eof())
{
break;
}
out_value += c;
}

return true;
}

bool parse_field(KeyType in_key, auto &out_value)
{
if (KeyType key; parse_key(key), key != in_key)
{
return false;
}

return parse_value(out_value);
}

private:
std::istream &m_is;
};


} // end of namespace sadhbhcraft::exchange
#endif//INCLUDED_SIMPLE_PARSER_HPP
43 changes: 43 additions & 0 deletions include/exchange/msg_header.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef INCLUDED_MSG_HEADER_HPP
#define INCLUDED_MSG_HEADER_HPP

#include "exchange/concepts.hpp"


namespace sadhbhcraft::exchange {

template <MsgParserConcept MsgParserType>
struct MsgHeader
{
using KeyType = typename MsgParserType::KeyType;
using StringType = typename MsgParserType::StringType;
using IntegerType = typename MsgParserType::IntegerType;

static constexpr KeyType FixVersion = 8;
static constexpr KeyType BodyLength = 9;
static constexpr KeyType MsgType = 35;
static constexpr KeyType SenderCompId = 49;
static constexpr KeyType TargetCompId = 56;
static constexpr KeyType ApplVerID = 1128;
static constexpr KeyType Checksum = 10;

StringType fix_version;
StringType sender_comp_id;
StringType target_comp_id;
IntegerType body_length;
IntegerType msg_type;

template<typename P>
bool parse_message(P &&parser) requires std::is_same_v<std::remove_cvref_t<P>, MsgParserType>
{
// These fields must be in this exact order
return parser.parse_field(FixVersion, fix_version) &&
parser.parse_field(BodyLength, body_length) &&
parser.parse_field(MsgType, msg_type) &&
parser.parse_field(SenderCompId, sender_comp_id) &&
parser.parse_field(TargetCompId, target_comp_id);
}
};

} // end of namespace sadhbhcraft::exchange
#endif//INCLUDED_MSG_HEADER_HPP
98 changes: 98 additions & 0 deletions include/exchange/msg_new_order_single.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#ifndef INCLUDED_MSG_NEW_ORDER_SINGLE_HPP
#define INCLUDED_MSG_NEW_ORDER_SINGLE_HPP

#include "exchange/concepts.hpp"


namespace sadhbhcraft::exchange {

template <MsgParserConcept MsgParserType>
struct NewOrderSingle
{
using KeyType = typename MsgParserType::KeyType;
using StringType = typename MsgParserType::StringType;
using IntegerType = typename MsgParserType::IntegerType;
using DecimalType = typename MsgParserType::DecimalType;

static constexpr KeyType ClOrdID = 11;
static constexpr KeyType OrdType = 40; // 1 MKT, 2 LMT
static constexpr KeyType Price = 44;
static constexpr KeyType OrderQty = 38;
static constexpr KeyType Side = 54; // 1 BUY, 2 SELL
static constexpr KeyType TransactTime = 60;
static constexpr KeyType Symbol = 55;
static constexpr KeyType TimeInForce = 59; //1 GTC, 3 IOC

unsigned
cl_ord_id_bit : 1 = {0},
transact_time_bit : 1 = {0},
symbol_bit : 1 = {0},
ord_type_bit : 1 = {0},
side_bit : 1 = {0},
time_in_force_bit : 1 = {0},
price_bit : 1 = {0},
order_qty_bit : 1 = {0};

StringType cl_ord_id;
StringType transact_time;
StringType symbol;
IntegerType ord_type;
IntegerType side;
IntegerType time_in_force;
DecimalType price;
DecimalType order_qty;


template<typename P>
bool parse_message(P &&parser) requires std::is_same_v<std::remove_cvref_t<P>, MsgParserType>
{
for (;;)
{
KeyType key;
if (!parser.parse_key(key))
{
break;
}

switch (key)
{
case ClOrdID:
cl_ord_id_bit = parser.parse_value(cl_ord_id);
break;
case OrdType:
ord_type_bit = parser.parse_value(ord_type);
break;
case Price:
price_bit = parser.parse_value(price);
break;
case OrderQty:
order_qty_bit = parser.parse_value(order_qty);
break;
case Side:
side_bit = parser.parse_value(side);
break;
case TransactTime:
transact_time_bit = parser.parse_value(transact_time);
break;
case Symbol:
symbol_bit = parser.parse_value(symbol);
break;
case TimeInForce:
time_in_force_bit = parser.parse_value(time_in_force);
break;
}
}

return cl_ord_id_bit &&
transact_time_bit &&
symbol_bit &&
ord_type_bit &&
side_bit &&
time_in_force_bit &&
price_bit &&
order_qty_bit;
}
};

} // end of namespace sadhbhcraft::exchange
#endif//INCLUDED_MSG_NEW_ORDER_SINGLE_HPP
1 change: 0 additions & 1 deletion include/lib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@

namespace sadhbhcraft::orderbook
{

} // end of namespace sadhbhcraft::orderbook
#endif // INCLUDED_LIB_HPP
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "lib.hpp"

#include <iostream>
#include <sstream>


namespace scob = sadhbhcraft::orderbook;
Expand Down
6 changes: 4 additions & 2 deletions tests/test_async.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "util/async.hpp"
#include "util/generator.hpp"

#include <functional>
#include <vector>
#include <iostream>

Expand All @@ -20,6 +21,7 @@ struct OrderQuantity
int quantity;
};


class OrderSizeLimit
{
public:
Expand Down Expand Up @@ -62,7 +64,7 @@ struct Level
.order = iter->order,
.quantity = quantity
};
co_await ep(oq);
co_await ep(std::ref(oq));
iter->quantity -= oq.quantity;
quantity -= oq.quantity;
co_yield oq;
Expand All @@ -74,7 +76,7 @@ struct Level
.order = iter->order,
.quantity = iter->quantity
};
co_await ep(oq);
co_await ep(std::ref(oq));
quantity -= oq.quantity;
iter->quantity = 0; // remainder is cancelled
co_yield oq;
Expand Down
Loading