From 549b4f5d63f24b263f5d584c3a3bae9ddd3b801c Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 18 May 2025 18:10:47 -0400 Subject: [PATCH 01/27] cmake update --- CMakeLists.txt | 53 ++++--- DataService/src/CMakeLists.txt | 48 ++++--- FIXGateway/src/CMakeLists.txt | 67 +++++---- FIXGateway/src/FileLog.h | 4 +- FIXGateway/src/SocketAcceptor.cpp | 4 +- FIXGateway/src/SocketAcceptor.h | 12 +- FIXGateway/src/SocketConnection.cpp | 2 +- GenTools/CMakeLists.txt | 32 ++--- GenTools/idl/CMakeLists.txt | 29 ++-- LatencyTest/CMakeLists.txt | 47 ++++--- MatchingEngine/src/CMakeLists.txt | 58 ++++---- MatchingEngine/src/Market.cpp | 6 +- MatchingEngine/src/Market.h | 24 ++-- MiscClients/spring_reactjs/README.md | 2 +- .../src/main/resources/fixclient.cfg | 4 +- .../webtrader_reactjs/src/App.js | 1 + README.md | 4 +- docker/Docker.Build_Distributed_ATS | 10 +- docker/build_dependences.sh | 24 ++++ docker/dockerize_dats.sh | 10 +- download_deps_and_build_all.sh | 130 ------------------ 21 files changed, 234 insertions(+), 337 deletions(-) create mode 100755 docker/build_dependences.sh delete mode 100755 download_deps_and_build_all.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index f7923b9..8372c2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,43 +1,39 @@ -cmake_minimum_required(VERSION 3.12.4) - -if(NOT CMAKE_VERSION VERSION_LESS 3.0) - cmake_policy(SET CMP0048 NEW) -endif() +cmake_minimum_required(VERSION 3.29) project(DistributedATS) -#set(CMAKE_SUPPRESS_REGENERATION true) - -# Find requirements -if(NOT fastcdr_FOUND) - find_package(fastcdr REQUIRED) -endif() -if(NOT fastdds_FOUND) - find_package(fastdds 3 REQUIRED) -endif() +set(CMAKE_PREFIX_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -FIND_PACKAGE( Boost 1.40 COMPONENTS program_options REQUIRED ) -INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} ) -link_directories(${Boost_LIBRARY_DIRS}) +find_package( Boost ) +find_package( DDS REQUIRED ) +find_package( log4cxx REQUIRED ) +find_package( quickfix REQUIRED ) +find_package( liquibook REQUIRED ) -link_directories(${QUICKFIX_INSTALL_PREFIX}/lib) +set(DDS_INCLUDE_DIR "${DDS_INSTALL_PREFIX}/include") +set(DDS_LIBRARY_DIR "${DDS_INSTALL_PREFIX}/lib") +set(QUICKFIX_INCLUDE_DIR "${QUICKFIX_INSTALL_PREFIX}/include") +set(QUICKFIX_LIBRARY_DIR "${QUICKFIX_INSTALL_PREFIX}/lib") +set(LOG4CXX_INCLUDE_DIR "${LOG4CXX_INSTALL_PREFIX}/include") +set(LOG4CXX_LIBRARY_DIR "${LOG4CXX_INSTALL_PREFIX}/lib") -include_directories(Common) -add_subdirectory(GenTools/idl) +set(LIQUIBOOK_INCLUDE_DIR "${LIQUIBOOK_INSTALL_PREFIX}/include") -include_directories(GenTools/idl) -add_subdirectory(FIXGateway/src) -add_subdirectory(DataService/src) -add_subdirectory(MatchingEngine/src) -add_subdirectory(LatencyTest) +include_directories( Common ) +add_subdirectory( GenTools/idl ) -set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed") +include_directories( GenTools/idl ) +add_subdirectory( FIXGateway/src ) +add_subdirectory( DataService/src ) +add_subdirectory( MatchingEngine/src ) +add_subdirectory( LatencyTest ) install(DIRECTORY MiscATS DESTINATION ${CMAKE_INSTALL_PREFIX}) + install(CODE " file(GLOB_RECURSE SCRIPT_FILES \"\${CMAKE_INSTALL_PREFIX}/MiscATS/*.sh\") @@ -45,6 +41,7 @@ install(CODE " execute_process(COMMAND chmod +x \${script}) endforeach() ") + install(FILES FIXGateway/scripts/fixgateway.sh DataService/scripts/dataservice.sh MatchingEngine/scripts/matchingengine.sh @@ -53,5 +50,5 @@ install(FILES FIXGateway/scripts/fixgateway.sh GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -install(FILES config/log4cxx.xml DESTINATION config) -install(FILES FIXGateway/spec/FIX44.xml DESTINATION spec) +install( FILES config/log4cxx.xml DESTINATION config ) +install( FILES FIXGateway/spec/FIX44.xml DESTINATION spec ) diff --git a/DataService/src/CMakeLists.txt b/DataService/src/CMakeLists.txt index a6e8953..aa85451 100644 --- a/DataService/src/CMakeLists.txt +++ b/DataService/src/CMakeLists.txt @@ -1,36 +1,44 @@ cmake_minimum_required(VERSION 3.12.4) -if(NOT CMAKE_VERSION VERSION_LESS 3.0) - cmake_policy(SET CMP0048 NEW) -endif() +message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") +message(DDS_INCLUDE_DIR="${DDS_INCLUDE_DIR}") +message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") -project(DataService) +message(QUICKFIX_INCLUDE_DIR="${QUICKFIX_INCLUDE_DIR}") +message(QUICKFIX_LIBRARY_DIR="${QUICKFIX_LIBRARY_DIR}") -# Find requirements -if(NOT fastcdr_FOUND) - find_package(fastcdr REQUIRED) -endif() +include_directories(${DDS_INCLUDE_DIR}) +link_directories(${DDS_LIBRARY_DIR}) -if(NOT fastdds_FOUND) - find_package(fastdds 3 REQUIRED) -endif() +include_directories(${QUICKFIX_INCLUDE_DIR}) +link_directories(${QUICKFIX_LIBRARY_DIR}) -find_package(log4cxx REQUIRED) +include_directories(${LOG4CXX_INCLUDE_DIR}) +link_directories(${LOG4CXX_LIBRARY_DIR}) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +include_directories(${Boost_INCLUDE_DIR}) +link_directories(${Boost_LIBRARY_DIRS}) -link_directories(${CMAKE_INSTALL_PREFIX}/lib) +file(GLOB DISTRIBUTED_ATS_DATASERVICE_SRC *.cpp) -file(GLOB DISTRIBUTED_ATS_DATASERVICE_SRC *) add_executable(DataService ${DISTRIBUTED_ATS_DATASERVICE_SRC}) -link_directories(DistributedATSLib quickfix log4cxx) -target_link_libraries(DataService DistributedATSLib quickfix log4cxx boost_program_options sqlite3) + +find_package(Boost REQUIRED COMPONENTS program_options) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(DataService + PRIVATE + DistributedATSLib + quickfix + log4cxx + Boost::program_options + fastcdr + fastdds +) set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed") -install(TARGETS DataService +install(TARGETS DataService PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dats ) diff --git a/FIXGateway/src/CMakeLists.txt b/FIXGateway/src/CMakeLists.txt index 7691bef..d49ee7f 100644 --- a/FIXGateway/src/CMakeLists.txt +++ b/FIXGateway/src/CMakeLists.txt @@ -1,42 +1,41 @@ cmake_minimum_required(VERSION 3.12.4) -if(NOT CMAKE_VERSION VERSION_LESS 3.0) - cmake_policy(SET CMP0048 NEW) -endif() - project(FIXGateway) -# Find requirements -if(NOT fastcdr_FOUND) - find_package(fastcdr REQUIRED) -endif() - -if(NOT fastdds_FOUND) - find_package(fastdds 3 REQUIRED) -endif() - -find_package(log4cxx REQUIRED) - -# Set C++11 -include(CheckCXXCompilerFlag) -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG OR - CMAKE_CXX_COMPILER_ID MATCHES "Clang") - check_cxx_compiler_flag(-std=c++11 SUPPORTS_CXX11 -g) - if(SUPPORTS_CXX11) - add_compile_options(-std=c++11 -g) - else() - message(FATAL_ERROR "Compiler doesn't support C++11") - endif() -endif() - -link_directories(${CMAKE_INSTALL_PREFIX}/lib) -link_directories(${CMAKE_QUICKFIX_PREFIX}/lib) -#link_directories(${Boost_LIBRARY_DIRS}) - -file(GLOB DISTRIBUTED_ATS_FIX_GATEWAY_SRC *) +message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") +message(DDS_INCLUDE_DIR="${DDS_INCLUDE_DIR}") +message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") + +message(QUICKFIX_INCLUDE_DIR="${QUICKFIX_INCLUDE_DIR}") +message(QUICKFIX_LIBRARY_DIR="${QUICKFIX_LIBRARY_DIR}") + +include_directories(${DDS_INCLUDE_DIR}) +link_directories(${DDS_LIBRARY_DIR}) + +include_directories(${QUICKFIX_INCLUDE_DIR}) +link_directories(${QUICKFIX_LIBRARY_DIR}) + +include_directories(${LOG4CXX_INCLUDE_DIR}) +link_directories(${LOG4CXX_LIBRARY_DIR}) + +include_directories(${Boost_INCLUDE_DIR}) +link_directories(${Boost_LIBRARY_DIRS}) + +file(GLOB DISTRIBUTED_ATS_FIX_GATEWAY_SRC *.cpp) add_executable(FIXGateway ${DISTRIBUTED_ATS_FIX_GATEWAY_SRC}) -link_directories(DistributedATSLib quickfix log4cxx) -target_link_libraries(FIXGateway DistributedATSLib quickfix log4cxx boost_program_options) + +find_package(Boost REQUIRED COMPONENTS program_options) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(FIXGateway + PRIVATE + DistributedATSLib + quickfix + log4cxx + Boost::program_options + fastcdr + fastdds +) set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed") diff --git a/FIXGateway/src/FileLog.h b/FIXGateway/src/FileLog.h index 496ef63..b6eead6 100644 --- a/FIXGateway/src/FileLog.h +++ b/FIXGateway/src/FileLog.h @@ -85,11 +85,11 @@ class FileLog : public FIX::Log { void backup(); void onIncoming(const std::string &value) { - m_messages << FIX::UtcTimeStampConvertor::convert(FIX::UtcTimeStamp(), 9) + m_messages << FIX::UtcTimeStampConvertor::convert(FIX::UtcTimeStamp::now(), 9) << " : " << value << std::endl; } void onOutgoing(const std::string &value) { - m_messages << FIX::UtcTimeStampConvertor::convert(FIX::UtcTimeStamp(), 9) + m_messages << FIX::UtcTimeStampConvertor::convert(FIX::UtcTimeStamp::now(), 9) << " : " << value << std::endl; } void onEvent(const std::string &value) { diff --git a/FIXGateway/src/SocketAcceptor.cpp b/FIXGateway/src/SocketAcceptor.cpp index 90c4e42..a34b004 100644 --- a/FIXGateway/src/SocketAcceptor.cpp +++ b/FIXGateway/src/SocketAcceptor.cpp @@ -129,7 +129,7 @@ void SocketAcceptor::onStart() { m_pServer = 0; } -bool SocketAcceptor::onPoll(double timeout) { +bool SocketAcceptor::onPoll() { if (!m_pServer) return false; @@ -150,7 +150,7 @@ bool SocketAcceptor::onPoll(double timeout) { } std::cout << "Polling" << std::endl; - m_pServer->block(*this, true, timeout); + m_pServer->block(*this, true); return true; } diff --git a/FIXGateway/src/SocketAcceptor.h b/FIXGateway/src/SocketAcceptor.h index 6b56912..6cc0a09 100644 --- a/FIXGateway/src/SocketAcceptor.h +++ b/FIXGateway/src/SocketAcceptor.h @@ -62,15 +62,13 @@ class SocketAcceptor : public FIX::Acceptor, FIX::SocketServer::Strategy { typedef std::set Sessions; typedef std::map PortToSessions; typedef std::map SocketConnections; - // typedef std::map - // PendingLogonSocketConnection; - void onConfigure(const FIX::SessionSettings &) throw(FIX::ConfigError); - void onInitialize(const FIX::SessionSettings &) throw(FIX::RuntimeError); + void onConfigure(const FIX::SessionSettings &) EXCEPT(ConfigError); + void onInitialize(const FIX::SessionSettings &) EXCEPT(RuntimeError); - void onStart(); - bool onPoll(double timeout); - void onStop(); + void onStart() override; + bool onPoll() override; + void onStop() override; void onConnect(FIX::SocketServer &, int, int); void onWrite(FIX::SocketServer &, int); diff --git a/FIXGateway/src/SocketConnection.cpp b/FIXGateway/src/SocketConnection.cpp index 1ee3014..f032b53 100644 --- a/FIXGateway/src/SocketConnection.cpp +++ b/FIXGateway/src/SocketConnection.cpp @@ -242,6 +242,6 @@ void SocketConnection::readMessages(SocketMonitor &s) { void SocketConnection::onTimeout() { if (m_pSession) - m_pSession->next(); + m_pSession->next(UtcTimeStamp()); } } // namespace DistributedATS diff --git a/GenTools/CMakeLists.txt b/GenTools/CMakeLists.txt index f8b5d94..a579ffa 100644 --- a/GenTools/CMakeLists.txt +++ b/GenTools/CMakeLists.txt @@ -1,29 +1,19 @@ -cmake_minimum_required(VERSION 3.12.4) - -if(NOT CMAKE_VERSION VERSION_LESS 3.0) - cmake_policy(SET CMP0048 NEW) -endif() - project(DistributedATSLib) -# Find requirements -if(NOT fastcdr_FOUND) - find_package(fastcdr REQUIRED) -endif() +message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") +message(DDS_INCLUDE_DIR="${DDS_INCLUDE_DIR}") +message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") +message(QUICKFIX_INCLUDE_DIR="${QUICKFIX_INCLUDE_DIR}") +message(QUICKFIX_LIBRARY_DIR="${QUICKFIX_LIBRARY_DIR}") -if(NOT fastdds_FOUND) - find_package(fastdds 3 REQUIRED) -endif() +include_directories(${DDS_INCLUDE_DIR}) +include_directories(${QUICKFIX_INCLUDE_DIR}) +link_directories(${DDS_LIBRARY_DIR}) +link_directories(${QUICKFIX_LIBRARY_DIR}) -find_package(log4cxx REQUIRED) +file(GLOB DISTRIBUTED_ATS_LIB *) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +include_directories(${DDS_INCLUDE_DIR}) -link_directories(${CMAKE_INSTALL_PREFIX}/lib) -link_directories(${QUICKFIX_INSTALL_PREFIX}/lib) -file(GLOB DISTRIBUTED_ATS_LIB *) -include_directories(${CMAKE_INSTALL_PREFIX}/include) add_library(DistributedATSLib SHARED ${DISTRIBUTED_ATS_LIB}) target_link_libraries(DistributedATSLib quickfix fastcdr fastdds log4cxx) diff --git a/GenTools/idl/CMakeLists.txt b/GenTools/idl/CMakeLists.txt index 3cb6d31..8e1a110 100644 --- a/GenTools/idl/CMakeLists.txt +++ b/GenTools/idl/CMakeLists.txt @@ -1,31 +1,24 @@ cmake_minimum_required(VERSION 3.12.4) -if(NOT CMAKE_VERSION VERSION_LESS 3.0) - cmake_policy(SET CMP0048 NEW) -endif() - project(DistributedATSLib) -# Find requirements -if(NOT fastcdr_FOUND) - find_package(fastcdr REQUIRED) -endif() +message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") +message(DDS_INCLUDE_DIR="${DDS_INCLUDE_DIR}") +message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") -if(NOT fastdds_FOUND) - find_package(fastdds 3 REQUIRED) -endif() +message(QUICKFIX_INCLUDE_DIR="${QUICKFIX_INCLUDE_DIR}") +message(QUICKFIX_LIBRARY_DIR="${QUICKFIX_LIBRARY_DIR}") -find_package(log4cxx REQUIRED) +include_directories(${DDS_INCLUDE_DIR}) +link_directories(${DDS_LIBRARY_DIR}) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +include_directories(${QUICKFIX_INCLUDE_DIR}) +link_directories(${QUICKFIX_LIBRARY_DIR}) -link_directories(${CMAKE_INSTALL_PREFIX}/lib) -link_directories(${QUICKFIX_INSTALL_PREFIX}/lib) +include_directories(${LOG4CXX_INCLUDE_DIR}) +link_directories(${LOG4CXX_LIBRARY_DIR}) file(GLOB DISTRIBUTED_ATS_LIB *) -include_directories(${CMAKE_INSTALL_PREFIX}/include) add_library(DistributedATSLib SHARED ${DISTRIBUTED_ATS_LIB}) target_link_libraries(DistributedATSLib quickfix fastcdr fastdds log4cxx) diff --git a/LatencyTest/CMakeLists.txt b/LatencyTest/CMakeLists.txt index 438e6d8..9a6b370 100644 --- a/LatencyTest/CMakeLists.txt +++ b/LatencyTest/CMakeLists.txt @@ -1,29 +1,38 @@ cmake_minimum_required(VERSION 3.12.4) -if(NOT CMAKE_VERSION VERSION_LESS 3.0) - cmake_policy(SET CMP0048 NEW) -endif() - project(LatencyTest) -# Find requirements -if(NOT fastcdr_FOUND) - find_package(fastcdr REQUIRED) -endif() +message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") +message(DDS_INCLUDE_DIR="${DDS_INCLUDE_DIR}") +message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") + +message(QUICKFIX_INCLUDE_DIR="${QUICKFIX_INCLUDE_DIR}") +message(QUICKFIX_LIBRARY_DIR="${QUICKFIX_LIBRARY_DIR}") -if(NOT fastdds_FOUND) - find_package(fastdds 3 REQUIRED) -endif() +include_directories(${DDS_INCLUDE_DIR}) +link_directories(${DDS_LIBRARY_DIR}) -find_package(log4cxx REQUIRED) +include_directories(${QUICKFIX_INCLUDE_DIR}) +link_directories(${QUICKFIX_LIBRARY_DIR}) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +include_directories(${LOG4CXX_INCLUDE_DIR}) +link_directories(${LOG4CXX_LIBRARY_DIR}) -link_directories(${CMAKE_INSTALL_PREFIX}/lib) +include_directories(${Boost_INCLUDE_DIR}) +link_directories(${Boost_LIBRARY_DIRS}) -file(GLOB DISTRIBUTED_ATS_LATENCY_TEST_SRC *) +file(GLOB DISTRIBUTED_ATS_LATENCY_TEST_SRC *.cpp) add_executable(LatencyTest ${DISTRIBUTED_ATS_LATENCY_TEST_SRC}) -link_directories(DistributedATSLib quickfix log4cxx) -target_link_libraries(LatencyTest DistributedATSLib quickfix log4cxx boost_program_options) + +find_package(Boost REQUIRED COMPONENTS program_options) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(LatencyTest + PRIVATE + DistributedATSLib + quickfix + log4cxx + Boost::program_options + fastcdr + fastdds +) diff --git a/MatchingEngine/src/CMakeLists.txt b/MatchingEngine/src/CMakeLists.txt index c836803..d7cb7b7 100644 --- a/MatchingEngine/src/CMakeLists.txt +++ b/MatchingEngine/src/CMakeLists.txt @@ -1,39 +1,49 @@ cmake_minimum_required(VERSION 3.12.4) -if(NOT CMAKE_VERSION VERSION_LESS 3.0) - cmake_policy(SET CMP0048 NEW) -endif() +message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") +message(DDS_INCLUDE_DIR="${DDS_INCLUDE_DIR}") +message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") -project(MatchingEngine) +message(QUICKFIX_INCLUDE_DIR="${QUICKFIX_INCLUDE_DIR}") +message(QUICKFIX_LIBRARY_DIR="${QUICKFIX_LIBRARY_DIR}") -# Find requirements -if(NOT fastcdr_FOUND) - find_package(fastcdr REQUIRED) -endif() +message(LIQUIBOOK_LIBRARY_DIR="${LIQUIBOOK_LIBRARY_DIR}") -if(NOT fastdds_FOUND) - find_package(fastdds 3 REQUIRED) -endif() +include_directories(${DDS_INCLUDE_DIR}) +link_directories(${DDS_LIBRARY_DIR}) -find_package(log4cxx REQUIRED) +include_directories(${QUICKFIX_INCLUDE_DIR}) +link_directories(${QUICKFIX_LIBRARY_DIR}) -# Set C++11 -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +include_directories(${LOG4CXX_INCLUDE_DIR}) +link_directories(${LOG4CXX_LIBRARY_DIR}) -include_directories(${LIQUIBOOK_HOME}) -#include_directories(${QUICKFIX_INSTALL_PREFIX}/include) +include_directories(${Boost_INCLUDE_DIR}) +link_directories(${Boost_LIBRARY_DIRS}) -link_directories(${CMAKE_INSTALL_PREFIX}/lib) -link_directories(${QUICKFIX_INSTALL_PREFIX}/lib) +include_directories(${LIQUIBOOK_INCLUDE_DIR}) + +file(GLOB DISTRIBUTED_ATS_MATCHING_ENGINE_SRC *.cpp) -file(GLOB DISTRIBUTED_ATS_MATCHING_ENGINE_SRC *) add_executable(MatchingEngine ${DISTRIBUTED_ATS_MATCHING_ENGINE_SRC}) -link_directories(DistributedATSLib quickfix log4cxx boost_program_options) -target_link_libraries(MatchingEngine DistributedATSLib quickfix log4cxx boost_program_options) -install(TARGETS MatchingEngine +find_package(Boost REQUIRED COMPONENTS program_options) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(MatchingEngine + PRIVATE + DistributedATSLib + quickfix + log4cxx + Boost::program_options + fastcdr + fastdds +) + +set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed") + +install(TARGETS MatchingEngine PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dats ) + diff --git a/MatchingEngine/src/Market.cpp b/MatchingEngine/src/Market.cpp index 6d826f5..1414dd4 100644 --- a/MatchingEngine/src/Market.cpp +++ b/MatchingEngine/src/Market.cpp @@ -389,7 +389,7 @@ void Market::on_fill(const OrderPtr &order, const OrderPtr &matched_order, void Market::on_cancel(const OrderPtr &order) { order->onCancelled(); DistributedATS_ExecutionReport::ExecutionReport executionReport; - order->populateExecutionReport(executionReport, FIX::ExecType_CANCELLED); + order->populateExecutionReport(executionReport, FIX::ExecType_CANCELED); publishExecutionReport(executionReport); // out() << "\tCanceled: " << *order<< std::endl; @@ -400,13 +400,13 @@ void Market::on_cancel_reject(const OrderPtr &order, const char *reason) { // out() << "\tCancel Reject: " <<*order<< " : " << reason << std::endl; } -void Market::on_replace(const OrderPtr &order, const int32_t &size_delta, +void Market::on_replace(const OrderPtr &order, const int64_t &size_delta, liquibook::book::Price new_price) { // out() << "\tCancel Reject: " <<*order<< " : " << size_delta << " : " << // new_price << std::endl; order->onReplaced(size_delta, new_price); DistributedATS_ExecutionReport::ExecutionReport executionReport; - order->populateExecutionReport(executionReport, FIX::ExecType_REPLACE); + order->populateExecutionReport(executionReport, FIX::ExecType_REPLACED); publishExecutionReport(executionReport); } diff --git a/MatchingEngine/src/Market.h b/MatchingEngine/src/Market.h index e39f81a..93e98c8 100644 --- a/MatchingEngine/src/Market.h +++ b/MatchingEngine/src/Market.h @@ -142,29 +142,29 @@ class Market : public liquibook::book::OrderListener, // Implementation of LiquiBook interfaces // // OrderListener interface - virtual void on_accept(const OrderPtr &order); - virtual void on_reject(const OrderPtr &order, const char *reason); + virtual void on_accept(const OrderPtr &order) override; + virtual void on_reject(const OrderPtr &order, const char *reason) override; virtual void on_fill(const OrderPtr &order, const OrderPtr &matched_order, liquibook::book::Quantity fill_qty, - liquibook::book::Cost fill_cost); - virtual void on_cancel(const OrderPtr &order); - virtual void on_cancel_reject(const OrderPtr &order, const char *reason); - virtual void on_replace(const OrderPtr &order, const int32_t &size_delta, - liquibook::book::Price new_price); - virtual void on_replace_reject(const OrderPtr &order, const char *reason); + liquibook::book::Cost fill_cost) override; + virtual void on_cancel(const OrderPtr &order) override; + virtual void on_cancel_reject(const OrderPtr &order, const char *reason) override; + virtual void on_replace(const OrderPtr &order, const int64_t &size_delta, + liquibook::book::Price new_price) override; + virtual void on_replace_reject(const OrderPtr &order, const char *reason) override; // TradeListener interface virtual void on_trade(const OrderBook *book, liquibook::book::Quantity qty, - liquibook::book::Cost cost); + liquibook::book::Cost cost) override; // OrderBookListener interface - virtual void on_order_book_change(const OrderBook *book); + virtual void on_order_book_change(const OrderBook *book) override; // BboListener interface - void on_bbo_change(const DepthOrderBook *book, const BookDepth *depth); + void on_bbo_change(const DepthOrderBook *book, const BookDepth *depth) override; // Implement DepthListener interface - void on_depth_change(const DepthOrderBook *book, const BookDepth *depth); + void on_depth_change(const DepthOrderBook *book, const BookDepth *depth) override; OrderBookPtr addBook(const std::string &symbol, bool useDepthBook); diff --git a/MiscClients/spring_reactjs/README.md b/MiscClients/spring_reactjs/README.md index d322a8c..940da80 100644 --- a/MiscClients/spring_reactjs/README.md +++ b/MiscClients/spring_reactjs/README.md @@ -8,4 +8,4 @@ mvn spring-boot:run ##### Browser URL: -http://localhost:8080/index.html +http://localhost:8080 diff --git a/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg b/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg index c6e2cbf..b6014d8 100644 --- a/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg +++ b/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg @@ -1,8 +1,8 @@ [DEFAULT] ConnectionType=initiator TargetCompID=FIX_GWY_1 -SocketConnectHost=distributed_ats -#SocketConnectHost=127.0.0.1 +#SocketConnectHost=distributed_ats +SocketConnectHost=127.0.0.1 #SocketConnectHost=165.22.179.176 StartTime=00:00:00 EndTime=24:00:00 diff --git a/MiscClients/spring_reactjs/webtrader_reactjs/src/App.js b/MiscClients/spring_reactjs/webtrader_reactjs/src/App.js index 57fcb18..ca0f0b0 100644 --- a/MiscClients/spring_reactjs/webtrader_reactjs/src/App.js +++ b/MiscClients/spring_reactjs/webtrader_reactjs/src/App.js @@ -26,6 +26,7 @@ function App() const marketDataAndPositionsRef = React.useRef(); const url = window.location.href; + //const url = 'http://localhost:8080'; const last_sequence_number = useRef(0); // sequence number between front-end and rest controller const last_session_state = useRef(null); diff --git a/README.md b/README.md index a6ab868..9de1eb4 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,9 @@ DistributedATS is a [**FIX Protocol-based**](https://www.fixtrading.org) alterna ### Building Distributed ATS and it's dependencies ``` -download_deps_and_build_all.sh +./build.sh # Uses default install directory +./build.sh /custom/path # Installs to custom path +source /path/to/DistributedATS/dats_env.sh # To set env vars ``` ### Docker diff --git a/docker/Docker.Build_Distributed_ATS b/docker/Docker.Build_Distributed_ATS index 2a47d64..b41c5f3 100644 --- a/docker/Docker.Build_Distributed_ATS +++ b/docker/Docker.Build_Distributed_ATS @@ -1,12 +1,8 @@ -FROM ubuntu:latest +FROM ubuntu:latest as dependency_builder RUN apt-get update RUN apt install -y vim cmake curl build-essential libapr1-dev libaprutil1-dev git libboost-all-dev sqlite3 libsqlite3-dev libtool libasio-dev libtinyxml2-dev zip python3-pip RUN pip install psutil --break-system-packages -ADD build_distributed_ats.sh / -RUN /build_distributed_ats.sh - -EXPOSE 15001 -EXPOSE 16001 -EXPOSE 17001 +ADD build_dependences.sh / +RUN /build_dependences.sh diff --git a/docker/build_dependences.sh b/docker/build_dependences.sh new file mode 100755 index 0000000..1be8773 --- /dev/null +++ b/docker/build_dependences.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -x + +build_and_install() { + + local repo="$1" + local branch="$2" + + git clone -b "$branch" "$repo" + + cd $(basename "$repo" .git) + + mkdir -p build && cd build + cmake .. + cmake --build . --target install +} + +build_and_install "https://github.com/foonathan/memory.git" "main" +build_and_install "https://github.com/eProsima/Fast-CDR.git" "master" +build_and_install "https://github.com/eProsima/Fast-DDS.git" "master" +build_and_install "https://github.com/apache/logging-log4cxx.git" "master" +build_and_install "https://github.com/quickfix/quickfix.git" "master" +build_and_install "https://github.com/mkipnis/liquibook.git" "cmake" diff --git a/docker/dockerize_dats.sh b/docker/dockerize_dats.sh index 0175662..87dce2a 100755 --- a/docker/dockerize_dats.sh +++ b/docker/dockerize_dats.sh @@ -4,9 +4,9 @@ set -x # Core docker build -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS . -docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . -docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . +#docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . +#docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . -docker push ghcr.io/mkipnis/distributed_ats:latest -docker push ghcr.io/mkipnis/dats_crypto_clob:latest -docker push ghcr.io/mkipnis/dats_ust_clob:latest +#docker push ghcr.io/mkipnis/distributed_ats:latest +#docker push ghcr.io/mkipnis/dats_crypto_clob:latest +#docker push ghcr.io/mkipnis/dats_ust_clob:latest diff --git a/download_deps_and_build_all.sh b/download_deps_and_build_all.sh deleted file mode 100755 index 7b7ef8f..0000000 --- a/download_deps_and_build_all.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -set -x - -# Define directories -DATS_SOURCE_DIR="$(pwd)" -DATS_HOME="$HOME/DistributedATS" -DEPS_BUILD_DIR="$HOME/distributed_ats_deps_build" -INSTALL_DIR="${1:-$DEPS_BUILD_DIR}" -LD_LIBRARY_PATH="LD_LIBRARY_PATH" - -mkdir -p "$DEPS_BUILD_DIR" -mkdir -p "$DATS_HOME" - -# Mac-specific flags -CMAKE_FLAGS="" -if [[ "$OSTYPE" == "darwin"* ]]; then - export CXXFLAGS="-DWAZOO_64_BIT -std=c++11 -stdlib=libc++" - CMAKE_FLAGS="-G Xcode" - LD_LIBRARY_PATH="DYLD_LIBRARY_PATH" -fi - -# Dependency versions -FOONATHAN_MEMORY_PKG=0.7-3 -FAST_CDR_PKG=2.3.0 -ASIO_PKG=1-28-0 -FAST_DDS_PKG=3.2.1 -LOG4CXX_PKG=1.2.0 -QUICKFIX_PKG=1.15.1 -LIQUIBOOK_PKG=2.0.0 - -# Download helper -download_if_missing() { - local url=$1 - local dest=$2 - if [[ ! -f "$dest" ]]; then - echo "Downloading $(basename "$dest")..." - curl -L "$url" -o "$dest" || { - echo " Failed to download $(basename "$dest")." - exit 1 - } - fi -} - -# Download dependencies -download_if_missing "https://github.com/foonathan/memory/archive/refs/tags/v$FOONATHAN_MEMORY_PKG.tar.gz" "$DEPS_BUILD_DIR/memory-v$FOONATHAN_MEMORY_PKG.tar.gz" -download_if_missing "https://github.com/eProsima/Fast-CDR/archive/refs/tags/v$FAST_CDR_PKG.tar.gz" "$DEPS_BUILD_DIR/Fast-CDR-v$FAST_CDR_PKG.tar.gz" -download_if_missing "https://github.com/eProsima/Fast-DDS/archive/refs/tags/v$FAST_DDS_PKG.tar.gz" "$DEPS_BUILD_DIR/Fast-DDS-v$FAST_DDS_PKG.tar.gz" -#download_if_missing "https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-$ASIO_PKG.tar.gz" "$DEPS_BUILD_DIR/asio-$ASIO_PKG.tar.gz" -download_if_missing "https://github.com/apache/logging-log4cxx/archive/refs/tags/rel/v$LOG4CXX_PKG.tar.gz" "$DEPS_BUILD_DIR/log4cxx-$LOG4CXX_PKG.tar.gz" -download_if_missing "https://github.com/quickfix/quickfix/archive/refs/tags/v$QUICKFIX_PKG.tar.gz" "$DEPS_BUILD_DIR/quickfix-v$QUICKFIX_PKG.tar.gz" -download_if_missing "https://github.com/enewhuis/liquibook/archive/refs/tags/$LIQUIBOOK_PKG.tar.gz" "$DEPS_BUILD_DIR/liquibook-$LIQUIBOOK_PKG.tar.gz" - -export INSTALL_PREFIX="$INSTALL_DIR" - -build_and_install() { - - local tarball="$1" - local dir="$2" - local configure_cmd="${3:-./configure --prefix=$INSTALL_PREFIX --exec-prefix=$INSTALL_PREFIX}" - local build_cmd="${4:-make install -j $(nproc)}" - - cd "$DEPS_BUILD_DIR" - [[ ! -d "$dir" ]] && tar xvf "$tarball" - cd "$dir" - - if [[ -f CMakeLists.txt ]]; then - mkdir -p build && cd build - cmake .. -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" -DBUILD_SHARED_LIBS=ON "$configure_cmd" - cmake --build . --target install - else - eval "$configure_cmd" - eval "$build_cmd" - fi - -} - -[[ ! -f $INSTALL_DIR/include/log4cxx/log4cxx.h ]] && build_and_install "$DEPS_BUILD_DIR/log4cxx-$LOG4CXX_PKG.tar.gz" "$DEPS_BUILD_DIR/logging-log4cxx-rel-v$LOG4CXX_PKG" "-DBUILD_TESTING=false" -[[ ! -f $INSTALL_DIR/include/foonathan_memory/foonathan/memory/config.hpp ]] && build_and_install "$DEPS_BUILD_DIR/memory-v$FOONATHAN_MEMORY_PKG.tar.gz" "memory-$FOONATHAN_MEMORY_PKG" "" -[[ ! -f $INSTALL_DIR/include/fastcdr/config.h ]] && build_and_install "$DEPS_BUILD_DIR/Fast-CDR-v$FAST_CDR_PKG.tar.gz" "Fast-CDR-$FAST_CDR_PKG" "" -#[[ ! -f $INSTALL_DIR/include/asio.hpp ]] && build_and_install "$DEPS_BUILD_DIR/asio-$ASIO_PKG.tar.gz" "asio-asio-$ASIO_PKG" "cd asio && ./autogen.sh && ./configure --prefix=$INSTALL_PREFIX --exec-prefix=$INSTALL_PREFIX}" -[[ ! -f $INSTALL_DIR/include/fastdds/config.hpp ]] && build_and_install "$DEPS_BUILD_DIR/Fast-DDS-v$FAST_DDS_PKG.tar.gz" "Fast-DDS-$FAST_DDS_PKG" "" -[[ ! -f $INSTALL_DIR/include/quickfix/config-all.h ]] && build_and_install "$DEPS_BUILD_DIR/quickfix-v$QUICKFIX_PKG.tar.gz" "quickfix-$QUICKFIX_PKG" "-DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_EXTENSIONS=OFF" -[[ ! -f $INSTALL_DIR/liquibook-$LIQUIBOOK_PKG/src/liquibook_export.h ]] && build_and_install "$DEPS_BUILD_DIR/liquibook-$LIQUIBOOK_PKG.tar.gz" "liquibook-$LIQUIBOOK_PKG" ":" ":" - - -# Generate environment script -cat < "$HOME/DistributedATS/dats_env.sh" -export DATS_HOME=\$HOME/DistributedATS -export DEPS_HOME=$INSTALL_DIR -export $LD_LIBRARY_PATH=\$DEPS_HOME/lib:\$DATS_HOME/lib:\$LD_LIBRARY_PATH -export LOG4CXX_CONFIGURATION=$DATS_HOME/config/log4cxx.xml - -#echo Specific Specific - -#echo Crypto ATS -export BASEDIR_ATS=\$DATS_HOME/MiscATS/CryptoCLOB -export DATS_LOG_HOME=\$BASEDIR_ATS/logs -mkdir -p \$BASEDIR_ATS/logs - -#echo US Treasuries -#export BASEDIR_ATS=\$DATS_HOME/MiscATS/USTreasuryCLOB -#export DATS_LOG_HOME=\$BASEDIR_ATS/logs -#mkdir -p \$BASEDIR_ATS/logs - -#echo US Treasuries -#export BASEDIR_ATS=\$DATS_HOME/MiscATS/MultiMatchingEngineATS -#export DATS_LOG_HOME=\$BASEDIR_ATS/logs -#mkdir -p \$BASEDIR_ATS/logs - -EOM - -cd $DATS_SOURCE_DIR - -# Build DistributedATS -mkdir -p build -cd build - -cmake $CMAKE_FLAGS .. \ - -Dfastcdr_DIR=$INSTALL_DIR/lib/cmake/fastcdr/ \ - -Dfastdds_DIR=$INSTALL_DIR/share/fastdds/cmake/ \ - -Dfoonathan_memory_DIR=$INSTALL_DIR/lib/foonathan_memory/cmake/ \ - -Dlog4cxx_DIR=$INSTALL_DIR/lib/cmake/log4cxx \ - -DCMAKE_INSTALL_PREFIX="$HOME/DistributedATS" \ - -DLIQUIBOOK_HOME="$INSTALL_DIR/liquibook-$LIQUIBOOK_PKG/src" \ - -DQUICKFIX_INSTALL_PREFIX="$INSTALL_DIR" - -cmake --build . --target install --config Debug From 4f757c77413526b0f30850ae76d4c1e24a00c175 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 18 May 2025 18:12:31 -0400 Subject: [PATCH 02/27] cmake update --- build_with_cmake.sh | 71 +++++++++++++++++++++++++++++++++ docker/build_distributed_ats.sh | 4 +- 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100755 build_with_cmake.sh diff --git a/build_with_cmake.sh b/build_with_cmake.sh new file mode 100755 index 0000000..f13d5cb --- /dev/null +++ b/build_with_cmake.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +set -ex # Print each command and exit on error + +# Detect OS for library path +OS="$(uname)" +if [[ "$OS" == "Darwin" ]]; then + LIB_PATH_VAR="DYLD_LIBRARY_PATH" +else + LIB_PATH_VAR="LD_LIBRARY_PATH" +fi + +# Create and enter build directory +mkdir -p build +cd build + +# Get absolute path to current directory (fallback for macOS without realpath) +get_abs_path() { + if command -v realpath >/dev/null 2>&1; then + realpath "$1" + else + # Fallback using Python for macOS + python3 -c "import os; print(os.path.abspath('$1'))" + fi +} + +ROOT_DIR="$(get_abs_path ..)" + +# Set default paths +if [ -z "$1" ]; then + DDS_HOME="$ROOT_DIR/dds" + QUICKFIX_HOME="$ROOT_DIR/quickfix" + LOG4CXX_HOME="$ROOT_DIR/log4cxx" + INSTALL_PREFIX="$ROOT_DIR/DistributedATS" +else + INSTALL_PREFIX="$(get_abs_path "$1")" +fi + +# Run cmake and build +cmake ${CMAKE_FLAGS:-} .. -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" +cmake --build . --target install --config Debug -v + +# Write the environment setup script +cat < "$INSTALL_PREFIX/dats_env.sh" +#!/usr/bin/env bash + +export DATS_HOME="$INSTALL_PREFIX" +export DDS_HOME="$DDS_HOME" +export QUICKFIX_HOME="$QUICKFIX_HOME" +export LOG4CXX_HOME="$LOG4CXX_HOME" + +export $LIB_PATH_VAR="\$DATS_HOME/lib:\$DDS_HOME/lib:\$QUICKFIX_HOME/lib:\$LOG4CXX_HOME/lib:\$$LIB_PATH_VAR" +export LOG4CXX_CONFIGURATION="\$DATS_HOME/config/log4cxx.xml" + +# Select one ATS config +export BASEDIR_ATS="\$DATS_HOME/MiscATS/CryptoCLOB" +export DATS_LOG_HOME="\$BASEDIR_ATS/logs" +mkdir -p "\$DATS_LOG_HOME" + +# Uncomment one of these to switch ATS +# export BASEDIR_ATS="\$DATS_HOME/MiscATS/USTreasuryCLOB" +# export DATS_LOG_HOME="\$BASEDIR_ATS/logs" +# mkdir -p "\$DATS_LOG_HOME" + +# export BASEDIR_ATS="\$DATS_HOME/MiscATS/MultiMatchingEngineATS" +# export DATS_LOG_HOME="\$BASEDIR_ATS/logs" +# mkdir -p "\$DATS_LOG_HOME" + +EOM + +chmod +x "$INSTALL_PREFIX/dats_env.sh" diff --git a/docker/build_distributed_ats.sh b/docker/build_distributed_ats.sh index 9df12f1..511b26f 100755 --- a/docker/build_distributed_ats.sh +++ b/docker/build_distributed_ats.sh @@ -1,6 +1,6 @@ #!/bin/bash -[[ ! -f /opt/distributed_ats_src ]] && git clone -b master https://github.com/mkipnis/DistributedATS /opt/distributed_ats_src +[[ ! -f /opt/distributed_ats_src ]] && git enhancements_0424 -b master https://github.com/mkipnis/DistributedATS /opt/distributed_ats_src cd /opt/distributed_ats_src -HOME=/opt ./download_deps_and_build_all.sh +HOME=/opt ./build_with_cmake.sh From 0a6e09eb57e372183d8af56f8cc6a9fc44de402a Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 18 May 2025 18:19:28 -0400 Subject: [PATCH 03/27] cmake update --- CMakeLists.txt | 2 +- docker/Docker.Build_Distributed_ATS | 3 +++ docker/build_distributed_ats.sh | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8372c2e..e9d9af6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.29) +cmake_minimum_required(VERSION 3.28.3) project(DistributedATS) diff --git a/docker/Docker.Build_Distributed_ATS b/docker/Docker.Build_Distributed_ATS index b41c5f3..fecce7e 100644 --- a/docker/Docker.Build_Distributed_ATS +++ b/docker/Docker.Build_Distributed_ATS @@ -6,3 +6,6 @@ RUN pip install psutil --break-system-packages ADD build_dependences.sh / RUN /build_dependences.sh + +ADD build_distributed_ats.sh / +RUN /build_distributed_ats.sh diff --git a/docker/build_distributed_ats.sh b/docker/build_distributed_ats.sh index 511b26f..f56ae3f 100755 --- a/docker/build_distributed_ats.sh +++ b/docker/build_distributed_ats.sh @@ -1,6 +1,6 @@ #!/bin/bash -[[ ! -f /opt/distributed_ats_src ]] && git enhancements_0424 -b master https://github.com/mkipnis/DistributedATS /opt/distributed_ats_src +git clone -b enhancements_0424 https://github.com/mkipnis/DistributedATS /opt/distributed_ats_src cd /opt/distributed_ats_src HOME=/opt ./build_with_cmake.sh From 0db28a6055dbc21928e44fdcafc59e98e515ba98 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 18 May 2025 18:19:57 -0400 Subject: [PATCH 04/27] cmake update --- cmake/DDSConfig.cmake | 61 +++++++++++++++++++++++++++++++++++++ cmake/liquibookConfig.cmake | 26 ++++++++++++++++ cmake/log4cxxConfig.cmake | 25 +++++++++++++++ cmake/quickfixConfig.cmake | 25 +++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 cmake/DDSConfig.cmake create mode 100644 cmake/liquibookConfig.cmake create mode 100644 cmake/log4cxxConfig.cmake create mode 100644 cmake/quickfixConfig.cmake diff --git a/cmake/DDSConfig.cmake b/cmake/DDSConfig.cmake new file mode 100644 index 0000000..2f71e0b --- /dev/null +++ b/cmake/DDSConfig.cmake @@ -0,0 +1,61 @@ +set(DDS_INCLUDE_DIRS "${DDS_ROOT_DIR}/include") +set(DDS_LIBRARY_DIRS "${DDS_ROOT_DIR}/lib") + +include(ExternalProject) + +if(NOT EXISTS "${DDS_INCLUDE_DIRS}/fastdds/config.hpp") + message(STATUS "FastDDS not found, building from source...") + + set(DDS_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/dds) + + include(ExternalProject) + + ExternalProject_Add(FoonathanMemory + GIT_REPOSITORY https://github.com/foonathan/memory.git + GIT_TAG main + UPDATE_DISCONNECTED TRUE + INSTALL_DIR ${DDS_INSTALL_PREFIX} + CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${DDS_INSTALL_PREFIX} + -DBUILD_SHARED_LIBS=ON + ) + + ExternalProject_Add(FastCDR + GIT_REPOSITORY https://github.com/eProsima/Fast-CDR.git + GIT_TAG master + UPDATE_DISCONNECTED TRUE + INSTALL_DIR ${DDS_INSTALL_PREFIX} + CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${DDS_INSTALL_PREFIX} + -DBUILD_SHARED_LIBS=ON + ) + + ExternalProject_Add(ASIO + GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git + GIT_TAG asio-1-28-0 + UPDATE_DISCONNECTED TRUE + SOURCE_SUBDIR asio + INSTALL_DIR ${DDS_INSTALL_PREFIX} + CONFIGURE_COMMAND cd / && ./autogen.sh && ./configure --prefix=${DDS_INSTALL_PREFIX} --exec-prefix=${DDS_INSTALL_PREFIX} --without-boost + BUILD_COMMAND cd / && make + INSTALL_COMMAND cd / && make install + ) + + ExternalProject_Add(FastDDS + GIT_REPOSITORY https://github.com/eProsima/Fast-DDS.git + GIT_TAG master + UPDATE_DISCONNECTED TRUE + #DEPENDS FastCDR FoonathanMemory ASIO + INSTALL_DIR ${DDS_INSTALL_PREFIX} + CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${DDS_INSTALL_PREFIX} + -DBUILD_SHARED_LIBS=ON + ) + + +endif() + +set(DDS_FOUND TRUE) diff --git a/cmake/liquibookConfig.cmake b/cmake/liquibookConfig.cmake new file mode 100644 index 0000000..3ca1d44 --- /dev/null +++ b/cmake/liquibookConfig.cmake @@ -0,0 +1,26 @@ +set(LIQUIBOOK_INCLUDE_DIRS "${LIQUIBOOK_ROOT_DIR}/include") +set(LIQUIBOOK_LIBRARY_DIRS "${LIQUIBOOK_ROOT_DIR}/lib") + +include(ExternalProject) + +if(NOT EXISTS "${LIQUIBOOK_INCLUDE_DIRS}/liquibook_export.h") + message(STATUS "Liquibook not found, building from source...") + + set(LIQUIBOOK_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/liquibook) + + include(ExternalProject) + + ExternalProject_Add(LiquiBook + GIT_REPOSITORY https://github.com/enewhuis/liquibook.git + GIT_TAG master + UPDATE_DISCONNECTED TRUE + INSTALL_DIR "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + SOURCE_SUBDIR src + INSTALL_COMMAND mkdir -p ${CMAKE_BINARY_DIR}/liquibook && cp -r / ${LIQUIBOOK_INSTALL_PREFIX}/include + ) + +endif() + +set(liquibook_FOUND TRUE) diff --git a/cmake/log4cxxConfig.cmake b/cmake/log4cxxConfig.cmake new file mode 100644 index 0000000..2858c55 --- /dev/null +++ b/cmake/log4cxxConfig.cmake @@ -0,0 +1,25 @@ +set(LOG4CXX_INCLUDE_DIRS "${LOG4CXX_ROOT_DIR}/include") +set(LOG4CXX_LIBRARY_DIRS "${LOG4CXX_ROOT_DIR}/lib") + +include(ExternalProject) + +if(NOT EXISTS "${LOG4CXX_INCLUDE_DIRS}/log4cxx/log4cxx.h") + message(STATUS "Log4cxx not found, building from source...") + + set(LOG4CXX_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/log4cxx) + + include(ExternalProject) + + ExternalProject_Add(Log4cxx + GIT_REPOSITORY https://github.com/apache/logging-log4cxx.git + GIT_TAG master + UPDATE_DISCONNECTED TRUE + CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${LOG4CXX_INSTALL_PREFIX} + -DBUILD_SHARED_LIBS=ON + ) + +endif() + +set(Log4cxx_FOUND TRUE) diff --git a/cmake/quickfixConfig.cmake b/cmake/quickfixConfig.cmake new file mode 100644 index 0000000..e686fee --- /dev/null +++ b/cmake/quickfixConfig.cmake @@ -0,0 +1,25 @@ +set(QUICKFIX_INCLUDE_DIR "${QUICKFIX_ROOT_DIR}/include") +set(QUICKFIX_LIBRARY_DIR "${QUICKFIX_ROOT_DIR}/lib") + +include(ExternalProject) + +if(NOT EXISTS "${QUICKFIX_INCLUDE_DIR}/config-all.h") + message(STATUS "Quickfix not found, building from source...") + + set(QUICKFIX_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/quickfix) + + include(ExternalProject) + + ExternalProject_Add(QuickFIX + GIT_REPOSITORY https://github.com/quickfix/quickfix.git + GIT_TAG master + UPDATE_DISCONNECTED TRUE + CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${QUICKFIX_INSTALL_PREFIX} + -DBUILD_SHARED_LIBS=ON + ) + +endif() + +set(quickfix_FOUND TRUE) From 63d7baa34455d49dfa8f8f8cbf8300f1ef4f7ae8 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Mon, 19 May 2025 04:10:26 +0000 Subject: [PATCH 05/27] cmake update --- DataService/src/CMakeLists.txt | 1 + cmake/quickfixConfig.cmake | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/DataService/src/CMakeLists.txt b/DataService/src/CMakeLists.txt index aa85451..bc730d0 100644 --- a/DataService/src/CMakeLists.txt +++ b/DataService/src/CMakeLists.txt @@ -34,6 +34,7 @@ target_link_libraries(DataService Boost::program_options fastcdr fastdds + sqlite3 ) set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed") diff --git a/cmake/quickfixConfig.cmake b/cmake/quickfixConfig.cmake index e686fee..58060dc 100644 --- a/cmake/quickfixConfig.cmake +++ b/cmake/quickfixConfig.cmake @@ -3,7 +3,7 @@ set(QUICKFIX_LIBRARY_DIR "${QUICKFIX_ROOT_DIR}/lib") include(ExternalProject) -if(NOT EXISTS "${QUICKFIX_INCLUDE_DIR}/config-all.h") +if(NOT EXISTS "${QUICKFIX_INCLUDE_DIR}/quickfix/config-all.h") message(STATUS "Quickfix not found, building from source...") set(QUICKFIX_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/quickfix) From e25d67b30c54a4071b268529ed268357a84717a9 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Wed, 21 May 2025 18:58:14 -0400 Subject: [PATCH 06/27] prevent db create if file doesnt exits --- DataService/src/SQLiteConnection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataService/src/SQLiteConnection.hpp b/DataService/src/SQLiteConnection.hpp index 8359dbf..187d866 100644 --- a/DataService/src/SQLiteConnection.hpp +++ b/DataService/src/SQLiteConnection.hpp @@ -132,7 +132,7 @@ class SQLiteConnection private: void connect() { - int rc = sqlite3_open(m_pDatabase.getDatabase().c_str(), &m_pConnection); + int rc = sqlite3_open_v2(m_pDatabase.getDatabase().c_str(), &m_pConnection, SQLITE_OPEN_READONLY, nullptr); if (rc != SQLITE_OK) { From a5d9a9947cdfd7eebeebedaafd22a87337a900de Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Wed, 21 May 2025 20:54:13 -0400 Subject: [PATCH 07/27] include db files in install --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d9af6..3a7332e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,9 @@ add_subdirectory( DataService/src ) add_subdirectory( MatchingEngine/src ) add_subdirectory( LatencyTest ) -install(DIRECTORY MiscATS DESTINATION ${CMAKE_INSTALL_PREFIX}) +install(DIRECTORY ${CMAKE_SOURCE_DIR}/MiscATS/ + DESTINATION MiscATS + FILES_MATCHING PATTERN "*.db" PATTERN "*.sh") install(CODE " file(GLOB_RECURSE SCRIPT_FILES From bd2fee4a09e76894f0e201eecfe080c3490ef88a Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Fri, 23 May 2025 10:46:16 -0400 Subject: [PATCH 08/27] docker update --- CMakeLists.txt | 2 +- GenTools/idl/CMakeLists.txt | 5 ++++ build_with_cmake.sh | 1 + cmake/DDSConfig.cmake | 25 +++++++++--------- docker/Docker.Build_Distributed_ATS | 9 ++++++- docker/Docker.Crypto_CLOB | 8 ++---- docker/build_dependences.sh | 15 +++++++---- docker/build_distributed_ats.sh | 3 ++- docker/crypto_clob_env.sh | 27 ++++++------------- docker/docker-compose-crypto.yml | 40 +++++++++++++++++------------ docker/dockerize_dats.sh | 4 +-- 11 files changed, 76 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a7332e..5367af2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ add_subdirectory( LatencyTest ) install(DIRECTORY ${CMAKE_SOURCE_DIR}/MiscATS/ DESTINATION MiscATS - FILES_MATCHING PATTERN "*.db" PATTERN "*.sh") + FILES_MATCHING PATTERN "*.db" PATTERN "*.sh" PATTERN "*.ini" PATTERN "*.cfg") install(CODE " file(GLOB_RECURSE SCRIPT_FILES diff --git a/GenTools/idl/CMakeLists.txt b/GenTools/idl/CMakeLists.txt index 8e1a110..beebf49 100644 --- a/GenTools/idl/CMakeLists.txt +++ b/GenTools/idl/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.12.4) project(DistributedATSLib) + message(STATUS "Current source dir: ${CMAKE_CURRENT_SOURCE_DIR}") message(DDS_INCLUDE_DIR="${DDS_INCLUDE_DIR}") message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") @@ -9,6 +10,7 @@ message(DDS_LIBRARY_DIR="${DDS_LIBRARY_DIR}") message(QUICKFIX_INCLUDE_DIR="${QUICKFIX_INCLUDE_DIR}") message(QUICKFIX_LIBRARY_DIR="${QUICKFIX_LIBRARY_DIR}") + include_directories(${DDS_INCLUDE_DIR}) link_directories(${DDS_LIBRARY_DIR}) @@ -20,6 +22,9 @@ link_directories(${LOG4CXX_LIBRARY_DIR}) file(GLOB DISTRIBUTED_ATS_LIB *) add_library(DistributedATSLib SHARED ${DISTRIBUTED_ATS_LIB}) +add_dependencies(DistributedATSLib FastDDS) +add_dependencies(DistributedATSLib QuickFIX) +add_dependencies(DistributedATSLib Log4cxx) target_link_libraries(DistributedATSLib quickfix fastcdr fastdds log4cxx) install(TARGETS DistributedATSLib diff --git a/build_with_cmake.sh b/build_with_cmake.sh index f13d5cb..3df0cb9 100755 --- a/build_with_cmake.sh +++ b/build_with_cmake.sh @@ -6,6 +6,7 @@ set -ex # Print each command and exit on error OS="$(uname)" if [[ "$OS" == "Darwin" ]]; then LIB_PATH_VAR="DYLD_LIBRARY_PATH" + CMAKE_FLAGS="-G Xcode" else LIB_PATH_VAR="LD_LIBRARY_PATH" fi diff --git a/cmake/DDSConfig.cmake b/cmake/DDSConfig.cmake index 2f71e0b..92bafa3 100644 --- a/cmake/DDSConfig.cmake +++ b/cmake/DDSConfig.cmake @@ -10,6 +10,17 @@ if(NOT EXISTS "${DDS_INCLUDE_DIRS}/fastdds/config.hpp") include(ExternalProject) + ExternalProject_Add(ASIO + GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git + GIT_TAG asio-1-28-0 + UPDATE_DISCONNECTED TRUE + SOURCE_SUBDIR asio + INSTALL_DIR ${DDS_INSTALL_PREFIX} + CONFIGURE_COMMAND cd / && ./autogen.sh && ./configure --prefix=${DDS_INSTALL_PREFIX} --exec-prefix=${DDS_INSTALL_PREFIX} --without-boost + BUILD_COMMAND cd / && make + INSTALL_COMMAND cd / && make install + ) + ExternalProject_Add(FoonathanMemory GIT_REPOSITORY https://github.com/foonathan/memory.git GIT_TAG main @@ -25,6 +36,7 @@ if(NOT EXISTS "${DDS_INCLUDE_DIRS}/fastdds/config.hpp") GIT_REPOSITORY https://github.com/eProsima/Fast-CDR.git GIT_TAG master UPDATE_DISCONNECTED TRUE + DEPENDS FoonathanMemory ASIO INSTALL_DIR ${DDS_INSTALL_PREFIX} CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} @@ -32,22 +44,11 @@ if(NOT EXISTS "${DDS_INCLUDE_DIRS}/fastdds/config.hpp") -DBUILD_SHARED_LIBS=ON ) - ExternalProject_Add(ASIO - GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git - GIT_TAG asio-1-28-0 - UPDATE_DISCONNECTED TRUE - SOURCE_SUBDIR asio - INSTALL_DIR ${DDS_INSTALL_PREFIX} - CONFIGURE_COMMAND cd / && ./autogen.sh && ./configure --prefix=${DDS_INSTALL_PREFIX} --exec-prefix=${DDS_INSTALL_PREFIX} --without-boost - BUILD_COMMAND cd / && make - INSTALL_COMMAND cd / && make install - ) - ExternalProject_Add(FastDDS GIT_REPOSITORY https://github.com/eProsima/Fast-DDS.git GIT_TAG master UPDATE_DISCONNECTED TRUE - #DEPENDS FastCDR FoonathanMemory ASIO + DEPENDS FastCDR INSTALL_DIR ${DDS_INSTALL_PREFIX} CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} diff --git a/docker/Docker.Build_Distributed_ATS b/docker/Docker.Build_Distributed_ATS index fecce7e..c0039a3 100644 --- a/docker/Docker.Build_Distributed_ATS +++ b/docker/Docker.Build_Distributed_ATS @@ -1,4 +1,4 @@ -FROM ubuntu:latest as dependency_builder +FROM ubuntu:latest as dats_dependency_builder RUN apt-get update RUN apt install -y vim cmake curl build-essential libapr1-dev libaprutil1-dev git libboost-all-dev sqlite3 libsqlite3-dev libtool libasio-dev libtinyxml2-dev zip python3-pip @@ -9,3 +9,10 @@ RUN /build_dependences.sh ADD build_distributed_ats.sh / RUN /build_distributed_ats.sh + +FROM ubuntu:latest +RUN apt-get update && apt-get install --no-install-recommends -y \ + libboost-all-dev vim python3-pip libapr1-dev libaprutil1-dev libtinyxml2-dev \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +COPY --from=dats_dependency_builder /usr/local /usr/local diff --git a/docker/Docker.Crypto_CLOB b/docker/Docker.Crypto_CLOB index 02bd1d6..f66994a 100644 --- a/docker/Docker.Crypto_CLOB +++ b/docker/Docker.Crypto_CLOB @@ -4,9 +4,5 @@ EXPOSE 15001 EXPOSE 16001 EXPOSE 17001 -WORKDIR /opt/DistributedATS - -COPY crypto_clob_env.sh dats_env.sh -COPY start_crypto_clob.sh /opt/DistributedATS/MiscATS/CryptoCLOB/scripts/ - -RUN chmod +x dats_env.sh +COPY crypto_clob_env.sh /usr/local/dats_env.sh +RUN chmod +x /usr/local/dats_env.sh diff --git a/docker/build_dependences.sh b/docker/build_dependences.sh index 1be8773..fc112ca 100755 --- a/docker/build_dependences.sh +++ b/docker/build_dependences.sh @@ -1,19 +1,24 @@ #!/bin/bash -set -x +set -x -build_and_install() { +# Default to system prefix if not specified by user +DEFAULT_INSTALL_DIR="/usr/local" +INSTALL_DIR="${1:-$DEFAULT_INSTALL_DIR}" +build_and_install() { local repo="$1" local branch="$2" - + git clone -b "$branch" "$repo" - cd $(basename "$repo" .git) + cd "$(basename "$repo" .git)" || exit 1 mkdir -p build && cd build - cmake .. + cmake .. -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" cmake --build . --target install + + cd ../.. || exit 1 } build_and_install "https://github.com/foonathan/memory.git" "main" diff --git a/docker/build_distributed_ats.sh b/docker/build_distributed_ats.sh index f56ae3f..7c87b35 100755 --- a/docker/build_distributed_ats.sh +++ b/docker/build_distributed_ats.sh @@ -3,4 +3,5 @@ git clone -b enhancements_0424 https://github.com/mkipnis/DistributedATS /opt/distributed_ats_src cd /opt/distributed_ats_src -HOME=/opt ./build_with_cmake.sh +cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr/local -DDDS_ROOT_DIR=/usr/local -DLOG4CXX_ROOT_DIR=/usr/local -DQUICKFIX_ROOT_DIR=/usr/local -DLIQUIBOOK_ROOT_DIR=/usr/local +cmake --build build --verbose --target install diff --git a/docker/crypto_clob_env.sh b/docker/crypto_clob_env.sh index fc6da81..474162b 100644 --- a/docker/crypto_clob_env.sh +++ b/docker/crypto_clob_env.sh @@ -1,22 +1,11 @@ -export DATS_HOME=/opt/DistributedATS -export DEPS_HOME=/opt/distributed_ats_deps_build -export LD_LIBRARY_PATH=$DEPS_HOME/lib:$DATS_HOME/lib:$LD_LIBRARY_PATH -export LOG4CXX_CONFIGURATION=/opt/DistributedATS/config/log4cxx.xml - -#echo Specific Specific - -#echo Crypto ATS +# dependencies +export DATS_HOME=/usr/local +export DEPS_HOME=/usr/local +export LD_LIBRARY_PATH=$DEPS_HOME/lib:$LD_LIBRARY_PATH +export LOG4CXX_CONFIGURATION=$DATS_HOME/config/log4cxx.xml +export FASTDDS_DEFAULT_PROFILES_FILE=/usr/local/FastDDS.xml + +# ATS HOME export BASEDIR_ATS=$DATS_HOME/MiscATS/CryptoCLOB export DATS_LOG_HOME=$BASEDIR_ATS/logs mkdir -p $BASEDIR_ATS/logs - -#echo US Treasuries -#export BASEDIR_ATS=$DATS_HOME/MiscATS/USTreasuryCLOB -#export DATS_LOG_HOME=$BASEDIR_ATS/logs -#mkdir -p $BASEDIR_ATS/logs - -#echo US Treasuries -#export BASEDIR_ATS=$DATS_HOME/MiscATS/MultiMatchingEngineATS -#export DATS_LOG_HOME=$BASEDIR_ATS/logs -#mkdir -p $BASEDIR_ATS/logs - diff --git a/docker/docker-compose-crypto.yml b/docker/docker-compose-crypto.yml index c5ea1e0..8b134a4 100644 --- a/docker/docker-compose-crypto.yml +++ b/docker/docker-compose-crypto.yml @@ -1,17 +1,25 @@ version: '2' services: - # Core Services: Matching Engines, FIX Gateways + fast_dds_discovery: + container_name: discovery_service + image: ghcr.io/mkipnis/distributed_ats:latest + command: > + bash -c "LD_LIBRARY_PATH=/usr/local/lib:\$LD_LIBRARY_PATH /usr/local/bin/fastdds discovery -q 51000" + ports: + - "51000:51000" + restart: unless-stopped + distributed_ats: container_name: distributed_ats image: ghcr.io/mkipnis/dats_crypto_clob:latest + depends_on: + - discovery_service command: > - bash -c "cd /opt/DistributedATS/ && - . ./dats_env.sh && - cd /opt/DistributedATS/MiscATS/CryptoCLOB/scripts && ./start_crypto_clob.sh" + bash -c "cd /usr/local && source ./dats_env.sh && cd $$BASEDIR_ATS/scripts && ./start_ats.sh" volumes: - - ./data_ats:/opt/DistributedATS/DataService/sql/sqlite - - ./logs_ats:/opt/DistributedATS/MiscATS/CryptoCLOB/logs + - ./data_ats:/usr/local/MiscATS/CryptoCLOB/data + - ./logs_ats:/usr/local/MiscATS/CryptoCLOB/logs ports: - "15001:15001" - "16001:16001" @@ -19,13 +27,13 @@ services: restart: unless-stopped # WebTrader Front-End - distributed_ats_webtrader: - container_name: distributed_ats_webtrader - image: ghcr.io/mkipnis/distributed_ats_webtrader:latest - depends_on: - - distributed_ats - volumes: - - ./webtrader_logs:/usr/local/tomcat/logs - ports: - - "8080:8080" - restart: unless-stopped + # distributed_ats_webtrader: + # container_name: distributed_ats_webtrader + # image: ghcr.io/mkipnis/distributed_ats_webtrader:latest + # depends_on: + # - distributed_ats + # volumes: + # - ./webtrader_logs:/usr/local/tomcat/logs + # ports: + # - "8080:8080" + # restart: unless-stopped diff --git a/docker/dockerize_dats.sh b/docker/dockerize_dats.sh index 87dce2a..308b6a4 100755 --- a/docker/dockerize_dats.sh +++ b/docker/dockerize_dats.sh @@ -3,8 +3,8 @@ set -x # Core -docker build -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS . -#docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . +docker build -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS.debug . +docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . #docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . #docker push ghcr.io/mkipnis/distributed_ats:latest From 8226416d2875c5c1b423ef2d58ac90a9ceb10cb3 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Fri, 23 May 2025 12:47:06 -0400 Subject: [PATCH 09/27] docker compose updates --- docker/Docker.Crypto_CLOB | 1 + docker/Docker.UST_CLOB | 9 +++------ docker/FastDDS.xml | 30 ++++++++++++++++++++++++++++++ docker/docker-compose-crypto.yml | 23 +++++++++++------------ docker/docker-compose-ust.yml | 21 ++++++++++++++------- docker/dockerize_dats.sh | 2 +- docker/ust_clob_env.sh | 26 ++++++++------------------ 7 files changed, 68 insertions(+), 44 deletions(-) create mode 100644 docker/FastDDS.xml diff --git a/docker/Docker.Crypto_CLOB b/docker/Docker.Crypto_CLOB index f66994a..1119678 100644 --- a/docker/Docker.Crypto_CLOB +++ b/docker/Docker.Crypto_CLOB @@ -5,4 +5,5 @@ EXPOSE 16001 EXPOSE 17001 COPY crypto_clob_env.sh /usr/local/dats_env.sh +COPY FastDDS.xml /usr/local/ RUN chmod +x /usr/local/dats_env.sh diff --git a/docker/Docker.UST_CLOB b/docker/Docker.UST_CLOB index 7770bd7..bd30cae 100644 --- a/docker/Docker.UST_CLOB +++ b/docker/Docker.UST_CLOB @@ -4,9 +4,6 @@ EXPOSE 15001 EXPOSE 16001 EXPOSE 17001 -WORKDIR /opt/DistributedATS - -COPY ust_clob_env.sh dats_env.sh -COPY start_ust_clob.sh /opt/DistributedATS/MiscATS/USTreasuryCLOB/scripts/ - -RUN chmod +x dats_env.sh +COPY ust_clob_env.sh /usr/local/dats_env.sh +COPY FastDDS.xml /usr/local/ +RUN chmod +x /usr/local/dats_env.sh diff --git a/docker/FastDDS.xml b/docker/FastDDS.xml new file mode 100644 index 0000000..3bc020f --- /dev/null +++ b/docker/FastDDS.xml @@ -0,0 +1,30 @@ +?xml version="1.0" encoding="utf-8" ?> + + + + + tcp_transport_client + TCPv4 + + + + + + + tcp_transport_client + + false + + + + +
127.0.0.1
+ 51000 +
+
+
+
+
+
+
+
diff --git a/docker/docker-compose-crypto.yml b/docker/docker-compose-crypto.yml index 8b134a4..4b5fafb 100644 --- a/docker/docker-compose-crypto.yml +++ b/docker/docker-compose-crypto.yml @@ -5,7 +5,7 @@ services: container_name: discovery_service image: ghcr.io/mkipnis/distributed_ats:latest command: > - bash -c "LD_LIBRARY_PATH=/usr/local/lib:\$LD_LIBRARY_PATH /usr/local/bin/fastdds discovery -q 51000" + bash -c "LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fastdds discovery -q 51000" ports: - "51000:51000" restart: unless-stopped @@ -18,7 +18,6 @@ services: command: > bash -c "cd /usr/local && source ./dats_env.sh && cd $$BASEDIR_ATS/scripts && ./start_ats.sh" volumes: - - ./data_ats:/usr/local/MiscATS/CryptoCLOB/data - ./logs_ats:/usr/local/MiscATS/CryptoCLOB/logs ports: - "15001:15001" @@ -27,13 +26,13 @@ services: restart: unless-stopped # WebTrader Front-End - # distributed_ats_webtrader: - # container_name: distributed_ats_webtrader - # image: ghcr.io/mkipnis/distributed_ats_webtrader:latest - # depends_on: - # - distributed_ats - # volumes: - # - ./webtrader_logs:/usr/local/tomcat/logs - # ports: - # - "8080:8080" - # restart: unless-stopped + distributed_ats_webtrader: + container_name: distributed_ats_webtrader + image: ghcr.io/mkipnis/distributed_ats_webtrader:latest + depends_on: + - distributed_ats + volumes: + - ./webtrader_logs:/usr/local/tomcat/logs + ports: + - "8080:8080" + restart: unless-stopped diff --git a/docker/docker-compose-ust.yml b/docker/docker-compose-ust.yml index 44104d7..e6ff1bd 100644 --- a/docker/docker-compose-ust.yml +++ b/docker/docker-compose-ust.yml @@ -1,17 +1,24 @@ version: '2' services: - # Core Services: Matching Engines, FIX Gateways + fast_dds_discovery: + container_name: discovery_service + image: ghcr.io/mkipnis/distributed_ats:latest + command: > + bash -c "LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fastdds discovery -q 51000" + ports: + - "51000:51000" + restart: unless-stopped + distributed_ats: container_name: distributed_ats - image: ghcr.io/mkipnis/dats_ust_clob:latest + image: ghcr.io/mkipnis/dats_ust_clob:latest + depends_on: + - discovery_service command: > - bash -c "cd /opt/DistributedATS/ && - . ./dats_env.sh && - cd /opt/DistributedATS/MiscATS/USTreasuryCLOB/scripts && ./start_ust_clob.sh" + bash -c "cd /usr/local && source ./dats_env.sh && cd $$BASEDIR_ATS/scripts && ./start_ats.sh" volumes: - - ./data_ats:/opt/DistributedATS/DataService/sql/sqlite - - ./logs_ats:/opt/DistributedATS/MiscATS/USTreasuryCLOB/logs + - ./logs_ats:/usr/local/MiscATS/CryptoCLOB/logs ports: - "15001:15001" - "16001:16001" diff --git a/docker/dockerize_dats.sh b/docker/dockerize_dats.sh index 308b6a4..11174fe 100755 --- a/docker/dockerize_dats.sh +++ b/docker/dockerize_dats.sh @@ -5,7 +5,7 @@ set -x # Core docker build -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS.debug . docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . -#docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . +docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . #docker push ghcr.io/mkipnis/distributed_ats:latest #docker push ghcr.io/mkipnis/dats_crypto_clob:latest diff --git a/docker/ust_clob_env.sh b/docker/ust_clob_env.sh index df7da7e..b200dc3 100644 --- a/docker/ust_clob_env.sh +++ b/docker/ust_clob_env.sh @@ -1,21 +1,11 @@ -export DATS_HOME=/opt/DistributedATS -export DEPS_HOME=/opt/distributed_ats_deps_build -export LD_LIBRARY_PATH=$DEPS_HOME/lib:$DATS_HOME/lib:$LD_LIBRARY_PATH -export LOG4CXX_CONFIGURATION=/opt/DistributedATS/config/log4cxx.xml - -#echo Specific Specific - -#echo Crypto ATS -#export BASEDIR_ATS=$DATS_HOME/MiscATS/CryptoCLOB -#export DATS_LOG_HOME=$BASEDIR_ATS/logs -#mkdir -p $BASEDIR_ATS/logs - -#echo US Treasuries +# dependencies +export DATS_HOME=/usr/local +export DEPS_HOME=/usr/local +export LD_LIBRARY_PATH=$DEPS_HOME/lib:$LD_LIBRARY_PATH +export LOG4CXX_CONFIGURATION=$DATS_HOME/config/log4cxx.xml +export FASTDDS_DEFAULT_PROFILES_FILE=/usr/local/FastDDS.xml + +# ATS HOME export BASEDIR_ATS=$DATS_HOME/MiscATS/USTreasuryCLOB export DATS_LOG_HOME=$BASEDIR_ATS/logs mkdir -p $BASEDIR_ATS/logs - -#echo US Treasuries -#export BASEDIR_ATS=$DATS_HOME/MiscATS/MultiMatchingEngineATS -#export DATS_LOG_HOME=$BASEDIR_ATS/logs -#mkdir -p $BASEDIR_ATS/logs From 1ba97073cf134dc47de46872ef94c2d175f67d17 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sat, 19 Jul 2025 23:06:26 -0400 Subject: [PATCH 10/27] update --- CMakeLists.txt | 18 +-- DataService/scripts/data_service_manager.py | 107 +++++++++++++++++ DataService/src/MarketDataService.cpp | 2 + DataService/src/RefDataService.cpp | 3 +- DataService/src/SQLiteConnection.hpp | 7 +- FIXGateway/scripts/fix_gateway_manager.py | 98 +++++++++++++++ .../scripts/matching_engine_manager.py | 107 +++++++++++++++++ MatchingEngine/src/Market.cpp | 2 +- MatchingEngine/src/Market.h | 5 +- .../SecurityListDataReaderListenerImpl.cpp | 6 +- .../SecurityListRequestDataWriterListener.h | 55 ++++++--- MiscATS/CryptoCLOB/crypto_ats.json | 10 ++ MiscATS/CryptoCLOB/data/distributed_ats.db | Bin 3248128 -> 3248128 bytes MiscATS/CryptoCLOB/scripts/start_ats.sh | 51 -------- MiscATS/CryptoCLOB/scripts/stop_ats.sh | 26 ---- MiscATS/CryptoCLOB/sql/populate_db.sh | 37 +++--- .../multi_matching_engine.json | 9 ++ .../scripts/start_ats.sh | 47 -------- .../scripts/stop_ats.sh | 22 ---- MiscATS/USTreasuryCLOB/scripts/start_ats.sh | 39 ------ MiscATS/USTreasuryCLOB/scripts/stop_ats.sh | 16 --- MiscATS/USTreasuryCLOB/ust_ats.json | 7 ++ MiscATS/start_ats.py | 112 ++++++++++++++++++ MiscATS/stop_ats.py | 58 +++++++++ build_with_cmake.sh | 16 +-- 25 files changed, 588 insertions(+), 272 deletions(-) create mode 100644 DataService/scripts/data_service_manager.py create mode 100644 FIXGateway/scripts/fix_gateway_manager.py create mode 100644 MatchingEngine/scripts/matching_engine_manager.py create mode 100644 MiscATS/CryptoCLOB/crypto_ats.json delete mode 100755 MiscATS/CryptoCLOB/scripts/start_ats.sh delete mode 100755 MiscATS/CryptoCLOB/scripts/stop_ats.sh create mode 100644 MiscATS/MultiMatchingEngineATS/multi_matching_engine.json delete mode 100755 MiscATS/MultiMatchingEngineATS/scripts/start_ats.sh delete mode 100755 MiscATS/MultiMatchingEngineATS/scripts/stop_ats.sh delete mode 100755 MiscATS/USTreasuryCLOB/scripts/start_ats.sh delete mode 100755 MiscATS/USTreasuryCLOB/scripts/stop_ats.sh create mode 100644 MiscATS/USTreasuryCLOB/ust_ats.json create mode 100644 MiscATS/start_ats.py create mode 100644 MiscATS/stop_ats.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 5367af2..f8e46e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,19 +34,11 @@ add_subdirectory( LatencyTest ) install(DIRECTORY ${CMAKE_SOURCE_DIR}/MiscATS/ DESTINATION MiscATS - FILES_MATCHING PATTERN "*.db" PATTERN "*.sh" PATTERN "*.ini" PATTERN "*.cfg") - -install(CODE " - file(GLOB_RECURSE SCRIPT_FILES - \"\${CMAKE_INSTALL_PREFIX}/MiscATS/*.sh\") - foreach(script \${SCRIPT_FILES}) - execute_process(COMMAND chmod +x \${script}) - endforeach() -") - -install(FILES FIXGateway/scripts/fixgateway.sh - DataService/scripts/dataservice.sh - MatchingEngine/scripts/matchingengine.sh + FILES_MATCHING PATTERN "*.db" PATTERN "*.py" PATTERN "*.ini" PATTERN "*.cfg" PATTERN "*.json") + +install(FILES FIXGateway/scripts/fix_gateway_manager.py + DataService/scripts/data_service_manager.py + MatchingEngine/scripts/matching_engine_manager.py DESTINATION scripts PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE diff --git a/DataService/scripts/data_service_manager.py b/DataService/scripts/data_service_manager.py new file mode 100644 index 0000000..3ea0565 --- /dev/null +++ b/DataService/scripts/data_service_manager.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +import os +import sys +import time +import subprocess +from pathlib import Path +import psutil + +PROGNAME = "DataService" + + +def get_config_file(): + if len(sys.argv) < 3: + print(f"Usage: {sys.argv[0]} [start|stop|check] ") + sys.exit(1) + return sys.argv[2] + + +def get_paths(config_file): + basedir = os.environ.get("BASEDIR_ATS", ".") + dats_home = os.environ.get("DATS_HOME") + if not dats_home: + print("DATS_HOME is not set.") + sys.exit(1) + + config_path = Path(basedir) / "config" / config_file + log_path = Path(basedir) / "logs" / f"{PROGNAME}.{config_file}.console.log" + binary_path = Path(dats_home) / "bin" / PROGNAME + return binary_path, config_path, log_path, basedir + + +def source_dats_env(): + dats_home = os.environ.get("DATS_HOME") + env_script = Path(dats_home) / "dats_env.sh" + if env_script.exists(): + subprocess.call(f"source {env_script}", shell=True, executable="/bin/bash") + + +def check_process(config_path): + for proc in psutil.process_iter(['pid', 'cmdline']): + try: + cmdline = proc.info['cmdline'] + if cmdline and PROGNAME in cmdline[0] and str(config_path) in ' '.join(cmdline): + print(f"{PROGNAME} [{config_path.name}] is running - {proc.pid}") + return proc.pid + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): + continue + print(f"{PROGNAME} [{config_path.name}] is not running") + return None + + +def start_process(binary_path, config_path, log_path): + print(f"Starting: {PROGNAME} -c {config_path}") + for key in sorted(os.environ): + print(f"{key}={os.environ[key]}") + if check_process(config_path) is None: + with open(log_path, "a") as f: + subprocess.Popen([str(binary_path), "-c", str(config_path)], + stdout=f, stderr=subprocess.STDOUT) + time.sleep(1) + check_process(config_path) + + +def stop_process(config_path): + cmd_str = f"{PROGNAME} -c {config_path}" + print(f"Stopping: {cmd_str}") + pid = check_process(config_path) + if pid: + os.system(f"pkill -SIGTERM -f \"{cmd_str}\"") + time.sleep(1) + + for _ in range(10): + if check_process(config_path) is None: + break + time.sleep(1) + else: + os.system(f"pkill -KILL -U {os.getuid()} -f \"{cmd_str}\"") + + +def main(): + if len(sys.argv) < 3: + print(f"Usage: {sys.argv[0]} [start|stop|check] ") + sys.exit(1) + + command = sys.argv[1].lower() + config_file = get_config_file() + + binary_path, config_path, log_path, basedir = get_paths(config_file) + source_dats_env() + + if command == "start": + start_process(binary_path, config_path, log_path) + elif command == "stop": + stop_process(config_path) + elif command == "check": + check_process(config_path) + else: + print("Unknown command") + sys.exit(1) + + with open(log_path, "a") as f: + f.write(f"{time.strftime('%Y%m%d.%H%M%S')} run-done : pid,{os.getpid()}\n") + + +if __name__ == "__main__": + main() diff --git a/DataService/src/MarketDataService.cpp b/DataService/src/MarketDataService.cpp index 6e19962..6a7f381 100644 --- a/DataService/src/MarketDataService.cpp +++ b/DataService/src/MarketDataService.cpp @@ -209,6 +209,8 @@ int MarketDataService::service (void) std::this_thread::sleep_for(std::chrono::duration(1000)); } }; + + return 0; } bool MarketDataService::populateMarketDataSnapshotFullRefresh( const Instrument& instrument, diff --git a/DataService/src/RefDataService.cpp b/DataService/src/RefDataService.cpp index e85fc3b..02fecf1 100644 --- a/DataService/src/RefDataService.cpp +++ b/DataService/src/RefDataService.cpp @@ -94,7 +94,8 @@ void RefDataService::populateUserGroupInstrumentMap() " m.market_name=im_map.market_name and " \ " im_map.market_name=ugm_map.market_name"); - LOG4CXX_INFO(logger, "Populating security list"); + LOG4CXX_INFO(logger, "Populating security list : "); + LOG4CXX_INFO(logger, "Query : " + sqliteQuery.getQuery()); m_sqliteConnection->execute(sqliteQuery); diff --git a/DataService/src/SQLiteConnection.hpp b/DataService/src/SQLiteConnection.hpp index 187d866..32a1ef1 100644 --- a/DataService/src/SQLiteConnection.hpp +++ b/DataService/src/SQLiteConnection.hpp @@ -42,8 +42,6 @@ class SQLiteQuery public: SQLiteQuery( const std::string& query ) : m_stmt(0), m_query( query ) { - - std::cout << query << std::endl; } ~SQLiteQuery() @@ -95,6 +93,11 @@ class SQLiteQuery { return m_rows[row][column]; } + + std::string getQuery() + { + return m_query; + } private: sqlite3_stmt* m_stmt; diff --git a/FIXGateway/scripts/fix_gateway_manager.py b/FIXGateway/scripts/fix_gateway_manager.py new file mode 100644 index 0000000..a137a7a --- /dev/null +++ b/FIXGateway/scripts/fix_gateway_manager.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +import os +import sys +import time +import subprocess +from pathlib import Path +import psutil + +PROGNAME = "FIXGateway" + + +def usage(): + print(f"Usage: {sys.argv[0]} [start|stop|check] ") + sys.exit(1) + + +def get_paths(config_file): + basedir = os.environ.get("BASEDIR_ATS", ".") + dats_home = os.environ.get("DATS_HOME") + if not dats_home: + print("DATS_HOME is not set.") + sys.exit(1) + + config_path = Path(basedir) / "config" / config_file + log_path = Path(basedir) / "logs" / f"{PROGNAME}.{config_file}.console.log" + binary_path = Path(dats_home) / "bin" / PROGNAME + return binary_path, config_path, log_path + + +def check_process(config_path): + for proc in psutil.process_iter(['pid', 'cmdline']): + try: + cmdline = proc.info['cmdline'] + if cmdline and PROGNAME in cmdline[0] and str(config_path) in ' '.join(cmdline): + print(f"{PROGNAME} [{config_path.name}] is running - {proc.pid}") + return proc.pid + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): + continue + print(f"{PROGNAME} [{config_path.name}] is not running") + return None + + +def start_process(binary_path, config_path, log_path): + process_str = f"{PROGNAME} -c {config_path}" + print(f"Starting: {process_str}") + for key in sorted(os.environ): + print(f"{key}={os.environ[key]}") + if check_process(config_path) is None: + with open(log_path, "a") as f: + subprocess.Popen([str(binary_path), "-c", str(config_path)], + stdout=f, stderr=subprocess.STDOUT) + time.sleep(1) + check_process(config_path) + + +def stop_process(config_path): + process_str = f"{PROGNAME} -c {config_path}" + print(f"Stopping: {process_str}") + pid = check_process(config_path) + if pid: + os.system(f"pkill -SIGTERM -f \"{process_str}\"") + time.sleep(1) + + # Try up to 10 seconds to let it exit + for _ in range(10): + if check_process(config_path) is None: + break + time.sleep(1) + else: + os.system(f"pkill -KILL -U {os.getuid()} -f \"{process_str}\"") + + +def main(): + if len(sys.argv) < 3: + usage() + + command = sys.argv[1].lower() + config_file = sys.argv[2] + + binary_path, config_path, log_path = get_paths(config_file) + + if command == "start": + start_process(binary_path, config_path, log_path) + elif command == "stop": + stop_process(config_path) + elif command == "check": + check_process(config_path) + else: + usage() + + # Final run log + with open(log_path, "a") as f: + f.write(f"{time.strftime('%Y%m%d.%H%M%S')} run-done : pid,{os.getpid()}\n") + + +if __name__ == "__main__": + main() diff --git a/MatchingEngine/scripts/matching_engine_manager.py b/MatchingEngine/scripts/matching_engine_manager.py new file mode 100644 index 0000000..e8e2237 --- /dev/null +++ b/MatchingEngine/scripts/matching_engine_manager.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +import os +import sys +import time +import subprocess +from pathlib import Path +import psutil + +PROGNAME = "MatchingEngine" + +def get_config_file(): + if len(sys.argv) < 3: + print(f"Usage: {sys.argv[0]} [start|stop|check] ") + sys.exit(1) + return sys.argv[2] + + +def get_paths(config_file): + basedir = os.environ.get("BASEDIR_ATS", ".") + dats_home = os.environ.get("DATS_HOME") + if not dats_home: + print("DATS_HOME is not set.") + sys.exit(1) + + config_path = Path(basedir) / "config" / config_file + log_path = Path(basedir) / "logs" / f"{PROGNAME}.{config_file}.console.log" + binary_path = Path(dats_home) / "bin" / PROGNAME + return binary_path, config_path, log_path, basedir + + +def source_dats_env(): + dats_home = os.environ.get("DATS_HOME") + env_script = Path(dats_home) / "dats_env.sh" + if env_script.exists(): + subprocess.call(f"source {env_script}", shell=True, executable="/bin/bash") + + +def check_process(config_path): + for proc in psutil.process_iter(['pid', 'cmdline']): + try: + cmdline = proc.info['cmdline'] + if cmdline and PROGNAME in cmdline[0] and str(config_path) in ' '.join(cmdline): + print(f"{PROGNAME} [{config_path.name}] is running - {proc.pid}") + return proc.pid + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): + continue + print(f"{PROGNAME} [{config_path.name}] is not running") + return None + + +def start_process(binary_path, config_path, log_path): + print(f"Starting: {PROGNAME} -c {config_path}") + for key in sorted(os.environ): + print(f"{key}={os.environ[key]}") + if check_process(config_path) is None: + with open(log_path, "a") as f: + subprocess.Popen([str(binary_path), "-c", str(config_path)], + stdout=f, stderr=subprocess.STDOUT) + time.sleep(1) + check_process(config_path) + + +def stop_process(config_path): + cmd_str = f"{PROGNAME} -c {config_path}" + print(f"Stopping: {cmd_str}") + pid = check_process(config_path) + if pid: + os.system(f"pkill -SIGTERM -f \"{cmd_str}\"") + time.sleep(1) + + for _ in range(10): + if check_process(config_path) is None: + break + time.sleep(1) + else: + os.system(f"pkill -KILL -U {os.getuid()} -f \"{cmd_str}\"") + + +def main(): + if len(sys.argv) < 3: + print(f"Usage: {sys.argv[0]} [start|stop|check] ") + sys.exit(1) + + command = sys.argv[1].lower() + config_file = get_config_file() + + binary_path, config_path, log_path, basedir = get_paths(config_file) + + source_dats_env() + + if command == "start": + start_process(binary_path, config_path, log_path) + elif command == "stop": + stop_process(config_path) + elif command == "check": + check_process(config_path) + else: + print("Unknown command") + sys.exit(1) + + with open(log_path, "a") as f: + f.write(f"{time.strftime('%Y%m%d.%H%M%S')} run-done : pid,{os.getpid()}\n") + + +if __name__ == "__main__": + main() diff --git a/MatchingEngine/src/Market.cpp b/MatchingEngine/src/Market.cpp index 1414dd4..eb2fa1e 100644 --- a/MatchingEngine/src/Market.cpp +++ b/MatchingEngine/src/Market.cpp @@ -54,7 +54,7 @@ Market::Market(DataWriterContainerPtr dataWriterContainerPtr, PriceDepthPublisherQueuePtr& price_depth_publisher_queue_ptr) : dataWriterContainerPtr_(dataWriterContainerPtr), _marketName(marketName), _dataServiceName(dataServiceName), - _price_depth_publisher_queue_ptr( price_depth_publisher_queue_ptr ) +_price_depth_publisher_queue_ptr( price_depth_publisher_queue_ptr ), _ready_to_trade(false) { stats_ptr_ = std::make_shared(); } diff --git a/MatchingEngine/src/Market.h b/MatchingEngine/src/Market.h index 93e98c8..24ddf99 100644 --- a/MatchingEngine/src/Market.h +++ b/MatchingEngine/src/Market.h @@ -168,7 +168,8 @@ class Market : public liquibook::book::OrderListener, OrderBookPtr addBook(const std::string &symbol, bool useDepthBook); - bool is_ready_to_trade() { return (books_.size() > 0); }; + bool get_ready_to_trade() { return _ready_to_trade.load(); }; + void set_ready_to_trade( bool ready_to_trade ) { _ready_to_trade.store(ready_to_trade); }; public: @@ -216,6 +217,8 @@ class Market : public liquibook::book::OrderListener, std::string _marketName; // Quickfix field 207 - Security Exchange std::string _dataServiceName; + std::atomic _ready_to_trade; + }; typedef std::shared_ptr market_ptr; diff --git a/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp b/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp index 3dd30ca..66f379e 100644 --- a/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp +++ b/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp @@ -51,7 +51,7 @@ void SecurityListDataReaderListenerImpl::on_data_available( DistributedATS_SecurityList::SecurityList security_list; eprosima::fastdds::dds::SampleInfo info; - if (_marketPtr->is_ready_to_trade()) + if (_marketPtr->get_ready_to_trade() == true) return; if (reader->take_next_sample(&security_list, &info) == eprosima::fastdds::dds::RETCODE_OK) @@ -59,12 +59,16 @@ void SecurityListDataReaderListenerImpl::on_data_available( std::stringstream ss; SecurityListLogger::log(ss, security_list); LOG4CXX_INFO(logger, "SecurityList : [" << ss.str() << "]"); + + std::cout << "Security:" << ss.str() << std::endl; for (uint32_t sec_index = 0; sec_index < security_list.c_NoRelatedSym().size(); sec_index++) { std::string instrument = security_list.c_NoRelatedSym()[sec_index].Symbol(); _marketPtr->addBook(instrument, true); } + + _marketPtr->set_ready_to_trade(true); // request to recieve opening price _marketPtr->publishMarketDataRequest(); diff --git a/MatchingEngine/src/SecurityListRequestDataWriterListener.h b/MatchingEngine/src/SecurityListRequestDataWriterListener.h index de154b5..9afbb0f 100644 --- a/MatchingEngine/src/SecurityListRequestDataWriterListener.h +++ b/MatchingEngine/src/SecurityListRequestDataWriterListener.h @@ -1,3 +1,9 @@ +#include +#include +#include +#include +#include + #pragma once namespace DistributedATS @@ -5,44 +11,55 @@ namespace DistributedATS class SecurityListRequestDataWriterListener : public eprosima::fastdds::dds::DataWriterListener { - - public: +public: - SecurityListRequestDataWriterListener( const market_ptr& marketPtr ) : matched_(0), _market_ptr(marketPtr) + SecurityListRequestDataWriterListener(const market_ptr& marketPtr) + : matched_(0), _market_ptr(marketPtr), thread_started_(false) { } - ~SecurityListRequestDataWriterListener() override - { - } + ~SecurityListRequestDataWriterListener() override = default; void on_publication_matched( - eprosima::fastdds::dds::DataWriter* dwr, - const eprosima::fastdds::dds::PublicationMatchedStatus& info) override + eprosima::fastdds::dds::DataWriter* dwr, + const eprosima::fastdds::dds::PublicationMatchedStatus& info) override { - if (info.current_count_change >= 1) + if (info.current_count_change > 0) { matched_ = info.total_count; - LOG4CXX_INFO(logger, "SecurityListRequestDataWriterListener Publisher Matched:" << matched_); - if ( !_market_ptr->is_ready_to_trade() ) - _market_ptr->publishSecurityListRequest(dwr); + //std::cout << "[Listener] Publisher Matched: " << matched_ << std::endl; + + // Start thread only once + bool expected = false; + if (thread_started_.compare_exchange_strong(expected, true)) + { + std::thread([this, dwr]() { + while (!_market_ptr->get_ready_to_trade()) + { + //std::cout << "[Listener] Publishing Security Lise Exchange " << matched_ << std::endl; + _market_ptr->publishSecurityListRequest(dwr); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + }).detach(); + } } else if (info.current_count_change == -1) { matched_ = info.total_count; - LOG4CXX_INFO(logger, "SecurityListRequestDataWriterListener Publisher UnMatched:" << matched_); + std::cout << "[Listener] Publisher UnMatched: " << matched_ << std::endl; } else { - LOG4CXX_INFO(logger, "Is not a valid value for PublicationMatchedStatus current count change." << info.current_count_change); + std::cout << "[Listener] Invalid current_count_change: " << info.current_count_change << std::endl; } } - private: - market_ptr _market_ptr; - std::atomic_int matched_; - }; +private: + market_ptr _market_ptr; + std::atomic_int matched_; + std::atomic thread_started_; // <--- Ensures thread is only started once +}; using security_list_request_data_writer_listener_ptr = std::unique_ptr; -}; +}; // namespace DistributedATS diff --git a/MiscATS/CryptoCLOB/crypto_ats.json b/MiscATS/CryptoCLOB/crypto_ats.json new file mode 100644 index 0000000..3aa71ae --- /dev/null +++ b/MiscATS/CryptoCLOB/crypto_ats.json @@ -0,0 +1,10 @@ +[ + ["data_service_manager.py", "data_service_a.ini"], + ["data_service_manager.py", "data_service_b.ini"], + ["matching_engine_manager.py", "matching_engine_MARKET_BTC.ini"], + ["matching_engine_manager.py", "matching_engine_MARKET_ETH.ini"], + ["matching_engine_manager.py", "matching_engine_MARKET_OTHER_COIN.ini"], + ["fix_gateway_manager.py", "fix_gwy_1.cfg"], + ["fix_gateway_manager.py", "fix_gwy_2.cfg"], + ["fix_gateway_manager.py", "fix_gwy_3.cfg"] +] \ No newline at end of file diff --git a/MiscATS/CryptoCLOB/data/distributed_ats.db b/MiscATS/CryptoCLOB/data/distributed_ats.db index 440cc49b6f1240b24178ada81ff96b0f3f646fca..366d8143fa2363631e9061d75f87cc2e14dba65f 100644 GIT binary patch delta 63573 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
  • ${tA~K&=slOQ@?*?{?*e?wOC~x;1tK1 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 R6{Jgkxqc?q4H`W5{|DtPc98%8 delta 24664 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 DWYJR0 diff --git a/MiscATS/CryptoCLOB/scripts/start_ats.sh b/MiscATS/CryptoCLOB/scripts/start_ats.sh deleted file mode 100755 index aae85ee..0000000 --- a/MiscATS/CryptoCLOB/scripts/start_ats.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -trap cleanup 1 2 3 6 - -cleanup() -{ - echo "Caught Signal ... cleaning up..." - - $BASEDIR_ATS/scripts/stop_ats.sh - - echo "Done." - - exit 1; -} - -sleep 1 -$DATS_HOME/scripts/dataservice.sh start data_service_a.ini - -sleep 1 -$DATS_HOME/scripts/dataservice.sh start data_service_b.ini - -sleep 1 -$DATS_HOME/scripts/matchingengine.sh start matching_engine_MARKET_BTC.ini - -sleep 1 -$DATS_HOME/scripts/matchingengine.sh start matching_engine_MARKET_ETH.ini - -sleep 1 -$DATS_HOME/scripts/matchingengine.sh start matching_engine_MARKET_OTHER_COIN.ini - -sleep 1 -$DATS_HOME/scripts/fixgateway.sh start fix_gwy_1.cfg - -sleep 1 -$DATS_HOME/scripts/fixgateway.sh start fix_gwy_2.cfg - -sleep 1 -$DATS_HOME/scripts/fixgateway.sh start fix_gwy_3.cfg - -while true; do - $DATS_HOME/scripts/dataservice.sh check data_service_a.ini - $DATS_HOME/scripts/dataservice.sh check data_service_b.ini - $DATS_HOME/scripts/matchingengine.sh check matching_engine_MARKET_BTC.ini - $DATS_HOME/scripts/matchingengine.sh check matching_engine_MARKET_ETH.ini - $DATS_HOME/scripts/matchingengine.sh check matching_engine_MARKET_OTHER_COIN.ini - $DATS_HOME/scripts/fixgateway.sh check fix_gwy_1.cfg - $DATS_HOME/scripts/fixgateway.sh check fix_gwy_2.cfg - $DATS_HOME/scripts/fixgateway.sh check fix_gwy_3.cfg - - sleep 2; -done diff --git a/MiscATS/CryptoCLOB/scripts/stop_ats.sh b/MiscATS/CryptoCLOB/scripts/stop_ats.sh deleted file mode 100755 index a439ae6..0000000 --- a/MiscATS/CryptoCLOB/scripts/stop_ats.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -sleep 1 -$DATS_HOME/scripts/dataservice.sh stop data_service_a.ini - -sleep 1 -$DATS_HOME/scripts/dataservice.sh stop data_service_b.ini - -sleep 1 -$DATS_HOME/scripts/matchingengine.sh stop matching_engine_MARKET_BTC.ini - -sleep 1 -$DATS_HOME/scripts/matchingengine.sh stop matching_engine_MARKET_ETH.ini - -sleep 1 -$DATS_HOME/scripts/matchingengine.sh stop matching_engine_MARKET_OTHER_COIN.ini - -sleep 1 -$DATS_HOME/scripts/fixgateway.sh stop fix_gwy_1.cfg - -sleep 1 -$DATS_HOME/scripts/fixgateway.sh stop fix_gwy_2.cfg - -sleep 1 -$DATS_HOME/scripts/fixgateway.sh stop fix_gwy_3.cfg - diff --git a/MiscATS/CryptoCLOB/sql/populate_db.sh b/MiscATS/CryptoCLOB/sql/populate_db.sh index c60e78f..4c3b259 100755 --- a/MiscATS/CryptoCLOB/sql/populate_db.sh +++ b/MiscATS/CryptoCLOB/sql/populate_db.sh @@ -1,6 +1,7 @@ #!/bin/sh -$SQLITE_HOME/bin/sqlite3 $DATS_HOME/DataService/sql/sqlite/distributed_ats.db < Date: Sun, 20 Jul 2025 17:48:21 +0000 Subject: [PATCH 11/27] updated ust_ats --- MiscATS/USTreasuryCLOB/ust_ats.json | 2 +- docker/Docker.Crypto_CLOB | 2 +- docker/Docker.UST_CLOB | 2 +- docker/{crypto_clob_env.sh => dats_env.sh} | 5 ---- docker/docker-compose-crypto.yml | 9 +++--- docker/docker-compose-ust.yml | 7 ++--- docker/dockerize_dats.sh | 2 +- docker/start_ust_clob.sh | 35 ---------------------- docker/ust_clob_env.sh | 11 ------- 9 files changed, 11 insertions(+), 64 deletions(-) rename docker/{crypto_clob_env.sh => dats_env.sh} (65%) delete mode 100755 docker/start_ust_clob.sh delete mode 100644 docker/ust_clob_env.sh diff --git a/MiscATS/USTreasuryCLOB/ust_ats.json b/MiscATS/USTreasuryCLOB/ust_ats.json index 2b05c89..c30dd9c 100644 --- a/MiscATS/USTreasuryCLOB/ust_ats.json +++ b/MiscATS/USTreasuryCLOB/ust_ats.json @@ -3,5 +3,5 @@ ["data_service_manager.py", "data_service_b.ini"], ["matching_engine_manager.py", "matching_engine_MARKET_UST.ini"], ["fix_gateway_manager.py", "fix_gwy_1.cfg"], - ["fix_gateway_manager.py", "fix_gwy_2.cfg"], + ["fix_gateway_manager.py", "fix_gwy_2.cfg"] ] diff --git a/docker/Docker.Crypto_CLOB b/docker/Docker.Crypto_CLOB index 1119678..aa99419 100644 --- a/docker/Docker.Crypto_CLOB +++ b/docker/Docker.Crypto_CLOB @@ -4,6 +4,6 @@ EXPOSE 15001 EXPOSE 16001 EXPOSE 17001 -COPY crypto_clob_env.sh /usr/local/dats_env.sh +COPY dats_env.sh /usr/local/dats_env.sh COPY FastDDS.xml /usr/local/ RUN chmod +x /usr/local/dats_env.sh diff --git a/docker/Docker.UST_CLOB b/docker/Docker.UST_CLOB index bd30cae..aa99419 100644 --- a/docker/Docker.UST_CLOB +++ b/docker/Docker.UST_CLOB @@ -4,6 +4,6 @@ EXPOSE 15001 EXPOSE 16001 EXPOSE 17001 -COPY ust_clob_env.sh /usr/local/dats_env.sh +COPY dats_env.sh /usr/local/dats_env.sh COPY FastDDS.xml /usr/local/ RUN chmod +x /usr/local/dats_env.sh diff --git a/docker/crypto_clob_env.sh b/docker/dats_env.sh similarity index 65% rename from docker/crypto_clob_env.sh rename to docker/dats_env.sh index 474162b..ab359fc 100644 --- a/docker/crypto_clob_env.sh +++ b/docker/dats_env.sh @@ -4,8 +4,3 @@ export DEPS_HOME=/usr/local export LD_LIBRARY_PATH=$DEPS_HOME/lib:$LD_LIBRARY_PATH export LOG4CXX_CONFIGURATION=$DATS_HOME/config/log4cxx.xml export FASTDDS_DEFAULT_PROFILES_FILE=/usr/local/FastDDS.xml - -# ATS HOME -export BASEDIR_ATS=$DATS_HOME/MiscATS/CryptoCLOB -export DATS_LOG_HOME=$BASEDIR_ATS/logs -mkdir -p $BASEDIR_ATS/logs diff --git a/docker/docker-compose-crypto.yml b/docker/docker-compose-crypto.yml index 4b5fafb..8f58a97 100644 --- a/docker/docker-compose-crypto.yml +++ b/docker/docker-compose-crypto.yml @@ -1,8 +1,8 @@ -version: '2' +version: '3' services: fast_dds_discovery: - container_name: discovery_service + container_name: fast_dds_discovery image: ghcr.io/mkipnis/distributed_ats:latest command: > bash -c "LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fastdds discovery -q 51000" @@ -14,9 +14,9 @@ services: container_name: distributed_ats image: ghcr.io/mkipnis/dats_crypto_clob:latest depends_on: - - discovery_service + - fast_dds_discovery command: > - bash -c "cd /usr/local && source ./dats_env.sh && cd $$BASEDIR_ATS/scripts && ./start_ats.sh" + bash -c "cd /usr/local && source ./dats_env.sh && cd MiscATS && BASEDIR_ATS=`pwd`/CryptoCLOB python3 start_ats.py --ats CryptoCLOB/crypto_ats.json" volumes: - ./logs_ats:/usr/local/MiscATS/CryptoCLOB/logs ports: @@ -25,7 +25,6 @@ services: - "17001:17001" restart: unless-stopped - # WebTrader Front-End distributed_ats_webtrader: container_name: distributed_ats_webtrader image: ghcr.io/mkipnis/distributed_ats_webtrader:latest diff --git a/docker/docker-compose-ust.yml b/docker/docker-compose-ust.yml index e6ff1bd..3e3f49b 100644 --- a/docker/docker-compose-ust.yml +++ b/docker/docker-compose-ust.yml @@ -14,15 +14,14 @@ services: container_name: distributed_ats image: ghcr.io/mkipnis/dats_ust_clob:latest depends_on: - - discovery_service + - fast_dds_discovery command: > - bash -c "cd /usr/local && source ./dats_env.sh && cd $$BASEDIR_ATS/scripts && ./start_ats.sh" + bash -c "cd /usr/local && source ./dats_env.sh && cd MiscATS && BASEDIR_ATS=`pwd`/USTreasuryCLOB python3 start_ats.py --ats USTreasuryCLOB/ust_ats.json" volumes: - - ./logs_ats:/usr/local/MiscATS/CryptoCLOB/logs + - ./logs_ats:/usr/local/MiscATS/USTreasuryCLOB/logs ports: - "15001:15001" - "16001:16001" - - "17001:17001" restart: unless-stopped # WebTrader Front-End diff --git a/docker/dockerize_dats.sh b/docker/dockerize_dats.sh index 11174fe..306b75d 100755 --- a/docker/dockerize_dats.sh +++ b/docker/dockerize_dats.sh @@ -3,7 +3,7 @@ set -x # Core -docker build -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS.debug . +docker build --no-cache -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS . docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . diff --git a/docker/start_ust_clob.sh b/docker/start_ust_clob.sh deleted file mode 100755 index 8642b2a..0000000 --- a/docker/start_ust_clob.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -trap cleanup 1 2 3 6 - -cleanup() -{ - echo "Caught Signal ... cleaning up..." - - $BASEDIR_ATS/scripts/stop_ats.sh - - echo "Done." - - exit 1; -} - -sleep 1 -$DATS_HOME/scripts/matchingengine.sh start matching_engine_MARKET_UST.ini - -sleep 1 -$DATS_HOME/scripts/dataservice.sh start data_service_a.ini -$DATS_HOME/scripts/dataservice.sh start data_service_b.ini - -sleep 1 -$DATS_HOME/scripts/fixgateway.sh start fix_gwy_1.cfg -$DATS_HOME/scripts/fixgateway.sh start fix_gwy_2.cfg - -while true; do - $DATS_HOME/scripts/dataservice.sh check data_service_a.ini - $DATS_HOME/scripts/dataservice.sh check data_service_b.ini - $DATS_HOME/scripts/matchingengine.sh check matching_engine_MARKET_UST.ini - $DATS_HOME/scripts/fixgateway.sh check fix_gwy_1.cfg - $DATS_HOME/scripts/fixgateway.sh check fix_gwy_2.cfg - - sleep 10; -done diff --git a/docker/ust_clob_env.sh b/docker/ust_clob_env.sh deleted file mode 100644 index b200dc3..0000000 --- a/docker/ust_clob_env.sh +++ /dev/null @@ -1,11 +0,0 @@ -# dependencies -export DATS_HOME=/usr/local -export DEPS_HOME=/usr/local -export LD_LIBRARY_PATH=$DEPS_HOME/lib:$LD_LIBRARY_PATH -export LOG4CXX_CONFIGURATION=$DATS_HOME/config/log4cxx.xml -export FASTDDS_DEFAULT_PROFILES_FILE=/usr/local/FastDDS.xml - -# ATS HOME -export BASEDIR_ATS=$DATS_HOME/MiscATS/USTreasuryCLOB -export DATS_LOG_HOME=$BASEDIR_ATS/logs -mkdir -p $BASEDIR_ATS/logs From 2a642d452575556db29e29097296099a1f26484e Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 20 Jul 2025 19:56:25 +0000 Subject: [PATCH 12/27] docker updated --- docker/Docker.Build_DATS_Deps | 15 +++++++++++++++ docker/Docker.Build_Distributed_ATS | 7 ++----- docker/dockerize_dats.sh | 10 ++++++---- 3 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 docker/Docker.Build_DATS_Deps diff --git a/docker/Docker.Build_DATS_Deps b/docker/Docker.Build_DATS_Deps new file mode 100644 index 0000000..43939d9 --- /dev/null +++ b/docker/Docker.Build_DATS_Deps @@ -0,0 +1,15 @@ +FROM ubuntu:latest AS dats_dependency_builder + +RUN apt-get update +RUN apt install -y vim cmake curl build-essential libapr1-dev libaprutil1-dev git libboost-all-dev sqlite3 libsqlite3-dev libtool libasio-dev libtinyxml2-dev zip python3-pip +RUN pip install psutil --break-system-packages + +ADD build_dependences.sh / +RUN /build_dependences.sh + +FROM ubuntu:latest +RUN apt-get update && apt-get install --no-install-recommends -y \ + libboost-all-dev vim python3-pip libapr1-dev libaprutil1-dev libtinyxml2-dev \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +COPY --from=dats_dependency_builder /usr/local /usr/local diff --git a/docker/Docker.Build_Distributed_ATS b/docker/Docker.Build_Distributed_ATS index c0039a3..42b878b 100644 --- a/docker/Docker.Build_Distributed_ATS +++ b/docker/Docker.Build_Distributed_ATS @@ -1,12 +1,9 @@ -FROM ubuntu:latest as dats_dependency_builder +FROM ghcr.io/mkipnis/distributed_ats_deps AS dats_builder RUN apt-get update RUN apt install -y vim cmake curl build-essential libapr1-dev libaprutil1-dev git libboost-all-dev sqlite3 libsqlite3-dev libtool libasio-dev libtinyxml2-dev zip python3-pip RUN pip install psutil --break-system-packages -ADD build_dependences.sh / -RUN /build_dependences.sh - ADD build_distributed_ats.sh / RUN /build_distributed_ats.sh @@ -15,4 +12,4 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ libboost-all-dev vim python3-pip libapr1-dev libaprutil1-dev libtinyxml2-dev \ && apt-get clean && rm -rf /var/lib/apt/lists/* -COPY --from=dats_dependency_builder /usr/local /usr/local +COPY --from=dats_builder /usr/local /usr/local diff --git a/docker/dockerize_dats.sh b/docker/dockerize_dats.sh index 306b75d..126bce9 100755 --- a/docker/dockerize_dats.sh +++ b/docker/dockerize_dats.sh @@ -3,10 +3,12 @@ set -x # Core -docker build --no-cache -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS . +docker build -t ghcr.io/mkipnis/distributed_ats_deps:latest -f Docker.Build_DATS_Deps . +docker build -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS . docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . -#docker push ghcr.io/mkipnis/distributed_ats:latest -#docker push ghcr.io/mkipnis/dats_crypto_clob:latest -#docker push ghcr.io/mkipnis/dats_ust_clob:latest +docker push ghcr.io/mkipnis/distributed_ats_deps:latest +docker push ghcr.io/mkipnis/distributed_ats:latest +docker push ghcr.io/mkipnis/dats_crypto_clob:latest +docker push ghcr.io/mkipnis/dats_ust_clob:latest From 908fa26dd740505415ef0c2703a4e8bcf06bc680 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 20 Jul 2025 17:16:33 -0400 Subject: [PATCH 13/27] Update README.md --- MiscATS/USTreasuryCLOB/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MiscATS/USTreasuryCLOB/README.md b/MiscATS/USTreasuryCLOB/README.md index cd5bafd..32ffa96 100644 --- a/MiscATS/USTreasuryCLOB/README.md +++ b/MiscATS/USTreasuryCLOB/README.md @@ -1,6 +1,6 @@ -## Multiple Matching Engines +## Matching Engine -USTreasuryCLOB ATS consists of a single Matching Engine, three FIX Gateways, and two Data Services. +USTreasuryCLOB ATS consists of a single Matching Engine, two FIX Gateways, and two Data Services. The matching engine consumes and processes orders from the instrument group MARKET_UST that covers 300+ instruments ![N|Solid](https://raw.githubusercontent.com/mkipnis/DistributedATS/master/docs/Diagrams/USTreasuryCLOB.png?raw=true) From 11811fc25287604b707ef16bdbe15663062e1e8a Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sat, 6 Sep 2025 15:14:31 -0400 Subject: [PATCH 14/27] Create cmake-single-platform.yml --- .github/workflows/cmake-single-platform.yml | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/cmake-single-platform.yml diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml new file mode 100644 index 0000000..47daa92 --- /dev/null +++ b/.github/workflows/cmake-single-platform.yml @@ -0,0 +1,45 @@ +# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml +name: CMake on a single platform + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Boost + run: sudo apt-get update && sudo apt-get install -y libboost-all-dev + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + + - name: ✅ Build Success + run: echo "🎉 Build completed successfully!" + run: ctest -C ${{env.BUILD_TYPE}} + From 938f65db49f46ceefe1e9936e5e95afba550902f Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sat, 6 Sep 2025 15:17:26 -0400 Subject: [PATCH 15/27] Update cmake-single-platform.yml --- .github/workflows/cmake-single-platform.yml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 47daa92..26703ad 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -1,5 +1,3 @@ -# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage. -# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml name: CMake on a single platform on: @@ -14,9 +12,6 @@ env: jobs: build: - # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. - # You can convert this to a matrix build if you need cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: @@ -26,20 +21,14 @@ jobs: run: sudo apt-get update && sudo apt-get install -y libboost-all-dev - name: Configure CMake - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build - # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Test working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - - - name: ✅ Build Success - run: echo "🎉 Build completed successfully!" run: ctest -C ${{env.BUILD_TYPE}} + - name: ✅ Build Success + run: echo "🎉 Build completed successfully!" From 8f1fbd6da776649e2659a774f70acfae0da21d71 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sat, 6 Sep 2025 15:37:03 -0400 Subject: [PATCH 16/27] Update cmake-single-platform.yml --- .github/workflows/cmake-single-platform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 26703ad..fc5d20e 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v4 - name: Install Boost - run: sudo apt-get update && sudo apt-get install -y libboost-all-dev + run: sudo apt-get update && sudo apt-get install -y libboost-all-dev libapr1-dev libaprutil1-dev libtinyxml2-dev libsqlite3-dev libasio-dev - name: Configure CMake run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} From b729450b1353489b5b68b161367ff261b259ecd3 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sat, 6 Sep 2025 16:55:13 -0400 Subject: [PATCH 17/27] Update cmake-single-platform.yml --- .github/workflows/cmake-single-platform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index fc5d20e..fc7a51c 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install Boost + - name: Install dependencies run: sudo apt-get update && sudo apt-get install -y libboost-all-dev libapr1-dev libaprutil1-dev libtinyxml2-dev libsqlite3-dev libasio-dev - name: Configure CMake From 201f6aff36a465ecfd335363fe5442026f390441 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 12 Oct 2025 13:14:48 -0400 Subject: [PATCH 18/27] general updates --- MatchingEngine/src/Market.cpp | 3 +- MatchingEngine/src/Order.cpp | 6 +--- .../src/PriceDepthPublisherService.cpp | 34 ++++++------------- .../SecurityListDataReaderListenerImpl.cpp | 4 +-- .../SecurityListRequestDataWriterListener.h | 7 ---- MiscATS/CryptoCLOB/README.md | 3 +- MiscATS/MultiMatchingEngineATS/README.md | 3 +- MiscATS/USTreasuryCLOB/README.md | 3 +- 8 files changed, 17 insertions(+), 46 deletions(-) diff --git a/MatchingEngine/src/Market.cpp b/MatchingEngine/src/Market.cpp index eb2fa1e..c64d1d5 100644 --- a/MatchingEngine/src/Market.cpp +++ b/MatchingEngine/src/Market.cpp @@ -442,9 +442,8 @@ void Market::on_depth_change(const DepthOrderBook *book, std::stringstream ss; MarketDataIncrementalRefreshLogger::log(ss, md_update->priceDepth); LOG4CXX_INFO(logger, "MarketDataIncrementalRefresh : [" << ss.str() << "]"); - std::cout << "Update : " << ss.str() << std::endl; - int market_data_index = MARKET_DATA_PRICE_DEPTH * 2; // bids and asks + int market_data_index = MARKET_DATA_PRICE_DEPTH * 2; // bids and asks auto current_stats = stats_ptr_->find(book->symbol()); diff --git a/MatchingEngine/src/Order.cpp b/MatchingEngine/src/Order.cpp index 9adcc6d..dddb87d 100644 --- a/MatchingEngine/src/Order.cpp +++ b/MatchingEngine/src/Order.cpp @@ -105,7 +105,7 @@ void Order::onRejected(const char *reason) {} void Order::onFilled(liquibook::book::Quantity fill_qty, liquibook::book::Cost fill_cost) { quantityOnMarket_ -= fill_qty; - fillCost_ += fill_cost; + fillCost_ += (fill_cost * fill_qty); quantityFilled_ += fill_qty; std::stringstream msg; @@ -243,10 +243,6 @@ void Order::populateExecutionReport( executionReport.TimeInForce(FIX::TimeInForce_DAY); } - - // std::cout << "Transact Time : " << ACE_OS::gettimeofday().msec() << ":" << - // executionReport.TransactTime << std::endl; - if (quantityFilled() > 0) executionReport.AvgPx(std::nearbyint(fillCost() / quantityFilled())); // round to the nearest tick else diff --git a/MatchingEngine/src/PriceDepthPublisherService.cpp b/MatchingEngine/src/PriceDepthPublisherService.cpp index 562aef5..db74c2a 100644 --- a/MatchingEngine/src/PriceDepthPublisherService.cpp +++ b/MatchingEngine/src/PriceDepthPublisherService.cpp @@ -73,30 +73,21 @@ int PriceDepthPublisherService::service() // // Iterate through the queue and get the latest update // - - /*std::cout << "Queue Size : " - << _price_depth_publisher_queue_ptr->size() - << std::endl;*/ - - std::shared_ptr market_data_update; + std::shared_ptr market_data_update; - std::map - latestMarketDataUpdates; + std::map + latestMarketDataUpdates; - - while (_price_depth_publisher_queue_ptr->pop(market_data_update)) - { - latestMarketDataUpdates[market_data_update->symbol] = market_data_update->priceDepth; - - std::stringstream ss; - MarketDataIncrementalRefreshLogger::log(ss, latestMarketDataUpdates[market_data_update->symbol]); - LOG4CXX_INFO(logger, "MarketDataIncrementalRefresh : [" << ss.str() << "]"); - std::cout << "Update : " << ss.str() << std::endl; + while (_price_depth_publisher_queue_ptr->pop(market_data_update)) + { + latestMarketDataUpdates[market_data_update->symbol] = market_data_update->priceDepth; - } + std::stringstream ss; + MarketDataIncrementalRefreshLogger::log(ss, latestMarketDataUpdates[market_data_update->symbol]); + LOG4CXX_INFO(logger, "MarketDataIncrementalRefresh : [" << ss.str() << "]"); + } - DistributedATS_MarketDataIncrementalRefresh::MarketDataIncrementalRefresh chunkedIncrementalMarketDataRefresh; @@ -132,8 +123,6 @@ int PriceDepthPublisherService::service() chunkedIncrementalMarketDataRefresh, "MarketDataIncrementalRefresh"); - std::cout << "Publishing chunk of " << chunkedIncrementalMarketDataRefresh.c_NoMDEntries().size() << " updates" << std::endl; - std::stringstream ss; MarketDataIncrementalRefreshLogger::log( ss, chunkedIncrementalMarketDataRefresh); @@ -144,7 +133,6 @@ int PriceDepthPublisherService::service() if (ret != eprosima::fastdds::dds::RETCODE_OK) { LOG4CXX_ERROR(logger, "MarketDataIncrementalRefresh :" << ret); } - } } diff --git a/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp b/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp index 66f379e..95352fb 100644 --- a/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp +++ b/MatchingEngine/src/SecurityListDataReaderListenerImpl.cpp @@ -59,9 +59,7 @@ void SecurityListDataReaderListenerImpl::on_data_available( std::stringstream ss; SecurityListLogger::log(ss, security_list); LOG4CXX_INFO(logger, "SecurityList : [" << ss.str() << "]"); - - std::cout << "Security:" << ss.str() << std::endl; - + for (uint32_t sec_index = 0; sec_index < security_list.c_NoRelatedSym().size(); sec_index++) { std::string instrument = security_list.c_NoRelatedSym()[sec_index].Symbol(); diff --git a/MatchingEngine/src/SecurityListRequestDataWriterListener.h b/MatchingEngine/src/SecurityListRequestDataWriterListener.h index 9afbb0f..73d577e 100644 --- a/MatchingEngine/src/SecurityListRequestDataWriterListener.h +++ b/MatchingEngine/src/SecurityListRequestDataWriterListener.h @@ -27,7 +27,6 @@ class SecurityListRequestDataWriterListener : public eprosima::fastdds::dds::Dat if (info.current_count_change > 0) { matched_ = info.total_count; - //std::cout << "[Listener] Publisher Matched: " << matched_ << std::endl; // Start thread only once bool expected = false; @@ -36,7 +35,6 @@ class SecurityListRequestDataWriterListener : public eprosima::fastdds::dds::Dat std::thread([this, dwr]() { while (!_market_ptr->get_ready_to_trade()) { - //std::cout << "[Listener] Publishing Security Lise Exchange " << matched_ << std::endl; _market_ptr->publishSecurityListRequest(dwr); std::this_thread::sleep_for(std::chrono::seconds(1)); } @@ -46,11 +44,6 @@ class SecurityListRequestDataWriterListener : public eprosima::fastdds::dds::Dat else if (info.current_count_change == -1) { matched_ = info.total_count; - std::cout << "[Listener] Publisher UnMatched: " << matched_ << std::endl; - } - else - { - std::cout << "[Listener] Invalid current_count_change: " << info.current_count_change << std::endl; } } diff --git a/MiscATS/CryptoCLOB/README.md b/MiscATS/CryptoCLOB/README.md index 409895f..b7f35b2 100644 --- a/MiscATS/CryptoCLOB/README.md +++ b/MiscATS/CryptoCLOB/README.md @@ -23,8 +23,7 @@ The first matching engine consumes and processes orders from the instrument grou ### Starting ATS ``` - cd $DATS_HOME/MiscATS/CryptoCLOB/scipts - ./start_ats +BASEDIR_ATS=`pwd`/CryptoCLOB python3 start_ats.py --ats CryptoCLOB/crypto_ats.json ``` ## Test client diff --git a/MiscATS/MultiMatchingEngineATS/README.md b/MiscATS/MultiMatchingEngineATS/README.md index 183655d..a73d41c 100644 --- a/MiscATS/MultiMatchingEngineATS/README.md +++ b/MiscATS/MultiMatchingEngineATS/README.md @@ -24,8 +24,7 @@ The first matching engine consumes and processes orders from the instrument grou ### Starting ATS ``` - cd $DATS_HOME/MiscATS/MultiMatchingEngineATS/scipts - ./start_ats +BASEDIR_ATS=`pwd`/MultiMatchingEngineATS python3 start_ats.py --ats MultiMatchingEngineATS/multi_matching_engine.json ``` ## Test client diff --git a/MiscATS/USTreasuryCLOB/README.md b/MiscATS/USTreasuryCLOB/README.md index 32ffa96..d466bf0 100644 --- a/MiscATS/USTreasuryCLOB/README.md +++ b/MiscATS/USTreasuryCLOB/README.md @@ -25,8 +25,7 @@ The matching engine consumes and processes orders from the instrument group MARK ### Starting ATS ``` - cd $DATS_HOME/MiscATS/USTreasuryCLOB/scipts - ./start_ats + BASEDIR_ATS=`pwd`/USTreasuryCLOB python3 start_ats.py --ats USTreasuryCLOB/ust_ats.json ``` ## Test client From eb186d5f21970c645978c465a53a30480c762273 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 12 Oct 2025 18:22:09 +0000 Subject: [PATCH 19/27] updated asio cmake build --- cmake/DDSConfig.cmake | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/DDSConfig.cmake b/cmake/DDSConfig.cmake index 92bafa3..0764dda 100644 --- a/cmake/DDSConfig.cmake +++ b/cmake/DDSConfig.cmake @@ -10,15 +10,15 @@ if(NOT EXISTS "${DDS_INCLUDE_DIRS}/fastdds/config.hpp") include(ExternalProject) + ExternalProject_Add(ASIO - GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git - GIT_TAG asio-1-28-0 - UPDATE_DISCONNECTED TRUE - SOURCE_SUBDIR asio - INSTALL_DIR ${DDS_INSTALL_PREFIX} - CONFIGURE_COMMAND cd / && ./autogen.sh && ./configure --prefix=${DDS_INSTALL_PREFIX} --exec-prefix=${DDS_INSTALL_PREFIX} --without-boost - BUILD_COMMAND cd / && make - INSTALL_COMMAND cd / && make install + GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git + GIT_TAG asio-1-28-0 + UPDATE_DISCONNECTED TRUE + SOURCE_SUBDIR asio + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory /asio/include ${DDS_INSTALL_PREFIX}/include ) ExternalProject_Add(FoonathanMemory From b619b4cbd4796adfe59d5be58b7d03759992cf5c Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 12 Oct 2025 16:32:01 -0400 Subject: [PATCH 20/27] Update README.md --- README.md | 128 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 7eb3214..7573463 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,83 @@ DistributedATS is a [**FIX Protocol-based**](https://www.fixtrading.org) alterna ![N|Solid](https://raw.githubusercontent.com/mkipnis/DistributedATS/master/docs/Diagrams/CryptoCLOB.png?raw=true) [See: CryptoCLOB](https://github.com/mkipnis/DistributedATS/tree/master/MiscATS/CryptoCLOB) +### Examples +#### Crypto CLOB/ATS – three matching engines, each handling a subset of instruments. +* Users: CRYPTO_TRADER_1, CRYPTO_TRADER_2, CRYPTO_TRADER_3, CRYPTO_TRADER_4 : Password: TEST +* http://localhost:8080/ +``` +services: + fast_dds_discovery: + container_name: fast_dds_discovery + image: ghcr.io/mkipnis/distributed_ats:latest + command: > + bash -c "LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fastdds discovery -q 51000" + ports: + - "51000:51000" + + distributed_ats: + container_name: distributed_ats + image: ghcr.io/mkipnis/dats_crypto_clob:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "cd /usr/local && source ./dats_env.sh && cd MiscATS && BASEDIR_ATS=`pwd`/CryptoCLOB python3 start_ats.py --ats CryptoCLOB/crypto_ats.json" + volumes: + - ./logs_ats:/usr/local/MiscATS/CryptoCLOB/logs + ports: # FIX Gateways + - "15001:15001" + - "16001:16001" + - "17001:17001" + + distributed_ats_webtrader: + container_name: distributed_ats_webtrader + image: ghcr.io/mkipnis/distributed_ats_webtrader:latest + depends_on: + - distributed_ats + volumes: + - ./webtrader_logs:/usr/local/tomcat/logs + ports: + - "8080:8080" +``` + +#### US Treasuries CLOB/ATS – one matching engine that handles hundreds of instruments. +* Users: UST_TRADER_1, UST_TRADER_2, UST_TRADER_3, UST_TRADER_4 : Password: TEST +* http://localhost:8080/ +``` +services: + fast_dds_discovery: + container_name: discovery_service + image: ghcr.io/mkipnis/distributed_ats:latest + command: > + bash -c "LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fastdds discovery -q 51000" + ports: + - "51000:51000" + + distributed_ats: + container_name: distributed_ats + image: ghcr.io/mkipnis/dats_ust_clob:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "cd /usr/local && source ./dats_env.sh && cd MiscATS && BASEDIR_ATS=`pwd`/USTreasuryCLOB python3 start_ats.py --ats USTreasuryCLOB/ust_ats.json" + volumes: + - ./logs_ats:/usr/local/MiscATS/USTreasuryCLOB/logs + ports: # FIX Gateways + - "15001:15001" + - "16001:16001" + + # WebTrader Front-End + distributed_ats_webtrader: + container_name: distributed_ats_webtrader + image: ghcr.io/mkipnis/distributed_ats_webtrader:latest + depends_on: + - distributed_ats + volumes: + - ./webtrader_logs:/usr/local/tomcat/logs + ports: + - "8080:8080" +``` + ### Dependencies |Dependency|Component| @@ -71,54 +148,3 @@ DistributedATS is a [**FIX Protocol-based**](https://www.fixtrading.org) alterna ### Autogeneration of IDL from QuickFIX XML [GenTools](https://github.com/mkipnis/DistributedATS/tree/master/GenTools) is a utility that generates DDS IDL, FIX to IDL, and IDL to FIX adapters and IDL logger helper classes from QuickFIX's XML data dictionary. -### Building Distributed ATS and its dependencies - -To download and build all necessary dependencies, use the provided script: - -[download_deps_and_build_all.sh](https://github.com/mkipnis/DistributedATS/blob/master/download_deps_and_build_all.sh) - -To build the base Docker image: - -[Docker.Build_Distributed_ATS](https://github.com/mkipnis/DistributedATS/blob/master/docker/Docker.Build_Distributed_ATS) - - -## Basic ATS Examples -### Crypto Central Limit Order Book -- Docker Image: [Docker.Crypto_CLOB](https://github.com/mkipnis/DistributedATS/blob/master/docker/Docker.Crypto_CLOB) -- Docker Compose: [docker-compose-crypto.yml](https://github.com/mkipnis/DistributedATS/blob/master/docker/docker-compose-crypto.yml) -``` -sudo docker-compose -f docker-compose-crypto.yml up -d -``` -Upon starting the dockerized instance, open in the browser: -* http://localhost:8080 - -##### -Users: -- CRYPTO_TRADER_1 -- CRYPTO_TRADER_2 -- CRYPTO_TRADER_3 -- CRYPTO_TRADER_4 - -Password: -- TEST -##### - -### US Treasuries Central Limit Order Book - -- Docker Image: [Docker.UST_CLOB](https://github.com/mkipnis/DistributedATS/blob/master/docker/Docker.UST_CLOB) -- Docker Compose: [docker-compose-ust.yml](https://github.com/mkipnis/DistributedATS/blob/master/docker/docker-compose-ust.yml) -``` -sudo docker-compose -f docker-compose-ust.yml up -d -``` -Upon starting the dockerized instance, open in the browser: -* http://localhost:8080 -##### -Users: -- UST_TRADER_1 -- UST_TRADER_2 -- UST_TRADER_3 -- UST_TRADER_4 - -Password: -- TEST -###### From 74e3dcbde701b75c9fdf8b9f57e4986461fd08bc Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 12 Oct 2025 16:32:56 -0400 Subject: [PATCH 21/27] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7573463..4c6cfc1 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,11 @@ DistributedATS is a [**FIX Protocol-based**](https://www.fixtrading.org) alterna * [**Data Service**](https://github.com/mkipnis/DistributedATS/tree/master/DataService/src) authenticates users, provides reference data, services mass order status requests, and market data snapshots. Data Service services all non-critical to order flow DDS messages including *Logon*, *Logout*, *MassOrderStatusRequest*, *MarketDataSnapshot*. Data Service can service one or more FIX Gateways and Matching Engines. ![N|Solid](https://raw.githubusercontent.com/mkipnis/DistributedATS/master/docs/Diagrams/CryptoCLOB.png?raw=true) -[See: CryptoCLOB](https://github.com/mkipnis/DistributedATS/tree/master/MiscATS/CryptoCLOB) -### Examples -#### Crypto CLOB/ATS – three matching engines, each handling a subset of instruments. + + +## Examples +### Crypto CLOB/ATS – three matching engines, each handling a subset of instruments. * Users: CRYPTO_TRADER_1, CRYPTO_TRADER_2, CRYPTO_TRADER_3, CRYPTO_TRADER_4 : Password: TEST * http://localhost:8080/ ``` @@ -53,7 +54,8 @@ services: - "8080:8080" ``` -#### US Treasuries CLOB/ATS – one matching engine that handles hundreds of instruments. + +### US Treasuries CLOB/ATS – one matching engine that handles hundreds of instruments. * Users: UST_TRADER_1, UST_TRADER_2, UST_TRADER_3, UST_TRADER_4 : Password: TEST * http://localhost:8080/ ``` From 9cf96a778819be90f6527a843910441423bca565 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 12 Oct 2025 17:02:26 -0400 Subject: [PATCH 22/27] Update README.md --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4c6cfc1..9f01e94 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,13 @@ services: depends_on: - fast_dds_discovery command: > - bash -c "cd /usr/local && source ./dats_env.sh && cd MiscATS && BASEDIR_ATS=`pwd`/CryptoCLOB python3 start_ats.py --ats CryptoCLOB/crypto_ats.json" + bash -c "cd /usr/local && source ./dats_env.sh && + cd MiscATS && + BASEDIR_ATS=`pwd`/CryptoCLOB python3 start_ats.py --ats CryptoCLOB/crypto_ats.json" volumes: - ./logs_ats:/usr/local/MiscATS/CryptoCLOB/logs - ports: # FIX Gateways + ports: + # FIX Gateways - "15001:15001" - "16001:16001" - "17001:17001" @@ -74,7 +77,11 @@ services: depends_on: - fast_dds_discovery command: > - bash -c "cd /usr/local && source ./dats_env.sh && cd MiscATS && BASEDIR_ATS=`pwd`/USTreasuryCLOB python3 start_ats.py --ats USTreasuryCLOB/ust_ats.json" + bash -c "cd /usr/local && + source ./dats_env.sh && + cd MiscATS && + BASEDIR_ATS=`pwd`/USTreasuryCLOB + python3 start_ats.py --ats USTreasuryCLOB/ust_ats.json" volumes: - ./logs_ats:/usr/local/MiscATS/USTreasuryCLOB/logs ports: # FIX Gateways From 2941bd1b967cadf101934c99870e078460c05fec Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Sun, 12 Oct 2025 17:31:37 -0400 Subject: [PATCH 23/27] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9f01e94..4e6b146 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ services: bash -c "LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fastdds discovery -q 51000" ports: - "51000:51000" + restart: unless-stopped distributed_ats: container_name: distributed_ats @@ -77,16 +78,14 @@ services: depends_on: - fast_dds_discovery command: > - bash -c "cd /usr/local && - source ./dats_env.sh && - cd MiscATS && - BASEDIR_ATS=`pwd`/USTreasuryCLOB - python3 start_ats.py --ats USTreasuryCLOB/ust_ats.json" + bash -c "cd /usr/local && source ./dats_env.sh && + cd MiscATS && BASEDIR_ATS=`pwd`/USTreasuryCLOB python3 start_ats.py --ats USTreasuryCLOB/ust_ats.json" volumes: - ./logs_ats:/usr/local/MiscATS/USTreasuryCLOB/logs - ports: # FIX Gateways + ports: - "15001:15001" - "16001:16001" + restart: unless-stopped # WebTrader Front-End distributed_ats_webtrader: @@ -98,6 +97,7 @@ services: - ./webtrader_logs:/usr/local/tomcat/logs ports: - "8080:8080" + restart: unless-stopped ``` ### Dependencies From 6887ad1bc5b23c12c71c05e91ffa3c034d38d67a Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Thu, 23 Oct 2025 07:29:24 -0400 Subject: [PATCH 24/27] multi matching engine update --- .../src/main/resources/fixclient.cfg | 5 +- .../docker-compose-multi-matching-engine.yml | 101 ++++++++++++++++++ docker/docker-compose-webtrader.yml | 12 +++ docker/dockerize_dats.sh | 3 + docker/fixclient_docker.cfg | 1 - 5 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 docker/docker-compose-multi-matching-engine.yml create mode 100644 docker/docker-compose-webtrader.yml diff --git a/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg b/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg index b6014d8..73c3f0b 100644 --- a/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg +++ b/MiscClients/spring_reactjs/src/main/resources/fixclient.cfg @@ -1,9 +1,8 @@ [DEFAULT] ConnectionType=initiator TargetCompID=FIX_GWY_1 -#SocketConnectHost=distributed_ats -SocketConnectHost=127.0.0.1 -#SocketConnectHost=165.22.179.176 +SocketConnectHost=distributed_ats +#SocketConnectHost=127.0.0.1 StartTime=00:00:00 EndTime=24:00:00 HeartBtInt=30 diff --git a/docker/docker-compose-multi-matching-engine.yml b/docker/docker-compose-multi-matching-engine.yml new file mode 100644 index 0000000..e78e812 --- /dev/null +++ b/docker/docker-compose-multi-matching-engine.yml @@ -0,0 +1,101 @@ +version: '3.8' + +services: + + # DDS Discovery + fast_dds_discovery: + container_name: fast_dds_discovery + image: ghcr.io/mkipnis/distributed_ats:latest + command: > + bash -c "LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fastdds discovery -q 51000" + ports: + - "51000:51000" + restart: no + + + # FIX Gateways + fix_gateway_1: + container_name: distributed_ats + image: ghcr.io/mkipnis/multi_matching_engine_ats:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "/usr/local/bin/FIXGateway -c /usr/local/MiscATS/MultiMatchingEngineATS/config/fix_gwy_1.cfg" + environment: + - LOG_FILE_NAME=fix_gateway_1.log + volumes: + - ./logs:/var/log + ports: + - "15001:15001" + restart: no + + fix_gateway_2: + container_name: fix_gateway_2 + image: ghcr.io/mkipnis/multi_matching_engine_ats:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "/usr/local/bin/FIXGateway -c /usr/local/MiscATS/MultiMatchingEngineATS/config/fix_gwy_2.cfg" + environment: + - LOG_FILE_NAME=fix_gateway_2.log + volumes: + - ./logs:/var/log + ports: + - "16001:16001" + restart: no + + + # Data Services + data_service_a: + container_name: data_service_a + image: ghcr.io/mkipnis/multi_matching_engine_ats:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "/usr/local/bin/DataService -c /usr/local/MiscATS/MultiMatchingEngineATS/config/data_service_a.ini" + environment: + - LOG_FILE_NAME=data_service_a.log + volumes: + - ./logs:/var/log + restart: no + + data_service_b: + container_name: data_service_b + image: ghcr.io/mkipnis/multi_matching_engine_ats:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "/usr/local/bin/DataService -c /usr/local/MiscATS/MultiMatchingEngineATS/config/data_service_b.ini" + environment: + - LOG_FILE_NAME=data_service_b.log + volumes: + - ./logs:/var/log + restart: no + + + # Matching Engine + matching_engine_market_y: + container_name: market_y + image: ghcr.io/mkipnis/multi_matching_engine_ats:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "/usr/local/bin/MatchingEngine -c /usr/local/MiscATS/MultiMatchingEngineATS/config/matching_engine_MARKET_Y.ini" + environment: + - LOG_FILE_NAME=matching_engine_MARKET_Y.ini + volumes: + - ./logs:/var/log + restart: no + + matching_engine_market_z: + container_name: market_z + image: ghcr.io/mkipnis/multi_matching_engine_ats:latest + depends_on: + - fast_dds_discovery + command: > + bash -c "/usr/local/bin/MatchingEngine -c /usr/local/MiscATS/MultiMatchingEngineATS/config/matching_engine_MARKET_Z.ini" + environment: + - LOG_FILE_NAME=matching_engine_MARKET_Z.ini + volumes: + - ./logs:/var/log + restart: no diff --git a/docker/docker-compose-webtrader.yml b/docker/docker-compose-webtrader.yml new file mode 100644 index 0000000..3b74624 --- /dev/null +++ b/docker/docker-compose-webtrader.yml @@ -0,0 +1,12 @@ +version: '2' + +services: + # WebTrader Front-End + distributed_ats_webtrader: + container_name: distributed_ats_webtrader + image: ghcr.io/mkipnis/distributed_ats_webtrader:latest + volumes: + - ./webtrader_logs:/usr/local/tomcat/logs + ports: + - "8080:8080" + restart: no diff --git a/docker/dockerize_dats.sh b/docker/dockerize_dats.sh index 126bce9..539bba4 100755 --- a/docker/dockerize_dats.sh +++ b/docker/dockerize_dats.sh @@ -5,8 +5,11 @@ set -x # Core docker build -t ghcr.io/mkipnis/distributed_ats_deps:latest -f Docker.Build_DATS_Deps . docker build -t ghcr.io/mkipnis/distributed_ats:latest -f Docker.Build_Distributed_ATS . + +# Exchanges docker build --no-cache -t ghcr.io/mkipnis/dats_crypto_clob:latest -f Docker.Crypto_CLOB . docker build --no-cache -t ghcr.io/mkipnis/dats_ust_clob:latest -f Docker.UST_CLOB . +docker build --no-cache -t ghcr.io/mkipnis/multi_matching_engine_ats:latest -f Docker.MultiMatchingEngineATS . docker push ghcr.io/mkipnis/distributed_ats_deps:latest docker push ghcr.io/mkipnis/distributed_ats:latest diff --git a/docker/fixclient_docker.cfg b/docker/fixclient_docker.cfg index c6e2cbf..73c3f0b 100644 --- a/docker/fixclient_docker.cfg +++ b/docker/fixclient_docker.cfg @@ -3,7 +3,6 @@ ConnectionType=initiator TargetCompID=FIX_GWY_1 SocketConnectHost=distributed_ats #SocketConnectHost=127.0.0.1 -#SocketConnectHost=165.22.179.176 StartTime=00:00:00 EndTime=24:00:00 HeartBtInt=30 From 0f99a7a8095135d22a14920af9bab0204c848886 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Thu, 23 Oct 2025 07:38:31 -0400 Subject: [PATCH 25/27] Update README with Multi Matching Engine ATS details Added section for Multi Matching Engine ATS and Docker Compose files. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 4e6b146..73fba15 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,11 @@ services: restart: unless-stopped ``` +### Multi Matching Engine ATS, with each component running in a separate container +[Docker Compose - Multi Matching Engine ATS](docker/docker-compose-multi-matching-engine.yml) +[Docker Compose - WebTrader(docker/docker-compose-webtrader.yml) + + ### Dependencies |Dependency|Component| From c8216b75dc8fd4ae7f51e663f4ec896ca3ab2918 Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Thu, 23 Oct 2025 07:39:23 -0400 Subject: [PATCH 26/27] Fix formatting in README for Docker Compose links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73fba15..60fa61f 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,8 @@ services: ``` ### Multi Matching Engine ATS, with each component running in a separate container -[Docker Compose - Multi Matching Engine ATS](docker/docker-compose-multi-matching-engine.yml) -[Docker Compose - WebTrader(docker/docker-compose-webtrader.yml) +* [Docker Compose - Multi Matching Engine ATS](docker/docker-compose-multi-matching-engine.yml) +* [Docker Compose - WebTrader](docker/docker-compose-webtrader.yml) ### Dependencies From 5f507c4084a2d461089a5f6c75138f7dc61a733c Mon Sep 17 00:00:00 2001 From: Mike Kipnis Date: Thu, 23 Oct 2025 07:40:43 -0400 Subject: [PATCH 27/27] Fix typo in docker-compose file for matching engine --- docker/docker-compose-multi-matching-engine.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose-multi-matching-engine.yml b/docker/docker-compose-multi-matching-engine.yml index e78e812..f7c50fe 100644 --- a/docker/docker-compose-multi-matching-engine.yml +++ b/docker/docker-compose-multi-matching-engine.yml @@ -73,7 +73,7 @@ services: restart: no - # Matching Engine + # Matching Engines matching_engine_market_y: container_name: market_y image: ghcr.io/mkipnis/multi_matching_engine_ats:latest