Compare commits

..
5 Commits
360 changed files with 117623 additions and 135505 deletions

No files matched your search

+18
View File
@@ -7,6 +7,24 @@
"commands": [
"dotnet-format"
]
},
"fable": {
"version": "4.0.0-theta-018",
"commands": [
"fable"
]
},
"fantomas": {
"version": "5.2.2",
"commands": [
"fantomas"
]
},
"fake-cli": {
"version": "6.0.0",
"commands": [
"fake"
]
}
}
}
-129
View File
@@ -1,129 +0,0 @@
FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
# Note installations that take a while (more than 10s)
RUN apt-get update
RUN apt-get install -y ca-certificates
RUN apt-get install -y ccache
RUN apt-get install -y curl
RUN apt-get install -y fish
RUN apt-get install -y gdb
# git-all: ~250s
RUN apt-get install -y git-all
RUN apt-get install -y gnupg
# liblttng-ust-dev: ~30s
RUN apt-get install -y liblttng-ust-dev
RUN apt-get install -y libssh2-1-dev
RUN apt-get install -y locales
RUN apt-get install -y ninja-build
# openssh-server: ~40s
RUN apt-get install -y openssh-server
RUN apt-get install -y pkg-config
RUN apt-get install -y software-properties-common
RUN apt-get install -y sudo
RUN apt-get install -y tzdata
RUN apt-get install -y vim
RUN apt-get install -y zip
# Python: ~30s
RUN apt-get install -y \
python3-pip \
python3-venv \
&& python3 -m pip install --upgrade pip
# GCC
ARG gcc_major=13
RUN \
add-apt-repository ppa:ubuntu-toolchain-r/test \
&& apt-get update \
&& apt-get install -y g++-$gcc_major
# Clang
ARG clang_major=17
RUN \
curl -fsSL https://apt.llvm.org/llvm-snapshot.gpg.key 2> /dev/null \
| gpg --dearmor - \
| tee /usr/share/keyrings/llvm-snapshot.gpg > /dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-$clang_major main" \
| tee -a "/etc/apt/sources.list.d/llvm.list" \
&& apt-get update \
&& apt-get install -y \
clang-$clang_major \
clang-format-$clang_major \
clangd-$clang_major
# CMake
RUN \
curl -fsSL https://apt.kitware.com/keys/kitware-archive-latest.asc 2> /dev/null \
| gpg --dearmor - \
| tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" \
| tee /etc/apt/sources.list.d/kitware.list > /dev/null \
&& apt-get update \
&& apt-get install -y cmake
# Dotnet
RUN apt-get update && apt-get install -y dotnet7
# Node
ARG node_major=18
RUN mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$node_major.x nodistro main" \
| tee /etc/apt/sources.list.d/nodesource.list \
&& apt-get update \
&& apt-get install -y nodejs
# Emumba (deps)
RUN apt-get update && apt-get -y install rapidjson-dev
# Emumba
COPY emumba /emumba
RUN dpkg -i /emumba/emumba-deribit-connector-3.3.1-Linux.LICENSE_DISABLED.deb \
&& rm -r /emumba
# Pcap
RUN apt-get update && apt-get install -y libpcap0.8-dev
RUN apt-get update && apt-get install -y \
docker.io \
docker-compose \
docker-compose-v2
# Set up default executables (update-alternatives)
RUN \
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-$clang_major 100; \
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-$clang_major 100; \
update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-$clang_major 100; \
update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-$clang_major 100; \
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-$gcc_major 100; \
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-$gcc_major 100
# Add compiler symlinks for ccache
RUN \
ln -s /usr/bin/ccache /usr/local/bin/clang; \
ln -s /usr/bin/ccache /usr/local/bin/clang++; \
ln -s /usr/bin/ccache /usr/local/bin/clang-$clang_major; \
ln -s /usr/bin/ccache /usr/local/bin/clang++-$clang_major; \
ln -s /usr/bin/ccache /usr/local/bin/gcc; \
ln -s /usr/bin/ccache /usr/local/bin/g++
RUN locale-gen en_US.UTF-8
ARG docker_user="bts"
ARG docker_uid="1000"
ARG docker_pass="bts"
RUN \
groupadd -g "$docker_uid" "$docker_user" \
&& useradd \
-m \
-u "$docker_uid" \
-g "$docker_uid" \
-G sudo \
--password "$(openssl passwd -1 "$docker_pass")" \
"$docker_user"
RUN usermod -aG docker "$docker_user"
-43
View File
@@ -1,43 +0,0 @@
{
"dockerFile": "Dockerfile",
// Creates local dir to mount to HOME in docker
"initializeCommand": "mkdir -p ${localEnv:HOME}/.bts/devcontainer-mounts/${devcontainerId}",
"hostRequirements": {
"memory": "4gb",
"storage": "6gb"
},
"postCreateCommand": "/home/bts/spark/docker/sparkd/dev/devcontainer_post_create.sh",
"containerUser": "bts",
"workspaceMount": "source=${localWorkspaceFolder},target=/home/bts/spark,type=bind",
"workspaceFolder": "/home/bts/spark",
"updateRemoteUserUID": true,
"shutdownAction": "none",
// Note: If running multiple containers on the same host, each must use a
// unique set of ports. Usually we just add 1000 to each port as needed. For
// example, if 8000-8003 is taken, go with 9000-9003, then 10000-10003, etc.
"runArgs": [
"--shm-size",
"2gb",
"--network",
"host"
],
"mounts": [
"source=${localEnv:HOME}/.bts/devcontainer-mounts/${devcontainerId},target=/home/bts,type=bind",
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"customizations": {
"vscode": {
"settings": {
"clangd.arguments": [
"--compile-commands-dir=${workspaceFolder}/build/clang/debug"
]
},
"extensions": [
"eamodio.gitlens",
"llvm-vs-code-extensions.vscode-clangd",
"ms-vscode.cmake-tools",
"ms-vscode.cpptools"
]
}
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ trace_data/
/.ignore
*.rej
.clangd/
*CMakeDeps*.cmake
*CMakeDeps.cmake
/sniper.ipynb
/src/.clang-format
/src/server/sparkd/cmds/spartan/analysis/.ipynb_checkpoints
+6 -3
View File
@@ -1,6 +1,9 @@
[submodule "externals"]
path = externals
url = git@bitbucket.org:bluetradesys/externals.git
[submodule "vcpkg"]
path = vcpkg
url = https://github.com/microsoft/vcpkg.git
[submodule "docker/linux"]
path = docker/linux
url = git@bitbucket.org:bluetradesys/linux_docker.git
[submodule "docker/windows"]
path = docker/windows
url = git@bitbucket.org:bluetradesys/windows_docker.git
+76 -25
View File
@@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 3.12)
project(spark)
set(CMAKE_CXX_STANDARD 20)
if(WIN32)
set(platform "windows")
@@ -14,49 +13,101 @@ set(
CACHE
STRING
"External dependencies root folder (should contain folders: lib, bin, include")
set(EXTERNALS_BIN "${EXTERNALS_ROOT}/bin")
set(EXTERNALS_INCLUDE "${EXTERNALS_ROOT}/include")
set(EXTERNALS_LIB "${EXTERNALS_ROOT}/lib/$<CONFIG>")
set(BUILD_DOCS OFF CACHE BOOL "Build documentation")
set(SPARK_PYTHON "${EXTERNALS_ROOT}/python")
set(SPARK_BIN "${EXTERNALS_ROOT}/bin")
set(SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
set(BUILD_SDK OFF CACHE BOOL "Build the sdk")
set(EXPORT_MD_CONSUMER OFF CACHE BOOL "Export (extern) C functions for MD consumer interop")
if (WIN32)
set(BUILD_SPARKD OFF CACHE BOOL "Build sparkd")
set(BUILD_WEB OFF CACHE BOOL "Build the web server")
else()
set(BUILD_SPARKD ON CACHE BOOL "Build sparkd")
set(BUILD_WEB ON CACHE BOOL "Build the web server")
endif()
set(BUILD_WEB ON CACHE BOOL "Build the web server")
include_directories(BEFORE SYSTEM ${EXTERNALS_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${EXTERNALS_LIB})
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${SPARK_LIB})
add_compile_definitions(EXPORT_MD_CONSUMER="${EXPORT_MD_CONSUMER}")
if(WIN32)
# flags
set(
CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} \
/MP \
/WX /wd4251 /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 \
/bigobj \
/DCURL_STATICLIB \
/D_WINSOCK_DEPRECATED_NO_WARNINGS \
/D__TBB_NO_IMPLICIT_LINKAGE \
/DBOOST_ALL_NO_LIB \
/std:c++17 \
/D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} /MT")
set(
CMAKE_SHARED_LINKER_FLAGS_RELEASE
"${CMAKE_SHARED_LINKER_FLAGS_RELEASE} \
/DEBUG \
/OPT:REF \
/OPT:ICF \
/LTCG")
# subdirs
add_subdirectory(src/lib)
else()
# make sparkd look for libspark.so in its directory
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install/${CMAKE_BUILD_TYPE}/sparkd")
add_compile_definitions(SPARK_ENABLE_CCAPI)
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_FTX)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
# flags
set(
CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} \
-fPIC \
-Wall \
-pedantic \
-Wextra \
-Werror \
-Wno-missing-braces \
-Wno-ignored-qualifiers \
--std=c++17 -fdiagnostics-color")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -DNDEBUG -O3")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wno-undef")
# subdirs
if (BUILD_SPARKD)
add_subdirectory(src/server/sparkd)
add_subdirectory(src/data_files)
endif()
add_subdirectory(src/server/sparkd)
add_subdirectory(src/lib)
if (BUILD_WEB)
add_subdirectory(src/web)
endif()
if(BUILD_DOCS)
add_subdirectory(doc/user)
endif()
add_subdirectory(doc/user)
if(BUILD_SDK)
add_subdirectory(src/sdk)
endif()
add_subdirectory(src/data_files)
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/server
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/server/sparkd/sparkd ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/web ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/data_files ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
COMMAND
ln ARGS -sf
${EXTERNALS_ROOT}/lib/Release/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0
${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libACE-5.7.5.so ${CMAKE_BINARY_DIR}/server
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
COMMENT "Creating server runtime layout"
DEPENDS sparkd data_files_dir)
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
install(DIRECTORY "${CMAKE_BINARY_DIR}/server/plugins" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libACE-5.7.5.so" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/src/emumba/sparkd.lic" DESTINATION bin)
endif()
-215
View File
@@ -1,215 +0,0 @@
{
"version": 4,
"cmakeMinimumRequired": {
"major": 3,
"minor": 23,
"patch": 0
},
"configurePresets": [
{
"name": "spark",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build/${presetName}",
"environment": {
"SPARK_CMAKE_CXX_FLAGS": "/MP /WX /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 /bigobj /EHsc /DCURL_STATICLIB /D_WINSOCK_DEPRECATED_NO_WARNINGS /D__TBB_NO_IMPLICIT_LINKAGE /DBOOST_ALL_NO_LIB /std:c++20 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
},
"cacheVariables": {
"CMAKE_CXX_FLAGS": "$env{SPARK_CMAKE_CXX_FLAGS}",
"CMAKE_CXX_FLAGS_DEBUG": "$env{SPARK_CMAKE_CXX_FLAGS} /MTd",
"CMAKE_CXX_FLAGS_RELEASE": "$env{SPARK_CMAKE_CXX_FLAGS} /MT",
"CMAKE_CXX_STANDARD": "20",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
"CMAKE_SHARED_LINKER_FLAGS_DEBUG": "/DEBUG",
"CMAKE_SHARED_LINKER_FLAGS_RELEASE": "/OPT:REF /OPT:ICF /LTCG",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
"EXTERNALS_ROOT": "${sourceDir}/externals/windows",
"CONFIG_DEFAULTS_PATH": "config/defaults/*.conf",
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net7.0-windows",
"EXPORT_MD_CONSUMER": {
"type": "BOOL",
"value": "ON"
}
}
},
{
"name": "sparkd",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"platform": "",
"CMAKE_CXX_STANDARD": "20",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
"CMAKE_EXE_LINKER_FLAGS": "-Wno-undef",
"CONFIG_DEFAULTS_PATH": "config/defaults/*.conf",
"EXTERNALS_ROOT": "${sourceDir}/externals/linux",
"BUILD_SDK": {
"type": "BOOL",
"value": "OFF"
},
"BUILD_ADMIN_WEB_APP": {
"type": "BOOL",
"value": "ON"
}
}
},
{
"name": "sparkd-debug",
"inherits": "sparkd",
"hidden": true,
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_EXPORT_COMPILE_COMMANDS": {
"type": "BOOL",
"value": "ON"
},
"CCAPI_LOG_LEVEL": "Info"
}
},
{
"name": "sparkd-release",
"inherits": "sparkd",
"hidden": true,
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CCAPI_LOG_LEVEL": "Warn"
}
},
{
"name": "sparkd-debug-clang",
"inherits": "sparkd-debug",
"displayName": "Sparkd (Debug | Clang)",
"description": "Debug build compiled w/ clang",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -DDEBUG"
}
},
{
"name": "sparkd-debug-gcc",
"inherits": "sparkd-debug",
"displayName": "Sparkd (Debug | Gcc)",
"description": "Debug build compiled w/ gcc",
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -Wno-stringop-overread -DDEBUG"
}
},
{
"name": "sparkd-release-clang",
"inherits": "sparkd-release",
"displayName": "Sparkd (Release | Clang)",
"description": "Release build compiled w/ clang",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3"
}
},
{
"name": "sparkd-release-gcc",
"inherits": "sparkd-release",
"displayName": "Sparkd (Release | Gcc)",
"description": "Release build compiled w/ gcc",
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers -Wno-stringop-overflow --std=c++20 -fdiagnostics-color -Wno-stringop-overread -Wno-maybe-uninitialized -fno-omit-frame-pointer -DNDEBUG -O3"
}
}
],
"buildPresets": [
{
"name": "spark",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"hidden": true
},
{
"name": "spark-debug",
"displayName": "Spark (Debug)",
"inherits": "spark",
"configurePreset": "spark",
"configuration": "Debug"
},
{
"name": "spark-release",
"displayName": "Spark (Release)",
"inherits": "spark",
"configurePreset": "spark",
"configuration": "Release"
},
{
"name": "sparkd",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"hidden": true
},
{
"name": "sparkd-debug-clang",
"configurePreset": "sparkd-debug-clang",
"displayName": "Sparkd (Debug | Clang)",
"inherits": "sparkd"
},
{
"name": "sparkd-debug-clang-j6",
"configurePreset": "sparkd-debug-clang",
"displayName": "Sparkd (Debug | Clang | jobs=6)",
"inherits": "sparkd",
"jobs": 6
},
{
"name": "sparkd-debug-gcc",
"configurePreset": "sparkd-debug-gcc",
"displayName": "Sparkd (Debug | Gcc)",
"inherits": "sparkd"
},
{
"name": "sparkd-release-clang",
"configurePreset": "sparkd-release-clang",
"displayName": "Sparkd (Release | Clang)",
"inherits": "sparkd"
},
{
"name": "sparkd-release-gcc",
"configurePreset": "sparkd-release-gcc",
"displayName": "Sparkd (Release | Gcc)",
"inherits": "sparkd"
}
]
}
-39
View File
@@ -1,39 +0,0 @@
include(${CMAKE_SOURCE_DIR}/cmake/PackBasic.cmake)
include(GNUInstallDirs)
function(install_basic)
set(_options)
set(_one_value_args)
set(_multi_value_args HEADERS)
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
if (_ARGS_HEADERS)
set(${PROJECT_NAME}_HEADERS ${_ARGS_HEADERS})
else()
file(
GLOB_RECURSE ${PROJECT_NAME}_HEADERS
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.h
)
endif()
target_sources(${PROJECT_NAME}
PUBLIC
FILE_SET HEADERS FILES ${${PROJECT_NAME}_HEADERS})
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(
EXPORT ${PROJECT_NAME}Targets
FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
pack_basic()
endfunction()
-36
View File
@@ -1,36 +0,0 @@
include(CMakePackageConfigHelpers)
function(pack_basic)
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE PROJECT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
if(NOT GIT_FOUND OR PROJECT_VERSION STREQUAL "")
set(PROJECT_VERSION "0.0.0")
endif()
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
endfunction()
-12
View File
@@ -1,12 +0,0 @@
function(print_list var)
set(CMAKE_MESSAGE_INDENT "")
set(_var_str "")
foreach(item IN LISTS ${var})
set(_var_str "${_var_str}\n ${item}")
endforeach()
if ("${ARGN}" STREQUAL "VERBOSE")
message(VERBOSE "***${var}:${_var_str}")
else()
message("***${var}:${_var_str}")
endif()
endfunction()
+2 -2
View File
@@ -1,5 +1,5 @@
set(Protobuf_PROTOC_EXECUTABLE "${EXTERNALS_BIN}/protoc")
set(PROTOBUF_INCLUDE_DIRS "${EXTERNALS_INCLUDE}")
set(Protobuf_PROTOC_EXECUTABLE "${SPARK_BIN}/protoc")
set(PROTOBUF_INCLUDE_DIRS "${SPARK_INCLUDE}")
set(PROTOBUF_STATIC_LIB "libprotobuf")
function(Protobuf_Generate_Cpp SRCS HDRS)
Submodule
+1
Submodule docker/linux added at 6537812262.
+1
Submodule docker/windows added at de7d40c09d.
+5
View File
@@ -4,6 +4,8 @@ VisualStudioVersion = 17.3.32922.545
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\sparkcmd\sparkcmd.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
@@ -11,6 +13,9 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
ProjectSection(ProjectDependencies) = postProject
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25} = {FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
EndProject
@@ -63,9 +63,9 @@ namespace mbts.spark {
vs_input, vs_nonvol_data.contracts, aux_data_map);
_timer.stop();
var tag_str = tag == null ? "Null" : tag.ToString();
bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
$"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
$"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
// bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
// $"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
// $"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
_logger.log(_log_id, _log_id, _timer.lastIntervalTime);
_bb.post(_out_bb_computed_vol_tag, vs_output);
}
@@ -75,7 +75,7 @@ namespace mbts.spark {
var exp_price_map = OptionDriverPriceMap.get_vs_price_map(
all_sym_price_map, (s) => _option_symbols.Contains(s));
if (sc_data != null && vs_nonvol_input != null && exp_price_map != null) {
bts.Log.Gen.info($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
bts.Log.Gen.diag($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
"publishing VolSurfaceNonVolData");
_bb.post(_out_bb_vs_nonvol_data_tag,
new VolSurfaceNonVolData(
@@ -81,7 +81,7 @@ namespace mbts.analytics {
output.Add(symbol, symbol_data);
}
IReadOnlyDictionary<string, TData> ro_output = output;
bts.Log.Gen.info($"SymbolAggregationPublisher._on_timer publishing " +
bts.Log.Gen.diag($"SymbolAggregationPublisher._on_timer publishing " +
$"tag: {_out_tag} sz: {ro_output.Count}");
_bb.post(_out_tag, ro_output);
}
@@ -28,9 +28,10 @@ namespace mbts.spark {
_candidate_value.Changed += on_candidate_changed;
_is_dirty.Changed += (o, n) => {
Log.assert(o != n);
Log.Ui.info(
$"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
$"commited: {committed_value}; candidate: {candidate_value}");
// TODO: John, this was logged too many times
// Log.Ui.info(
// $"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
// $"commited: {committed_value}; candidate: {candidate_value}");
};
void on_committed_changed(object? oldval, object? newval) =>
@@ -3,16 +3,15 @@
using mbts.co2;
namespace mbts.analytics {
using Size = System.Single;
public class VolSurfaceMDUnit : IEquatable<VolSurfaceMDUnit> {
public readonly double bid_price, ask_price;
public readonly Size bid_size, ask_size;
public readonly uint bid_size, ask_size;
public readonly double mark_price = double.NaN;
private static VolSurfaceMDUnit _empty =
new VolSurfaceMDUnit(Double.NaN, 0, Double.NaN, 0, Double.NaN);
public VolSurfaceMDUnit(double this_bid_price, Size this_bid_size,
double this_ask_price, Size this_ask_size,
public VolSurfaceMDUnit(double this_bid_price, uint this_bid_size,
double this_ask_price, uint this_ask_size,
double this_mark_price) {
bid_price = this_bid_price;
bid_size = this_bid_size;
@@ -29,7 +28,7 @@ namespace mbts.analytics {
public VolSurfaceMDUnit(NativePriceSize bid, NativePriceSize ask,
double mark_price)
: this(bid.price, bid.size_f, ask.price, ask.size_f, mark_price) {
: this(bid.price, bid.size, ask.price, ask.size, mark_price) {
}
public bool is_two_sided() { return bid_size != 0 && ask_size != 0; }
@@ -42,7 +41,7 @@ namespace mbts.analytics {
}
public double get_weighted_mid_price(bool get_one_sided_mid = true) {
Size sum_q = bid_size + ask_size;
uint sum_q = bid_size + ask_size;
if (sum_q == 0) {
return Double.NaN;
}
@@ -88,8 +88,8 @@ namespace mbts.analytics {
public void set_driver_price(
IDictionary<VolSurfaceExpiration, double> driver_price_map) {
Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_driver_price " +
$"vs_id: {_vs_id} exp_count: {driver_price_map.Count}");
// Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_driver_price " +
// $"vs_id: {_vs_id} exp_count: {driver_price_map.Count}");
_driver_price_map = new Dictionary<VolSurfaceExpiration, double>(driver_price_map);
_compute_and_fire(InputType.DriverPrice);
}
+2 -8
View File
@@ -52,23 +52,17 @@ namespace bts {
string rv = "MergedMDDaemon Options:\n";
foreach (var kv in sec_map) {
var sec = kv.Value.security;
var md = kv.Value.md;
ulong time = 0;
NativePriceSize bid, ask;
var has_md = md.get_bbo(ref time, out bid, out ask);
if (sec.HasOption) {
rv += $"id: {kv.Key} desc: {sec.security_desc()} sym: {sec.Symbol} " +
$"exp: {sec.security_expiration()} " +
$"k: {sec.Option.Strike} cp: {sec.Option.CallPut} " +
$"bid: p: {bid.price} q: {bid.size} qf: {bid.size_f} ask: p: {ask.price} q: {ask.size} qf: {ask.size_f}" +
"\n";
$"k: {sec.Option.Strike} cp: {sec.Option.CallPut}" + "\n";
}
}
Log.Gen.info(rv);
}
private void _on_server_sec_map(IReadOnlyDictionary<uint, SecurityMD> sec_map) {
_log_options(sec_map);
//_log_options(sec_map);
bts.Log.Gen.info(String.Format("MergedMDDaemon._on_server_sec_map sz: {0}", sec_map.Count()));
_server_sec_map = new Dictionary<uint, SecurityMD>(sec_map);
_merge_and_post();
@@ -218,14 +218,10 @@ namespace mbts.spark {
background = buy_sell_background_fill_color;
hoverbackground = _mk_hover_bg_brush(dark, _darkbg, 0);
_num_root_orders = 0;
_filled = 0;
_quantity = 0;
foreach (var n in _root_nodes) {
_num_root_orders++;
_filled += n.filled_quantity();
_quantity += n.quantity();
}
(_num_root_orders, _filled, _quantity) = _root_nodes
.Select(n => (1u, n.filled_quantity(), n.quantity()))
.Sum();
if (_num_root_orders == 1) {
var order = _root_nodes.First();
border = _owner.model.order_gateway.factory.get_metadata(order).Color.rgb_brush();
+30 -8
View File
@@ -1,10 +1,12 @@
using mbts.analytics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BCG {
using Size = System.Single;
public enum BidAskAlertZone { buy, sell, none }
public class BBOPacket {
public enum MarketSide {
@@ -13,8 +15,8 @@ namespace BCG {
private double _bid_price => md.bid_price;
private double _ask_price => md.ask_price;
private Size _bid_size => md.bid_size;
private Size _ask_size => md.ask_size;
private UInt32 _bid_size => md.bid_size;
private UInt32 _ask_size => md.ask_size;
private static BBOPacket _null_pack = new BBOPacket(VolSurfaceMDUnit.empty);
public readonly VolSurfaceMDUnit md;
@@ -22,6 +24,21 @@ namespace BCG {
this.md = md;
}
public static bool bid_through_theo(BBOPacket md, mbts.spark.TheoPoint tp, bool is_call) {
return false;
// if (tp != null && md != null && md._md_row != null)
// return get_bid_price(md) > (is_call ? tp.call : tp.put);
// else
// return false;
}
public static bool ask_through_theo(BBOPacket md, mbts.spark.TheoPoint tp, bool is_call) {
// if (tp != null && md != null && md._md_row != null)
// return get_ask_price(md) < (is_call ? tp.call : tp.put);
// else
return false;
}
public static double get_mid_price(BBOPacket md) {
return (get_bid_price(md) + get_ask_price(md)) / 2.0;
}
@@ -30,16 +47,21 @@ namespace BCG {
return md != null ? md._bid_price : Double.NaN;
}
public static Size get_bid_size(BBOPacket md) {
return md != null ? md._bid_size : (Size)0;
public static UInt32 get_bid_size(BBOPacket md) {
return md != null ? md._bid_size : (UInt32)0;
}
public static double get_ask_price(BBOPacket md) {
return md != null ? md._ask_price : Double.NaN;
}
public static Size get_ask_size(BBOPacket md) {
return md != null ? md._ask_size : (Size)0;
public static UInt32 get_ask_size(BBOPacket md) {
return md != null ? md._ask_size : (UInt32)0;
}
public static Tuple<double, UInt32> get_md(BBOPacket md, bool is_bid) {
double price = is_bid ? BBOPacket.get_bid_price(md) : BBOPacket.get_ask_price(md);
UInt32 sz = is_bid ? BBOPacket.get_bid_size(md) : BBOPacket.get_ask_size(md);
return Tuple.Create(price, sz);
}
}
}
@@ -123,6 +123,15 @@ namespace BCG {
#endregion
#region Orders
[System.ComponentModel.Category("Orders / Algo")]
[System.ComponentModel.DisplayName("Default Account")]
public string Account { get; set; }
[System.ComponentModel.Category("Orders / Algo")]
[System.ComponentModel.DisplayName("Default Qty")]
public Nullable<double> DefaultQty { get; set; }
#endregion
public NMSheetSettingLayout() {
show_settings_header = false;
show_exp_navigator = false;
@@ -18,6 +18,7 @@ using mbts.spark.filters;
using System.Collections;
using System.Reactive.Linq;
using System.Threading;
using bts.api.orderman;
namespace BCG {
public partial class NMSheetControl : UserControl {
@@ -555,6 +556,17 @@ namespace BCG {
}
private void _launch_order_entry_window(NMSheetTheoGrid.GridCell cell,
OrderEntryWindow window_type) {
Func<string, bts.AccountTuple> get_account = (string default_acc) => {
string account = _settings.setting_layout.Account;
if (String.IsNullOrEmpty(account)) {
account = default_acc;
}
Nullable<uint> id = _get_account_id(account);
if (!id.HasValue) {
id = 0;
}
return new bts.AccountTuple(id.Value, account);
};
uint key;
var found = _sheet_data.get_security_key(cell.expiration,
cell.strike, cell.call_selected, out key);
@@ -566,7 +578,20 @@ namespace BCG {
if (sc_data.sec_md_map.TryGetValue(key, out var smd)) {
switch (window_type) {
case OrderEntryWindow.Ticket:
_threaded_bb.post(SparkTags.ShowOrderTicketFromSecurityTag, smd);
bool is_bid = NMSheetSettingColumnOrganization.get_column_info(cell.col).is_bid;
bts.AccountTuple acc_tup = get_account("SMALL");
Nullable<double> qty = _settings.setting_layout.DefaultQty;
OrderDefinition od = new OrderDefinition() {
SecurityKey = smd.id,
TimeInForce = TimeInForce.Gtc,
Account = acc_tup.name,
AccountId = acc_tup.id
};
BBOPacket bbo = _sheet_data.get_bbo(smd.id);
Tuple<double, UInt32> pr_sz = BBOPacket.get_md(bbo, is_bid);
UInt32 effective_qty = qty.HasValue ? Convert.ToUInt32(Math.Abs(qty.Value)) : pr_sz.Item2;
_threaded_bb.post(SparkTags.ShowOrderTicketTag,
(new OrderDefinitionImmutable(od), pr_sz.Item1, effective_qty));
break;
case OrderEntryWindow.Ladder:
_threaded_bb.post(SparkTags.ShowLadderTag, smd);
@@ -190,24 +190,13 @@ namespace mbts.analytics {
}
}
void _compute_swipe_sum() {
swipe_sum_puts = 0;
swipe_sum_calls = 0;
swipe_sum_net = 0;
foreach (var (row, exps) in _visible_selected_cells) {
foreach (var exp in exps) {
var (p, c, n) = row.get_cell_values(exp);
if (!p.is_nan()) {
swipe_sum_puts += p;
}
if (!c.is_nan()) {
swipe_sum_calls += c;
}
if (!n.is_nan()) {
swipe_sum_net += n;
}
}
}
}
void _compute_swipe_sum() =>
(swipe_sum_puts, swipe_sum_calls, swipe_sum_net) = _visible_selected_cells
.SelectMany(tup =>
tup.exps.Select(exp => {
var (p, c, n) = tup.row.get_cell_values(exp);
return (p.if_nan(0), c.if_nan(0), n.if_nan(0));
}))
.Sum();
}
}
@@ -121,7 +121,7 @@ namespace mbts.analytics {
timer.stop();
Log.Ui.info($"PNLReportCalculator n_pos: {output.position_data.Count()} " +
$"n_day_trades: {output.day_trades.Count()} time(msecs): {timer.lastIntervalTime}");
_log_before_posting(output.position_data);
//_log_before_posting(output.position_data);
_bus.post(SparkTags.ReportBlackboardTags.PNL.PNLData, output);
});
}
@@ -115,21 +115,21 @@ namespace mbts.analytics {
}
private void _handle_nonvol_data(VolSurfaceNonVolData vs_nonvol_data) {
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
_report.ReportName));
// bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
// _report.ReportName));
_vs_nonvol_data = vs_nonvol_data;
}
private void _handle_future_prices(
IReadOnlyDictionary<SecurityExpiration, FutureTheoStructure> future_prices_map) {
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_future_prices report {0}",
_report.ReportName));
// bts.Log.Gen.Diag(String.Format("SlideReportCalculator._handle_future_prices report {0}",
// _report.ReportName));
_future_prices_map = future_prices_map.ToDictionary(kv => kv.Key, kv => kv.Value.theo);
}
private void _handle_trades(IEnumerable<ITradeLogRow> trades) {
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_trades report {0}",
_report.ReportName));
// bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_trades report {0}",
// _report.ReportName));
_all_trades = trades.Where(t => t.is_active);
if (_report.CalcMode == Report.Types.ReportCalculationMode.PositionOrTheoChange) {
_compute_dirty = true;
+20 -32
View File
@@ -1,5 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
@@ -22,39 +21,33 @@
<RootNamespace>bts</RootNamespace>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<Version>$(major).$(minor).$(patch)</Version>
<Version Condition="'$(version)'=='..'">1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
<PackageReference Include="IronPython" Version="3.4.1" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="NAudio" Version="2.0.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="OxyPlot.Core" Version="2.1.2" />
<PackageReference Include="OxyPlot.Wpf" Version="2.1.2" />
<PackageReference Include="protobuf-net" Version="3.2.26" />
<PackageReference Include="System.Composition" Version="7.0.0-preview.2.22152.2" />
<PackageReference Include="System.Composition.AttributedModel" Version="7.0.0-preview.2.22152.2" />
<PackageReference Include="System.Composition.Hosting" Version="7.0.0-preview.2.22152.2" />
<PackageReference Include="System.Composition.TypedParts" Version="7.0.0-preview.2.22152.2" />
<PackageReference Include="System.Reactive" Version="6.0.0" />
<PackageReference Include="System.Reactive.Core" Version="6.0.0" />
<PackageReference Include="System.Reactive.Interfaces" Version="6.0.0" />
<PackageReference Include="System.Reactive.Linq" Version="6.0.0" />
<PackageReference Include="System.Reactive.PlatformServices" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\spark_api\spark_api.csproj" />
<ProjectReference Include="..\spark_core\spark_core.csproj" />
<PackageReference Include="System.Reactive.Core" Version="5.0.0" />
<PackageReference Include="System.Reactive.Interfaces" Version="5.0.0" />
<PackageReference Include="System.Reactive.Linq" Version="5.0.0" />
<PackageReference Include="System.Reactive.PlatformServices" Version="5.0.0" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<ProjectReference Include="../spark_api/spark_api.csproj" />
<ProjectReference Include="../spark_core/spark_core.csproj" />
<PackageReference Include="Google.Protobuf" Version="3.21.4" />
<PackageReference Include="IronPython" Version="2.7.12" />
<PackageReference Include="NAudio" Version="2.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
<PackageReference Include="protobuf-net" Version="3.1.17" />
<PackageReference Include="OxyPlot.Core" Version="2.1.2" />
<PackageReference Include="OxyPlot.Wpf" Version="2.1.2" />
</ItemGroup>
<ItemGroup>
@@ -62,20 +55,15 @@
<Resource Include="**/*.png" />
<ConfigDefaults Include="../../lib/config/defaults/*.conf" />
</ItemGroup>
<ItemGroup>
<Resource Remove="logo.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="logo.ico" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Sounds/game_sound_correct.wav" />
<EmbeddedResource Include="Sounds/whistle.wav" />
</ItemGroup>
<Target Name="diagnostic" AfterTargets="PreBuildEvent" />
</Project>
+2 -2
View File
@@ -35,7 +35,7 @@ namespace bts.core {
// TODO: for debugging purposes, remove it later
if (tag != mbts.spark.SparkTags.SparkTimer) {
var tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
bts.Log.Ui.diag($"SimpleBus.post tag:{tag} tid:{tid}");
//bts.Log.Ui.diag($"SimpleBus.post tag:{tag} tid:{tid}");
return;
}
} catch (Exception e) {
@@ -45,7 +45,7 @@ namespace bts.core {
public IObservable<T> subscribe<T>(ITag<T> tag) {
var tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
bts.Log.Ui.info($"SimpleBus.post tag:{tag} tid:{tid}");
//bts.Log.Ui.info($"SimpleBus.subscribe tag:{tag} tid:{tid}");
return subject<T>(tag);
}
}
@@ -162,7 +162,7 @@
// Compare bids
if (direct.int_price == implied.int_price) {
bid[x] = new NativePriceSize(direct.int_price, direct.size_f, implied.size_f);
bid[x] = new NativePriceSize(direct.int_price, direct.size, implied.size);
dbid_idx++;
ibid_idx++;
}
@@ -185,7 +185,7 @@
// Compare asks
if (direct.int_price == implied.int_price) {
ask[x] = new NativePriceSize(direct.int_price, direct.size_f, implied.size_f);
ask[x] = new NativePriceSize(direct.int_price, direct.size, implied.size);
dask_idx++;
iask_idx++;
}
@@ -1,15 +1,14 @@
namespace mbts.co2 {
using System.Runtime.InteropServices;
using Size = System.Single;
[StructLayout(LayoutKind.Sequential)]
public readonly struct NativePriceLevel {
readonly IntPrice _bid;
readonly IntPrice _ask;
readonly Size _bid_size;
readonly Size _ask_size;
readonly uint _bid_size;
readonly uint _ask_size;
public NativePriceLevel(IntPrice bid, Size bid_size, IntPrice ask, Size ask_size) {
public NativePriceLevel(IntPrice bid, uint bid_size, IntPrice ask, uint ask_size) {
_bid = bid;
_bid_size = bid_size;
_ask = ask;
@@ -5,29 +5,27 @@ namespace mbts.co2 {
using System;
using System.Runtime.InteropServices;
using Size = System.Single;
public readonly struct NativePriceSize : IEquatable<NativePriceSize> {
readonly IntPrice _price;
readonly Size _size;
readonly Size _direct_size;
readonly uint _size;
readonly uint _direct_size;
static NativePriceSize() =>
Log.assert(Marshal.SizeOf<NativePriceSize>() == 16);
public NativePriceSize(IntPrice price, Size size) {
public NativePriceSize(IntPrice price, uint size) {
_price = price;
_size = size;
_direct_size = size;
}
public NativePriceSize(long mantissa, sbyte exponent, Size size) {
public NativePriceSize(long mantissa, sbyte exponent, uint size) {
_price = new IntPrice(mantissa, exponent);
_size = size;
_direct_size = size;
}
public NativePriceSize(IntPrice price, Size direct_size, Size implied_size) {
public NativePriceSize(IntPrice price, uint direct_size, uint implied_size) {
_price = price;
_size = direct_size + implied_size;
_direct_size = direct_size;
@@ -38,18 +36,15 @@ namespace mbts.co2 {
public IntPrice int_price => _price;
public long mantissa => _price.mantissa;
public sbyte exponent => _price.exponent;
public uint size => (uint)_size;
public uint direct_size => (uint)_direct_size;
public uint implied_size => (uint)(_size - _direct_size);
public Size size_f => _size;
public Size direct_size_f => _direct_size;
public Size implied_size_f => _size - _direct_size;
public uint size => _size;
public uint direct_size => _direct_size;
public uint implied_size => _size - _direct_size;
public double price => _price.price();
public bool is_nan => _price.is_nan;
public override string ToString() =>
$"{price} {size_f} ({implied_size})";
$"{price} {size} ({implied_size})";
public override bool Equals(object obj) =>
obj is NativePriceSize p ? Equals(p) : base.Equals(obj);
+4 -5
View File
@@ -3,14 +3,13 @@ using mbts.co2;
namespace bts.md
{
using Size = System.Single;
public class PriceSize
{
public Size size { get; }
public Size direct_size { get; }
public Size implied_size { get; }
public uint size { get; }
public uint direct_size { get; }
public uint implied_size { get; }
public double price { get; }
public PriceSize(Size sz, Size direct_sz, Size implied_sz, double prx)
public PriceSize(uint sz, uint direct_sz, uint implied_sz, double prx)
{
size = sz;
direct_size = direct_sz;
@@ -1,7 +1,6 @@
namespace bts.api {
using System;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
public static class SecurityExtensions {
public static Security.ContractOneofCase contract_case(this SecurityType type) =>
@@ -97,8 +96,6 @@ namespace bts.api {
return security.Ice.SecurityDesc;
} else if (security.HasDeribit) {
return security.Deribit.SecurityDesc;
} else if (security.HasFtx) {
return security.Ftx.SecurityDesc;
}
Log.assert(false, "security_desc not implemented for exchange");
return null;
@@ -139,7 +136,6 @@ namespace bts.api {
domain.Venue.Bts => Venue.Bts,
domain.Venue.Sim => Venue.Sim,
domain.Venue.Deribit => Venue.Deribit,
domain.Venue.Ftx => Venue.Ftx,
domain.Venue.Glbx => Venue.Glbx,
domain.Venue.None => Venue.Unset,
_ => throw new NotImplementedException(),
@@ -150,7 +146,6 @@ namespace bts.api {
Venue.Bts => domain.Venue.Bts,
Venue.Sim => domain.Venue.Sim,
Venue.Deribit => domain.Venue.Deribit,
Venue.Ftx => domain.Venue.Ftx,
Venue.Glbx => domain.Venue.Glbx,
Venue.Unset => domain.Venue.None,
_ => throw new NotImplementedException(),
@@ -45,7 +45,7 @@
string.IsNullOrEmpty(exch_desc) ? format_option(symbol, option) : exch_desc;
static string _format(SecurityImmutable? security) =>
security.HasValue ? _format(security.Value) : "Unknown-security1";
security.HasValue ? _format(security.Value) : "Unknown-security";
static string _format(SecurityImmutable security, bool exchange_specific_formatting = true) {
switch (security.ContractCase) {
@@ -71,10 +71,8 @@
return string.Join("", _format_legs(new ContractLegEnumerable(security.Spread.Legs, 1)));
case Security.ContractOneofCase.Synthetic:
return security.Synthetic.Name;
case Security.ContractOneofCase.Spot:
return security.security_desc();
default:
return "Unknown-security2";
return "Unknown-security";
}
}
-34
View File
@@ -79,40 +79,6 @@ Misc:
To search for a publisher for an event search for make_stream<Event_Name>, for
example make_stream<OrderStateUpdateEvent>()
--------------------------------------------------------------------------
market data
--------------------------------------------------------------------------
adding exchanges:
the following places need to accommodate exchanges
managed:
- SecurityExtensions: public static string security_desc(this SecurityImmutable security) ..
- SecurityExtensions: public static Venue to_venue(this domain.Venue api_venue) ..
- SecurityExtensions: public static domain.Venue to_api_venue(this Venue venue) ..
C++
- AdminServiceUtils.cpp, 6 switch statements should compilation error
- Symbols.proto in Symbols
- Symbols.conf exchange section in SymbolLists and Symbols
- Security.proto, 3 places
- PlatformLoader.cpp, in get_system_md_symbols(), could be concverted into switch
- FixedSecurity.cpp, exchange_id(..) and convert_security(..) both switch
- QueryServer set_mic, switch
- VenueOption name(..) switch
---------------------------------------------------------------------------
adding security type
---------------------------------------------------------------------------
modified: src/lib/api/service_helpers/AdminServiceUtils.cpp
modified: src/lib/domain_model/Security.cpp
modified: src/lib/domain_model/Security.proto
modified: src/lib/md/MDConsumer.cpp
modified: src/lib/md/PlatformLoader.cpp
modified: src/lib/md/SecurityMapper.cpp
modified: src/lib/md/Shm/FixedSecurity.cpp
modified: src/lib/md/Shm/FixedSecurity.h
modified: src/lib/md/ccApi/CCMain.cpp
modified: src/lib/md/ccApi/CCMarketDataListener.cpp
modified: src/lib/md/relay/RelayClient.cpp
modified: src/lib/orderman/limiter/Limiter.cpp
ALGO:
----
+1
View File
@@ -0,0 +1 @@
set(sources api/analytics/ExpirationDriver.proto;api/analytics/TimeWeightedInterpolatedDriver.proto;api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/domain/Currency.proto;api/domain/SecurityCriteria.proto;api/domain/SecurityCriteriaClause.proto;api/domain/SecurityExpiration.proto;api/domain/SecurityMetadata.proto;api/domain/SecurityMetadataCollection.proto;api/domain/SecurityMetadataItem.proto;api/domain/SecurityType.proto;api/domain/TickDisplaySettings.proto;api/domain/TickFactors.proto;api/domain/Venue.proto;api/io/URL.proto;api/md/MarketDataSubscriptionParams.proto;api/md/binance/BinanceDepthStreamParams.proto;api/md/binance/BinanceMarketDataSubscriptionParams.proto;api/md/deribit/DeribitMarketDataSubscriptionParams.proto;api/md/ftx/FTXDepthStreamParams.proto;api/md/ftx/FTXMarketDataSubscriptionParams.proto;api/md/glbx/GlbxMarketDataSubscriptionParams.proto;api/md/huobi/HuobiMarketDataSubscriptionParams.proto;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/service_helpers/PositionUtilities.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/AnalyticsService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/BasePositionService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/MarketDataService.proto;api/services/MoneyFileService.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;communincation/websockets/tests/WebsocketSyncClientTests.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/SecurityMetadataCollection.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/position_cfg.conf;config/defaults/span.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/algo_types.proto;config/protos/cme_reference_data.proto;config/protos/exchange_sim_cfg.proto;config/protos/jetfix.proto;config/protos/keycode.proto;config/protos/logging.proto;config/protos/market_data.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/ports.proto;config/protos/position_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.proto;config/protos/spartan.proto;config/protos/spreader.proto;config/protos/subprocess.proto;config/protos/symbols.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/protos/ui.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain/AggressorSide.cpp;domain/NewOrder.cpp;domain/OrderDefinition.cpp;domain/OrderStatus.cpp;domain/OrderUpdate.cpp;domain/Side.cpp;domain/TimeInForce.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/sod.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;io/QueryParams.cpp;io/URL.cpp;io/http/CurlHandle.cpp;io/http/HTTPClient.cpp;io/http/HTTPHeaders.cpp;io/http/HTTPRequest.cpp;io/http/HTTPResponse.cpp;io/websocket/WebsocketClient.cpp;io/websocket/WebsocketClientConfiguration.cpp;io/websocket/WebsocketError.cpp;io/websocket/WebsocketMessage.cpp;io/websocket/WebsocketSSLClientInternal.cpp;io/websocket/tests/WebsocketClientTests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGatLine truncated
+1
View File
@@ -0,0 +1 @@
set(sources api/analytics/ExpirationDriver.proto;api/analytics/TimeWeightedInterpolatedDriver.proto;api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/domain/Currency.proto;api/domain/SecurityCriteria.proto;api/domain/SecurityCriteriaClause.proto;api/domain/SecurityExpiration.proto;api/domain/SecurityMetadata.proto;api/domain/SecurityMetadataCollection.proto;api/domain/SecurityMetadataItem.proto;api/domain/SecurityType.proto;api/domain/TickDisplaySettings.proto;api/domain/TickFactors.proto;api/domain/Venue.proto;api/io/URL.proto;api/md/MarketDataSubscriptionParams.proto;api/md/binance/BinanceDepthStreamParams.proto;api/md/binance/BinanceMarketDataSubscriptionParams.proto;api/md/deribit/DeribitMarketDataSubscriptionParams.proto;api/md/ftx/FTXDepthStreamParams.proto;api/md/ftx/FTXMarketDataSubscriptionParams.proto;api/md/glbx/GlbxMarketDataSubscriptionParams.proto;api/md/huobi/HuobiMarketDataSubscriptionParams.proto;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/service_helpers/PositionUtilities.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/AnalyticsService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/BasePositionService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/MarketDataService.proto;api/services/MoneyFileService.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/SecurityMetadataCollection.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/position_cfg.conf;config/defaults/span.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/algo_types.proto;config/protos/cme_reference_data.proto;config/protos/exchange_sim_cfg.proto;config/protos/jetfix.proto;config/protos/keycode.proto;config/protos/logging.proto;config/protos/market_data.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/ports.proto;config/protos/position_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.proto;config/protos/spartan.proto;config/protos/spreader.proto;config/protos/subprocess.proto;config/protos/symbols.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/protos/ui.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/sod.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;io/QueryParams.cpp;io/URL.cpp;io/http/CurlHandle.cpp;io/http/HTTPClient.cpp;io/http/HTTPHeaders.cpp;io/http/HTTPRequest.cpp;io/http/HTTPResponse.cpp;io/websocket/WebsocketClient.cpp;io/websocket/WebsocketClientConfiguration.cpp;io/websocket/WebsocketError.cpp;io/websocket/WebsocketMessage.cpp;io/websocket/WebsocketSSLClientInternal.cpp;io/websocket/tests/WebsocketClientTests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/CCApiDepthWalker.cpp;md/CCApiListenerAdaptor.cpp;md/CCApiRequestor.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MBOProcessor.cpp;md/MBOServiceServer.cpp;md/MDClient.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MarketDataError.cpp;md/MarketDataGateway.cpLine truncated
+162 -76
View File
@@ -1,84 +1,170 @@
cmake_minimum_required(VERSION 3.5)
project(libspark)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
include(GNUInstallDirs)
include(${CMAKE_SOURCE_DIR}/cmake/safe_dep_glob.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/Protobuf.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateDefaultConfig.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/PrintList.cmake)
if (DEFINED DOTNET_BINARY_DIR OR DEFINED DOTNET_WINDOWS_BINARY_DIR)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/AddCopyBinariesTarget.cmake)
endif()
if(WIN32)
if(BUILD_SPARKD)
message(FATAL_ERROR "Cannot build sparkd on Windows (Please set BUILD_SPARKD to False)")
endif()
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetWindowsClientSources.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetWindowsClientLinkLibraries.cmake)
elseif(${BUILD_SPARKD})
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetLinuxServerSources.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetLinuxServerLinkLibraries.cmake)
else()
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetLinuxClientSources.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GetLinuxClientLinkLibraries.cmake)
endif()
# Cpp sources
set(${PROJECT_NAME}_Sources)
get_cpp_sources(${PROJECT_NAME}_Sources)
print_list(${PROJECT_NAME}_Sources VERBOSE)
# Proto sources
get_proto_sources(_cfg_protos _non_cfg_protos _service_protos _cfg_defaults)
print_list(_cfg_protos VERBOSE)
print_list(_non_cfg_protos VERBOSE)
print_list(_service_protos VERBOSE)
print_list(_cfg_defaults VERBOSE)
update_deps_file("${${PROJECT_NAME}_Sources};${_cfg_protos};${_service_protos};${_non_cfg_protos};${_cfg_defaults}")
# Generate proto cpp
message(STATUS "Generating proto cpp")
protobuf_generate_cpp(_proto_srcs _proto_hdrs ${_non_cfg_protos} ${_cfg_protos})
service_compiler_generate_cpp(SERVICE_COMPILER_SRCS SERVICE_COMPILER_HDRS ${_service_protos})
message(STATUS "Generating default config")
generate_default_config(_cfg_protos _cfg_defaults)
add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_Sources} ${_proto_srcs} ${SERVICE_COMPILER_SRCS})
target_include_directories(
${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
get_link_libraries(_link_libs)
print_list(_link_libs VERBOSE)
target_link_libraries(${PROJECT_NAME} ${_link_libs})
# Copy binaries to Dotnet build dirs (for csprojs that depend on libspark)
if (DEFINED DOTNET_BINARY_DIR)
add_copy_binaries_target(
copy_to_dotnet_binary_dir
"${DOTNET_BINARY_DIR}"
"Copy ${PROJECT_NAME} bins to Dotnet build dir")
endif()
if(WIN32)
include(${CMAKE_SOURCE_DIR}/cmake/vs_filters.cmake)
endif()
foreach(_hdr ${_proto_hdrs})
file(RELATIVE_PATH _relative_path ${CMAKE_CURRENT_BINARY_DIR}/protobufs ${_hdr})
install(FILES ${_hdr} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${_relative_path})
endforeach()
include(${CMAKE_SOURCE_DIR}/cmake/InstallBasic.cmake)
# DEPENDENCIES
file(
GLOB_RECURSE _hdrs
GLOB_RECURSE Config_Protos
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.h
)
install_basic(HEADERS ${_hdrs})
config/protos/*.proto
api/domain/SecurityMetadataCollection.proto)
file(
GLOB_RECURSE Service_Protos
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
api/services/*.proto)
file(
GLOB_RECURSE NonConfig_Protos
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.proto)
list(REMOVE_ITEM NonConfig_Protos ${Service_Protos} ${Config_Protos})
file(
GLOB_RECURSE Conf_Defaults
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
config/defaults/*.conf)
if(WIN32)
file(
GLOB_RECURSE SparkLib_Sources
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
api/*.cpp
config/*.cpp
domain_model/*.cpp
expression/*.cpp
logging/*.cpp
io/*.cpp
md/*.cpp
os/*.cpp
quickbus/*.cpp
sparkproto/*.cpp
testing/*.cpp
utils/*.cpp)
else()
file(
GLOB_RECURSE SparkLib_Sources
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.cpp)
endif()
update_deps_file("${SparkLib_Sources};${Config_Protos};${Service_Protos};${NonConfig_Protos};${Conf_Defaults}")
# END DEPENDENCIES
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${NonConfig_Protos} ${Config_Protos})
service_compiler_generate_cpp(SERVICE_COMPILER_SRCS SERVICE_COMPILER_HDRS ${Service_Protos})
# generate list of config protos
set(config_proto_file ${CMAKE_CURRENT_BINARY_DIR}/config_proto_files.h)
# generate a string with the current config files
set(config_proto_str "const char * config_proto_files[] = { // generated file\n")
foreach(protopath ${Config_Protos})
get_filename_component(protoname ${protopath} NAME)
string(APPEND config_proto_str "\"${protoname}\",\n")
endforeach(protopath)
string(APPEND config_proto_str "} ;\n")
# compare with file and if there is any difference update the file
set(old_config_proto_str "")
if(EXISTS "${config_proto_file}")
file(READ "${config_proto_file}" old_config_proto_str)
endif()
if(NOT old_config_proto_str STREQUAL config_proto_str)
file(WRITE "${config_proto_file}" "${config_proto_str}")
endif()
# generate static defaults
set(config_defaults_file ${CMAKE_CURRENT_BINARY_DIR}/config_defaults.h)
# Defaults cannot be a single string because the compiler complains about a string longer than 65k
set(config_defaults_str "const char * config_static_defaults[] = { ")
foreach(cfg_file_path ${Conf_Defaults})
file(READ ${cfg_file_path} cfg_file_content)
string(REPLACE "\"" "\\\"" cfg_file_content_escaped ${cfg_file_content})
string(REPLACE "\n" ";" cfg_lines ${cfg_file_content_escaped})
foreach(line ${cfg_lines})
string(APPEND config_defaults_str "\n \"${line}\",")
endforeach(line)
endforeach(cfg_file_path)
string(APPEND config_defaults_str "};")
set(old_defaults_str "")
if(EXISTS ${config_defaults_file})
file(READ ${config_defaults_file} old_defaults_str)
endif()
if(NOT config_defaults_str STREQUAL old_defaults_str)
file(WRITE "${config_defaults_file}" "${config_defaults_str}")
endif()
# lib
if(WIN32)
add_library(libspark SHARED ${SparkLib_Sources} ${PROTO_SRCS} ${SERVICE_COMPILER_SRCS})
else()
add_library(libspark SHARED ${SparkLib_Sources} ${PROTO_SRCS} ${SERVICE_COMPILER_SRCS})
endif()
# include paths
target_include_directories(
libspark PUBLIC
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src)
if(WIN32)
target_link_libraries(
libspark
libcurl
debug
fmtd
optimized
fmt
libtbb
libboost_system
libboost_thread
libboost_filesystem
libboost_regex
libboost_chrono
libboost_date_time
libboost_atomic
libprotobuf
libprotoc
libssl
libcrypto
crypt32)
else()
target_link_libraries(
libspark
protobuf
double-conversion
boost_system
boost_thread
boost_filesystem
boost_regex
boost_chrono
boost_date_time
boost_atomic
SQLiteCpp
sqlite3
curl
uuid
ssl
crypto
fmt
tbb
cryptopp
pugixml
lttng-ust
Pcap++
Packet++
Common++
ssh2
-lrt
-ldl
-lpcap
-static-libgcc
-static-libstdc++
-pthread)
install(TARGETS libspark DESTINATION bin)
endif()
if(WIN32)
include(${CMAKE_SOURCE_DIR}/tools/vs_filters.cmake)
endif()
-5
View File
@@ -1,5 +0,0 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)
+3 -3
View File
@@ -13,7 +13,7 @@
#include "lib/config/protos/quickbus_cfg.pb.h"
#include "lib/config/protos/system.pb.h"
#ifdef _WIN32
#ifdef WIN32
#include <excpt.h>
#endif
@@ -59,7 +59,7 @@ CAPI Quickbus *api_create_quickbus(const char *qbconfig, long length) {
}
CAPI void api_destroy_quickbus(Quickbus *qbus) {
#ifndef _WIN32
#ifndef WIN32
if (qbus != nullptr) {
delete qbus;
}
@@ -186,7 +186,7 @@ CAPI void api_client_send(
void *extra) {
LOG(Api, Diag, "send rpc {}", ((int64_t)buffer));
std::string strbuf(buffer, buffer_length);
qbus::RPCRequest request(std::move(strbuf));
qbus::RPCRequest request(move(strbuf));
api_client_send_internal(
pclient, std::move(request), cb, rpc_connect_timeout_ms(), extra);
}
+1 -1
View File
@@ -60,7 +60,7 @@ CAPI void api_server_call_callback(
reinterpret_cast<qbus::ReplyHandler **>(ppvhandler);
std::string reply_buffer((const char *)buffer, (size_t)length);
qbus::RPCReplyPtr replyptr =
std::make_shared<qbus::RPCReply>(std::move(reply_buffer));
std::make_shared<qbus::RPCReply>(move(reply_buffer));
(**pphandler)(replyptr);
delete (*pphandler);
*pphandler = nullptr;
-11
View File
@@ -1,11 +0,0 @@
syntax = "proto3";
import "lib/api/domain/Venue.proto";
package bts.api.md;
message DepthStreamConfig {
bts.api.domain.Venue venue = 1;
repeated string symbols = 2;
uint32 num_levels = 3;
}
-10
View File
@@ -1,10 +0,0 @@
syntax = "proto3";
import "lib/api/md/DepthStreamConfig.proto";
package bts.api.md;
message MarketDataConfig {
repeated bts.api.md.DepthStreamConfig depth_streams = 1;
uint32 num_dispatcher_threads = 2;
}
@@ -0,0 +1,19 @@
syntax = "proto3";
import "lib/api/md/binance/BinanceMarketDataSubscriptionParams.proto";
import "lib/api/md/deribit/DeribitMarketDataSubscriptionParams.proto";
import "lib/api/md/ftx/FTXMarketDataSubscriptionParams.proto";
import "lib/api/md/glbx/GlbxMarketDataSubscriptionParams.proto";
import "lib/api/md/huobi/HuobiMarketDataSubscriptionParams.proto";
package bts.api.md;
message MarketDataSubscriptionParams {
oneof VenueParams {
bts.api.md.glbx.GlbxMarketDataSubscriptionParams glbx = 1;
bts.api.md.deribit.DeribitMarketDataSubscriptionParams deribit = 2;
bts.api.md.binance.BinanceMarketDataSubscriptionParams binance = 3;
bts.api.md.huobi.HuobiMarketDataSubscriptionParams huobi = 4;
bts.api.md.ftx.FTXMarketDataSubscriptionParams ftx = 5;
}
}
@@ -0,0 +1,7 @@
syntax = "proto3";
package bts.api.md.deribit;
message DeribitMarketDataSubscriptionParams {
// TODO
}
@@ -0,0 +1,9 @@
syntax = "proto3";
package bts.api.md.ftx;
message FTXDepthStreamParams {
repeated string symbols = 1;
uint32 num_levels = 2;
uint32 num_dispatcher_threads = 3;
}
@@ -0,0 +1,9 @@
syntax = "proto3";
import "lib/api/md/ftx/FTXDepthStreamParams.proto";
package bts.api.md.ftx;
message FTXMarketDataSubscriptionParams {
repeated FTXDepthStreamParams depth_streams = 2;
}
@@ -0,0 +1,7 @@
syntax = "proto3";
package bts.api.md.glbx;
message GlbxMarketDataSubscriptionParams {
// TODO
}
@@ -0,0 +1,7 @@
syntax = "proto3";
package bts.api.md.huobi;
message HuobiMarketDataSubscriptionParams {
// TODO
}
+1 -1
View File
@@ -72,7 +72,7 @@ class ClientChannel {
response_buffer + header_size,
response_size - header_size);
if (response->ParseFromZeroCopyStream(&data_stream)) {
on_response(Result<Response>(std::move(response)));
on_response(Result<Response>(move(response)));
return;
}
} else {
+1 -1
View File
@@ -28,7 +28,7 @@ void QuickbusClientChannel::send_core(
(*on_response)(buffer, length);
delete on_response;
};
OnReply *heap_on_response = new OnReply(std::move(on_response));
OnReply *heap_on_response = new OnReply(move(on_response));
api_client_send(
_pclient, request_envalope.c_str(), request_envalope.size(), trampoline,
heap_on_response);
+1 -1
View File
@@ -161,7 +161,7 @@ def to_type_model(field, msg):
elif field.type == types.TYPE_DOUBLE: return TypeModel("double", islist, "double?", jstype='number')
elif field.type == types.TYPE_FLOAT: return TypeModel("float", islist, "float?", jstype='number', fstype='float32')
elif field.type == types.TYPE_STRING: return TypeModel("string", islist, cpptype="std::string")
elif field.type == types.TYPE_BYTES: return TypeModel("ByteString", islist, cpptype="std::string", jstype='Uint8Array', fstype='Fable.Import.JS.Uint8Array')
elif field.type == types.TYPE_BYTES: return TypeModel("ByteString", islist, cpptype="std::string", jstype='Uint8Array', fstype='Fable.Core.JS.Uint8Array')
elif field.type == types.TYPE_BOOL: return TypeModel("bool", islist, "bool?", jstype='boolean', natural_key=True)
elif field.type == types.TYPE_ENUM:
nested_enums = [x.name for x in msg.enum_type]
@@ -11,8 +11,8 @@ using namespace rxcpp::operators;
{{#each service}}
// Constructor
{{name}}::{{name}}(std::unique_ptr<bts::api::ClientChannel> pchannel) : _pchannel(std::move(pchannel)) {}
{{name}}::{{name}}({{name}}&& other) : _pchannel(std::move(other._pchannel)) { }
{{name}}::{{name}}(std::unique_ptr<bts::api::ClientChannel> pchannel) : _pchannel(move(pchannel)) {}
{{name}}::{{name}}({{name}}&& other) : _pchannel(move(other._pchannel)) { }
{{#each method}}
{{#if server_streaming}}
@@ -52,7 +52,6 @@ bool AdminServiceUtils::has_exchange(
rv = conn.has_ice_connection();
break;
case api::Venue::VENUE_DERIBIT: // TODO
case api::Venue::VENUE_FTX:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
case api::Venue::VENUE_CBOECFE:
@@ -162,7 +161,6 @@ AdminServiceUtils::resolve_connection(
rv = resolve_sim_connection(data, account, sec);
break;
case api::Venue::VENUE_DERIBIT:
case api::Venue::VENUE_FTX:
rv = resolve_sim_connection(data, account, sec);
break;
case api::Venue::VENUE_CBOE:
@@ -412,7 +410,6 @@ std::string AdminServiceUtils::find_account_exchange_account(
}
case api::Venue::VENUE_UNSET:
case api::Venue::VENUE_DERIBIT: // TODO
case api::Venue::VENUE_FTX: // TODO
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
case api::Venue::VENUE_CBOECFE:
@@ -689,7 +686,6 @@ bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(
rv.set_customer_or_firm(sim_account_data->origin());
return rv;
} break;
case api::VENUE_FTX: // TODO
case api::Venue::VENUE_UNSET:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
@@ -1079,7 +1075,6 @@ std::string AdminServiceUtils::find_user_exchange_id(
break;
}
case api::Venue::VENUE_DERIBIT: // TODO
case api::Venue::VENUE_FTX: // TODO
case api::Venue::VENUE_UNSET:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
@@ -1108,7 +1103,6 @@ std::string AdminServiceUtils::find_user_company_id(
break;
}
case api::Venue::VENUE_DERIBIT:
case api::Venue::VENUE_FTX: // TODO
case api::Venue::VENUE_SIM:
case api::Venue::VENUE_SIMICE:
case api::Venue::VENUE_GLBX:
@@ -1646,8 +1640,6 @@ api::SecurityType AdminServiceUtils::security_type(
return api::SecurityType::SECURITYTYPE_FUTURE;
case api::Security::ContractCase::kOption:
return api::SecurityType::SECURITYTYPE_OPTION;
case api::Security::ContractCase::kSpot:
return api::SecurityType::SECURITYTYPE_STOCK;
case api::Security::ContractCase::kSpread:
return api::SecurityType::SECURITYTYPE_SPREAD;
case api::Security::ContractCase::kSynthetic:
-15
View File
@@ -1,15 +0,0 @@
function(add_copy_binaries_target tgt_name dest_dir)
set(_dest_files)
foreach (_dest_dir ${dest_dir})
set(_dest_file ${_dest_dir}/${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
list(APPEND _dest_files ${_dest_file})
add_custom_command(
OUTPUT ${_dest_file}
COMMAND ${CMAKE_COMMAND}
ARGS -E copy
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}
${_dest_file}
DEPENDS ${PROJECT_NAME})
endforeach()
add_custom_target(${tgt_name} ALL DEPENDS ${_dest_files} COMMENT ${ARGN})
endfunction()
-53
View File
@@ -1,53 +0,0 @@
function(generate_default_config cfg_protos cfg_defaults)
# generate list of config protos
set(_cfg_proto_file ${CMAKE_CURRENT_BINARY_DIR}/config_proto_files.h)
# generate a string with the current config files
set(_cfg_proto_str "const char * config_proto_files[] = { // generated file\n")
foreach(_proto_path ${${cfg_protos}})
get_filename_component(_proto_name ${_proto_path} NAME)
string(APPEND _cfg_proto_str "\"${_proto_name}\",\n")
endforeach(_proto_path)
string(APPEND _cfg_proto_str "} ;\n")
# compare with file and if there is any difference update the file
set(_old_cfg_proto_str "")
if(EXISTS "${_cfg_proto_file}")
file(READ "${_cfg_proto_file}" _old_cfg_proto_str)
endif()
if(NOT _old_cfg_proto_str STREQUAL _cfg_proto_str)
file(WRITE "${_cfg_proto_file}" "${_cfg_proto_str}")
endif()
# generate static defaults
set(_cfg_defaults_file ${CMAKE_CURRENT_BINARY_DIR}/config_defaults.h)
# Defaults cannot be a single string because the compiler complains about a
# string longer than 65k
set(_cfg_defaults_str "const char * config_static_defaults[] = { ")
foreach(_cfg_file_path ${${cfg_defaults}})
file(READ ${_cfg_file_path} _cfg_file_content)
string(REPLACE "\"" "\\\"" _cfg_file_content_escaped ${_cfg_file_content})
string(REPLACE "\n" ";" _cfg_lines ${_cfg_file_content_escaped})
foreach(_line ${_cfg_lines})
string(APPEND _cfg_defaults_str "\n \"${_line}\",")
endforeach(_line)
endforeach(_cfg_file_path)
string(APPEND _cfg_defaults_str "};")
set(_old_cfg_defaults_str "")
if(EXISTS ${_cfg_defaults_file})
file(READ ${_cfg_defaults_file} _old_cfg_defaults_str)
endif()
if(NOT _cfg_defaults_str STREQUAL _old_cfg_defaults_str)
file(WRITE "${_cfg_defaults_file}" "${_cfg_defaults_str}")
endif()
endfunction()
@@ -1,23 +0,0 @@
function(get_link_libraries dest)
set(${dest}
curl
tbb
boost_system
boost_thread
boost_filesystem
boost_regex
boost_chrono
boost_date_time
boost_atomic
protobuf
protoc
ssl
crypto
debug fmtd
optimized fmt
cryptopp
SQLiteCpp
sqlite3
uuid
PARENT_SCOPE)
endfunction()
-172
View File
@@ -1,172 +0,0 @@
function(get_proto_sources cfg_srcs non_cfg_srcs service_srcs cfg_defaults)
file(
GLOB_RECURSE _cfg_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
config/protos/*.proto
api/domain/SecurityMetadataCollection.proto)
file(
GLOB_RECURSE _service_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
api/services/*.proto)
file(
GLOB_RECURSE _non_cfg_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.proto)
list(REMOVE_ITEM _non_cfg_srcs ${_service_srcs} ${_cfg_srcs})
file(
GLOB_RECURSE _cfg_defaults
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${CONFIG_DEFAULTS_PATH})
set(_cfg_defaults)
foreach(cfg_path ${CONFIG_DEFAULTS_PATH})
file(
GLOB_RECURSE cfg_files
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${cfg_path})
list(APPEND _cfg_defaults ${cfg_files})
endforeach()
set(${cfg_srcs} ${_cfg_srcs} PARENT_SCOPE)
set(${non_cfg_srcs} ${_non_cfg_srcs} PARENT_SCOPE)
set(${service_srcs} ${_service_srcs} PARENT_SCOPE)
set(${cfg_defaults} ${_cfg_defaults} PARENT_SCOPE)
endfunction()
function(get_cpp_sources dest)
set(${dest}
api/core/ApiClientInterop.cpp
api/core/ApiServerInterop.cpp
api/md/MarketDataConfigUtils.cpp
api/public/ApiServer.cpp
api/public/ClientChannel.cpp
api/public/QuickbusClientChannel.cpp
api/public/ServerChannel.cpp
api/public/ServiceContext.cpp
api/test/ApiTests.cpp
api/test/HelloServiceServer.cpp
config/ConfigDownloader.cpp
config/ConfigErrorCollector.cpp
config/ConfigPropertyEvaluator.cpp
config/ConfigQuerier.cpp
config/ConfigValueQueue.cpp
config/ConfigurationException.cpp
config/ConfigurationState.cpp
config/PreprocessInputStream.cpp
config/config.cpp
config/tests/HTTPServer.cpp
config/tests/config_ref_tests.cpp
config/tests/config_tests.cpp
config/text_format/text_format.cpp
core/TimeSpan.cpp
core/TimeStamp.cpp
domain/DomainSecurityUtils.cpp
domain/SecurityCriteria.cpp
domain/SecurityCriteriaClause.cpp
domain_model/Security.cpp
domain_model/SecurityTests.cpp
domain_model/sod.cpp
domain_model/tests/domain_tests.cpp
expression/BooleanGrammar.cpp
expression/ExpressionEvaluator.cpp
expression/ParserExceptions.cpp
expression/Value.cpp
expression/tests/expression_parser_tests.cpp
io/http/CurlHandle.cpp
io/http/HTTPClient.cpp
io/http/HTTPHeaders.cpp
io/http/HTTPRequest.cpp
io/http/HTTPResponse.cpp
logging/LoggerHub.cpp
logging/Sink.cpp
logging/logging.cpp
logging/tests/logging_tests.cpp
md/Diag/MDPeriodicDumper.cpp
md/Diag/ShmDumper.cpp
md/MBOProcessor.cpp
md/MBOServiceServer.cpp
md/MDClient.cpp
md/MDConsumer.cpp
md/MDConsumerHandle.cpp
md/MDConsumerInterop.cpp
md/MDProducer.cpp
md/MDProducerHandle.cpp
md/MemorySegmentUtils.cpp
md/PriceSize.cpp
md/Product.cpp
md/SecurityCache.cpp
md/SecurityDB.cpp
md/SecurityIDRecorder.cpp
md/SecurityMapper.cpp
md/SecurityMarketState.cpp
md/SecurityOracle.cpp
md/SecurityStore.cpp
md/SettlementRecorder.cpp
md/Shm/FixedSecurity.cpp
md/SyntheticSecurityService.cpp
md/cme/MDP3Utils.cpp
md/common.cpp
md/ice/ICEUtils.cpp
md/relay/QueryServer.cpp
md/relay/RelayClient.cpp
md/relay/RelayRecorder.cpp
md/service/MarketDataServiceServer.cpp
md/test/Co2ManagedTestHelper.cpp
md/test/Co2TestInstrument.cpp
md/test/mbo_tests.cpp
md/test/md2_tests.cpp
md/test/md_test_utils.cpp
md/test/synthetic_book_merge_tests.cpp
os/os.cpp
os/tests/os_tests.cpp
quickbus/core/LocalNode.cpp
quickbus/core/Quickbus.cpp
quickbus/core/SubscriptionID.cpp
quickbus/core/TableID.cpp
quickbus/message_model/Update.cpp
quickbus/message_model/merge_updates.cpp
quickbus/network/QBConnection.cpp
quickbus/network/QBConnectionManager.cpp
quickbus/network/endpoint_description.cpp
quickbus/pubsub/TablePublisher.cpp
quickbus/pubsub/TableSubscriber.cpp
quickbus/pubsub/tests/qb_pubsub_tests.cpp
quickbus/routing/INode.cpp
quickbus/routing/NodeID.cpp
quickbus/routing/Router.cpp
quickbus/rpc/RPCClient.cpp
quickbus/rpc/RPCServer.cpp
quickbus/rpc/RPCSessionID.cpp
quickbus/rpc/rpc_utils.cpp
quickbus/rpc/tests/qb_rpc_tests.cpp
quickbus/tests/quickbus_tests.cpp
testing/catch_test_runner.cpp
utils/AuthSessionManager.cpp
utils/AuthToken.cpp
utils/Dispatcher.cpp
utils/FileUtils.cpp
utils/GrowableSPSCQueue.cpp
utils/HTTPStream.cpp
utils/MathUtils.cpp
utils/PBUtils.cpp
utils/Puid.cpp
utils/SecureLogon.cpp
utils/SharedMemory.cpp
utils/Sqlite_utils.cpp
utils/Uuid.cpp
utils/datetime.cpp
utils/download.cpp
utils/file_utils.cpp
utils/init_spark_lib.cpp
utils/is_unittest_environment.cpp
utils/sftp.cpp
utils/stats.cpp
utils/tests/AuthTokenTests.cpp
utils/tests/IDGeneratorTests.cpp
utils/tests/MathUtilsTests.cpp
utils/tests/SingleWriterConcurrentVectorTests.cpp
utils/thread_manager.cpp
PARENT_SCOPE)
endfunction()
@@ -1,35 +0,0 @@
function(get_link_libraries dest)
set(${dest}
protobuf
double-conversion
boost_system
boost_thread
boost_filesystem
boost_regex
boost_chrono
boost_date_time
boost_atomic
SQLiteCpp
sqlite3
curl
uuid
ssl
crypto
debug fmtd
optimized fmt
tbb
cryptopp
pugixml
lttng-ust
Pcap++
Packet++
Common++
ssh2
-lrt
-ldl
-lpcap
-static-libgcc
-static-libstdc++
-pthread
PARENT_SCOPE)
endfunction()
-45
View File
@@ -1,45 +0,0 @@
function(get_proto_sources cfg_srcs non_cfg_srcs service_srcs cfg_defaults)
file(
GLOB_RECURSE _cfg_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
config/protos/*.proto
api/domain/SecurityMetadataCollection.proto
api/md/MarketDataConfig.proto)
file(
GLOB_RECURSE _service_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
api/services/*.proto)
file(
GLOB_RECURSE _non_cfg_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.proto)
list(REMOVE_ITEM _non_cfg_srcs ${_service_srcs} ${_cfg_srcs})
file(
GLOB_RECURSE _cfg_defaults
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${CONFIG_DEFAULTS_PATH})
set(_cfg_defaults)
foreach(cfg_path ${CONFIG_DEFAULTS_PATH})
file(
GLOB_RECURSE cfg_files
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${cfg_path})
list(APPEND _cfg_defaults ${cfg_files})
endforeach()
set(${cfg_srcs} ${_cfg_srcs} PARENT_SCOPE)
set(${non_cfg_srcs} ${_non_cfg_srcs} PARENT_SCOPE)
set(${service_srcs} ${_service_srcs} PARENT_SCOPE)
set(${cfg_defaults} ${_cfg_defaults} PARENT_SCOPE)
endfunction()
function(get_cpp_sources dest)
file(
GLOB_RECURSE _dest
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.cpp)
set(${dest} ${_dest} PARENT_SCOPE)
endfunction()
@@ -1,20 +0,0 @@
function(get_link_libraries dest)
find_package(fmt CONFIG REQUIRED)
set(${dest}
crypt32
fmt::fmt-header-only
libcrypto
libcurl
libboost_system
libboost_thread
libboost_filesystem
libboost_regex
libboost_chrono
libboost_date_time
libboost_atomic
libprotobuf
libprotoc
libssl
libtbb
PARENT_SCOPE)
endfunction()
-162
View File
@@ -1,162 +0,0 @@
function(get_proto_sources cfg_srcs non_cfg_srcs service_srcs cfg_defaults)
file(
GLOB_RECURSE _cfg_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
config/protos/*.proto
api/domain/SecurityMetadataCollection.proto)
file(
GLOB_RECURSE _service_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
api/services/*.proto)
file(
GLOB_RECURSE _non_cfg_srcs
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
*.proto)
list(REMOVE_ITEM _non_cfg_srcs ${_service_srcs} ${_cfg_srcs})
file(
GLOB_RECURSE _cfg_defaults
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${CONFIG_DEFAULTS_PATH})
set(_cfg_defaults)
foreach(cfg_path ${CONFIG_DEFAULTS_PATH})
file(
GLOB_RECURSE cfg_files
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${cfg_path})
list(APPEND _cfg_defaults ${cfg_files})
endforeach()
set(${cfg_srcs} ${_cfg_srcs} PARENT_SCOPE)
set(${non_cfg_srcs} ${_non_cfg_srcs} PARENT_SCOPE)
set(${service_srcs} ${_service_srcs} PARENT_SCOPE)
set(${cfg_defaults} ${_cfg_defaults} PARENT_SCOPE)
endfunction()
function(get_cpp_sources dest)
set(${dest}
api/core/ApiClientInterop.cpp
api/core/ApiServerInterop.cpp
api/public/ApiServer.cpp
api/public/ClientChannel.cpp
api/public/QuickbusClientChannel.cpp
api/public/ServerChannel.cpp
api/public/ServiceContext.cpp
api/test/ApiTests.cpp
api/test/HelloServiceServer.cpp
config/ConfigCheck.cpp
config/ConfigDownloader.cpp
config/ConfigErrorCollector.cpp
config/ConfigPropertyEvaluator.cpp
config/ConfigValueQueue.cpp
config/ConfigurationException.cpp
config/ConfigurationState.cpp
config/PreprocessInputStream.cpp
config/ConfigLog.cpp
config/config.cpp
config/tests/HTTPServer.cpp
config/tests/config_ref_tests.cpp
config/tests/config_tests.cpp
config/text_format/text_format.cpp
domain_model/Security.cpp
domain_model/SecurityTests.cpp
domain_model/sod.cpp
domain_model/tests/domain_tests.cpp
expression/BooleanGrammar.cpp
expression/ExpressionEvaluator.cpp
expression/ParserExceptions.cpp
expression/Value.cpp
expression/tests/expression_parser_tests.cpp
logging/LoggerHub.cpp
logging/Sink.cpp
logging/logging.cpp
logging/tests/logging_tests.cpp
md/Diag/MDPeriodicDumper.cpp
md/Diag/ShmDumper.cpp
md/MBOProcessor.cpp
md/MBOServiceServer.cpp
md/MDClient.cpp
md/MDConsumer.cpp
md/MDConsumerHandle.cpp
md/MDConsumerInterop.cpp
md/MDProducer.cpp
md/MDProducerHandle.cpp
md/MarketDataError.cpp
md/MarketDataGateway.cpp
md/MarketDataRegistrationFactory.cpp
md/MemorySegmentUtils.cpp
md/PlatformLoader.cpp
md/PriceSize.cpp
md/Product.cpp
md/SecurityCache.cpp
md/SecurityDB.cpp
md/SecurityMapper.cpp
md/SecurityMarketState.cpp
md/SecurityOracle.cpp
md/SecurityStore.cpp
md/Shm/FixedSecurity.cpp
md/SyntheticSecurityService.cpp
md/cme/MDP3Utils.cpp
md/common.cpp
md/ice/ICEUtils.cpp
md/relay/QueryServer.cpp
md/relay/RelayClient.cpp
md/relay/RelayRecorder.cpp
md/service/MarketDataServiceServer.cpp
md/test/Co2ManagedTestHelper.cpp
md/test/Co2TestInstrument.cpp
md/test/mbo_tests.cpp
md/test/md2_tests.cpp
md/test/md_test_utils.cpp
md/test/synthetic_book_merge_tests.cpp
os/os.cpp
os/tests/os_tests.cpp
quickbus/core/LocalNode.cpp
quickbus/core/Quickbus.cpp
quickbus/core/SubscriptionID.cpp
quickbus/core/TableID.cpp
quickbus/message_model/Update.cpp
quickbus/message_model/merge_updates.cpp
quickbus/network/QBConnection.cpp
quickbus/network/QBConnectionManager.cpp
quickbus/network/endpoint_description.cpp
quickbus/pubsub/TablePublisher.cpp
quickbus/pubsub/TableSubscriber.cpp
quickbus/pubsub/tests/qb_pubsub_tests.cpp
quickbus/routing/INode.cpp
quickbus/routing/NodeID.cpp
quickbus/routing/Router.cpp
quickbus/rpc/RPCClient.cpp
quickbus/rpc/RPCServer.cpp
quickbus/rpc/RPCSessionID.cpp
quickbus/rpc/rpc_utils.cpp
quickbus/rpc/tests/qb_rpc_tests.cpp
quickbus/tests/quickbus_tests.cpp
testing/catch_test_runner.cpp
utils/AuthSessionManager.cpp
utils/AuthToken.cpp
utils/Dispatcher.cpp
utils/FileUtils.cpp
utils/GrowableSPSCQueue.cpp
utils/HTTPStream.cpp
utils/MathUtils.cpp
utils/PBUtils.cpp
utils/Puid.cpp
utils/SecureLogon.cpp
utils/SharedMemory.cpp
utils/Uuid.cpp
utils/datetime.cpp
utils/download.cpp
utils/file_utils.cpp
utils/init_spark_lib.cpp
utils/is_unittest_environment.cpp
utils/sftp.cpp
utils/stats.cpp
utils/tests/AuthTokenTests.cpp
utils/tests/MathUtilsTests.cpp
utils/tests/SingleWriterConcurrentVectorTests.cpp
utils/thread_manager.cpp
PARENT_SCOPE)
endfunction()
+2 -2
View File
@@ -29,7 +29,7 @@
#include "lib/config_defaults.h"
#include "lib/config_proto_files.h"
#ifdef _WIN32
#ifdef WIN32
#include <Winsock2.h>
#include <d2d1.h>
#else
@@ -566,7 +566,7 @@ void ConfigurationState::generate_all_config_proto(
&bts_config_dp, config_message, message_desc, ++field_number);
}
} else {
#ifdef _WIN32
#ifdef WIN32
// on linux the linker might throw away config protos that
// are not used in sparkd. On windows we build a dll so that
// should not happen
+2 -12
View File
@@ -19,7 +19,7 @@ SymbolList {
# symbol: "ES"
# symbol: "FYT"
# symbol: "FOB"
symbol: "GC"
# symbol: "GC"
# symbol: "GE"
# symbol: "HE"
# symbol: "HG"
@@ -37,7 +37,7 @@ SymbolList {
# symbol: "NUB"
# symbol: "RB"
# symbol: "RBT"
symbol: "SI"
# symbol: "SI"
# symbol: "SOM"
# symbol: "SR1"
# symbol: "SR3"
@@ -84,11 +84,6 @@ SymbolLists
key: "DERIBIT"
symbol: @SymbolList.symbol
}
list
{
key: "FTX"
symbol: @SymbolList.symbol
}
}
}
@@ -146,10 +141,5 @@ Symbols {
option: @SymbolLists.list[DERIBIT].symbol
spread: @SymbolLists.list[DERIBIT].symbol
}
ftx {
future: @SymbolLists.list[FTX].symbol
option: @SymbolLists.list[FTX].symbol
spread: @SymbolLists.list[FTX].symbol
}
}
}
+1 -1
View File
@@ -89,7 +89,7 @@ message JetFIX {
optional uint32 window_duration_msecs = 345
[ default = 1000 ]; // leave it alone
optional uint32 max_connection_attempts = 346 [ default = 3 ];
optional uint32 max_connection_attempts = 346 [ default = 10 ];
optional bool auto_fix_seq_num = 347 [ default = false ];
optional bool use_ilink3 = 348 [ default = false ];
}
-1
View File
@@ -23,5 +23,4 @@ message Symbols {
optional SecurityExchangeList ice = 30;
optional SecurityExchangeList simice = 40;
optional SecurityExchangeList deribit = 50;
optional SecurityExchangeList ftx = 60;
}
+6 -21
View File
@@ -33,32 +33,17 @@ std::string descriptor(api::Security const &sec) {
return "No descriptor for non glbx / ice exchange";
}
api::SecurityType security_type(api::Security const &security) {
switch (security.Contract_case()) {
case api::Security::ContractCase::kFuture:
api::SecurityType security_type(api::Security const &sec) {
if (sec.has_future())
return api::SecurityType::SECURITYTYPE_FUTURE;
case api::Security::ContractCase::kOption:
else if (sec.has_option())
return api::SecurityType::SECURITYTYPE_OPTION;
case api::Security::ContractCase::kSpot:
return api::SecurityType::SECURITYTYPE_STOCK;
case api::Security::ContractCase::kSpread:
else if (sec.has_spread())
return api::SecurityType::SECURITYTYPE_SPREAD;
case api::Security::ContractCase::kSynthetic:
else if (sec.has_synthetic())
return api::SecurityType::SECURITYTYPE_SYNTHETIC;
case api::Security::ContractCase::CONTRACT_NOT_SET:
else
return api::SecurityType::SECURITYTYPE_UNSET;
}
return api::SecurityType::SECURITYTYPE_UNSET;
// if (sec.has_future())
// return api::SecurityType::SECURITYTYPE_FUTURE;
// else if (sec.has_option())
// return api::SecurityType::SECURITYTYPE_OPTION;
// else if (sec.has_spread())
// return api::SecurityType::SECURITYTYPE_SPREAD;
// else if (sec.has_synthetic())
// return api::SecurityType::SECURITYTYPE_SYNTHETIC;
// else
// return api::SecurityType::SECURITYTYPE_UNSET;
}
boost::gregorian::date smallest_leg(
-10
View File
@@ -14,7 +14,6 @@ enum Venue {
VENUE_ICE = 306;
VENUE_SIMICE = 3;
VENUE_DERIBIT = 400;
VENUE_FTX = 410;
}
enum SecurityType {
@@ -103,10 +102,6 @@ message DeribitExchangeData {
int64 exchange_id = 10;
string security_desc = 20;
}
message FTXExchangeData {
int64 exchange_id = 10;
string security_desc = 20;
}
message CBOECFEExchangeData {
int64 exchange_id = 10;
string security_desc = 20;
@@ -142,9 +137,6 @@ message OptionContract {
PutOrCall call_put = 5;
}
message SpotContract{
}
message ContractLeg {
Security security = 10;
double quantity = 20;
@@ -197,7 +189,6 @@ message Security {
oneof Contract {
FutureContract future = 100;
OptionContract option = 101;
SpotContract spot = 102;
SpreadContract spread = 110;
SyntheticContract synthetic = 120;
}
@@ -207,7 +198,6 @@ message Security {
CBOECFEExchangeData cfe = 220;
ICEExchangeData ice = 230;
DeribitExchangeData deribit = 240;
FTXExchangeData ftx = 250;
}
}
message SecurityList {
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#ifndef _WIN32
#ifndef WIN32
#include <bits/stdint-uintn.h>
#endif
#include <cstdint>
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef _WIN32
#ifndef WIN32
#include "OutFIX.h"
namespace bts {
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef _WIN32
#ifndef WIN32
#include "AsyncReader.h"
#include "IConnection.h"
+1 -1
View File
@@ -1,3 +1,3 @@
#ifndef _WIN32
#ifndef WIN32
#include "IConnection.h"
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef _WIN32
#ifndef WIN32
#include "JetFIXGateway.h"
namespace bts {
+1 -1
View File
@@ -34,7 +34,7 @@ struct LogRec {
};
GCC_DIAG_RESTORE()
#ifndef _WIN32
#ifndef WIN32
// static_assert(sizeof(LogRec) == 256, "LogRec should be 128 bytes");
#endif
+1 -7
View File
@@ -4,7 +4,6 @@
#include <fmt/ostream.h>
#include <iostream>
#include <type_traits>
#include <vector>
namespace bts {
namespace log {
@@ -13,12 +12,7 @@ template <class Tuple, std::size_t... Is>
std::string format_tuple(
const char *msg_template, Tuple const &t, std::index_sequence<Is...>) {
try {
using ctx = fmt::format_context;
std::vector<fmt::basic_format_arg<ctx>> fmt_args;
(fmt_args.push_back(fmt::detail::make_arg<ctx>(std::get<Is>(t))), ...);
return fmt::vformat(
msg_template,
fmt::basic_format_args<ctx>(fmt_args.data(), fmt_args.size()));
return fmt::format(msg_template, std::get<Is>(t)...);
} catch (fmt::format_error const &e) {
return fmt::format(
"Bad log message template: '{}' Error: '{}'", msg_template, e.what());
+3 -3
View File
@@ -13,7 +13,7 @@
#include <fstream>
#include <iostream>
#ifndef _WIN32
#ifndef WIN32
#include <syslog.h>
#endif
@@ -22,7 +22,7 @@ namespace log {
struct InitSysLog {
InitSysLog() {
#ifndef _WIN32
#ifndef WIN32
openlog("spark", 0, LOG_USER);
#endif
}
@@ -72,7 +72,7 @@ Sink console_sink(LoggingConfig const &) {
}
Sink syslog_sink(LoggingConfig const &cfg) {
#ifdef _WIN32
#ifdef WIN32
return null_sink();
#else
auto f = formatter(cfg);
-2
View File
@@ -4,8 +4,6 @@
#include "lib/utils/bts_chrono.h"
#include "lib/logging/logging.h"
#include <fmt/chrono.h>
namespace bts {
int logging_tests;
-57
View File
@@ -1,57 +0,0 @@
#pragma once
#ifdef SPARK_ENABLE_CCAPI
#include "lib/api/domain/Venue.pb.h"
#include "lib/md/MarketDataListenerID.h"
#include <boost/algorithm/string/split.hpp>
#include <fmt/format.h>
#include <optional>
#include <string>
#include <tuple>
namespace bts::md {
class CCApiCorrelationID {
public:
static std::string fmt_market_depth(
api::domain::Venue venue,
std::string desc,
MarketDataListenerID listener_id);
static std::optional<
std::tuple<api::domain::Venue, std::string, MarketDataListenerID>>
parse_market_depth(const std::string &corr_id_str);
};
//////////////////////////////////////////////////
// Definition
//////////////////////////////////////////////////
inline std::string CCApiCorrelationID::fmt_market_depth(
api::domain::Venue venue,
std::string desc,
MarketDataListenerID listener_id) {
return fmt::format(
"{}.{}.{}", api::domain::Venue_Name(venue), desc, listener_id);
}
inline std::optional<
std::tuple<api::domain::Venue, std::string, MarketDataListenerID>>
CCApiCorrelationID::parse_market_depth(const std::string &corr_id_str) {
std::vector<std::string> parts;
boost::algorithm::split(parts, corr_id_str, [](auto c) { return c == '.'; });
if (parts.size() != 3) {
return std::nullopt;
}
api::domain::Venue venue;
if (!api::domain::Venue_Parse(parts.at(0), &venue)) {
return std::nullopt;
}
auto sec_desc = parts.at(1);
auto listener_id = MarketDataListenerID{
static_cast<std::uint32_t>(std::stoul(parts.at(2)))};
return std::make_tuple(venue, sec_desc, listener_id);
}
} // namespace bts::md
#endif
+206 -147
View File
@@ -1,184 +1,243 @@
#ifdef SPARK_ENABLE_CCAPI
#include "CCApiListenerAdaptor.h"
#include "lib/api/md/MarketDataConfig.pb.h"
#include "lib/domain/BUY_SELL.h"
#include "lib/domain/SecurityID.h"
#include "lib/logging/logging.h"
#include "lib/md/CCApiCorrelationID.h"
#include "lib/md/CCApiDepthWalker.h"
#include "lib/md/CCApiSecurityParser.h"
#include "lib/md/IMarketDataListener.h"
#include "lib/md/MarketDataListenerData.h"
#include "lib/persistence/IDGenerator.h"
#include "lib/utils/ContainsKey.h"
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
namespace bts::md {
using namespace bts::domain;
using std::string;
using std::unique_ptr;
using std::unordered_map;
using std::vector;
static bool parse_depth_msg(domain::Book &book, const ccapi::Message &msg) {
if (msg.getType() != ccapi::Message::Type::MARKET_DATA_EVENTS_MARKET_DEPTH) {
return false;
}
// The market data arrives in the following order:
// * bid levels (by price descending)
// * ask levels (by price ascending)
CCApiDepthWalker bid_walker{
"BID_PRICE", "BID_SIZE", &book[bts::domain::Side::Buy]};
CCApiDepthWalker ask_walker{
"ASK_PRICE", "ASK_SIZE", &book[bts::domain::Side::Sell]};
const auto &levels = msg.getElementList();
for (const auto &level : levels) {
// Each level has 2 entries, either:
// ["BID_PRICE", "BID_SIZE"], or
// ["ASK_PRICE", "ASK_SIZE"]
const auto &props = level.getNameValueMap();
for (const auto &[name, value] : props) {
bid_walker.parse_field(name, value) ||
ask_walker.parse_field(name, value);
}
}
// validate the book
bts_assert(bid_walker.price_idx == bid_walker.qty_idx);
bts_assert(ask_walker.price_idx == ask_walker.qty_idx);
bts_assert(book.is_sorted());
bts_assert(book[BUY].count_populated() == bid_walker.price_idx);
bts_assert(book[SELL].count_populated() == ask_walker.price_idx);
return true;
}
static domain::Book parse_depth_msg(const ccapi::Message &msg) {
domain::Book book;
parse_depth_msg(book, msg);
return book;
}
static void parse_securities_msg(
const ccapi::Message &msg,
std::unordered_map<std::string, std::unique_ptr<domain::Security>>
&securities,
std::vector<const domain::Security *> &added_secs,
std::vector<std::pair<const domain::Security *, const domain::Security *>>
&changed_secs,
std::vector<const domain::Security *> &all_secs) {
// std::vector<domain::Security
auto new_secs = CCApiSecurityParser::parse(msg.getElementList());
for (const auto &sec : new_secs) {
const auto &sym = sec.security_common.symbol;
bts_assert(!sym.empty());
auto it = securities.find(sym);
if (it == securities.end()) {
auto sec_ptr = std::make_unique<domain::Security>(sec);
added_secs.push_back(sec_ptr.get());
all_secs.push_back(sec_ptr.get());
securities[sym] = std::move(sec_ptr);
bts_assert(added_secs.back() != nullptr);
bts_assert(added_secs.back()->security_common.symbol == sym);
continue;
}
changed_secs.push_back({it->second.get(), &sec});
}
// auto added_msg = fmt::join(added_secs)
std::vector<std::string> added_sec_syms;
for (const auto *s : added_secs) {
added_sec_syms.push_back(s->security_common.symbol);
}
std::vector<std::string> changed_sec_syms;
for (const auto &[old_s, new_s] : changed_secs) {
added_sec_syms.push_back(fmt::format(
"{} -> {}", old_s->security_common.symbol,
new_s->security_common.symbol));
}
LOG(md, Info, "CCApi securities update. added: {}; changed: {}",
fmt::to_string(fmt::join(added_sec_syms, ", ")),
fmt::to_string(fmt::join(changed_sec_syms, ", ")));
}
struct CCApiListenerAdaptor::PImpl {
PImpl(
IMarketDataListener *const listener,
persistence::IDGenerator *const sec_id_store)
: listener(listener), sec_id_store(sec_id_store) {}
std::unordered_map<std::string, std::unique_ptr<domain::Security>>
securities;
std::unordered_map<std::uint32_t, IMarketDataListener *const> listeners;
MarketDataListenerID sec_id_counter{900'000};
IMarketDataListener *const listener;
persistence::IDGenerator *const sec_id_store;
unordered_map<SecurityID, unique_ptr<Security>> securities;
void on_instruments(const ccapi::Message &msg, api::domain::Venue venue) {
vector<const Security *> all_secs;
auto new_secs = CCApiSecurityParser::parse(msg.getElementList());
for (const auto &sec : new_secs) {
const auto &desc = sec.security_common.desc;
bts_assert(!desc.empty());
auto sec_id = SecurityID{
sec_id_store->get_or_add(api::domain::Venue_Name(venue), desc)};
if (CONTAINS_KEY(securities, sec_id)) {
// don't replace existing secs (in case code downstream relies on
// ptr equality)
continue;
}
auto sec_ptr = std::make_unique<Security>(sec);
sec_ptr->security_common.id.value() = sec_id_store->get_or_add(
api::domain::Venue_Name(venue), sec_ptr->security_common.desc);
all_secs.push_back(sec_ptr.get());
securities[sec_id] = std::move(sec_ptr);
}
listener->on_securities(all_secs);
void on_instruments(
const ccapi::Message &msg, IMarketDataListener &listener) {
std::vector<const domain::Security *> added_secs;
std::vector<std::pair<const domain::Security *, const domain::Security *>>
changed_secs;
std::vector<const domain::Security *> all_secs;
parse_securities_msg(msg, securities, added_secs, changed_secs, all_secs);
listener.on_securities(all_secs);
}
void on_instruments(const ccapi::Message &msg, const string &corr_id) {
// Correlation ID is the Venue
api::domain::Venue venue;
if (!api::domain::Venue_Parse(corr_id, &venue)) {
LOG(md, Error, "Failed to parse venue from ccapi correlation id '{}'",
corr_id);
return;
}
on_instruments(msg, venue);
}
void on_book(const ccapi::Message &msg, SecurityID sec_id) {
if (msg.getType() !=
ccapi::Message::Type::MARKET_DATA_EVENTS_MARKET_DEPTH) {
return;
}
Book book;
book.set_security_id(sec_id);
// The market data arrives in the following order:
// * bid levels (by price descending)
// * ask levels (by price ascending)
CCApiDepthWalker bid_walker{"BID_PRICE", "BID_SIZE", &book[BUY]};
CCApiDepthWalker ask_walker{"ASK_PRICE", "ASK_SIZE", &book[SELL]};
const auto &levels = msg.getElementList();
for (const auto &level : levels) {
// Each level has 2 entries, either:
// ["BID_PRICE", "BID_SIZE"], or
// ["ASK_PRICE", "ASK_SIZE"]
const auto &props = level.getNameValueMap();
for (const auto &[name, value] : props) {
bid_walker.parse_field(name, value) ||
ask_walker.parse_field(name, value);
}
}
// validate the book
bts_assert(bid_walker.price_idx == bid_walker.qty_idx);
bts_assert(ask_walker.price_idx == ask_walker.qty_idx);
bts_assert(book.is_sorted());
bts_assert(book[BUY].count_populated() == bid_walker.price_idx);
bts_assert(book[SELL].count_populated() == ask_walker.price_idx);
listener->on_book(book);
}
void on_book(const ccapi::Message &msg, const string &corr_id) {
// Correlation ID is a formatted string:
// "<venue>.<sec_desc>.<listener_id>"
const auto corr_id_res = CCApiCorrelationID::parse_market_depth(corr_id);
bts_assert(corr_id_res.has_value());
const auto [venue, sec_desc, listener_id] = *corr_id_res;
LOG(md, Diag, "listener_id: {}", listener_id);
const auto sec_id =
sec_id_store->get_or_add(api::domain::Venue_Name(venue), sec_desc);
on_book(msg, SecurityID{sec_id});
}
SecurityID get_sec_id(
const api::domain::Venue venue, const string &sec_desc) {
const auto sec_id =
sec_id_store->get_or_add(api::domain::Venue_Name(venue), sec_desc);
return SecurityID{sec_id};
void on_book(const ccapi::Message &msg, IMarketDataListener &listener) {
auto book = parse_depth_msg(msg);
listener.on_book(book);
}
};
CCApiListenerAdaptor::CCApiListenerAdaptor(
IMarketDataListener *const listener,
persistence::IDGenerator *const sec_id_store)
: me_(std::make_unique<PImpl>(listener, sec_id_store)) {}
CCApiListenerAdaptor::CCApiListenerAdaptor() : me_(std::make_unique<PImpl>()) {}
CCApiListenerAdaptor::~CCApiListenerAdaptor() = default;
bool CCApiListenerAdaptor::empty() const { return me_->listeners.empty(); }
void CCApiListenerAdaptor::register_listener(
IMarketDataListener *const listener, MarketDataListenerID id) {
bts_assert_msgf(
me_->listeners.find(id.value()) == me_->listeners.end(),
"MarketDataListener w/ id '{}' already registered", id);
me_->listeners.insert({id.value(), listener});
}
void CCApiListenerAdaptor::unregister_listener(MarketDataListenerID id) {
me_->listeners.erase(id.value());
}
static const char *Message_Type_Name(ccapi::Message::Type t) {
switch (t) {
case ccapi::Message::Type::UNKNOWN:
return "UNKNOWN";
case ccapi::Message::Type::AUTHORIZATION_SUCCESS:
return "AUTHORIZATION_SUCCESS";
case ccapi::Message::Type::AUTHORIZATION_FAILURE:
return "AUTHORIZATION_FAILURE";
case ccapi::Message::Type::MARKET_DATA_EVENTS_MARKET_DEPTH:
return "MARKET_DATA_EVENTS_MARKET_DEPTH";
case ccapi::Message::Type::MARKET_DATA_EVENTS_TRADE:
return "MARKET_DATA_EVENTS_TRADE";
case ccapi::Message::Type::MARKET_DATA_EVENTS_AGG_TRADE:
return "MARKET_DATA_EVENTS_AGG_TRADE";
case ccapi::Message::Type::EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE:
return "EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE";
case ccapi::Message::Type::EXECUTION_MANAGEMENT_EVENTS_PRIVATE_TRADE:
return "EXECUTION_MANAGEMENT_EVENTS_PRIVATE_TRADE";
case ccapi::Message::Type::SUBSCRIPTION_STARTED:
return "SUBSCRIPTION_STARTED";
case ccapi::Message::Type::SUBSCRIPTION_FAILURE:
return "SUBSCRIPTION_FAILURE";
case ccapi::Message::Type::SESSION_CONNECTION_UP:
return "SESSION_CONNECTION_UP";
case ccapi::Message::Type::SESSION_CONNECTION_DOWN:
return "SESSION_CONNECTION_DOWN";
case ccapi::Message::Type::INCORRECT_STATE_FOUND:
return "INCORRECT_STATE_FOUND";
case ccapi::Message::Type::CREATE_ORDER:
return "CREATE_ORDER";
case ccapi::Message::Type::CANCEL_ORDER:
return "CANCEL_ORDER";
case ccapi::Message::Type::GET_ORDER:
return "GET_ORDER";
case ccapi::Message::Type::GET_OPEN_ORDERS:
return "GET_OPEN_ORDERS";
case ccapi::Message::Type::CANCEL_OPEN_ORDERS:
return "CANCEL_OPEN_ORDERS";
case ccapi::Message::Type::GET_ACCOUNTS:
return "GET_ACCOUNTS";
case ccapi::Message::Type::GET_ACCOUNT_BALANCES:
return "GET_ACCOUNT_BALANCES";
case ccapi::Message::Type::GET_ACCOUNT_POSITIONS:
return "GET_ACCOUNT_POSITIONS";
case ccapi::Message::Type::GET_RECENT_TRADES:
return "GET_RECENT_TRADES";
case ccapi::Message::Type::GET_RECENT_AGG_TRADES:
return "GET_RECENT_AGG_TRADES";
case ccapi::Message::Type::GET_INSTRUMENT:
return "GET_INSTRUMENT";
case ccapi::Message::Type::GET_INSTRUMENTS:
return "GET_INSTRUMENTS";
case ccapi::Message::Type::RESPONSE_ERROR:
return "RESPONSE_ERROR";
case ccapi::Message::Type::REQUEST_FAILURE:
return "REQUEST_FAILURE";
case ccapi::Message::Type::GENERIC_ERROR:
return "GENERIC_ERROR";
case ccapi::Message::Type::CUSTOM:
return "CUSTOM";
case ccapi::Message::Type::FIX:
return "FIX";
case ccapi::Message::Type::FIX_FAILURE:
return "FIX_FAILURE";
case ccapi::Message::Type::GENERIC_PUBLIC_REQUEST:
return "GENERIC_PUBLIC_REQUEST";
case ccapi::Message::Type::GENERIC_PUBLIC_SUBSCRIPTION:
return "GENERIC_PUBLIC_SUBSCRIPTION";
case ccapi::Message::Type::GENERIC_PRIVATE_REQUEST:
return "GENERIC_PRIVATE_REQUEST";
default:
return "UNKNOWN";
}
}
bool CCApiListenerAdaptor::processEvent(
const ccapi::Event &event, ccapi::Session *) {
LOG(md, Diag, "Received ccapi event: {}", event.toString());
switch (event.getType()) {
case ccapi::Event::Type::SESSION_STATUS:
case ccapi::Event::Type::SUBSCRIPTION_STATUS:
case ccapi::Event::Type::REQUEST_STATUS:
// No processing needed
return true;
// one-time callback representing the reply to a ccapi 'REQUEST'
// Note: the GET_INSTRUMENTS msg arrives in an event of this type
case ccapi::Event::Type::RESPONSE:
// stream of callbacks representing the reply to a ccapi 'SUBSCRIBE'
// Note: the MARKET_DATA_EVENTS_MARKET_DEPTH msg arrives in an event of this
// type
case ccapi::Event::Type::SUBSCRIPTION_DATA:
break;
case ccapi::Event::Type::UNKNOWN:
case ccapi::Event::Type::AUTHORIZATION_STATUS:
case ccapi::Event::Type::FIX:
case ccapi::Event::Type::FIX_STATUS:
LOG(md, Error, "Unexpected ccapi event type '{}'",
ccapi::Event::typeToString(event.getType()));
break;
}
LOG(md, Error, "Received ccapi event: {}", event.toString());
const auto &msgs = event.getMessageList();
for (const auto &msg : msgs) {
const auto &corr_ids = msg.getCorrelationIdList();
for (const auto &corr_id : corr_ids) {
switch (msg.getType()) {
case ccapi::Message::Type::GET_INSTRUMENTS: {
// This message should only arrive with a RESPONSE event
bts_assert(event.getType() == ccapi::Event::Type::RESPONSE);
me_->on_instruments(msg, corr_id);
break;
MarketDataListenerID listener_id{
static_cast<std::uint32_t>(std::stoul(corr_id))};
auto listener_it = me_->listeners.find(listener_id.value());
if (listener_it == me_->listeners.end()) {
LOG(md, Warn,
"Received event associated w/ unknown correlationId '{}'",
corr_id);
continue;
}
auto &listener = *listener_it->second;
switch (msg.getType()) {
case ccapi::Message::Type::GET_INSTRUMENTS:
me_->on_instruments(msg, listener);
break;
case ccapi::Message::Type::MARKET_DATA_EVENTS_MARKET_DEPTH: {
// This message should only arrive with a SUBSCRIPTION_DATA event
bts_assert(
event.getType() == ccapi::Event::Type::SUBSCRIPTION_DATA);
me_->on_book(msg, corr_id);
me_->on_book(msg, listener);
break;
}
default:
LOG(md, Warn, "Unexpected ccapi message type '{}'",
ccapi::Message::typeToString(msg.getType()));
std::string msg_type_name = Message_Type_Name(msg.getType());
LOG(md, Warn, "Unexpected CCApi event type '{}'", msg_type_name);
break;
}
// switch (event.getType()) {
// case ccapi::Event::Type::UNKNOWN:
// break;
// }
}
}
return true;
+12 -17
View File
@@ -1,33 +1,28 @@
#pragma once
#ifdef SPARK_ENABLE_CCAPI
#include "lib/api/domain/Venue.pb.h"
#include "lib/md/IMarketDataListener.h"
#include "lib/md/MarketDataListenerID.h"
#include <ccapi_cpp/ccapi_event_handler.h>
#include <memory>
namespace bts::api::md {
class MarketDataConfig;
}
namespace bts::persistence {
class IDGenerator;
}
namespace bts::md {
class IMarketDataListener;
class CCApiListenerAdaptor : public ccapi::EventHandler {
public:
CCApiListenerAdaptor(
IMarketDataListener *const listener,
persistence::IDGenerator *const sec_id_store);
CCApiListenerAdaptor();
~CCApiListenerAdaptor();
MarketDataListenerID register_listener(IMarketDataListener *const listener);
void register_listener(
IMarketDataListener *const listener, MarketDataListenerID id);
void unregister_listener(MarketDataListenerID id);
bool processEvent(
const ccapi::Event &event, ccapi::Session *session) override;
bool empty() const;
private:
struct PImpl;
std::unique_ptr<PImpl> me_;
+38
View File
@@ -0,0 +1,38 @@
#ifdef SPARK_ENABLE_CCAPI
#include "CCApiRequestor.h"
#include "lib/logging/logging.h"
#include <optional>
namespace bts::md {
struct CCApiRequestor::PImpl {
ccapi::Request req;
ccapi::EventHandler *handler;
ccapi::SessionOptions opts;
ccapi::SessionConfigs cfgs;
std::optional<ccapi::Session> session;
};
CCApiRequestor::CCApiRequestor(
ccapi::EventHandler *const handler,
ccapi::SessionOptions opts,
ccapi::SessionConfigs cfgs)
: me_(std::make_unique<PImpl>()) {
// Store 'opts' and 'cfgs' in PImpl for diagnostic purposes
me_->opts = std::move(opts);
me_->cfgs = std::move(cfgs);
me_->handler = handler;
}
CCApiRequestor::~CCApiRequestor() { me_->session->stop(); }
void CCApiRequestor::request(ccapi::Request &req) {
LOG(md, Info, "Making ccapi request: {}", req.toString());
if (!me_->session) {
me_->session.emplace(me_->opts, me_->cfgs, me_->handler);
}
me_->session->sendRequest(req);
}
} // namespace bts::md
#endif
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#ifdef SPARK_ENABLE_CCAPI
#include <ccapi_cpp/ccapi_event_handler.h>
#include <ccapi_cpp/ccapi_session.h>
#include <ccapi_cpp/ccapi_session_options.h>
#include <memory>
namespace bts::md {
class CCApiRequestor {
public:
explicit CCApiRequestor(
ccapi::EventHandler *const handler,
ccapi::SessionOptions opts,
ccapi::SessionConfigs cfgs);
~CCApiRequestor();
void request(ccapi::Request &req);
private:
struct PImpl;
std::unique_ptr<PImpl> me_;
};
} // namespace bts::md::ftx
#endif
-91
View File
@@ -1,91 +0,0 @@
#ifdef SPARK_ENABLE_CCAPI
#include "CCApiSession.h"
#include "lib/api/md/DepthStreamConfig.pb.h"
#include "lib/md/CCApiCorrelationID.h"
#include "lib/md/CCApiListenerAdaptor.h"
#include "lib/md/MarketDataListenerData.h"
#include "lib/md/MarketDataRegistrationFactory.h"
#include "lib/persistence/IDGenerator.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <ccapi_cpp/ccapi_event_dispatcher.h>
#include <ccapi_cpp/ccapi_request.h>
#include <ccapi_cpp/ccapi_session.h>
#include <ccapi_cpp/ccapi_session_configs.h>
#include <ccapi_cpp/ccapi_session_options.h>
#include <ccapi_cpp/ccapi_subscription.h>
namespace bts::md {
struct CCApiSession::PImpl {
PImpl(
const MarketDataListenerData listener_data,
bts::persistence::IDGenerator *const sec_id_store)
: listener_data(listener_data), sec_id_store(sec_id_store),
ccapi_dispatcher(
static_cast<int>(listener_data.cfg.num_dispatcher_threads())),
ccapi_listener(listener_data.listener, sec_id_store),
ccapi_session(
ccapi_opts, ccapi_cfgs, &ccapi_listener, &ccapi_dispatcher) {}
MarketDataListenerData listener_data;
bts::persistence::IDGenerator *sec_id_store;
ccapi::SessionOptions ccapi_opts;
ccapi::SessionConfigs ccapi_cfgs;
// Dispatches ccapi callbacks
ccapi::EventDispatcher ccapi_dispatcher;
// Handles ccapi sec/md callbacks
CCApiListenerAdaptor ccapi_listener;
// Manages ccapi connection to exchanges
ccapi::Session ccapi_session;
void request_securities(api::domain::Venue venue) {
auto venue_name = api::domain::Venue_Name(venue);
auto venue_name_lower = boost::algorithm::to_lower_copy(venue_name);
// The 'venue' in the request must be lower-case (ccapi expects this). The
// correlation id, however, should remain unchanged (in the callback, we
// parse the venue with 'api::domain::Venue_Parse')
ccapi::Request req(
ccapi::Request::Operation::GET_INSTRUMENTS, venue_name_lower);
req.setCorrelationId(venue_name);
ccapi_session.sendRequest(req);
}
void subscribe_md(const api::md::DepthStreamConfig &ds) {
const auto opts =
fmt::format("{}={}", CCAPI_MARKET_DEPTH_MAX, ds.num_levels());
auto venue_name = bts::api::domain::Venue_Name(ds.venue());
boost::algorithm::to_lower(venue_name);
for (const auto &symbol : ds.symbols()) {
const auto corr_id = CCApiCorrelationID::fmt_market_depth(
ds.venue(), symbol, listener_data.id);
ccapi::Subscription sub(
venue_name, symbol, CCAPI_MARKET_DEPTH, opts, corr_id);
ccapi_session.subscribe(sub);
}
}
};
CCApiSession::CCApiSession(
MarketDataListenerData listener_data,
bts::persistence::IDGenerator *sec_id_store)
: me_(std::make_unique<PImpl>(std::move(listener_data), sec_id_store)) {
std::unordered_set<api::domain::Venue> venues;
for (auto ds : me_->listener_data.cfg.depth_streams()) {
// Limit one sec request per Venue
if (venues.insert(ds.venue()).second) {
me_->request_securities(ds.venue());
}
me_->subscribe_md(ds);
}
}
CCApiSession::~CCApiSession() { me_->ccapi_session.stop(); }
} // namespace bts::md
#endif
-37
View File
@@ -1,37 +0,0 @@
#pragma once
#ifdef SPARK_ENABLE_CCAPI
#include "lib/api/domain/Venue.pb.h"
#include <memory>
namespace ccapi {
class Session;
}
namespace bts::persistence {
class IDGenerator;
}
namespace bts::md {
struct MarketDataListenerData;
class CCApiSession {
public:
explicit CCApiSession(
MarketDataListenerData listener_data,
bts::persistence::IDGenerator *sec_id_store);
CCApiSession(const CCApiSession &) = delete;
CCApiSession(CCApiSession &&) = default;
CCApiSession &operator=(const CCApiSession &) = delete;
CCApiSession &operator=(CCApiSession &&) = default;
~CCApiSession();
private:
struct PImpl;
std::unique_ptr<PImpl> me_;
};
} // namespace bts::md
#endif
+2 -2
View File
@@ -60,7 +60,7 @@ std::string print_book(
auto a = ask[x - 1];
if (!os::is_nan(a.price())) {
snprintf(
buffer, 512, "%5s %14s | %14.7f %5.5f\n", "", "", a.price(),
buffer, 512, "%5s %14s | %14.7f %5d\n", "", "", a.price(),
a.size());
ss << buffer;
}
@@ -69,7 +69,7 @@ std::string print_book(
for (uint32_t x = 0; x < COCONUT_MAX_DEPTH; ++x) {
auto b = bid[x];
if (!os::is_nan(b.price())) {
snprintf(buffer, 512, "%5.5f %14.7f | \n", b.size(), b.price());
snprintf(buffer, 512, "%5d %14.7f | \n", b.size(), b.price());
ss << buffer;
}
}
-4
View File
@@ -4,11 +4,9 @@
#include "MDProducerHandle.h"
#include "lib/domain_model/Security.h"
#include "lib/domain_model/SecurityKey.h"
#include "lib/utils/OSTREAM_FMT_IMPL.h"
#include "lib/utils/TimeStamp.h"
#include <btree/map.h>
#include <fmt/format.h>
#include <map>
#include <memory>
@@ -171,5 +169,3 @@ class MBOProcessor {
namespace std {
std::ostream &operator<<(std::ostream &os, const bts::md::inc::Update &);
}
OSTREAM_FMT_IMPL(bts::md::inc::Update);
+2 -3
View File
@@ -613,8 +613,7 @@ class MDConsumerImpl {
for (auto &s : symbols) {
if (s.type() == SECURITYTYPE_FUTURE ||
s.type() == SECURITYTYPE_OPTION ||
s.type() == api::SECURITYTYPE_STOCK) {
s.type() == SECURITYTYPE_OPTION) {
_instances.push_back(make_shared<MDConsumerInst>(
s.symbol(), s.type(), s.exchange(), shared, platform));
}
@@ -784,7 +783,7 @@ class MDConsumerImpl {
// recurse to find details
map<security_key, SecurityPtr> leg_map;
for (auto &leg : fill_leg_details(legs, depth + 1)) {
leg_map.insert(make_pair(leg->id(), std::move(leg)));
leg_map.insert(make_pair(leg->id(), move(leg)));
}
//
-1
View File
@@ -218,7 +218,6 @@ class BTS_EXPORT MDConsumerHandle {
switch (_type) {
case HANDLETYPE_VOID:
bts_assert_msg(false, "Handle not initialized");
break;
case HANDLETYPE_DEPTH:
return convert_security(book.cdata->security);
case HANDLETYPE_BBO:
+1 -1
View File
@@ -1,4 +1,4 @@
#if defined(EXPORT_MD_CONSUMER)
#ifdef _WIN32
#include "MDConsumer.h"
#include "SecurityCache.h"
#include "UserSymbol.h"
+2 -2
View File
@@ -134,7 +134,7 @@ MDProducer::MDProducer(Platform platform, MDProducerFlags flags)
: _mutex(new std::mutex()), _producers(), _id_recorder(),
_platform(platform), _flags(flags),
_smapper(flags & MDProducerFlags::SecurityMapper) {}
#ifndef _WIN32
#ifndef WIN32
MDProducer::MDProducer(
Platform platform, SecurityIDRecorder recorder, MDProducerFlags flags)
: _mutex(new std::mutex()), _producers(),
@@ -173,7 +173,7 @@ MDProducerImpl &MDProducer::get_producer(
} else {
newp.reset(new MDProducerImpl(symbol, type, exchange, _platform, _flags));
}
_producers.push_back(std::move(newp));
_producers.push_back(move(newp));
return *_producers.back();
}
+180 -63
View File
@@ -1,65 +1,145 @@
#ifdef SPARK_ENABLE_CCAPI
#include "lib/md/CCApiListenerAdaptor.h"
#include <ccapi_cpp/ccapi_macro.h>
#include "MarketDataGateway.h"
#include "lib/api/domain/Venue.pb.h"
#include "lib/api/md/DepthStreamConfig.pb.h"
#include "lib/api/md/MarketDataConfig.pb.h"
#include "MarketDataRegistration.h"
#include "lib/api/md/MarketDataSubscriptionParams.pb.h"
#include "lib/api/md/binance/BinanceMarketDataSubscriptionParams.pb.h"
#include "lib/core/ProtoPrinter.h"
#include "lib/domain/Venue.h"
#include "lib/logging/logging.h"
#include "lib/md/CCApiSession.h"
#include "lib/md/CompositeMarketDataListener.h"
#include "lib/md/IMarketDataListener.h"
#include "lib/md/MarketDataListenerData.h"
#include "lib/md/MarketDataListenerID.h"
#include "lib/md/MarketDataRegistration.h"
#include "lib/md/MarketDataRegistrationError.h"
#include "lib/md/MarketDataRegistrationFactory.h"
#include "lib/persistence/IDGenerator.h"
#include "lib/md/binance/BinanceDepthStreamSiteKey.h"
#include "lib/md/binance/BinanceDiffDepthSubscription.h"
#include "lib/md/binance/BinanceDiffDepthUpdate.h"
#include "lib/utils/ContainsKey.h"
#include "lib/utils/bts_assert.h"
#include <ccapi_cpp/ccapi_session.h>
#include <optional>
#include <unordered_map>
#include <vector>
namespace bts::md {
using std::string;
using std::vector;
static void _validate(
const api::md::DepthStreamConfig &ds,
std::uint32_t index,
vector<string> &errors) {
if (!api::domain::Venue_IsValid(ds.venue())) {
errors.push_back(fmt::format(
"DepthStreamConfig at index {} 'venue' is invalid", index));
}
if (ds.num_levels() == 0) {
errors.push_back(fmt::format(
"DepthStreamConfig at index {} 'num_levels' is 0", index));
}
if (ds.symbols().empty()) {
errors.push_back(fmt::format(
"DepthStreamConfig at index {} 'symbols' is empty", index));
}
}
static void _validate(
const api::md::MarketDataConfig &cfg, vector<string> errs) {
if (cfg.depth_streams().empty()) {
errs.push_back("MarketDataConfig 'depth_streams' is empty");
}
std::uint32_t ds_idx = 0;
for (const auto &ds : cfg.depth_streams()) {
_validate(ds, ds_idx++, errs);
}
}
struct MarketDataGateway::PImpl {
MarketDataRegistrationFactory registration_factory;
bts::persistence::IDGenerator &sec_id_store =
bts::persistence::IDGenerator::insance();
std::unordered_map<MarketDataListenerID, CCApiSession> sessions;
std::unordered_map<
binance::BinanceDepthStreamSiteKey,
binance::BinanceDiffDepthSubscription>
binance_subs;
std::unordered_map<MarketDataListenerID, MarketDataListenerData>
registered_listeners;
private:
ccapi::SessionOptions ccapi_opts_;
ccapi::SessionConfigs ccapi_cfgs_;
std::optional<ccapi::EventDispatcher> ccapi_dispatcher_;
std::optional<ccapi::Session> ccapi_session_;
std::optional<CCApiListenerAdaptor> ccapi_listener_;
public:
CCApiListenerAdaptor &ccapi_listener() {
if (!ccapi_listener_) {
return ccapi_listener_.emplace();
}
return *ccapi_listener_;
}
ccapi::Session &ccapi_session() {
if (!ccapi_session_) {
if (!ccapi_dispatcher_) {
ccapi_dispatcher_.emplace(2);
}
ccapi_session_.emplace(
ccapi_opts_, ccapi_cfgs_, &ccapi_listener(), &*ccapi_dispatcher_);
}
return *ccapi_session_;
}
//////////////////////////////////////////////////
// Binance
//////////////////////////////////////////////////
void subscribe_binance(
const api::md::binance::BinanceMarketDataSubscriptionParams &sub,
IMarketDataListener *listener) {
std::vector<binance::BinanceDiffDepthSubscription *> new_subs;
for (const auto &depth_stream : sub.depth_streams()) {
md::binance::BinanceDepthStreamSiteKey site_key(depth_stream);
auto [sub_it, is_new_sub] = binance_subs.try_emplace(
site_key, md::binance::BinanceDepthStreamParams{depth_stream});
if (is_new_sub) {
new_subs.push_back(&sub_it->second);
continue;
}
auto &sub = sub_it->second;
// add symbols to piggy back on existing subscription rather than
// create a new one
for (const auto &symbol : depth_stream.symbols()) {
sub.add_listener(symbol, listener);
}
}
for (auto *sub : new_subs) {
sub->connect();
}
}
void unsubscribe_binance(
const api::md::binance::BinanceMarketDataSubscriptionParams &sub,
IMarketDataListener *listener) {
for (const auto &depth_stream : sub.depth_streams()) {
md::binance::BinanceDepthStreamSiteKey site_key(depth_stream);
auto sub_it = binance_subs.find(site_key);
bts_assert(sub_it != binance_subs.end());
auto &sub = sub_it->second;
for (const auto &symbol : depth_stream.symbols()) {
bts_assert(sub.remove_listener(symbol, listener));
}
}
}
//////////////////////////////////////////////////
// FTX
//////////////////////////////////////////////////
void subscribe_ftx(
const api::md::ftx::FTXMarketDataSubscriptionParams &params,
IMarketDataListener *listener,
MarketDataListenerID listener_id) {
if (params.depth_streams().empty()) {
return;
}
bts_assert(params.depth_streams().size() == 1);
auto &depth_stream = params.depth_streams().at(0);
std::vector<std::string> symbols;
for (const auto &symbol : depth_stream.symbols()) {
symbols.push_back(symbol);
}
ccapi_listener().register_listener(listener, listener_id);
auto opts = fmt::format(
"{}={}", CCAPI_MARKET_DEPTH_MAX, depth_stream.num_levels());
for (const auto &symbol : symbols) {
std::string corr_id = fmt::format("{}", listener_id);
ccapi::Subscription sub(
"binance", symbol, CCAPI_MARKET_DEPTH, opts, corr_id);
ccapi_session().subscribe(sub);
}
}
void unsubscribe_ftx(MarketDataListenerID listener_id) {
bts_assert_msg(
ccapi_listener_.has_value(),
"Ignoring request to unsubscribe from FTX market data. "
"CCApiListenerAdaptor not created.");
ccapi_listener_->unregister_listener(listener_id);
if (ccapi_listener_->empty()) {
ccapi_session_.reset();
}
}
};
MarketDataGateway::MarketDataGateway()
@@ -68,35 +148,72 @@ MarketDataGateway::MarketDataGateway()
MarketDataGateway::~MarketDataGateway() = default;
MarketDataRegistration MarketDataGateway::subscribe(
const api::md::MarketDataConfig &cfg,
IMarketDataListener *listener) noexcept {
const MarketDataSubscription &sub, IMarketDataListener *listener) noexcept {
auto reg = me_->registration_factory.create();
bts_assert(reg.listener_id.has_value());
bts_assert(me_->sessions.find(*reg.listener_id) == me_->sessions.end());
bts_assert(
me_->registered_listeners.find(*reg.listener_id) ==
me_->registered_listeners.end());
LOG(md, bts::Info, "MarketDataGateway subscribing to data.\n{}\n",
core::ProtoPrinterFactory::create(&cfg));
core::ProtoPrinter<api::md::MarketDataSubscriptionParams>(
&sub.params()));
vector<string> cfg_errs;
_validate(cfg, cfg_errs);
if (!cfg_errs.empty()) {
return MarketDataRegistration{
{MarketDataRegistrationError::Type::CONFIG_ERROR,
fmt::to_string(fmt::join(cfg_errs, "\n"))}};
}
MarketDataListenerData listener_data;
auto &listener_data = me_->registered_listeners[*reg.listener_id];
listener_data.id = *reg.listener_id;
listener_data.listener = listener;
listener_data.cfg = cfg;
me_->sessions.try_emplace(
listener_data.id, listener_data, &me_->sec_id_store);
listener_data.subscription = sub;
switch (sub.venue()) {
case api::domain::Venue::BINANCE:
bts_assert(
sub.params().VenueParams_case() ==
api::md::MarketDataSubscriptionParams::kBinance);
me_->subscribe_binance(sub.params().binance(), listener);
break;
case api::domain::Venue::FTX:
bts_assert(
sub.params().VenueParams_case() ==
api::md::MarketDataSubscriptionParams::kFtx);
LOG(md, bts::Info, "MarketDataGateway subscribing to data.\n{}\n",
core::ProtoPrinter<api::md::MarketDataSubscriptionParams>(
&sub.params()));
me_->subscribe_ftx(sub.params().ftx(), listener, listener_data.id);
break;
default:
return MarketDataRegistration{
MarketDataListenerID{0},
MarketDataRegstrationError::Type::NOT_IMPLEMENTED};
}
return reg;
}
void MarketDataGateway::unsubscribe(MarketDataListenerID id) {
LOG(md, bts::Info, "Unsubscribing listener {}", id);
bts_assert(CONTAINS_KEY(me_->sessions, id));
me_->sessions.erase(id);
bts_assert(CONTAINS_KEY(me_->registered_listeners, id));
auto &ld = me_->registered_listeners[id];
auto *listener = ld.listener;
bts_assert(listener);
auto &sub = ld.subscription;
switch (sub.venue()) {
case api::domain::Venue::BINANCE:
bts_assert(
sub.params().VenueParams_case() ==
api::md::MarketDataSubscriptionParams::kBinance);
me_->unsubscribe_binance(sub.params().binance(), listener);
break;
case api::domain::Venue::FTX:
bts_assert(
sub.params().VenueParams_case() ==
api::md::MarketDataSubscriptionParams::kFtx);
me_->unsubscribe_ftx(id);
break;
default:
break;
}
me_->registered_listeners.erase(id);
}
} // namespace bts::md
+9 -5
View File
@@ -1,10 +1,14 @@
#pragma once
#include "MarketDataListenerID.h"
#include "MarketDataRegistrationFactory.h"
#include "MarketDataSubscription.h"
#include "lib/domain/SecurityID.h"
#include <cstdint>
#include <memory>
namespace bts::api::md {
class MarketDataConfig;
}
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
namespace bts::md {
@@ -21,7 +25,7 @@ class MarketDataGateway {
* @return MarketDataRegistration
*/
MarketDataRegistration subscribe(
const api::md::MarketDataConfig &, IMarketDataListener *) noexcept;
const MarketDataSubscription &, IMarketDataListener *) noexcept;
void unsubscribe(MarketDataListenerID id);
+4 -2
View File
@@ -1,14 +1,16 @@
#pragma once
#include "lib/api/md/MarketDataConfig.pb.h"
#include "lib/domain/SecurityID.h"
#include "lib/md/IMarketDataListener.h"
#include "lib/md/MarketDataListenerID.h"
#include "lib/md/MarketDataSubscription.h"
#include <unordered_set>
namespace bts::md {
struct MarketDataListenerData {
MarketDataListenerID id;
IMarketDataListener *listener;
api::md::MarketDataConfig cfg;
MarketDataSubscription subscription;
};
} // namespace bts::md
+1 -16
View File
@@ -8,25 +8,10 @@ namespace bts::md {
class MarketDataRegistration {
public:
MarketDataRegistration() = default;
explicit MarketDataRegistration(MarketDataListenerID listener_id);
explicit MarketDataRegistration(MarketDataRegistrationError error);
// will have a value when there is no error
std::optional<MarketDataListenerID> listener_id;
// domain::Venue venue = domain::Venue::Glbx;
MarketDataRegistrationError error = {};
MarketDataRegstrationError error = {};
};
//////////////////////////////////////////////////
// Definition
//////////////////////////////////////////////////
inline MarketDataRegistration::MarketDataRegistration(
MarketDataListenerID listener_id)
: listener_id(listener_id), error() {}
inline MarketDataRegistration::MarketDataRegistration(
MarketDataRegistrationError error)
: listener_id(std::nullopt), error(error) {}
} // namespace bts::md
+2 -4
View File
@@ -1,10 +1,9 @@
#pragma once
#include <optional>
#include <string>
namespace bts::md {
struct MarketDataRegistrationError {
struct MarketDataRegstrationError {
enum class Type {
NO_ERROR = 0,
NETWORK_ERROR = 1,
@@ -15,8 +14,7 @@ struct MarketDataRegistrationError {
// Any error that occurred on our end. As this error type is vague, the
// accompanying error message should provide adequate information and
// context
INTERNAL_ERROR = 3,
CONFIG_ERROR = 4
INTERNAL_ERROR = 3
};
Type error_type{Type::NO_ERROR};
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include "lib/api/domain/Venue.pb.h"
#include "lib/api/md/MarketDataSubscriptionParams.pb.h"
#include "lib/api/md/deribit/DeribitMarketDataSubscriptionParams.pb.h"
#include "lib/api/md/glbx/GlbxMarketDataSubscriptionParams.pb.h"
#include <variant>
namespace bts::md {
class MarketDataSubscription {
public:
api::domain::Venue venue() const;
MarketDataSubscription() = default;
explicit MarketDataSubscription(
api::md::MarketDataSubscriptionParams params);
MarketDataSubscription(const MarketDataSubscription &) = default;
MarketDataSubscription(MarketDataSubscription &&) = default;
MarketDataSubscription &operator=(const MarketDataSubscription &) = default;
MarketDataSubscription &operator=(MarketDataSubscription &&) = default;
const api::md::MarketDataSubscriptionParams &params() const;
private:
api::md::MarketDataSubscriptionParams params_{};
};
//////////////////////////////////////////////////
// Definition
//////////////////////////////////////////////////
inline MarketDataSubscription::MarketDataSubscription(
api::md::MarketDataSubscriptionParams params)
: params_(std::move(params)) {}
inline const api::md::MarketDataSubscriptionParams &
MarketDataSubscription::params() const {
return params_;
}
inline api::domain::Venue MarketDataSubscription::venue() const {
switch (params_.VenueParams_case()) {
case api::md::MarketDataSubscriptionParams::VenueParamsCase::kBinance:
return api::domain::Venue::BINANCE;
case api::md::MarketDataSubscriptionParams::VenueParamsCase::kDeribit:
return api::domain::Venue::DERIBIT;
case api::md::MarketDataSubscriptionParams::VenueParamsCase::kFtx:
return api::domain::Venue::FTX;
case api::md::MarketDataSubscriptionParams::VenueParamsCase::kGlbx:
return api::domain::Venue::GLBX;
case api::md::MarketDataSubscriptionParams::VenueParamsCase::kHuobi:
return api::domain::Venue::HUOBI;
default:
return api::domain::Venue::NONE;
}
}
} // namespace bts::md
-24
View File
@@ -235,30 +235,6 @@ size_t get_system_md_symbols(
&result);
}
}
{
if (exchange == api::VENUE_FTX || exchange == api::VENUE_UNSET) {
auto const &e = config::get<config::system_symbols::Symbols>().ftx();
if (type == api::SECURITYTYPE_FUTURE ||
type == api::SECURITYTYPE_UNSET) {
add_symbols_to_result(
e.future(), api::VENUE_FTX, api::SECURITYTYPE_FUTURE, &result);
}
if (type == api::SECURITYTYPE_OPTION ||
type == api::SECURITYTYPE_UNSET) {
add_symbols_to_result(
e.option(), api::VENUE_FTX, api::SECURITYTYPE_OPTION, &result);
}
if (type == api::SECURITYTYPE_STOCK ||
type == api::SECURITYTYPE_UNSET) {
add_symbols_to_result(
e.option(), api::VENUE_FTX, api::SECURITYTYPE_STOCK, &result);
}
if (type == api::SECURITYTYPE_SPREAD ||
type == api::SECURITYTYPE_UNSET)
add_symbols_to_result(
e.spread(), api::VENUE_FTX, api::SECURITYTYPE_SPREAD, &result);
}
}
for (const auto &u : result) {
LOG(md, Info, "get_system_md_symbols loaded sym: {} exch: {} type: {}",
u.symbol(), Venue_Name(u.exchange()), SecurityType_Name(u.type()));
Loaded 100 of 360 files, more files were not shown because too many files have changed in this diff. Show more