Compare commits

..
1 Commits
Author SHA1 Message Date
johncolvin-og ea4e599ac6 fix build: Fix a few path errors in publish target 2023-05-31 21:59:51 -04:00
2003 changed files with 627060 additions and 178781 deletions

No files matched your search

-1
View File
@@ -4,7 +4,6 @@ BinPackParameters: false
AlignAfterOpenBracket: AlwaysBreak
AlwaysBreakTemplateDeclarations: true
PenaltyReturnTypeOnItsOwnLine: 140
ReflowComments: false
---
Language: Proto
IndentWidth: 2
+2 -2
View File
@@ -9,7 +9,7 @@
]
},
"fable": {
"version": "4.0.6",
"version": "4.0.0-theta-018",
"commands": [
"fable"
]
@@ -27,4 +27,4 @@
]
}
}
}
}
+1 -5
View File
@@ -50,8 +50,4 @@ trace_data/
*.tmp/*
/.venv*/*
.cache/
/src/Spark.Admin.WebApp/tsconfig.*.g.json
/src/Spark.Admin.WebApp/src/bin/
**/CMakeDeps.cmake
**/CMakeDeps_win.cmake
**/devcontainer.json
src/web/api/tsconfig.*.g.json
+6
View File
@@ -1,3 +1,9 @@
[submodule "externals"]
path = externals
url = git@bitbucket.org:bluetradesys/externals.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
+50 -153
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,27 +13,16 @@ set(
CACHE
STRING
"External dependencies root folder (should contain folders: lib, bin, include")
set(SPARK_PYTHON "${EXTERNALS_ROOT}/python")
set(SPARK_BIN "${EXTERNALS_ROOT}/bin")
set(SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/$<CONFIG>")
set(BUILD_API_SERVER OFF CACHE BOOL "Build the api server")
set(BUILD_DOCS OFF CACHE BOOL "Build documentation")
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
set(BUILD_SDK OFF CACHE BOOL "Build the sdk")
if (WIN32)
set(BUILD_SPARKD OFF CACHE BOOL "Build sparkd")
set(BUILD_ADMIN_WEB_APP OFF CACHE BOOL "Build the Admin WebApp")
else()
set(BUILD_SPARKD ON CACHE BOOL "Build sparkd")
set(BUILD_ADMIN_WEB_APP ON CACHE BOOL "Build the Admin WebApp")
endif()
set(BUILD_WEB ON CACHE BOOL "Build the web server")
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${SPARK_LIB})
if(BUILD_API_SERVER)
add_compile_definitions(SPARK_ENABLE_API_SERVER)
endif()
if(WIN32)
# flags
set(
@@ -47,7 +35,7 @@ if(WIN32)
/D_WINSOCK_DEPRECATED_NO_WARNINGS \
/D__TBB_NO_IMPLICIT_LINKAGE \
/DBOOST_ALL_NO_LIB \
/std:c++20 \
/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")
@@ -59,158 +47,67 @@ if(WIN32)
/OPT:ICF \
/LTCG")
add_compile_definitions(SHARED_MEMORY_PREFIX="spark")
add_compile_definitions(APP_DATA_DIR="\$\{APPDATA\}/bts/")
# 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")
set(SPARK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/$<CONFIG>")
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_EXCHANGE_FTX)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
if(BUILD_API_SERVER)
add_compile_definitions(APP_DATA_DIR="\$\{HOME\}/spark_api/")
add_compile_definitions(SHARED_MEMORY_PREFIX="spark_api")
elseif(BUILD_SPARKD)
add_compile_definitions(SHARED_MEMORY_PREFIX="sparkd")
add_compile_definitions(APP_DATA_DIR="\$\{HOME\}/sparkdata/")
# Note: All macros that begin w/ 'CCAPI' are ccapi's macros (defined and/or
# read by their code). We override some below.
add_compile_definitions(SPARK_ENABLE_CCAPI)
# This allows us to override hardcoded exchange-urls with ones read from
# config (i.e., resolved at runtime rather than compile-time)
add_compile_definitions(CCAPI_EXPOSE_INTERNAL)
# Enable ccapi services
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
# Enable ccapi exchanges
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_COIN_FUTURES)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_USDS_FUTURES)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_OKX)
set(CCAPI_LOG_LEVEL
"Warn"
CACHE STRING "<Fatal|Error|Warn|Info|Debug|Trace> Log level for ccapi")
string(TOUPPER "${CCAPI_LOG_LEVEL}" _ccapi_log_level_upper)
add_compile_definitions("CCAPI_ENABLE_LOG_${_ccapi_log_level_upper}")
# ** Binance **
add_compile_definitions(CCAPI_BINANCE_URL_REST_BASE="https://api.binance.com")
add_compile_definitions(BINANCE_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
add_compile_definitions(BINANCE_PRICE_STATS_PATH="/api/v3/ticker/24hr")
# ** Binance US **
add_compile_definitions(BINANCE_US_INSTRUMENTS_PATH="/api/v3/exchangeInfo")
add_compile_definitions(BINANCE_US_PRICE_STATS_PATH="/api/v3/ticker/24hr")
# ** Binance USDS Futures **
add_compile_definitions(CCAPI_BINANCE_USDS_FUTURES_URL_REST_BASE="https://dapi.binance.com")
add_compile_definitions(BINANCE_USDS_FUTURES_INSTRUMENTS_PATH="/dapi/v1/exchangeInfo")
add_compile_definitions(BINANCE_USDS_FUTURES_PRICE_STATS_PATH="/dapi/v1/ticker/24hr")
# ** Deribit **
add_compile_definitions(DERIBIT_INSTRUMENT_PATH="/api/v2/public/get_instrument")
add_compile_definitions(DERIBIT_INSTRUMENTS_PATH="/api/v2/public/get_instruments")
add_compile_definitions(DERIBIT_COMBOS_PATH="/api/v2/public/get_combos")
add_compile_definitions(DERIBIT_TICKER_PATH="/api/v2/public/ticker")
add_compile_definitions(DERIBIT_CURRENCIES_METHOD="public/get_currencies")
add_compile_definitions(DERIBIT_INSTRUMENT_METHOD="public/get_instrument")
add_compile_definitions(DERIBIT_INSTRUMENTS_METHOD="public/get_instruments")
add_compile_definitions(DERIBIT_COMBO_DETAILS_METHOD="public/get_combo_details")
add_compile_definitions(DERIBIT_COMBOS_METHOD="public/get_combos")
# ** Okx **
add_compile_definitions(OKX_INSTRUMENTS_PATH="/api/v5/public/instruments")
add_compile_definitions(OKX_UNDERLYING_PATH="/api/v5/public/underlying")
endif()
# 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_ADMIN_WEB_APP)
add_subdirectory(src/Spark.Admin.WebApp)
endif()
if (BUILD_API_SERVER)
set(_cs_source_dirs
spark_api
spark_api_server
spark_core
spark_websocket)
foreach(cs_source_dir IN LISTS _cs_source_dirs)
file(GLOB cs_source_dir "${CMAKE_SOURCE_DIR}/src/client/${cs_source_dir}/*.cs")
list(APPEND _api_server_sources ${cs_source_dir})
endforeach()
list(APPEND _api_server_sources
${CMAKE_SOURCE_DIR}/src/client/spark_api/spark_api.csproj
${CMAKE_SOURCE_DIR}/src/client/spark_api_server/spark_api_server.csproj
${CMAKE_SOURCE_DIR}/src/client/spark_core/spark_core.csproj
${CMAKE_SOURCE_DIR}/src/client/spark_websocket/spark_websocket.csproj)
set(_out_dir ${CMAKE_BINARY_DIR}/$<CONFIG>)
set(_api_server_dlls
${CMAKE_BINARY_DIR}/$<CONFIG>/bin/net7.0/spark_api.dll
${CMAKE_BINARY_DIR}/$<CONFIG>/bin/net7.0/spark_core.dll
${CMAKE_BINARY_DIR}/$<CONFIG>/bin/net7.0/spark_websocket.dll
${CMAKE_BINARY_DIR}/$<CONFIG>/bin/net7.0/spark_api_server)
add_custom_command(
OUTPUT ${_api_server_dlls}
COMMAND dotnet build ${CMAKE_SOURCE_DIR}/Spark.Api.Server.sln --verbosity minimal --configuration $<CONFIG>
COMMENT "Building Spark.Api.Server.sln"
DEPENDS ${_api_server_sources})
add_custom_command(
OUTPUT
${CMAKE_BINARY_DIR}/$<CONFIG>/bin/net7.0/libspark.so
COMMAND ln -sf ARGS ${CMAKE_BINARY_DIR}/src/lib/$<CONFIG>/libspark.so ${CMAKE_BINARY_DIR}/$<CONFIG>/bin/net7.0
COMMENT "Symlink libspark to api server bins"
DEPENDS ${_api_server_dlls})
add_custom_target(websocket_api_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/$<CONFIG>/bin/net7.0/libspark.so)
endif()
if(BUILD_DOCS)
add_subdirectory(doc/user)
if (BUILD_WEB)
add_subdirectory(src/web)
endif()
add_subdirectory(doc/user)
if(BUILD_SDK)
add_subdirectory(src/sdk)
endif()
add_subdirectory(src/data_files)
if(BUILD_SPARKD)
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}/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_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)
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
install(
DIRECTORY "${CMAKE_BINARY_DIR}/server/plugins"
DESTINATION "${SPARK_INSTALL_PREFIX}/bin")
install(
FILES
"${SPARK_LIB}/libACE-5.7.5.so"
"${SPARK_LIB}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0"
"${CMAKE_SOURCE_DIR}/externals/src/emumba/sparkd.lic"
DESTINATION "${SPARK_INSTALL_PREFIX}/bin")
endif()
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()
-351
View File
@@ -1,351 +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",
"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_SHARED_LINKER_FLAGS_DEBUG": "/DEBUG",
"CMAKE_SHARED_LINKER_FLAGS_RELEASE": "/OPT:REF /OPT:ICF /LTCG",
"EXTERNALS_ROOT": "${sourceDir}/externals/windows",
"CONFIG_DEFAULTS_PATH": "config/profiles/default/*.conf"
}
},
{
"name": "sparkd",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"platform": "",
"CMAKE_BUILD_WITH_INSTALL_RPATH": {
"type": "BOOL",
"value": "ON"
},
"CMAKE_CXX_STANDARD": "20",
"CMAKE_INSTALL_RPATH": ".",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}/sparkd",
"CMAKE_EXE_LINKER_FLAGS": "-Wno-undef",
"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",
"CONFIG_DEFAULTS_PATH": "config/profiles/md_dev/*.conf;config/profiles/default/*.conf"
}
},
{
"name": "sparkd-release",
"inherits": "sparkd",
"hidden": true,
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CCAPI_LOG_LEVEL": "Warn",
"CONFIG_DEFAULTS_PATH": "config/profiles/md_prod/*.conf;config/profiles/default/*.conf"
}
},
{
"name": "sparkd-debug-clang",
"inherits": "sparkd-debug",
"displayName": "Debug (clang)",
"description": "Debug build compiled w/ clang",
"binaryDir": "${sourceDir}/build/clang/debug",
"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",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/clang/debug/sparkd"
}
},
{
"name": "sparkd-debug-gcc",
"inherits": "sparkd-debug",
"displayName": "Debug (gcc)",
"description": "Debug build compiled w/ gcc",
"binaryDir": "${sourceDir}/build/gcc/debug",
"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",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/gcc/debug/sparkd"
}
},
{
"name": "sparkd-release-clang",
"inherits": "sparkd-release",
"displayName": "Release (clang)",
"description": "Release build compiled w/ clang",
"binaryDir": "${sourceDir}/build/clang/release",
"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",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/clang/release/sparkd"
}
},
{
"name": "sparkd-release-gcc",
"inherits": "sparkd-release",
"displayName": "Release (gcc)",
"description": "Release build compiled w/ gcc",
"binaryDir": "${sourceDir}/build/gcc/release",
"cacheVariables": {
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -Wno-stringop-overread -Wno-maybe-uninitialized -fno-omit-frame-pointer -DNDEBUG -O3",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/gcc/release/sparkd"
}
},
{
"name": "spark-api-server-base",
"inherits": "spark",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"BUILD_API_SERVER": {
"type": "bool",
"value": "ON"
},
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0",
"DOTNET_WINDOWS_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0-windows"
}
},
{
"name": "spark-api-server-windows",
"inherits": "spark-api-server-base",
"displayName": "Spark Api Server",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Visual Studio 17 2022"
},
{
"name": "spark-api-server-linux",
"inherits": "spark-api-server-base",
"displayName": "Spark Api Server",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"generator": "Ninja Multi-Config",
"cacheVariables": {
"BUILD_ADMIN_WEB_APP": {
"type": "BOOL",
"value": "OFF"
}
}
},
{
"name": "sparkd-publish",
"inherits": "sparkd-release-gcc",
"displayName": "Publish",
"description": "Production build compiled w/ gcc and ready to ship"
},
{
"name": "sparkd-ccapi-diag",
"inherits": "sparkd-debug-clang",
"displayName": "Debug (ccapi diag)",
"description": "Debug build w/ ccapi log level 'Trace'",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CCAPI_LOG_LEVEL": "Trace"
}
}
],
"buildPresets": [
{
"name": "spark",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"hidden": true
},
{
"name": "spark-debug",
"displayName": "Debug",
"inherits": "spark",
"configurePreset": "spark",
"configuration": "Debug"
},
{
"name": "spark-release",
"displayName": "Release",
"inherits": "spark",
"configurePreset": "spark",
"configuration": "Release"
},
{
"name": "sparkd",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"hidden": true,
"targets": [
"data_files_dir",
"admin_web_app_bundle",
"install",
"libspark",
"rapidjson_project",
"server_layout",
"sparkd"
]
},
{
"name": "sparkd-debug-clang",
"configurePreset": "sparkd-debug-clang",
"displayName": "Debug (clang)",
"inherits": "sparkd"
},
{
"name": "sparkd-debug-gcc",
"configurePreset": "sparkd-debug-gcc",
"displayName": "Debug (gcc)",
"inherits": "sparkd"
},
{
"name": "sparkd-release-clang",
"configurePreset": "sparkd-release-clang",
"displayName": "Release (clang)",
"inherits": "sparkd"
},
{
"name": "sparkd-release-gcc",
"configurePreset": "sparkd-release-gcc",
"displayName": "Release (gcc)",
"inherits": "sparkd"
},
{
"name": "spark-api-server-windows",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"hidden": true,
"configurePreset": "spark-api-server-windows"
},
{
"name": "spark-api-server-windows-debug",
"displayName": "Spark Api Server (Debug)",
"inherits": "spark-api-server-windows",
"configuration": "Debug"
},
{
"name": "spark-api-server-windows-release",
"displayName": "Spark Api Server (Debug)",
"inherits": "spark-api-server-windows",
"configuration": "Release"
},
{
"name": "spark-api-server-linux",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"hidden": true,
"configurePreset": "spark-api-server-linux"
},
{
"name": "spark-api-server-linux-debug",
"inherits": "spark-api-server-linux",
"displayName": "Spark Api Server (Debug)",
"configuration": "Debug"
},
{
"name": "spark-api-server-linux-release",
"inherits": "spark-api-server-linux",
"displayName": "Spark Api Server (Release)",
"configuration": "Release"
},
{
"name": "sparkd-publish",
"configurePreset": "sparkd-publish",
"displayName": "Publish",
"inherits": "sparkd",
"targets": "install"
},
{
"name": "sparkd-ccapi-diag",
"configurePreset": "sparkd-ccapi-diag",
"displayName": "Debug (ccapi diag)",
"inherits": "sparkd"
}
]
}
-83
View File
@@ -1,83 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
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("{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_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{89D666E6-B500-498F-B026-4D167F68ADFC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
MinSizeRel|x64 = MinSizeRel|x64
Release|x64 = Release|x64
RelWithDebInfo|x64 = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.ActiveCfg = Debug|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.Build.0 = Debug|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.Build.0 = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.Debug|x64.ActiveCfg = Debug|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.Debug|x64.Build.0 = Debug|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.MinSizeRel|x64.ActiveCfg = Debug|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.MinSizeRel|x64.Build.0 = Debug|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.Release|x64.ActiveCfg = Release|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.Release|x64.Build.0 = Release|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.RelWithDebInfo|x64.ActiveCfg = Debug|x64
{EFC9FC4D-E92B-4C6D-9B97-26D38EAA118D}.RelWithDebInfo|x64.Build.0 = Debug|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.Debug|x64.ActiveCfg = Debug|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.Debug|x64.Build.0 = Debug|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.MinSizeRel|x64.ActiveCfg = Debug|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.MinSizeRel|x64.Build.0 = Debug|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.Release|x64.ActiveCfg = Release|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.Release|x64.Build.0 = Release|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.RelWithDebInfo|x64.ActiveCfg = Debug|x64
{89D666E6-B500-498F-B026-4D167F68ADFC}.RelWithDebInfo|x64.Build.0 = Debug|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal
-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
View File
@@ -121,6 +121,8 @@ function(Service_Compiler_Generate_Cpp SRCS HDRS)
endforeach()
set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
# remove some warnings from protobuf generated files
if(WIN32)
set_source_files_properties(${${SRCS}} PROPERTIES COMPILE_FLAGS
-223
View File
@@ -1,223 +0,0 @@
[cmake]: https://cmake.org/
[cmake ext]: https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools
[cmake presets]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html
[cpp ext]: https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools
[clangd ext]: https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd
[dotnet]: https://dotnet.microsoft.com/en-us/download/dotnet
[ninja build]: https://ninja-build.org/
[ninja multi-config generator]: https://cmake.org/cmake/help/latest/generator/Ninja%20Multi-Config.html
[python]: https://www.python.org/
[py venv]: https://docs.python.org/3/library/venv.html
[visual studio]: https://visualstudio.microsoft.com/
[visual studio generator]: https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2017%202022.html
# C++ Intellisense for Spark on Windows (VS Code)
**Steps**
1. Install the **[C++ extension][cpp ext]**
2. Install the **[CMake extension][cmake ext]**
3. Copy `c_cpp_properties.json` from this folder to `$workspaceFolder/.vscode/`
4. In the VS Code Command Palette, run **CMake: Select Configure Preset**, then
select '**spark**' from the dropdown
**Notes**
* Intellisense won't work for generated files/types until you build libspark
# C++ Intellisense for Sparkd on Linux (VS Code)
1. Install the **[CMake extension][cmake ext]**
2. Install the **[Clangd extension][clangd ext]**
3. (Optional) Install the **[C++ extension][cpp ext]** (*needed for debugging,
but intellisense should work without it*).
4. If the **[C++ extension][cpp ext]** is installed, disable its intellisense in
your workspace settings (*Clangd intellisense is better*)
```
"C_Cpp.intelliSenseEngine": "disabled"
```
5. In the VS Code Command Palette, run **CMake: Select Configure Preset**, then select the
**[preset][cmake presets]** you wish to build from the dropdown
* *The **Clang** presets may work best with the **Clangd** extension*
* *Intellisense won't work for generated files/types until you build libspark*
# Build Spark on Windows
### Dependencies
* **[CMake][cmake]** (version >= 3.23)
* **[Python][python]** (version >= 3.9)
* **[Visual Studio][visual studio]** (2022)
* **[Dotnet][dotnet]** (sdk version >= 7.0.0)
### References
* **[CMakePresets][cmake presets]**
* **[Visual Studio 17 2022 (CMake generator)][visual studio generator]**
* **[Python Virtual Environment][py venv]**
### Notes
* *Run commands from the repo root dir unless otherwise noted*
1. Set up the **[Python virtual environment][py venv]**<br>
```
# Create the virtual environment
python3 -m venv .venv
# Activate the virtual environment
.venv\bin\activate.bat
# Update pip
python -m pip install --upgrade pip
# Install packages
pip install -r requirements.txt
```
2. Build
* *Run commands in python virtual environment*
```
# Configure
cmake --preset spark
# Build Debug
cmake --build --preset spark-debug
dotnet build spark_client.sln --configuration Debug
# Build Release
cmake --build --preset spark-release
dotnet build spark_client.sln --configuration Release
```
# Build Sparkd on Linux
### **Dependencies**
* **[CMake][cmake]** (version >= 3.23)
* **[Ninja Build][ninja build]**
* **[Python][python]** (version >= 3.9)
* **[Docker][docker]**
### **References**
* **[CMakePresets][cmake presets]**
* **[Ninja (CMake generator)][ninja generator]**
* **[Python Virtual Environment][py venv]**
* **[Devcontainer](devcontainer)**
### Prerequisites
* Open repository in a VS Code [Devcontainer](../docker/sparkd/dev/README.md), or
create your own [docker container](../docker/sparkd/dev/README.md) in which to build
### Notes
* *Run commands from the repo root dir unless otherwise noted*<br>
1. Set up the **[Python virtual environment][py venv]**
```
# Create the virtual environment
python3 -m venv .venv
# Activate the virtual environment
. .venv/bin/activate
# Update pip
python -m pip install --upgrade pip
# Install packages
pip install -r requirements.txt
```
2. Build
* *Run commands in python virtual environment*
```
# Configure clang debug
cmake --preset sparkd-clang-debug
# Build clang debug
cmake --build --preset spark-clang-debug
# Configure gcc release
cmake --build --preset sparkd-gcc-release
# Build gcc release
cmake --build --preset sparkd-gcc-release
```
# Build Spark Api Server on Windows
### **Dependencies**
* **[CMake][cmake]** (version >= 3.23)
* **[Python][python]** (version >= 3.9)
* **[Visual Studio][visual studio]** (version)
* **[Dotnet][dotnet]** (sdk version >= 7.0.0)
### **References**
* **[CMakePresets][cmake presets]**
* **[Visual Studio 17 2022 (CMake generator)][visual studio generator]**
* **[Python Virtual Environment][py venv]**
### Notes
* *Run commands from the repo root dir unless otherwise noted*
1. Set up the **[Python Virtual Environment][py venv]**
```
# Create the virtual environment
python3 -m venv .venv
# Activate the virtual environment
.venv\bin\activate.bat
# Update pip
python -m pip install --upgrade pip
# Install packages
pip install -r requirements.txt
```
2. Build
* *Run in python virtual environment*
```
# Configure
cmake --preset spark-api-server-windows
# Build debug
cmake --build --preset spark-api-server-windows-debug
dotnet build Spark.Api.Server.sln --configuration Debug
# Build release
cmake --build --preset spark-api-server-windows-release
dotnet build Spark.Api.Server.sln --configuration Release
```
# Build Spark Api Server on Linux
### **Dependencies**
* **[CMake][cmake]** (version >= 3.23)
* **[Python][python]** (version >= 3.9)
* **[Dotnet][dotnet]** (sdk version >= 7.0.0)
### **References**
* **[CMakePresets][cmake presets]**
* **[Ninja Multi-Config (CMake generator)][ninja multi-config generator]**
* **[Python Virtual Environment][py venv]**
### Prerequisites
* Open repository in a VS Code [Devcontainer](../docker/sparkd/dev/README.md), or
create your own [docker container](../docker/sparkd/dev/README.md) in which to build
### Notes
* *Run commands from the repo root dir unless otherwise noted*
1. Set up the **[Python Virtual Environment][py venv]**
```
# Create the virtual environment
python3 -m venv .venv
# Activate the virtual environment
. .venv/bin/activate
# Update pip
python -m pip install --upgrade pip
# Install packages
pip install -r requirements.txt
```
2. Build
* *Run in python virtual environment*
```
# Configure
cmake --preset spark-api-server-linux
# Build debug
cmake --build --preset spark-api-server-linux-debug
dotnet build Spark.Api.Server.sln --configuration Debug
# Build release
cmake --build --preset spark-api-server-linux-release
dotnet build Spark.Api.Server.sln --configuration Release
```
-27
View File
@@ -1,27 +0,0 @@
{
"version": 4,
"configurations": [
{
"name": "Windows",
"intelliSenseMode": "windows-msvc-x64",
"includePath": [
"${workspaceFolder}/src/",
"${workspaceFolder}/build/src/",
"${workspaceFolder}/externals/windows/include/"
],
"defines": ["_WIN32", "__x86_64__"],
"browse": {
"path": [
"${workspaceRoot}/src",
"${workspaceRoot}/build/src"
],
"limitSymbolsToIncludedHeaders": true
},
"cStandard": "c17",
"cppStandard": "c++17",
"configurationProvider": "ms-vscode.cmake-tools",
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.34.31933/bin/Hostx64/x64/cl.exe",
"mergeConfigurations": true
}
]
}
+1
View File
@@ -0,0 +1 @@
set(sources /home/taha/spark/doc/user/build.sh;content/_index.md;content/bts_spark/Glossary/_index.md;content/bts_spark/Help/_index.md;content/bts_spark/Help/about_spark.png;content/bts_spark/Help/image39.png;content/bts_spark/Help/image58.png;content/bts_spark/Launcher/_index.md;content/bts_spark/Launcher/image38.png;content/bts_spark/Launcher/image68.png;content/bts_spark/Logging-In-to-the-System/_index.md;content/bts_spark/Logging-In-to-the-System/image3.png;content/bts_spark/Logging-In-to-the-System/image64.png;content/bts_spark/Market/_index.md;content/bts_spark/Market/change_securities.png;content/bts_spark/Market/image11.png;content/bts_spark/Market/image14.png;content/bts_spark/Market/image20.png;content/bts_spark/Market/image21.png;content/bts_spark/Market/image23.png;content/bts_spark/Market/image24.png;content/bts_spark/Market/image34.png;content/bts_spark/Market/image49.png;content/bts_spark/Market/image53.png;content/bts_spark/Market/image66.png;content/bts_spark/Market/image69.png;content/bts_spark/Market/market_view.png;content/bts_spark/Market/settings_icon.png;content/bts_spark/Market/time_and_sales.png;content/bts_spark/My-Windows/_index.md;content/bts_spark/My-Windows/image15.png;content/bts_spark/My-Windows/image16.png;content/bts_spark/My-Windows/image37.png;content/bts_spark/Settings/_index.md;content/bts_spark/Settings/image51.png;content/bts_spark/Settings/image9.png;content/bts_spark/Spreader/_index.md;content/bts_spark/Spreader/image10.png;content/bts_spark/Spreader/image13.png;content/bts_spark/Spreader/image18.png;content/bts_spark/Spreader/image19.png;content/bts_spark/Spreader/image28.png;content/bts_spark/Spreader/image29.png;content/bts_spark/Spreader/image31.png;content/bts_spark/Spreader/image35.png;content/bts_spark/Spreader/image40.png;content/bts_spark/Spreader/image43.png;content/bts_spark/Spreader/image54.png;content/bts_spark/Spreader/image55.png;content/bts_spark/Spreader/image56.png;content/bts_spark/Spreader/image6.png;content/bts_spark/Spreader/image7.png;content/bts_spark/Spreader/image70.png;content/bts_spark/Spreader/image72.png;content/bts_spark/Spreader/image8.png;content/bts_spark/Trading/OrderTypes/index.md;content/bts_spark/Trading/_index.md;content/bts_spark/Trading/algo_studio.png;content/bts_spark/Trading/collapse_all_icon.png;content/bts_spark/Trading/cover_algo_control.png;content/bts_spark/Trading/expand_all_icon.png;content/bts_spark/Trading/image1.png;content/bts_spark/Trading/image17.png;content/bts_spark/Trading/image2.png;content/bts_spark/Trading/image25.png;content/bts_spark/Trading/image27.png;content/bts_spark/Trading/image33.png;content/bts_spark/Trading/image42.png;content/bts_spark/Trading/image44.png;content/bts_spark/Trading/image47.png;content/bts_spark/Trading/image48.png;content/bts_spark/Trading/image5.png;content/bts_spark/Trading/image50.png;content/bts_spark/Trading/image52.png;content/bts_spark/Trading/image57.png;content/bts_spark/Trading/image59.png;content/bts_spark/Trading/image60.png;content/bts_spark/Trading/image61.png;content/bts_spark/Trading/image62.png;content/bts_spark/Trading/image73.png;content/bts_spark/Trading/image74.png;content/bts_spark/Trading/join_algo_control.png;content/bts_spark/Trading/ladder.png;content/bts_spark/Trading/ladder_badges.png;content/bts_spark/Trading/ladder_main_part.png;content/bts_spark/Trading/lean_algo_control.png;content/bts_spark/Trading/mini_orderbook.png;content/bts_spark/Trading/oco_algo_control.png;content/bts_spark/Trading/offset_algo_control.png;content/bts_spark/Trading/pnl_calculation.png;content/bts_spark/Trading/pnl_window.png;content/bts_spark/Trading/recreate_icon.png;content/bts_spark/Trading/settings_icon.png;content/bts_spark/Trading/spark_menu_order_book.png;content/bts_spark/Trading/top_algo_control.png;content/bts_spark/Trading/trigger_algo_control.png;content/bts_spark/_index.md;content/release_notes/_index.md;content/system_requirements/_index.md;static/book.js;static/favicon.ico;static/image.js;templates/index.html;templates/page.html;templates/section.html;templates/shortcodes/back_button.html)
Submodule
+1
Submodule docker/linux added at 6537812262.
-103
View File
@@ -1,103 +0,0 @@
FROM ubuntu:22.10
RUN \
apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
clang-13 \
clang-format-13 \
clangd-13 \
clang-15 \
clang-format-15 \
clangd-15 \
cmake \
curl \
dotnet7 \
fish \
g++-11 \
g++-12 \
gnupg \
liblttng-ust-dev \
libssh2-1-dev \
libpcap0.8-dev \
locales \
ninja-build \
nodejs \
npm \
openssh-server \
python3-pip \
python3-venv \
rapidjson-dev \
software-properties-common \
sqlite3 \
sudo \
tar \
vim \
wget
# this is done here so that ccache sees clang++ installed, not clang-10
RUN \
apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y ccache
# emumba deps
RUN \
apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
tzdata \
build-essential \
cmake-curses-gui \
git-all \
doxygen \
python3-sphinx \
graphviz \
libgtest-dev \
libssl-dev \
libboost-filesystem-dev \
libboost-program-options-dev \
libboost-test-dev \
libboost-date-time-dev \
zlib1g-dev \
netcat-traditional \
net-tools \
gdb gdbserver \
pkg-config
# set up default executables (update-alternatives)
RUN \
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-13 100; \
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-13 100; \
update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-13 100; \
update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-13 100; \
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100; \
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 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-13; \
ln -s /usr/bin/ccache /usr/local/bin/clang++-13; \
ln -s /usr/bin/ccache /usr/local/bin/clang-15; \
ln -s /usr/bin/ccache /usr/local/bin/clang++-15; \
ln -s /usr/bin/ccache /usr/local/bin/gcc; \
ln -s /usr/bin/ccache /usr/local/bin/g++; \
ln -s /usr/bin/ccache /usr/local/bin/gcc-11; \
ln -s /usr/bin/ccache /usr/local/bin/g++-11; \
ln -s /usr/bin/ccache /usr/local/bin/gcc-12; \
ln -s /usr/bin/ccache /usr/local/bin/g++-12
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"
-64
View File
@@ -1,64 +0,0 @@
[dev containers]: https://code.visualstudio.com/docs/devcontainers/containers
[dev containers ext]: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
[docker repo sparkd-dev]: https://hub.docker.com/repository/docker/bluetradingsystems/sparkd-dev/general
# Sparkd Dev Container
## How to create a VS Code [Dev Container][dev containers]
1. Make sure the **[Dev Containers][dev containers ext]** extension is installed
1. Make sure your Docker image is up to date
```
docker pull bluetradingsystems/sparkd-dev:latest
```
1. Copy **devcontainer.json** from this folder to **$workspaceFolder/.devcontainer/**.
1. In the VS Code Command Palette, run **Dev Containers: Reopen in Container**
---
## How to create a Sparkd Container in the terminal (without VS Code)
1. Make sure your Docker image is up to date
```
docker pull bluetradingsystems/sparkd-dev:latest
```
2. Start the container
```
# Replace <cont_name> with a name for the container. The container's
# "$HOME" dir will be mounted to "$HOME/.sparkd-dev/mounts/<cont_name> on
# the host
./start_docker.sh --container <cont_name> --mount-existing
```
* *Replace <cont_name> with a name for the container*
* *The container's `$HOME` dir will be mounted to
`$HOME/.sparkd-dev/mounts<cont_name>` on the host*<br>
* *Run: `./start_docker.sh --help` to see additional options*
3. *(Optional) Attach VS Code to the running container.*<br>
Run **Dev Containers: Attach to Running Container** from the command palette,
then select your container in the dropdown
---
## How to update the Docker image
1. Change the image by modifying the Dockerfile (don't tag arbitrary
images on your machine and push them to our repo on Docker Hub)
1. After modifying the Dockerfile, (re)build the image
```
# Run in this dir
docker build -t bluetradingsystems/sparkd-dev:latest .
```
***Note:** Your docker login must have write permissions to push to the
[sparkd-dev][docker repo sparkd-dev] repository*
2. Commit the changes to Dockerfile in git
3. Push the new image to Docker Hub
```
docker push johncolvin/bluetradingsystems:sparkd-dev
```
***Note:** The image doesn't have to be on Docker Hub, we can simply build
it from scratch on our local machines (with the Dockerfile). However, this
takes time. It is significantly quicker to download a prebuilt image, so we
store it on a remote repository to save time when setting up a new dev
machine.*
-123
View File
@@ -1,123 +0,0 @@
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar
# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color|*-256color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# Add an "alert" alias for long running commands. Use like so:
# sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
if [[ ! -v XDG_CONFIG_HOME ]]; then
export XDG_CONFIG_HOME="$HOME/.config"
fi
export PATH="$HOME/.local/bin:$PATH"
-25
View File
@@ -1,25 +0,0 @@
if ! set -q XDG_CONFIG_HOME
set -g XDG_CONFIG_HOME "$HOME/.config"
end
set fish_config_home $XDG_CONFIG_HOME/fish
if test -f "$fish_config_home/aliases.fish"
source "$fish_config_home/aliases.fish"
end
# enable general colors and case insensitive search in 'less'
set -x LESS "$LESS -R -Q -I"
set -x LC_ALL en_US.UTF-8
# enable syntax highlighting in 'less'
# set highlight color scheme in 'less' (fg)(bg)
set -g LESS_TERMCAP_md (tput bold)(tput setaf 36)
set -g LESS_TERMCAP_me (tput sgr0)
set -g LESS_TERMCAP_so (tput setaf 232)(tput setab 49)
set -q TERM
if test $status != 0; or test $TERM = 'xterm'
set -g TERM 'xterm-256color'
end
# Fix impossible-to-see navy blue command text color
set fish_color_command F8F8F2
set -g PATH "$HOME/.local/bin" "$PATH"
-32
View File
@@ -1,32 +0,0 @@
{
"image": "bluetradingsystems/sparkd-dev:latest",
"initializeCommand": "${localWorkspaceFolder}/docker/sparkd/dev/devcontainer_initialize.sh",
"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",
"-p",
"8000:8000",
"-p",
"8001:8001",
"-p",
"8002:8002",
"-p",
"8003:8003"
],
"mounts": [
"source=${localEnv:HOME}/.sparkd-dev/mounts/sparkd-dev,target=/home/bts,type=bind"
]
}
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
mkdir -p "$HOME/.sparkd-dev/mounts/sparkd-dev"
@@ -1,33 +0,0 @@
#!/usr/bin/env bash
this_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
repo_dir="$(cd "$this_dir" && git rev-parse --show-toplevel)"
tools_dir="$repo_dir/tools"
gen_tag="GENERATED BY $(basename "${BASH_SOURCE[0]}")"
function copy_if_not_exist() {
src="$1"
dest="$2"
if [[ ! -e "$src" ]]; then
echo "Unable to copy $src to $dest. Source file doesn't exist"
exit 1
fi
if [[ ! -e "$dest" ]]; then
cp "$src" "$dest"
fi
}
# Init bashrc
echo "Initializing bashrc"
copy_if_not_exist "$this_dir/bashrc" "$HOME/.bashrc"
# Init fish config
echo "Initializing fish config"
fish_cfg_dir="$HOME/.config/fish/"
mkdir -p "$fish_cfg_dir"
exec "$tools_dir/write_tag_block.sh" \
--tag "$gen_tag" \
--replace \
--in-place \
--file "$fish_cfg_dir/config.fish" \
--text "$(cat "$this_dir/config.fish")"
-250
View File
@@ -1,250 +0,0 @@
#!/usr/bin/env bash
function _exit() {
if [[ "$#" -gt 1 ]]; then
# When there are multiple args, the last arg is the exit code.
echo "${@:1:($# - 1)}"
exit "${@: -1}"
fi
echo "$1"
exit 0
}
help_text="\
Add or update a user's uid
This script is intended to be run in a Docker container as a means to obtain
file permissions in mounted directories owned by the specified UID.
Usage: set_user.sh [OPTIONS] USER UID
Positionals:
USER The name of the user
Options:
--user USER The name of the user (defaults to 'bts')
--uid UID The new uid to give USER (defaults to '1000')
--group GROUP The primary group to give USER (defaults to USER)
--gid GID The primary gid to give USER (defaults to UID)
--pass PASSWORD The password to give USER (defaults to USER, only applies
if USER hasn't been created yet)
--modify-existing Update UID/GID even if USER already exists
-h,--help Print this help message and exit
"
function _add_group() {
if [[ "$#" -ne 2 ]]; then
_exit "'_add_group' requires exactly 2 args (group, gid). Received $#." 1
fi
local group="$1"
local gid="$2"
# Check if gid already exists
local existing_group=""
existing_group="$(getent group "$gid" | cut -d : -f 1)"
if [[ -n "$existing_group" ]]; then
if [[ "$existing_group" != "$group" ]]; then
echo "\
The gid '$gid' is already in use by group '$existing_group' (will not rename \
the group)"
fi
return
fi
# Check if group with same name already exists
local existing_gid=""
existing_gid="$(getent group "$group" | cut -d : -f 3)"
if [[ -n "$existing_gid" ]]; then
# The group already exists. Only modify if --modify-existing was specified.
if [[ "$modify_existing" -eq 0 ]]; then
_exit "\
The group '$group' already exists with gid '$existing_gid'.
Specify --modify-existing to change the gid anyways." 1
fi
echo "Changing gid for group '$group' from '$existing_gid' to '$gid'"
groupmod -g "$gid" "$group"
else
# The group doesn't exist. Add it
echo "Adding group '$group:$gid'"
groupadd -g "$gid" "$group"
fi
}
function _add_user() {
local user="$1"
local uid="$2"
local group="$3"
local gid="$4"
local pass="$5"
if [[ "$#" -ne 5 ]]; then
_exit "'_add_user' requires exactly 5 args (user, uid, group, gid, pass). \
Received $#." 1
fi
# Check if uid is being used by another user
local existing_user=""
existing_user="$(getent passwd "$uid" | cut -d : -f 1)"
if [[ -n "$existing_user" ]]; then
if [[ "$existing_user" != "$user" ]]; then
_exit "The uid '$uid' is already in use by user '$existing_user'." 1
fi
echo "The user '$user' already has the specified uid '$uid'."
# Modify gid if necessary
local existing_gid=""
existing_gid="$(id -g "$user" 2> /dev/null)"
if [[ "$existing_gid" = "$gid" ]]; then
echo "The user '$user' already has the specified gid '$gid'."
return
fi
if [[ "$modify_existing" -eq 0 ]]; then
_exit "\
The user '$user' is associated with the primary group '$existing_gid'.
Specify --modify-existing to change the gid anyways." 1
fi
echo "Changing primary group for '$user' from '$existing_gid' to '$gid'."
usermod -g "$gid" "$user"
return
fi
# Check if user with same name already exists
local existing_uid=""
existing_uid="$(id -u "$user" 2> /dev/null)"
if [[ -n "$existing_uid" ]]; then
if [[ "$existing_uid" = "$uid" ]]; then
_exit "The user '$user' already has the specified uid '$uid'" 0
fi
if [[ "$modify_existing" -eq 0 ]]; then
_exit "\
User '$user' already exists with uid '$existing_uid'.
Specify --modify-existing to change the uid anyways." 1
fi
echo "Changing uid for user '$user' from '$existing_uid' to '$uid'"
if ! usermod -u "$uid" -g "$gid" "$user"; then
_exit "usermod exited with code $?" 1
fi
return
fi
# The user doesn't exist. Add it
echo "Adding user '$user:$uid' (group='$group:$gid', password='$pass')"
useradd -m -u "$uid" -g "$gid" -G sudo --password "$(openssl passwd -1 "$pass")" "$user"
}
function _update_fish_dir_perms() {
local user="$1"
local uid="$2"
local gid="$3"
# When a fish shell session starts, a temp dir named '/tmp/fish.<user>' is
# created with the user's current uid/gid. If such a dir exists for the
# specified USER, make sure the uid/gid match the new values.
fish_dir="/tmp/fish.$user"
if [[ -d "$fish_dir" ]]; then
perms="$uid:$gid"
existing_perms="$(stat -c %u:%g "$fish_dir")"
if [[ "$existing_perms" != "$perms" ]]; then
echo "Changing uid:gid for dir '$fish_dir' from '$existing_perms' to '$perms'"
chown -R "$perms" "$fish_dir"
fi
fi
}
user=""
group=""
pass=""
declare -i uid=0
declare -i gid=0
declare -i modify_existing=0
while [[ $# -gt 0 ]]; do
case "$1" in
--user)
if [[ -z "$2" ]]; then
_exit "USER (--user) must be non-empty" 1
elif [[ "$2" = "root" ]]; then
_exit "USER (--user) cannot be 'root'" 1
fi
user="$2"
shift 2
;;
--group)
if [[ -z "$2" ]]; then
_exit "GROUP (--group) must be non-empty" 1
elif [[ "$2" = "root" ]]; then
_exit "GROUP (--group) cannot be 'root'" 1
fi
group="$2"
shift 2
;;
--uid)
if [[ -z "$2" ]]; then
_exit "UID (--uid) must be non-empty" 1
fi
uid="$2"
shift 2
;;
--gid)
if [[ -z "$2" ]]; then
_exit "GID (--gid) must be non-empty" 1
fi
gid="$2"
shift 2
;;
--pass)
if [[ -z "$2" ]]; then
_exit "PASS (--pass) must be non-empty" 1
fi
pass="$2"
shift 2
;;
--modify-existing)
modify_existing=1
shift 1
;;
-h)
;&
--help)
_exit "$help_text" 0
;;
*)
if [[ -z "$1" ]]; then
_exit "Invalid positional argument '$1'" 1
elif [[ -z "$user" ]]; then
user="$1"
elif [[ -z "$uid" ]]; then
uid="$1"
else
_exit "Unexpected argument '$1'" 1
fi
shift 1
;;
esac
done
if [[ -z "$user" ]]; then
user="bts"
fi
if [[ $uid -eq 0 ]]; then
uid=1000
fi
# In general, a user's primary group/gid matches the user's name/uid.
# If group/gid args weren't specified, set them to name/uid.
if [[ -z "$group" ]]; then
group="$user"
fi
if [[ $gid -eq 0 ]]; then
gid=$uid
fi
if [[ -z "$pass" ]]; then
pass="$user"
fi
_add_group "$group" "$gid"
_add_user "$user" "$uid" "$group" "$gid" "$pass"
_update_fish_dir_perms "$user" "$uid" "$gid"
-230
View File
@@ -1,230 +0,0 @@
#!/usr/bin/env bash
function _exit() {
if [[ "$#" -gt 1 ]]; then
# When there are multiple args, the last arg is the exit code.
echo "${@:1:($# - 1)}"
exit "${@: -1}"
fi
echo "$1"
exit 0
}
help_text="\
Start a docker dev container
Usage: start_docker.sh [OPTIONS] image container
Positionals:
image The image to instantiate
container The name for the container
Options:
-u,--user USER The user to add in the container (defaults to 'bts')
-p,--pass PASS The password for USER in the container (defaults to USER)
-i,--image IMAGE The image to instantiate (defaults to 'bluetradingsystems/sparkd-dev:latest')
-c,--container CONT The name for the container
-m,--mount MOUNT The name for the folder (outside the container) to create/mount to the home
directory in the container. Mount folders are added here: $mount_prefix
--mount-existing Mount the specified dir even if it already exists
--port <cont_port>:<host_port> OR [<cont_port>:<host_port>,...] Port mapping(s). May be
specified multiple times.
-h,--help Print this help message and exit
"
mount_prefix="$HOME/.sparkd-dev/mounts"
declare docker_user=""
declare docker_pass=""
declare image_name=""
declare cont_name=""
declare mount_name=""
declare -i mount_existing=0
declare -a port_mappings=()
while [[ $# -gt 0 ]]; do
case "$1" in
-u)
;&
--user)
if [[ -z "$2" ]]; then
_exit "User (-u,--user) must be non-empty" 1
fi
docker_user="$2"
shift 2
;;
-p)
;&
--pass)
if [[ -z "$2" ]]; then
_exit "Password (-p,--pass) must be non-empty" 1
fi
docker_pass="$2"
shift 2
;;
-i)
;&
--image)
if [[ -n "$image_name" ]]; then
_exit "Unexpected argument '$1'" 1
elif [[ -z "$2" ]]; then
_exit "Image (-i,--image) must be non-empty" 1
fi
image_name="$2"
shift 2
;;
-c)
;&
--container)
if [[ -n "$cont_name" ]]; then
_exit "Unexpected argument '$1'" 1
elif [[ -z "$2" ]]; then
_exit "Container (-c,--container) must be non-empty" 1
fi
cont_name="$2"
shift 2
;;
--port)
# Parse port(s) arg, and append the result to 'port_mappings'
# Note: port(s) may be specified in bracketed notation:
# [a:b,c:d,...,y:z]
next_ports="$(echo "$2" | sed -e 's/\[//g' -e 's/\]//g' -e 's/,/ /g')"
if [[ "${#port_mappings[@]}" -gt 0 ]]; then
next_ports=" $next_ports"
fi
port_mappings+=("$next_ports")
shift 2
;;
-m)
;&
--mount)
if [[ -z "$2" ]]; then
echo "Mount (-m,--mount) must be non-empty"
fi
mount_name="$2"
shift 2
;;
--mount-existing)
mount_existing=1
shift 1
;;
-h)
;&
--help)
_exit "$help_text" 0
;;
*)
if [[ -z "$1" ]]; then
_exit "Invalid positional argument '$1'" "$help_text" 1
elif [[ -z "$image_name" ]]; then
image_name="$1"
elif [[ -z "$cont_name" ]]; then
cont_name="$1"
else
_exit "Unexpected argument '$1'" "$help_text" 1
fi
shift 1
;;
esac
done
if [[ -z "$image_name" ]]; then
image_name="bluetradingsystems/sparkd-dev:latest"
fi
host_name="$(hostname)"
if [[ -n "$cont_name" ]]; then
host_name="$host_name.$cont_name"
fi
if [[ -z "$mount_name" ]]; then
mount_name="$cont_name"
fi
if [[ -z "$mount_name" && -z "$cont_name" ]]; then
_exit "Please specify mount (-m,--mount) and/or container (-c,--container)" 1
fi
if [[ -z "$docker_user" ]]; then
docker_user="bts"
fi
if [[ "$docker_user" = "root" ]]; then
_exit "USER (--user) cannot be 'root'" 1
fi
cont_home="/home/$docker_user"
home_src="$mount_prefix/$mount_name"
home_tgt="$cont_home"
this_dir="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
repo_src="$(cd "$this_dir" && git rev-parse --show-toplevel)"
repo_tgt="$cont_home/spark"
working_dir="$cont_home"
if [[ $mount_existing -eq 0 && -e "$home_src" ]]; then
# Don't overwrite existing dir (might be mounted in another container)
_exit "Mount dir '$home_src' already exists (use --mount-existing to mount \
an existing directory)" 1
fi
mkdir -p "$home_src"
if [[ "${#port_mappings[@]}" -eq 0 ]]; then
port_mappings=("8000:8000" "8001:8001" "8002:8002" "8003:8003")
fi
# Adapt port_mappings into args for `docker run` by prepending "-p " to each
# item
declare -a docker_port_args=()
for port_mapping in "${port_mappings[@]}"; do
docker_port_args+=("-p $port_mapping")
done
echo "Starting container '$cont_name'
image_name : $image_name
cont_name : $cont_name
home_src : $home_src
home_tgt : $home_tgt
repo_src : $repo_src
repo_tgt : $repo_tgt
working dir : $working_dir
ports : ${port_mappings[*]}
"
# DON'T wrap $docker_port_args in quotes. We want bash to split args by
# whitespace
docker run \
--net bridge \
-h "$host_name" \
-e "TZ=America/New_York" \
--cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--name "$cont_name" \
-v "$home_src:$home_tgt" \
-v "$repo_src:$repo_tgt" \
-w "$working_dir" \
${docker_port_args[*]} \
--shm-size=4024m \
-t \
-i \
-d \
-e DISPLAY="$DISPLAY" \
"$image_name"
# Add user w/ same uid and gid as the current user outside of docker, so the
# user inside the docker has file permissions in the mounted dir.
docker_group="$docker_user"
docker_uid="$(id -u "$USER")"
docker_gid="$(id -g "$USER")"
if [[ -z "$docker_pass" ]]; then
docker_pass="$docker_user"
fi
docker exec -u root -it "$cont_name" "$repo_tgt/docker/sparkd/dev/set_user.sh" \
--user "$docker_user" \
--uid "$docker_uid" \
--group "$docker_group" \
--gid "$docker_gid" \
--pass "$docker_pass"
# Run same script VS Code runs to initialize the container
docker exec -u "$docker_user" -it "$cont_name" "$repo_tgt/docker/sparkd/dev/devcontainer_post_create.sh"
-64
View File
@@ -1,64 +0,0 @@
#!/usr/bin/env bash
function print_help_and_exit() {
cat <<EOF
Open a shell inside the docker container
Usage: docker_shell.sh [OPTIONS] [CONTAINER]
Options:
-u,--user The user to login with in the container (defaults to the current user)
-c,--container The container name (may also be specified as positional arg)
-h,--help Print this help message and exit
EOF
exit "$1"
}
declare docker_user=""
declare cont_name=""
while [[ $# -gt 0 ]]; do
case "$1" in
-u)
;&
--user)
if [[ -z "$2" ]]; then
echo "User (-u,--user) must be non-empty"
print_help_and_exit 1
fi
docker_user="$2"
shift 2
;;
-h)
;&
--help)
print_help_and_exit 0
;;
-c)
;&
--container)
shift 1
;&
*)
if [[ ! -z "$cont_name" ]]; then
echo "Unexpected argument '$1'"
print_help_and_exit 1
fi
cont_name="$1"
shift 1
;;
esac
done
if [[ -z "$cont_name" ]]; then
echo "Please specify the container ([-c,--container])"
print_help_and_exit 1
fi
if [[ -z "$docker_user" ]]; then
docker_user="$USER"
fi
docker exec -u "$docker_user" -it "$cont_name" bash
-233
View File
@@ -1,233 +0,0 @@
#!/usr/bin/env bash
mount_prefix="$HOME/.spark-dev/mounts"
function print_help_and_exit() {
cat <<EOF
Start a docker dev container
Usage: start_docker.sh [OPTIONS] image container
Positionals:
image The image to instantiate
container The name for the container
Options:
-u,--user USER The user to add in the container (defaults to the current user)
-p,--pass PASS The password for USER in the container (defaults to USER)
-i,--image IMAGE The image to instantiate
-c,--container CONT The name for the container
-m,--mount MOUNT The name for the folder (outside the container) to create/mount to the home
directory in the container. Mount folders are added here: $mount_prefix
--mount-existing Mount the specified dir even if it already exists
--port <cont_port>:<host_port> OR [<cont_port>:<host_port>,...] Port mapping(s). May be
specified multiple times.
-h,--help Print this help message and exit
EOF
exit "$1"
}
declare docker_user=""
declare docker_pass=""
declare image_name=""
declare cont_name=""
declare mount_name=""
declare -i mount_existing=0
declare -a port_mappings=()
while [[ $# -gt 0 ]]; do
case "$1" in
-u)
;&
--user)
if [[ -z "$2" ]]; then
echo "User (-u,--user) must be non-empty"
print_help_and_exit 1
fi
docker_user="$2"
shift 2
;;
-p)
;&
--pass)
if [[ -z "$2" ]]; then
echo "Password (-p,--pass) must be non-empty"
print_help_and_exit 1
fi
docker_pass="$2"
shift 2
;;
-i)
;&
--image)
if [[ -n "$image_name" ]]; then
echo "Unexpected argument '$1'"
print_help_and_exit 1
elif [[ -z "$2" ]]; then
echo "Image (-i,--image) must be non-empty"
print_help_and_exit 1
fi
image_name="$2"
shift 2
;;
-c)
;&
--container)
if [[ -n "$cont_name" ]]; then
echo "Unexpected argument '$1'"
print_help_and_exit 1
elif [[ -z "$2" ]]; then
echo "Container (-c,--container) must be non-empty"
print_help_and_exit 1
fi
cont_name="$2"
shift 2
;;
--port)
# Parse port(s) arg, and append the result to 'port_mappings'
# Note: port(s) may be specified in bracketed notation:
# [a:b,c:d,...,y:z]
next_ports="$(echo "$2" | sed -e 's/\[//g' -e 's/\]//g' -e 's/,/ /g')"
if [[ "${#port_mappings[@]}" -gt 0 ]]; then
next_ports=" $next_ports"
fi
port_mappings+=("$next_ports")
shift 2
;;
-m)
;&
--mount)
if [[ -z "$2" ]]; then
echo "Mount (-m,--mount) must be non-empty"
fi
mount_name="$2"
shift 2
;;
--mount-existing)
mount_existing=1
shift 1
;;
-h)
;&
--help)
print_help_and_exit 0
;;
*)
if [[ -z "$1" ]]; then
echo "Invalid positional argument '$1'"
print_help_and_exit 1
elif [[ -z "$image_name" ]]; then
image_name="$1"
elif [[ -z "$cont_name" ]]; then
cont_name="$1"
else
echo "Unexpected argument '$1'"
print_help_and_exit 1
fi
shift 1
;;
esac
done
if [[ -z "$image_name" ]]; then
image_name="bluetradingsystems/spark-crypto-dev"
fi
host_name="$(hostname)"
if [[ -n "$cont_name" ]]; then
host_name="$host_name.$cont_name"
fi
if [[ -z "$mount_name" ]]; then
mount_name="$cont_name"
fi
if [[ -z "$mount_name" && -z "$cont_name" ]]; then
echo "Please specify mount (-m,--mount) and/or container (-c,--container)"
print_help_and_exit 1
fi
if [[ -z "$docker_user" ]]; then
docker_user="$USER"
fi
home_src=$mount_prefix/$mount_name
home_tgt=$HOME
repo_src=$(git rev-parse --show-superproject-working-tree)
repo_tgt=$HOME/$(basename "$repo_src")
working_dir=$HOME
if [[ $mount_existing -eq 0 && -e "$home_src" ]]; then
# Don't overwrite existing dir (might be mounted in another container)
echo "Mount dir '$home_src' already exists (use --mount-existing to mount an existing directory)"
print_help_and_exit 1
fi
mkdir -p "$home_src"
if [[ "${#port_mappings[@]}" -eq 0 ]]; then
port_mappings=("8000:8000" "8001:8001" "8002:8002" "8003:8003")
fi
# Adapt port_mappings into args for `docker run` by prepending "-p " to each
# item
declare -a docker_port_args=()
for port_mapping in "${port_mappings[@]}"; do
docker_port_args+=("-p $port_mapping")
done
echo "Starting container '$cont_name'
image_name : $image_name
cont_name : $cont_name
home_src : $home_src
home_tgt : $home_tgt
repo_src : $repo_src
repo_tgt : $repo_tgt
working dir : $working_dir
ports : ${port_mappings[*]}
"
# DON'T wrap $docker_port_args in quotes. We want bash to split args by
# whitespace
docker run \
--net bridge \
-h "$host_name" \
-e "TZ=America/New_York" \
--cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--name "$cont_name" \
-v "$home_src:$home_tgt" \
-v "$repo_src:$repo_tgt" \
-w "$working_dir" \
${docker_port_args[*]} \
--shm-size=4024m \
-t \
-i \
-d \
-e DISPLAY="$DISPLAY" \
"$image_name" \
bash
# Add user w/ same uid and gid as the current user outside of docker, so the
# user inside the docker has file permissions in the mounted dir.
docker_group="$docker_user"
docker_user_uid="$(id -u "$USER")"
docker_user_gid="$(id -g "$USER")"
echo "Adding user in container '$cont_name'
name : $docker_user
uid : $docker_user_uid
gid : $docker_user_gid"
if [[ -z "$docker_pass" ]]; then
docker_pass="$docker_user"
echo "Giving user '$docker_user' a secure password: $docker_pass"
fi
docker exec -u root -it "$cont_name" groupadd -g "$docker_user_gid" "$docker_group"
docker exec -u root -it "$cont_name" useradd -u "$docker_user_uid" -g "$docker_user_gid" "$docker_user"
docker exec -u root -it "$cont_name" usermod --password "$(openssl passwd -1 "$docker_pass")" "$docker_user"
docker exec -u root -it "$cont_name" usermod -aG sudo "$docker_user"
docker exec -u root -it "$cont_name" "$repo_tgt/externals/src/emumba/install_emumba-deribit-connector.sh"
+1
Submodule docker/windows added at de7d40c09d.
+2 -6
View File
@@ -1,22 +1,18 @@
astroid==2.7.3
autopep8==1.5.7
certifi==2023.5.7
charset-normalizer==3.1.0
cffi==1.14.6
colorama==0.4.4
idna==3.4
isort==5.9.3
lazy-object-proxy==1.6.0
mccabe==0.6.1
platformdirs==2.3.0
protobuf==4.21.12
protobuf==3.19.1
pybars3==0.9.7
pycodestyle==2.7.0
pycparser==2.20
pylint==2.10.2
PyMeta3==0.5.1
requests==2.31.0
termcolor==1.1.0
toml==0.10.2
urllib3==2.0.3
wrapt==1.12.1
yapf==0.31.0
+41
View File
@@ -0,0 +1,41 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sparkd", "src\server\sparkd\sparkd.vcxproj", "{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{502FD050-679A-3B50-B438-098500700919}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
MinSizeRel|x64 = MinSizeRel|x64
Release|x64 = Release|x64
RelWithDebInfo|x64 = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.Debug|x64.ActiveCfg = Debug|x64
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.Debug|x64.Build.0 = Debug|x64
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.MinSizeRel|x64.ActiveCfg = Release|x64
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.MinSizeRel|x64.Build.0 = Release|x64
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.Release|x64.ActiveCfg = Release|x64
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.Release|x64.Build.0 = Release|x64
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{BBBAFD38-312D-4A8D-9AF0-F2BDEE72CE6F}.RelWithDebInfo|x64.Build.0 = Release|x64
{502FD050-679A-3B50-B438-098500700919}.Debug|x64.ActiveCfg = Debug|x64
{502FD050-679A-3B50-B438-098500700919}.Debug|x64.Build.0 = Debug|x64
{502FD050-679A-3B50-B438-098500700919}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{502FD050-679A-3B50-B438-098500700919}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{502FD050-679A-3B50-B438-098500700919}.Release|x64.ActiveCfg = Release|x64
{502FD050-679A-3B50-B438-098500700919}.Release|x64.Build.0 = Release|x64
{502FD050-679A-3B50-B438-098500700919}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{502FD050-679A-3B50-B438-098500700919}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6A7249D7-B40C-4656-9347-60072D0B8FDB}
EndGlobalSection
EndGlobal
+1 -1
View File
@@ -8,7 +8,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\l
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}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\sparkcmd\sparkcmd.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
EndProject
@@ -1,21 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Spark.Admin.WebApp", "src\Spark.Admin.WebApp.fsproj", "{C3143A6F-8D32-4F9E-84EE-B34AF3F3A862}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C3143A6F-8D32-4F9E-84EE-B34AF3F3A862}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3143A6F-8D32-4F9E-84EE-B34AF3F3A862}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3143A6F-8D32-4F9E-84EE-B34AF3F3A862}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3143A6F-8D32-4F9E-84EE-B34AF3F3A862}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
+55
View File
@@ -0,0 +1,55 @@
<Project>
<PropertyGroup>
<ComputerSpecificConfig>..\..\tools\override\$(computername).props</ComputerSpecificConfig>
<SparkRoot>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\..))</SparkRoot>
<SourceRoot>$([System.IO.Path]::GetFullPath($(SparkRoot)\src))</SourceRoot>
<Externals>$(SparkRoot)\externals\windows</Externals>
<DepotName>$([System.IO.Path]::GetFileName($([System.IO.Path]::GetFullPath($(SparkRoot)))))</DepotName>
<ErrorReport>None</ErrorReport>
<Prefer32Bit>False</Prefer32Bit>
<Deterministic>true</Deterministic>
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
<LangVersion>11</LangVersion>
</PropertyGroup>
<PropertyGroup Label="Output">
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\bin</OutputPath>
<BaseIntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</IntermediateOutputPath>
<ProtoOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</ProtoOutputPath>
<GenDir>$(BaseOutputPath)\gen\$(MSBuildProjectName)</GenDir>
</PropertyGroup>
<Import
Project="$(ComputerSpecificConfig)"
Condition="Exists($(ComputerSpecificConfig))" />
<PropertyGroup Label="ProtoBuf">
<ProtocPluginBase>$(SparkRoot)\src\lib\api\service_compiler</ProtocPluginBase>
<protoc>$(Externals)\bin\protoc.exe</protoc>
<protogen>$(Externals)\bin\protogen.exe</protogen>
</PropertyGroup>
<ItemDefinitionGroup>
<Proto2></Proto2>
<Proto3>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCS>%(OutBase)%(FileName).cs</OutCS>
<OutCSClient>%(OutBase)%(FileName).client.pb.cs</OutCSClient>
<OutCSServer>%(OutBase)%(FileName).server.pb.cs</OutCSServer>
<OutCSImmutable>%(OutBase)%(FileName).immutable.pb.cs</OutCSImmutable>
<CompileOptions></CompileOptions>
</Proto3>
<Proto3Excel>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCSExcel>%(OutBase)%(FileName).excel.pb.cs</OutCSExcel>
<CompileOptions></CompileOptions>
</Proto3Excel>
</ItemDefinitionGroup>
</Project>
+94
View File
@@ -0,0 +1,94 @@
<Project>
<Target
Name="CompileProto2"
Condition="'@(Proto2)'!=''"
Inputs="$(MSBuildProjectFile);$(protogen);%(Proto2.FullPath)"
Outputs="$(GenDir)\proto2\%(Proto2.filename).cs"
AfterTargets="PreBuildEvent">
<PropertyGroup>
<SourceRelativeFile>$([System.String]::Copy('%(proto2.fullpath)').Replace($(SourceRoot), ''))</SourceRelativeFile>
<SourceRelativeDir>$([System.IO.Path]::GetDirectoryName($(SourceRelativeFile)))</SourceRelativeDir>
<WorkingDirectory>$(GenDir)\proto2</WorkingDirectory>
</PropertyGroup>
<MakeDir Directories="$(WorkingDirectory)" />
<Copy
SourceFiles="%(Proto2.FullPath)"
DestinationFolder="$(WorkingDirectory)"
SkipUnchangedFiles="True"
UseHardLinksIfPossible="True" />
<Error
Text="protogen.exe does not exist. If you forgot to clone with externals try: git submodule update --init --recursive"
Condition="!Exists($(protogen))" />
<Exec
Command="$(Protogen) %(Proto2.filename)%(proto2.extension) --csharp_out=. -I. -I$(SourceRoot) -I$(Externals)\include"
WorkingDirectory="$(WorkingDirectory)" />
<ItemGroup>
<Compile Include="$(WorkingDirectory)\%(Proto2.filename).cs" />
</ItemGroup>
</Target>
<!--
Run this after GetAssemblyVersion because it happens after the Xaml compiler
and exists in both xaml and non-xaml projects. One of the (many) xaml compile
passes wipes out the additional compile includes that we add.
-->
<Target
Name="CompileProto3"
AfterTargets="GetAssemblyVersion"
Condition="'@(Proto3)'!=''"
Inputs="$(protoc);
%(Proto3.Identity);$(ProtocPluginBase)\plugin.py;
$(ProtocPluginBase)\templates\c#\client.pb.cs;
$(ProtocPluginBase)\templates\c#\server.pb.cs;
$(ProtocPluginBase)\templates\c#\immutable.pb.cs;"
Outputs="%(Proto3.OutCS);%(Proto3.OutCSServer);%(Proto3.OutCSClient);%(Proto3.OutCSImmutable)">
<MakeDir Directories="%(Proto3.OutBase)" />
<Message
Importance="High"
Text="Generating service %(Proto3.FileName)" />
<Exec Command="$(SparkRoot)\.venv\Scripts\activate.bat" />
<Exec Command="set PYTHONPATH=$(SparkRoot)\.venv\Scripts\python" />
<Exec
Command="
$(protoc) %* %(Proto3.FullPath) ^
--error_format=msvs ^
--proto_path=$(SourceRoot) ^
--plugin=&quot;protoc-gen-service=$(ProtocPluginBase)\plugin.cmd&quot; ^
--service_out=lang=c#,strip_out_path=1:%(Proto3.OutBase) ^
--csharp_out=%(CompileOptions)%(Proto3.OutBase)"
WorkingDirectory="%(relativedir)" />
<ItemGroup>
<Compile Include="%(Proto3.OutCS)" />
<Compile Include="%(Proto3.OutCSClient)" />
<Compile Include="%(Proto3.OutCSServer)" />
<Compile Include="%(Proto3.OutCSImmutable)" />
</ItemGroup>
</Target>
<Target Name="RemoveSystemRuntimeFromRefPack"
BeforeTargets="_HandlePackageFileConflicts"
Condition="'@(Reference -> WithMetadataValue('NugetPackageId', 'System.Runtime.Experimental'))' != ''">
<ItemGroup>
<Reference Remove="@(Reference)"
Condition="$([System.String]::Copy(%(Reference.Identity)).Contains('System.Runtime.dll')) and
'%(Reference.NuGetPackageId)' == 'Microsoft.NETCore.App.Ref'" />
</ItemGroup>
</Target>
<Target
Name="AfterClean"
AfterTargets="Clean">
<Delete Files="%(Proto3.OutCS)" />
<Delete Files="%(Proto3.OutCSClient)" />
<Delete Files="%(Proto3.OutCSServer)" />
<Delete Files="%(Proto3.OutCSImmutable)" />
<Delete Files="$(GenDir)\proto2\*" />
</Target>
<Target
Name="Test"
DependsOnTargets="Build"></Target>
</Project>
-89
View File
@@ -1,89 +0,0 @@
<Project>
<PropertyGroup>
<ComputerSpecificConfig>..\..\tools\override\$(computername).props</ComputerSpecificConfig>
<SparkRoot>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\..))</SparkRoot>
<SourceRoot>$([System.IO.Path]::GetFullPath($(SparkRoot)\src))</SourceRoot>
<DepotName>$([System.IO.Path]::GetFileName($([System.IO.Path]::GetFullPath($(SparkRoot)))))</DepotName>
<ErrorReport>None</ErrorReport>
<Prefer32Bit>False</Prefer32Bit>
<Deterministic>true</Deterministic>
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
<LangVersion>11</LangVersion>
</PropertyGroup>
<Choose>
<When Condition="'$(OS)' == 'Windows_NT'">
<PropertyGroup>
<Externals>$(SparkRoot)/externals/windows</Externals>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<Externals>$(SparkRoot)/externals/linux</Externals>
</PropertyGroup>
</Otherwise>
</Choose>
<PropertyGroup Label="Output">
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\bin</OutputPath>
<BaseIntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</IntermediateOutputPath>
<ProtoOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</ProtoOutputPath>
</PropertyGroup>
<Import
Project="$(ComputerSpecificConfig)"
Condition="Exists($(ComputerSpecificConfig))" />
<PropertyGroup Label="ProtoBuf">
<ProtocPluginBase>$(SparkRoot)\src\lib\api\service_compiler</ProtocPluginBase>
</PropertyGroup>
<Choose>
<When Condition="'$(OS)' == 'Windows_NT'">
<PropertyGroup Label="ProtoBuf">
<protoc>$(Externals)/bin/protoc.exe</protoc>
<ProtocPlugin>$(ProtocPluginBase)/plugin.cmd</ProtocPlugin>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup Label="ProtoBuf">
<protoc>$(Externals)/bin/protoc</protoc>
<ProtocPlugin>$(ProtocPluginBase)/plugin.sh</ProtocPlugin>
</PropertyGroup>
</Otherwise>
</Choose>
<ItemDefinitionGroup>
<!--
Google automatically converts .proto filenames to TitleCase when
generating .cs files. Unless the .proto file is already in TitleCase
(against Google's recommended practice to use snake_case .proto files),
the 'CSName' must be overridden with the TitleCase formatting.
For example:
<ProtoService Include="foo_bar.proto" CSName="FooBar" />
-->
<Proto>
<OutDir>$(ProtoOutputPath)/</OutDir>
<CSName>%(FileName)</CSName>
</Proto>
<!--
Each .proto (service) input file produces 4 output files. For example,
'foo_bar.proto' produces:
* FooBar.cs
* foo_bar.client.pb.cs
* foo_bar.server.pb.cs
* foo_bar.immutable.pb.cs
-->
<ProtoService>
<OutDir>$(ProtoOutputPath)/</OutDir>
<CSName>%(FileName)</CSName>
</ProtoService>
</ItemDefinitionGroup>
</Project>
-110
View File
@@ -1,110 +0,0 @@
<Project>
<!--
Run this after GetAssemblyVersion because it happens after the Xaml compiler
and exists in both xaml and non-xaml projects. One of the (many) xaml compile
passes wipes out the additional compile includes that we add.
-->
<Target
Name="CompileProtos"
AfterTargets="GetAssemblyVersion"
Condition="'@(Proto)'!=''"
Inputs="$(protoc);
%(Proto.Identity);$(ProtocPluginBase)/plugin.py;
$(ProtocPluginBase)/templates/c#/immutable.pb.cs;"
Outputs="
%(Proto.OutDir)/%(Proto.CSName).cs;
%(Proto.OutDir)/%(Proto.FileName).immutable.pb.cs">
<MakeDir Directories="%(Proto.OutDir)" />
<Message
Importance="High"
Text="Generating Proto %(Proto.FileName)" />
<PropertyGroup>
<GenProtosCmd>$(protoc) %(Proto.FullPath)</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --error_format=msvs</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --proto_path=$(SourceRoot)</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --plugin=&quot;protoc-gen-spark-csharp=$(ProtocPlugin)&quot;</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --spark-csharp_out=lang=c#,templates=immutable.pb.cs,strip_out_path=1:%(Proto.OutDir)</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --csharp_out=%(Proto.OutDir)</GenProtosCmd>
</PropertyGroup>
<Exec Command="$(GenProtosCmd)" WorkingDirectory="%(Proto.RelativeDir)" />
<ItemGroup>
<Compile Include="%(Proto.OutDir)/%(Proto.CSName).cs" />
<Compile Include="%(Proto.OutDir)/%(Proto.FileName).immutable.pb.cs" />
</ItemGroup>
</Target>
<!--
Run this after GetAssemblyVersion because it happens after the Xaml compiler
and exists in both xaml and non-xaml projects. One of the (many) xaml compile
passes wipes out the additional compile includes that we add.
-->
<Target
Name="CompileProtoServices"
AfterTargets="GetAssemblyVersion"
Condition="'@(ProtoService)'!=''"
Inputs="$(protoc);
%(ProtoService.Identity);$(ProtocPluginBase)/plugin.py;
$(ProtocPluginBase)/templates/c#/client.pb.cs;
$(ProtocPluginBase)/templates/c#/server.pb.cs;
$(ProtocPluginBase)/templates/c#/immutable.pb.cs;"
Outputs="
%(ProtoService.OutDir)/%(ProtoService.CSName).cs;
%(ProtoService.OutDir)/%(ProtoService.FileName).client.pb.cs;
%(ProtoService.OutDir)/%(ProtoService.FileName).server.pb.cs;
%(ProtoService.OutDir)/%(ProtoService.FileName).immutable.pb.cs">
<MakeDir Directories="%(ProtoService.OutDir)" />
<Message
Importance="High"
Text="Generating ProtoService %(ProtoService.FileName)" />
<PropertyGroup>
<GenProtosCmd>$(protoc) %(ProtoService.FullPath)</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --error_format=msvs</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --proto_path=$(SourceRoot)</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --plugin=&quot;protoc-gen-service=$(ProtocPlugin)&quot;</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --service_out=lang=c#,strip_out_path=1:%(ProtoService.OutDir)</GenProtosCmd>
<GenProtosCmd>$(GenProtosCmd) --csharp_out=%(ProtoService.OutDir)</GenProtosCmd>
</PropertyGroup>
<Exec Command="$(GenProtosCmd)" WorkingDirectory="%(ProtoService.RelativeDir)" />
<ItemGroup>
<Compile Include="%(ProtoService.OutDir)/%(ProtoService.CSName).cs" />
<Compile Include="%(ProtoService.OutDir)/%(ProtoService.FileName).client.pb.cs" />
<Compile Include="%(ProtoService.OutDir)/%(ProtoService.FileName).server.pb.cs" />
<Compile Include="%(ProtoService.OutDir)/%(ProtoService.FileName).immutable.pb.cs" />
</ItemGroup>
</Target>
<Target Name="RemoveSystemRuntimeFromRefPack"
BeforeTargets="_HandlePackageFileConflicts"
Condition="'@(Reference -> WithMetadataValue('NugetPackageId', 'System.Runtime.Experimental'))' != ''">
<ItemGroup>
<Reference Remove="@(Reference)"
Condition="$([System.String]::Copy(%(Reference.Identity)).Contains('System.Runtime.dll')) and
'%(Reference.NuGetPackageId)' == 'Microsoft.NETCore.App.Ref'" />
</ItemGroup>
</Target>
<Target
Name="CleanProtos"
AfterTargets="Clean">
<Delete Files="%(Proto.OutDir)/%(Proto.CSName).cs" />
<Delete Files="%(Proto.OutDir)/%(Proto.FileName).client.pb.cs" />
<Delete Files="%(Proto.OutDir)/%(Proto.FileName).server.pb.cs" />
<Delete Files="%(Proto.OutDir)/%(Proto.FileName).immutable.pb.cs" />
<Delete Files="%(ProtoService.OutDir)/%(ProtoService.CSName).cs" />
<Delete Files="%(ProtoService.OutDir)/%(ProtoService.FileName).client.pb.cs" />
<Delete Files="%(ProtoService.OutDir)/%(ProtoService.FileName).server.pb.cs" />
<Delete Files="%(ProtoService.OutDir)/%(ProtoService.FileName).immutable.pb.cs" />
</Target>
<Target
Name="Test"
DependsOnTargets="Build"></Target>
</Project>
@@ -1,32 +0,0 @@
namespace Spark.Console {
using CommandLine;
using System;
using System.Collections.Generic;
public static class CommandParserEx {
public static TResult parse_and_run<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(
this Parser parser,
IEnumerable<string> args,
Func<T1, TResult> on_args1,
Func<T2, TResult> on_args2,
Func<T3, TResult> on_args3,
Func<T4, TResult> on_args4,
Func<T5, TResult> on_args5,
Func<T6, TResult> on_args6,
Func<T7, TResult> on_args7,
Func<T8, TResult> on_args8,
Func<IEnumerable<Error>, TResult> on_error) =>
parser.ParseArguments<T1, T2, T3, T4, T5, T6, T7, T8>(args)
.MapResult(
on_args1,
on_args2,
on_args3,
on_args4,
on_args5,
on_args6,
on_args7,
on_args8,
on_error);
}
}
@@ -1,24 +0,0 @@
namespace Spark.Console {
using bts;
using mbts.config;
using System;
using System.Linq;
class ConfigCommand {
public static int run(ConfigCommandOptions opts) {
Configuration.initialize(opts.sparkd);
var keys = opts.keys?.ToArray() ?? Array.Empty<string>();
var excluded_keys = opts.excluded_keys?.ToArray() ?? Array.Empty<string>();
return Configuration.run_config_query(
keys,
keys.Length,
excluded_keys,
excluded_keys.Length,
opts.all,
opts.list_keys,
opts.verbose);
}
}
}
@@ -1,30 +0,0 @@
namespace Spark.Console {
using CommandLine;
using System.Collections.Generic;
[Verb("config", HelpText = "Get config values")]
class ConfigCommandOptions {
[Option(
"query", MetaValue = "keys", HelpText = "Keys to query (supports regular expressions)")]
public IEnumerable<string>? keys { get; set; }
[Option(
"exclude",
MetaValue = "keys",
HelpText = "Keys to exclude from query (supports regular expressions)")]
public IEnumerable<string>? excluded_keys { get; set; }
[Option("all", HelpText = "Query all keys")]
public bool all { get; set; }
[Option("list-keys", HelpText = "List available keys")]
public bool list_keys { get; set; }
[Option("verbose", HelpText = "Show verbose output")]
public bool verbose { get; set; }
[Option("sparkd", MetaValue = "URL", HelpText = "The sparkd server")]
public string? sparkd { get; set; }
}
}
@@ -1,47 +0,0 @@
namespace Spark.Console {
using bts.api;
using bts.api.core;
using bts.md;
using System;
using System.Linq;
static class MBOCommand {
public static int run(MBOCommandOptions o) {
_dump_mbo(o.key, o.side);
return 0;
}
static void _dump_mbo(uint key, Side side) {
using var ctx = new ServiceContext();
var mbo = ctx.locate<MBOService>();
var data = mbo.get_orders_for_security(
new MBOSecurityQuery { SecurityId = key, PriceLevel = double.NaN });
Console.WriteLine($"Order data for {data.SecurityId}");
var price = 0.0;
var color = Console.ForegroundColor;
if (side == Side.Sell || side == Side.Undefined) {
Console.ForegroundColor = ConsoleColor.Red;
foreach (var e in data.Ask.Reverse()) {
if (e.Price != price) {
price = e.Price;
Console.WriteLine("================");
}
Console.WriteLine(e);
}
}
if (side == Side.Buy || side == Side.Undefined) {
Console.ForegroundColor = ConsoleColor.Blue;
foreach (var e in data.Bid) {
if (e.Price != price) {
price = e.Price;
Console.WriteLine("================");
}
Console.WriteLine(e);
}
}
Console.ForegroundColor = color;
}
}
}
@@ -1,14 +0,0 @@
namespace Spark.Console {
using bts.api;
using CommandLine;
[Verb("mbo", HelpText = "MBO diagnostic command")]
public class MBOCommandOptions {
[Option('k', "key", Required = true)]
public uint key { get; set; }
[Option('s', "side", Default = Side.Undefined)]
public Side side { get; set; }
}
}
@@ -1,17 +0,0 @@
namespace Spark.Console {
using CommandLine;
[Verb("order-stress", HelpText = "Create a bunch of orders")]
public class OrderStressOptions {
// Maybe options to create fewer orders or sleep
[Option('s', "sleep", HelpText = "Sleep ms between order submission", Default = 100)]
public int sleep { get; set; }
[Option('d', "depth", HelpText = "How many orders per side", Default = 10u)]
public uint depth { get; set; }
[Option('q', "quanityt", HelpText = "Order quantity", Default = 1u)]
public uint quantity { get; set; }
};
}
@@ -1,110 +0,0 @@
namespace Spark.Console {
using bts.api.core;
using bts.api.diagnostic;
using System;
using System.IO;
using System.Reflection;
using System.Reactive.Linq;
using Spark.Core;
using System.Threading;
static class ScriptCommand {
public static int run(ScriptCommandOptions o) {
if (o.server) {
_run_server();
return 0;
}
if (o.host is null) {
Console.WriteLine("Please specify host");
return 1;
}
if (!o.file.is_null_or_empty() && File.Exists(o.file)) {
_run_client(o.host, File.OpenRead(o.file));
return 0;
}
_run_client(o.host, Console.OpenStandardInput());
return 0;
}
static void _run_client(string qualifier, Stream stream) {
using var ctx = new ServiceContext();
ShellDiagnosticService diag = ctx.locate<ShellDiagnosticService>(qualifier);
var script_id = diag.create(null);
ShellScriptHost script = ctx.locate<ShellScriptHost>(script_id.Id);
try {
using var sub = script.subscribei_output().Subscribe(_script_output);
using var reader = new StreamReader(stream);
var status = ScriptResult.Complete;
for (var line = string.Empty; line != "#q"; line = prompt_input()) {
var result = script.run(new ScriptLines { Lines = { line } });
status = result.Res;
switch (status) {
case ScriptResult.Invalid:
Console.WriteLine($"Syntax error: '{result.Message}'");
break;
case ScriptResult.RunError:
Console.WriteLine($"Exception: {result.Message}");
break;
case ScriptResult.Complete:
if (!result.Message.is_null_or_empty()) {
Console.WriteLine(result.Message);
}
break;
}
}
string prompt_input() {
_write_prompt(status);
return reader.ReadLine() ??
throw new InvalidOperationException("Received null input");
}
} catch (Exception e) {
Console.WriteLine($"Done. {e.Message}");
} finally {
try {
script.dispose(null);
script.Dispose();
} catch (Exception) { }
}
}
static void _script_output(Update<ScriptLinesImmutable, int> update) {
foreach (var lines in update.added) {
foreach (var line in lines.Lines) {
Console.WriteLine(line);
}
}
}
static void _write_prompt(ScriptResult status) {
switch (status) {
case ScriptResult.Complete:
Console.Write(">>> ");
break;
case ScriptResult.Incomplete:
Console.Write("... ");
break;
case ScriptResult.Invalid:
Console.Write("?>> ");
break;
case ScriptResult.RunError:
Console.Write("!>> ");
break;
}
}
static void _run_server() {
// for debugging
using var ctx = new ServiceContext();
var stype = SparkReflectionHelper.find_type(
"bts.api.diagnostic.ShellDiagnosticsServiceServer");
var server = Activator.CreateInstance(stype, ctx);
while (true) {
Thread.Sleep(1000);
GC.KeepAlive(server);
}
}
}
}
@@ -1,15 +0,0 @@
namespace Spark.Console {
using CommandLine;
[Verb("script", HelpText = "Remote control for shell diagnostic host")]
public class ScriptCommandOptions {
[Option('s', "server", HelpText = "Run a script server for testing.")]
public bool server { get; set; }
[Option('h', "host", HelpText = "Connect to {host}")]
public string? host { get; set; }
[Option('f', "fromfile", HelpText = "Read commands from file instead of stdin")]
public string? file { get; set; }
}
}
@@ -1,16 +0,0 @@
namespace Spark.Console {
using bts;
using System;
using System.Reflection;
class SettingsCommand {
public static int run(SettingsCommandOptions _) {
var type = SparkReflectionHelper.find_type(
"bts.api.diagnostic.ShellDiagnosticsServiceServer");
var run = type.GetMethod("run", BindingFlags.Static | BindingFlags.Public);
Log.notnull(run).Invoke(null, Array.Empty<object>());
return 0;
}
}
}
@@ -1,6 +0,0 @@
namespace Spark.Console {
using CommandLine;
[Verb("settings", HelpText = "Copy workspaces around")]
class SettingsCommandOptions { }
}
@@ -1,95 +0,0 @@
namespace Spark.Console {
using bts.api.core;
using bts.test;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Threading;
class TailService {
static PrintFormat _format = PrintFormat.ToString;
static bool _timestamp = false;
enum PrintFormat {
ToString,
Json
}
public static int run(TailServiceOptions o) {
var split = o.method?.Split('.');
if (split?.Length != 2) {
Console.WriteLine("Try --method [ServiceName].[Method]");
return -1;
}
if (o.json) {
_format = PrintFormat.Json;
}
if (o.time) {
_timestamp = true;
}
_tail(split[0], split[1]);
return 0;
}
class SubscriptionLogger<T> : IObserver<T> {
public void OnCompleted() =>
ConsoleEx.WriteLine("Completed.", ConsoleColor.Yellow);
public void OnError(Exception error) =>
ConsoleEx.WriteLine($"Error. '{error}'", ConsoleColor.Red);
public void OnNext(T value) {
if (_timestamp) {
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff"));
Console.Write(" ");
}
if (value is null) {
return;
}
switch (_format) {
case PrintFormat.Json:
dynamic dv = value;
var json = JsonConvert.SerializeObject(new { dv.added, dv.removed, dv.changed });
Console.WriteLine(json);
break;
case PrintFormat.ToString:
Console.WriteLine(value);
break;
}
}
}
static void _tail(string service_name, string method_name) {
var service_type = SparkReflectionHelper.find_service_type(service_name);
var subscribe_method = service_type.GetMethod("subscribei_" + method_name) ??
throw new InvalidOperationException();
using var ctx = new ServiceContext();
var locate = typeof(ServiceContext).GetMethod("locate")?.MakeGenericMethod(service_type) ??
throw new InvalidOperationException();
var service = locate.Invoke(ctx, new[] { string.Empty });
// Subscribe with null qualifier
object observable = subscribe_method.Invoke(service, new object?[] { null })
?? throw new InvalidOperationException();
Type update_type = observable.GetType().GetGenericArguments()
.First(arg => arg.Name.StartsWith("Update"));
Type observer_type = typeof(SubscriptionLogger<>).MakeGenericType(update_type);
var observer = Activator.CreateInstance(observer_type)
?? throw new InvalidOperationException(
$"Activator failed to instantiate observer of type '{observer_type}'");
var subscribe = observable.GetType().GetMethod("Subscribe", new[] { observer_type }) ??
throw new InvalidOperationException(
"Failed to find 'IObservable.Subscribe' method via reflection");
var dispose = subscribe.Invoke(observable, new[] { observer });
while (true) {
Thread.Sleep(1000);
}
}
}
}
@@ -1,21 +0,0 @@
namespace Spark.Console {
using CommandLine;
[Verb("tail", HelpText = "'console dsqa'")]
class TailServiceOptions {
[Option('m', "method", Required = true, HelpText = "'[ServiceName].[Method]' to call")]
public string? method { get; set; }
[Option('t', "time", HelpText = "Include timestamp")]
public bool time { get; set; }
[Option('p', "path", HelpText = "Path inside the row to use for display. Ex: 'Id' or 'Name' ")]
public string? path { get; set; }
[Option('a', "all", HelpText = "Include 'all' rows on every print")]
public bool all { get; set; }
[Option('j', "json", HelpText = "Format rows as json")]
public bool json { get; set; }
}
}
@@ -1,83 +0,0 @@
namespace Spark.Console {
using bts.test;
using mbts.config;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
static class TestCommand {
static readonly Lazy<TestEnumerator> _enumerator_backing = new(
() => new TestEnumerator("spark_test"));
static TestEnumerator _enumerator => _enumerator_backing.Value;
public static int run(TestCommandOptions o) {
if (o.type == TestType.Unit) {
// Skip loading any local config
Configuration.initialize_for_test();
} else {
Configuration.initialize(o.sparkd);
}
ConsoleEx.WriteLine(JsonConvert.SerializeObject(o), ConsoleColor.DarkGray);
if (o.list) {
_list_tests(o.type);
return 0;
}
if (o.tests is null) {
Console.WriteLine("Please specify test(s) to run");
return 1;
}
if (o.timeout == 0 && o.tests.TryGetSingle(out var test) && !o.self_contained) {
using var trr = new TestResultReceiver(true);
InProcessTestRunner.run_test_synchronously(
test, o.type, _enumerator, trr.get_reporter());
trr.print_summary();
if (trr.ResultCount == 0) {
ConsoleEx.Write("No ", ConsoleColor.Red);
ConsoleEx.Write(o.type.ToString(), ConsoleColor.Yellow);
ConsoleEx.WriteLine($" tests matched filter '{test}'", ConsoleColor.Red);
return -1;
}
return trr.ErrorCount;
}
if (o.tests.Any()) {
return _run_tests(o, _enumerator.match(o.type, o.tests));
}
return _run_tests(o, _enumerator.get_of_type(o.type));
}
static int _run_tests(TestCommandOptions o, IEnumerable<TestMethod> tests) {
var runner = new TestRunner();
// waits for all child processes to exit or time out
return runner.run_tests(tests, o.timeout, o.self_contained);
}
static void _list_tests(TestType test_type) {
Console.WriteLine("All tests: ");
foreach (var t in _enumerator.get_groups_of_type(test_type)) {
ConsoleEx.WriteLine(t.name, ConsoleColor.Green);
foreach (var test in t.methods) {
Console.Write($" {test.name}");
if (test.ignored) {
var reason = test.ignored_reason;
if (string.IsNullOrEmpty(reason)) {
ConsoleEx.Write(" (ignored)", ConsoleColor.Yellow);
continue;
}
ConsoleEx.Write($" (ignored: '{test.ignored_reason}')", ConsoleColor.Yellow);
}
Console.WriteLine();
}
}
}
}
}
@@ -1,28 +0,0 @@
namespace Spark.Console {
using bts.test;
using CommandLine;
using System.Collections.Generic;
[Verb("test", HelpText = "Run Tests")]
class TestCommandOptions {
[Option('t', "timeout", HelpText = "Timeout unit tets", Default = 0u)]
public uint timeout { get; set; }
[Option('l', "list", HelpText = "List tests")]
public bool list { get; set; }
[Option('i', "insular", HelpText = "Tests run sparkd and use their own config (if specified)")]
public bool self_contained { get; set; }
[Option("type", HelpText = "Run all tests of type [Unit|System|Shell]")]
public TestType type { get; set; }
[Value(1, MetaName = "Tests", HelpText = "Test list")]
public IEnumerable<string>? tests { get; set; }
[Option("sparkd", MetaValue = "URL", HelpText = "The sparkd server")]
public string? sparkd { get; set; }
}
}
@@ -1,128 +0,0 @@
namespace Spark.Console {
using bts.api;
using bts.api.admin;
using bts.api.core;
using bts.api.synthetic;
using bts.api.user;
using bts.metrics;
using System;
using System.Threading;
class TestService {
public static int run(TestServiceOptions o) {
if (o.synthetic) {
_synthetic_test();
}
if (o.user) {
_user_test();
}
if (o.admin) {
_admin_test();
}
if (o.latency) {
_latency_test();
}
if (o.market_data) {
_market_data();
}
return 0;
}
static void _market_data() {
using var ctx = new ServiceContext();
var md = ctx.locate<MarketDataService>();
md.subscribe_securities().Table().Subscribe(update => {
Console.WriteLine($"got {update.state.Count} securities");
});
while (true) {
Thread.Sleep(1000);
}
}
static void _synthetic_test() {
using var ctx = new ServiceContext();
var security = new Security {
Symbol = "ES",
Exchange = Venue.Bts,
Currency = "USD",
Synthetic = new SyntheticContract {
Name = "Synthetic1",
PriceCalc = SyntheticContract.Types.PriceCalc.Standard,
Legs = {
new ContractLeg {
Security = new Security {
Id = 2,
Symbol = "ES",
// ESH8
Future = new FutureContract {
ExpirationYear = 2018,
ExpirationMonth = 3,
ExpirationDay = 16
}
}
},
new ContractLeg {
Security = new Security {
Id = 5,
Symbol = "ES",
// ESU8
Future = new FutureContract {
ExpirationYear = 2018,
ExpirationMonth = 9,
ExpirationDay = 21
}
}
}
}
}
};
var service = ctx.locate<SyntheticSecurityService>();
try {
var result = service.create_synthetic(security);
if (result.Error == CreateResult.Types.Error.Ok) {
Console.WriteLine(result.Key);
}
} catch (ApiException e) {
Console.WriteLine(e.Message);
}
}
static void _user_test() {
var ctx = new ServiceContext();
var s = ctx.locate<AuthService>();
var resp = s.get_users(new GetUsersRequest());
Console.WriteLine("{0}", resp);
}
static void _admin_test() {
var ctx = new ServiceContext();
var s = ctx.locate<AdminService>();
using var d = s.subscribei_admin_data().Subscribe(Console.WriteLine);
while (true) {
Thread.Sleep(100);
}
}
static void _latency_test() {
var ctx = new ServiceContext();
var s = ctx.locate<ShellLatencyService>();
ulong sequence = 0;
var factor = TimeSpan.TicksPerMillisecond / 1000;
while (true) {
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
var reply = s.ping(new BufferMessage() { Sequence = ++sequence });
sw.Stop();
Console.WriteLine(
$"{reply.Sequence} - {sw.ElapsedMilliseconds}ms -- {sw.ElapsedTicks / factor} us");
Thread.Sleep(1000);
}
}
}
}
@@ -1,21 +0,0 @@
namespace Spark.Console {
using CommandLine;
[Verb("test-service", HelpText = "Scratch space for testing services")]
public class TestServiceOptions {
[Option(nameof(synthetic))]
public bool synthetic { get; set; }
[Option(nameof(user))]
public bool user { get; set; }
[Option(nameof(admin))]
public bool admin { get; set; }
[Option(nameof(latency))]
public bool latency { get; set; }
[Option("md")]
public bool market_data { get; set; }
}
}
-45
View File
@@ -1,45 +0,0 @@
namespace Spark.Console {
using bts;
using bts.utils;
using System;
using CommandLine;
class Program {
static int Main(string[] args) {
// Initializing config is up to each individual command
// We call provide_command_line here in case config is first
// initialized from c++ instead of c#
BTSNativeMethods.provide_command_line(args, args.Length);
var parser = new Parser(ps => {
ps.CaseInsensitiveEnumValues = true;
ps.HelpWriter = Console.Out;
});
// Note: this can be made to infer the options type list from the list of delegates
return parser.parse_and_run<
ConfigCommandOptions,
ScriptCommandOptions,
TailServiceOptions,
TestServiceOptions,
SettingsCommandOptions,
TestCommandOptions,
OrderStressOptions,
MBOCommandOptions,
int
>(
BTS.remove_config_arg(args),
ConfigCommand.run,
ScriptCommand.run,
TailService.run,
TestService.run,
SettingsCommand.run,
TestCommand.run,
OrderStressCommand.run,
MBOCommand.run,
errors => 1);
}
}
}
@@ -1,37 +0,0 @@
namespace Spark.Console {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
static class SparkReflectionHelper {
static readonly Assembly _spark_api_assembly;
static readonly Assembly _spark_assembly;
static SparkReflectionHelper() {
_spark_assembly = load_assembly("Spark");
_spark_api_assembly = load_assembly("spark_api");
static Assembly load_assembly(string ass_name) =>
Assembly.Load(ass_name) ?? throw new InvalidOperationException(
$"Failed to load assembly '{ass_name}'");
}
static IEnumerable<Assembly> _assemblies {
get {
yield return _spark_assembly;
yield return _spark_api_assembly;
}
}
public static Type find_type(string name) =>
_assemblies.Select(a => a.GetType(name)).ExceptNull().FirstOrDefault() ??
throw new InvalidOperationException($"Failed to find type '{name}'");
public static Type find_service_type(string name) =>
_spark_api_assembly.GetExportedTypes()
.FirstOrDefault(t => t.Name == name) ??
throw new InvalidOperationException(
$"Failed to find service '{name}' in spark_api.dll");
}
}
@@ -3,6 +3,7 @@ namespace mbts.spark {
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.reactive;
using bts.utils;
using mbts;
@@ -17,7 +18,6 @@ namespace mbts.spark {
using Spark.Core;
using Spark.Core.Collections;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using Spark.ViewModel.Commands;
using System;
@@ -148,7 +148,7 @@ namespace mbts.spark {
private static bool _direct_valid_driver(SecurityExpiration driver_exp) {
return driver_exp != null && /*driver_exp.expiration >= DateTime.Now.Date &&*/
(driver_exp.security_tuple.security_type == SecurityType.Future ||
driver_exp.security_tuple.security_type == SecurityType.Spot);
driver_exp.security_tuple.security_type == SecurityType.Stock);
}
// returns the driver sectup (it assumes all expirations of this option sectup
// are being driven by the same sectup)
@@ -202,4 +202,4 @@ namespace mbts.spark {
}
#endregion
}
}
}
@@ -1,120 +0,0 @@
namespace mbts.spark {
using bts;
using bts.api;
using mbts;
using mbts.analytics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
// For each vs, it sends the vol surface calc request (_do_periodic_auto_fit)
// and then commits the response
public class SingleVolSurfaceAutoFitSource : IDisposable {
private readonly ThreadedBlackboard _bb;
private readonly int _vs_id;
private readonly ITag<VolSurfaceInput> _vs_input_tag;
private readonly ITag<VolSurfaceCalculationResponse> _vs_calc_response_tag;
private DateTime _last_req_time = DateTime.MinValue;
private TimeSpan _req_period = TimeSpan.MaxValue;
private int _req_id = 0;
public SingleVolSurfaceAutoFitSource(int vs_id, ThreadedBlackboard bb) {
_bb = bb;
_vs_id = vs_id;
_vs_input_tag = SparkTags.VolSurfaceCommittedInputTag(vs_id);
_vs_calc_response_tag = SparkTags.VolSurfaceAutoCalculationResponseTag(vs_id);
_bb.subscribe(_vs_input_tag);
_bb.subscribe(_vs_calc_response_tag);
_bb.subscribe(SparkTags.CurrentUser);
_bb.data_callback += _on_bb_data;
_bb.timer_callback += _on_bb_timer;
}
private void _on_bb_data(object tag, object data) {
if (tag.Equals(_vs_input_tag))
_possibly_autofit();
else if (tag.Equals(_vs_calc_response_tag)) {
VolSurfaceCalculationResponse calc_resp = data as VolSurfaceCalculationResponse;
bts.Log.Gen.info($"SingleVolSurfaceAutoFitSource._on_bb_data vs_id: {_vs_id} " +
$"received calculation response");
_bb.post(SparkTags.VolSurfaceCommitTag(_vs_id),
calc_resp.volsurface_calculation_output.volsurface_input);
}
}
private bool _user_has_vs_control() {
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
string current_user = _bb.read_state(SparkTags.CurrentUser).name;
return vs_input != null &&
vs_input.surface_settings.core_settings.vs_manager == current_user;
}
private void _on_bb_timer() {
_possibly_autofit();
}
private void _possibly_autofit() {
var auto_fit_period = _get_auto_fit_periodic();
if (!auto_fit_period.HasValue)
return;
if (DateTime.Now - _last_req_time <= auto_fit_period)
return;
if (!_user_has_vs_control())
return;
// auto fit here
bts.Log.Gen.info($"SingleVolSurfaceAutoFitSource vs_id: {_vs_id} requesting fit " +
$"last_req_time: {_last_req_time} period: {auto_fit_period.Value}");
_send_request();
}
private Nullable<TimeSpan> _get_auto_fit_periodic() {
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
if (vs_input == null)
return null;
var fit_settings =
VolSurfaceDataFunctions.get_market_fit_settings(vs_input.surface_settings);
if (fit_settings == null)
return null;
var auto_fit_setting = fit_settings.vs_auto_fit_settings;
if (auto_fit_setting == null)
return null;
if (auto_fit_setting.auto_fit_region == VolSurfaceEnums.VolCurveFitRegion.None)
return null;
var time_based_fit_setting = auto_fit_setting.time_based_settings;
if (time_based_fit_setting == null)
return null;
if (!time_based_fit_setting.period_seconds.HasValue)
return null;
return TimeSpan.FromSeconds(time_based_fit_setting.period_seconds.Value);
}
private void _send_request() {
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
if (vs_input == null)
return;
VolCurveMarketFitAction mf_action = new VolCurveMarketFitAction(
VolCurveMarketFitAction.ActionType.FitWholeCurve, null, false);
VolCurveAction vc_action = new VolCurveAction(mf_action);
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
vs_input.surface_parameters.curve_parameters_map.ToDictionary(
i => i.Item1,
i => vc_action
);
VolSurfaceCalculationRequest req = new VolSurfaceCalculationRequest(vs_input,
_req_id++, action_map, true, true);
_last_req_time = DateTime.Now;
_bb.post(SparkTags.VolSurfaceAutoCalculationRequestTag(_vs_id), req);
}
#region IDisposable
public void Dispose() {
_bb.data_callback -= _on_bb_data;
_bb.timer_callback -= _on_bb_timer;
}
#endregion
}
}
@@ -4,7 +4,6 @@
using bts.api.analytics;
using mbts.analytics;
using mbts.ui;
using Spark.Core.Protobuf;
@@ -14,7 +13,6 @@
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Windows;
// For a single VolSurface this class
// 1. Listents to commmits and calls the service to persist data
@@ -26,6 +24,7 @@
private readonly ITag<VolSurfaceInput> _in_bb_committ_tag;
private readonly AnalyticsService _analytics_service;
private readonly HighPerformanceTimer _timer = new HighPerformanceTimer();
private readonly string _user;
private readonly List<IDisposable> _disposables = new List<IDisposable>();
private IDictionary<UInt64, VolSurfaceInputSnapshot> _snp_shot_map = new
Dictionary<UInt64, VolSurfaceInputSnapshot>();
@@ -36,10 +35,10 @@
volsurface_id));
_volsurface_id = volsurface_id;
_bb = threaded_bb;
_user = "TEST_USER"; // TODO
_in_bb_committ_tag = SparkTags.VolSurfaceCommitTag(volsurface_id);
_analytics_service = analytics_service;
_bb.subscribe(_in_bb_committ_tag);
_bb.subscribe(SparkTags.CurrentUser);
_bb.data_callback += _on_bb_data;
var vs_sub = _analytics_service.subscribei_volsurfaces()
.ObserveOn(SynchronizationContext.Current)
@@ -55,10 +54,8 @@
private void _on_vss(bts.api.core.Update<VolSurfaceEntryImmutable, UInt64> update) {
IEnumerable<VolSurfaceEntryImmutable> all_vss = update.all;
var this_vs_vss = all_vss.Where(vs => vs.VsId == _volsurface_id);
bts.Log.Gen.info(
$"SingleVolSurfaceGateway._on_vss vs_count: {this_vs_vss.Count()} " +
$"all: {update.all.Count()} added: {update.added.Count()} " +
$"updated: {update.changed.Count()} removed: {update.removed.Count()}");
bts.Log.Gen.info(String.Format("SingleVolSurfaceGateway._on_vss count:{0} vs_count:{1}",
all_vss.Count(), this_vs_vss.Count()));
if (this_vs_vss.Count() == 0) {
return;
}
@@ -86,39 +83,22 @@
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) =>
ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs.Volsurface.ToByteArray());
// private void _show_save_error(string message) {
// BTSMessageBox.Show(message, "Vol Save Error", BTSMessageBoxButtons.OK);
// }
private void _on_bb_data(object tag, object data) {
if (_in_bb_committ_tag.Equals(tag)) {
try {
_timer.start();
VolSurfaceInput vs_input = data as VolSurfaceInput;
var user_tup = _bb.read_state(SparkTags.CurrentUser);
string current_user = user_tup.name;
string vs_manager = vs_input.surface_settings.core_settings.vs_manager;
if (current_user != vs_manager) {
string msg = $"User {current_user} does not have the permission to save vols. " +
$"Permission can be obtained via the grid context menu item 'Acquire ownership from {vs_manager}'";
BTSMessageBox.Show(msg, "Vol Save Error", BTSMessageBoxButtons.OK);
return;
}
_sanitize_input(ref vs_input);
vs_input = VolSurfaceDataFunctions.unset_driver_overrides(vs_input);
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, current_user);
vs_input.saver_login = _user;
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, _user);
_timer.stop();
Log.Gen.info(String.Format(
"SingleVolSurfaceGateway._on_bb_data Time to commit volsurface {0} {1} msecs",
_volsurface_id, _timer.lastIntervalTime));
var archived_theos = _get_theos();
if (archived_theos != null) {
_timer.start();
if (archived_theos != null)
_analytics_service.archive_theos(archived_theos);
_timer.stop();
Log.Gen.info($"SingleVolSurfaceGateway._on_bb_data archiving theos vs_id: {_volsurface_id} size: " +
$"{archived_theos.SecTheo.Count} time: {_timer.lastIntervalTime} msecs");
}
} catch (Exception ex) {
Log.Gen.warn(ex.ToString());
_bb.post(SparkTags.MessageDisplayTag,
@@ -36,11 +36,7 @@ namespace mbts.spark {
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Committed, _vs_id, _bb,
a_syms => new SingleVolSurfaceCommittedOutputRetriever(_vs_id, _bb, a_syms)),
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Combined, _vs_id, _bb,
a_syms => new SingleVolSurfaceRequestCalculator(
SingleVolSurfaceRequestCalculator.RequestType.UI, _vs_id, a_syms, _bb)),
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Combined, _vs_id, _bb,
a_syms => new SingleVolSurfaceRequestCalculator(
SingleVolSurfaceRequestCalculator.RequestType.AUTO, _vs_id, a_syms, _bb)),
a_syms => new SingleVolSurfaceRequestCalculator(_vs_id, a_syms, _bb)),
new SingleVolSurfaceMarketImpliedVolSource(_vs_id, _bb),
// new SingleVolSurfaceTheoSource(_vs_id, _bb),
// TODO: suspending heatmaps for now (12/24/21)
@@ -48,7 +44,6 @@ namespace mbts.spark {
// server work that can optionally be done on the client
new SingleVolSurfaceDataSource (SingleVolSurfaceDataSource.SymbolListType.Committed, _vs_id, _bb,
a_syms => new SingleVolSurfaceInterpGreeksPublisher (_vs_id, _bb, a_syms)),
new SingleVolSurfaceAutoFitSource(_vs_id, _bb),
};
}
@@ -18,16 +18,10 @@ namespace mbts.spark {
// Pubs :
// 1. Calc Resp
public class SingleVolSurfaceRequestCalculator : IDisposable {
public enum RequestType {
UI = 0,
AUTO
}
private readonly RequestType _request_type = RequestType.UI;
private readonly int _vs_id;
private readonly HashSet<string> _symbols;
private readonly ThreadedBlackboard _bb;
private readonly ITag<VolSurfaceCalculationRequest> _in_bb_request_tag;
private readonly ITag<VolSurfaceCalculationRequest> _in_bb_auto_request_tag;
private readonly ITag<VolSurfaceNonVolData> _in_bb_nonvol_data_tag;
private readonly ITag<VolSurfaceStandardTime> _in_bb_vs_standard_time_tag;
private readonly ITag<VolSurfaceEnums.MarketSide> _in_bb_market_impliedvol_side_tag;
@@ -36,22 +30,18 @@ namespace mbts.spark {
/// data
private VolSurfaceOutput _last_output;
public SingleVolSurfaceRequestCalculator(RequestType request_type,
int vs_id, IEnumerable<string> symbols,
public SingleVolSurfaceRequestCalculator(int vs_id, IEnumerable<string> symbols,
ThreadedBlackboard threaded_bb) {
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id} request_type: {request_type}");
_request_type = request_type;
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id}");
_vs_id = vs_id;
_symbols = new HashSet<string>(symbols);
_bb = threaded_bb;
_in_bb_request_tag = SparkTags.VolSurfaceCalculationRequestTag(vs_id);
_in_bb_auto_request_tag = SparkTags.VolSurfaceAutoCalculationRequestTag(vs_id);
_in_bb_nonvol_data_tag = SparkTags.VolSurfaceNonVolDataTag(vs_id);
_in_bb_vs_standard_time_tag = SparkTags.VolSurfaceStandardTimeTag(vs_id);
_in_bb_market_impliedvol_side_tag = SparkTags.VolSurfaceMarketImpliedVolSide(vs_id);
_in_bb_dirty_tag = SparkTags.VolSurfaceDirtyStateTag(vs_id);
_bb.subscribe(_in_bb_request_tag);
_bb.subscribe(_in_bb_auto_request_tag);
_bb.subscribe(_in_bb_nonvol_data_tag);
_bb.subscribe(_in_bb_vs_standard_time_tag);
_bb.subscribe(_in_bb_vs_standard_time_tag);
@@ -61,21 +51,11 @@ namespace mbts.spark {
}
private void _on_bb_data(object tag, object data) {
switch (_request_type) {
case RequestType.UI: {
if (_in_bb_request_tag.Equals(tag) || _in_bb_dirty_tag.Equals(tag))
_recompute_and_publish(true);
else if (_in_bb_nonvol_data_tag.Equals(tag) || _in_bb_vs_standard_time_tag.Equals(tag))
_recompute_and_publish(false);
break;
}
case RequestType.AUTO: {
if (tag.Equals(_in_bb_auto_request_tag)) {
_serve_auto_request();
}
break;
}
}
if (_in_bb_request_tag.Equals(tag) || _in_bb_dirty_tag.Equals(tag))
_recompute_and_publish(true);
else if (_in_bb_nonvol_data_tag.Equals(tag) || _in_bb_vs_standard_time_tag.Equals(tag))
_recompute_and_publish(false);
}
private void _recompute_and_publish(bool is_new_request) {
@@ -100,7 +80,7 @@ namespace mbts.spark {
nonvol_data.driver_price_map,
vs_standard_time, true);
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
_post_process_action(_bb, _vs_id, effective_req, aux_data_map);
_post_process_action(effective_req, aux_data_map);
_last_output = GeneralVolSurfaceCalculator.compute(effective_req.volsurface_input,
nonvol_data.contracts,
aux_data_map,
@@ -109,49 +89,16 @@ namespace mbts.spark {
effective_req.cascade_up,
effective_req.cascade_down);
_timer.stop();
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish vs_id: {_vs_id} " +
$"time: {_timer.lastIntervalTime}");
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time: " +
$"{_timer.lastIntervalTime}");
_bb.post(SparkTags.VolSurfaceCalculationResponseTag(_vs_id),
new VolSurfaceCalculationResponse(_last_output, effective_req.request_id));
}
}
}
private void _serve_auto_request() {
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._serve_auto_request " +
$"vs_id: {_vs_id} auto request received");
bool is_dirty = _bb.read_state(_in_bb_dirty_tag, false);
VolSurfaceNonVolData nonvol_data = _bb.read_state(_in_bb_nonvol_data_tag);
VolSurfaceStandardTime vs_standard_time = _bb.read_state(_in_bb_vs_standard_time_tag);
VolSurfaceCalculationRequest auto_req = _bb.read_state(_in_bb_auto_request_tag);
if (is_dirty || nonvol_data == null || vs_standard_time == null || auto_req == null) {
return;
}
_timer.start();
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map =
VolSurfaceUtilityFunctions.compute_aux_data(auto_req.volsurface_input,
nonvol_data.input,
nonvol_data.driver_price_map,
vs_standard_time, true);
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
_post_process_action(_bb, _vs_id, auto_req, aux_data_map);
var vs_output = GeneralVolSurfaceCalculator.compute(auto_req.volsurface_input,
nonvol_data.contracts,
aux_data_map,
action_map,
null,
auto_req.cascade_up,
auto_req.cascade_down);
_timer.stop();
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._serve_auto_request vs_id: {_vs_id} " +
$"time: {_timer.lastIntervalTime}");
_bb.post(SparkTags.VolSurfaceAutoCalculationResponseTag(_vs_id),
new VolSurfaceCalculationResponse(vs_output, auto_req.request_id));
}
/// Computes the impl vol if the action is fit to market
private static IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
ThreadedBlackboard bb, int vs_id,
private IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
VolSurfaceCalculationRequest req,
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map) {
IDictionary<VolSurfaceExpiration, VolCurveAction> rv = req.action_map;
@@ -162,7 +109,7 @@ namespace mbts.spark {
VolCurveAction rep_action = rv.ElementAt(0).Value;
if (rep_action.action_type == VolCurveAction.ActionType.FitToMarket) {
IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> impl_vol_map =
_fill_in_implied_vols(bb, vs_id, req.volsurface_input, req.action_map, aux_data_map,
_fill_in_implied_vols(req.volsurface_input, req.action_map, aux_data_map,
req.cascade_up, req.cascade_down);
rv = impl_vol_map.ToDictionary(kv => kv.Key, kv => new VolCurveAction(
new VolCurveMarketFitAction(rep_action.market_fit_action.fit_action, kv.Value,
@@ -172,8 +119,7 @@ namespace mbts.spark {
return rv;
}
private static IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
ThreadedBlackboard bb, int vs_id,
private IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
VolSurfaceInput vs_inp,
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map,
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map,
@@ -194,15 +140,15 @@ namespace mbts.spark {
applicable_exps = applicable_exps.Where(vs_exp => master_exps.Contains(vs_exp));
VolSurfaceEnums.MarketSide impliedvol_side =
SingleVolSurfaceMarketImpliedVolSource._get_market_impliedvol_side(bb, vs_id);
SingleVolSurfaceMarketImpliedVolSource._get_market_impliedvol_side(_bb, _vs_id);
foreach (VolSurfaceExpiration vs_exp in applicable_exps) {
VolSurfaceExpiration md_exp;
VolCurveMarketImpliedVolData exp_impl_data =
VolSurfaceCoreFunctions.compute_implied_vols(vs_inp, vs_exp, aux_data_map,
arg_vs_exp => SingleVolSurfaceMarketImpliedVolSource.get_option_bbo(bb, arg_vs_exp),
arg_vs_exp => SingleVolSurfaceMarketImpliedVolSource.get_option_bbo(_bb, arg_vs_exp),
impliedvol_side,
SingleVolSurfaceMarketImpliedVolSource._ignore_market_implied_vol_source_settings(
bb, vs_id),
_bb, _vs_id),
out md_exp);
rv[vs_exp] = exp_impl_data;
}
@@ -160,8 +160,8 @@ namespace mbts.spark {
public static IEnumerable<bts.api.SecurityTuple> get_vs_sectups(
int vs_id, ThreadedBlackboard bb) {
var vs_usage_list = bb.read_state(SparkTags.VolSurfaceUsageTag);
return (vs_usage_list?.get_sectups(vs_id)).empty_if_null();
VolSurfaceUsageListImmutable vs_usage_list = bb.read_state(SparkTags.VolSurfaceUsageTag);
return vs_usage_list.get_sectups(vs_id);
}
@@ -242,4 +242,4 @@ namespace mbts.spark {
}
#endregion
}
}
}
@@ -123,10 +123,10 @@ namespace mbts.spark {
}
Log.Ui.info($"VolSurfaceUsageList name_to_ids count: {name_to_ids.Count}");
var vs_usage = mbts.config.Configuration.get<bts.config.toggles.VolSurfaceUsage>();
Log.Ui.info($"VolSurfaceUsageList vs_usage acount: {vs_usage.Items.Count}");
foreach (var u in vs_usage.Items) {
string option_name = u.OptionName;
string vs_name = u.VsName;
Log.Ui.info($"VolSurfaceUsageList vs_usage acount: {vs_usage.vol_surface_usage.Count}");
foreach (var u in vs_usage.vol_surface_usage) {
string option_name = u.option_name;
string vs_name = u.vs_name;
int vs_key;
if (name_to_ids.TryGetValue(vs_name, out vs_key)) {
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
@@ -270,7 +270,6 @@ namespace mbts.spark {
new mbts.analytics.VolSurfaceNonVolInput(exp_param_map.exp_map.ToDictionary()));
} else if (_in_bb_req_vol.Equals(tag)) {
ClientArchivedVolRequest client_req = _bb.read_state(_in_bb_req_vol);
bts.Log.Ui.info($"VolSurfaceBusManager._on_bb_update ClientArchivedVolRequest: {client_req.ToString()}");
ArchivedTheoRetrieval ret = client_req.ret;
if (ret == null || ret.SecTup == null) {
bts.Log.Ui.warn($"VolSurfaceBusManager malformed ArchivedTheoRetrieval");
@@ -5,7 +5,6 @@ using bts.api;
using bts.collections;
using System.Linq;
using bts.api.orderman;
using bts.api.analytics;
using bts;
namespace mbts.spark {
@@ -24,8 +23,6 @@ namespace mbts.spark {
_order_service = order_service;
_bb.subscribe(SparkTags.AllInterpGreeks);
_bb.subscribe(SparkTags.SystemContractsTag);
_bb.subscribe(SparkTags.CurrentUser);
_bb.subscribe(SparkTags.VolSurfaceUsageTag);
_bb.data_callback += _on_data;
}
@@ -58,27 +55,6 @@ namespace mbts.spark {
return rv;
}
private IReadOnlyDictionary<string, OptionTheoInterpolationData>
_filter_for_publish(IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos) {
// find the symbol vs vs_id, get the committed vs, see if it is
// owned by the current user, and only then publish it
HashSet<string> syms = new HashSet<string>();
var usage = _bb.read_state(SparkTags.VolSurfaceUsageTag);
string current_user = _bb.read_state(SparkTags.CurrentUser).name;
foreach (var u in (usage?.UsageList).empty_if_null()) {
VolSurfaceInput vs_input =
_bb.read_state(SparkTags.VolSurfaceCommittedInputTag(u.VsId));
if (vs_input != null) {
if (vs_input.surface_settings.core_settings.vs_manager ==
current_user) {
syms.Add(u.SecTup.Symbol);
}
}
}
return
all_theos.Where(kv => syms.Contains(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value);
}
private void _publish_data() {
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag, null);
IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos =
@@ -88,11 +64,6 @@ namespace mbts.spark {
if (sc_data == null || all_theos == null || all_drivers == null)
return;
_timer.start();
all_theos = _filter_for_publish(all_theos);
if (all_theos.Count == 0) {
bts.Log.Gen.info($"InterpTheosServerPublisher._publish_data all_theos.Count == 0");
return;
}
IDictionary<UInt32, DriverMD> driver_map = _get_drivers(all_drivers, sc_data);
IEnumerable<Tuple<SecurityImmutable, TheoPoint>> theo_map = _get_theos(all_theos, sc_data);
// assemble it together and send it to the server
@@ -115,7 +86,6 @@ namespace mbts.spark {
ptp.Vega = is_call ? tp.cvega : tp.pvega;
ptp.Theta = is_call ? tp.c_theta : tp.p_theta;
ptp.Rho = Double.NaN;
ptp.Vol = tp.vol;
ptp_list.Add(ptp);
}
bts.api.orderman.PrecomputedTheos server_theos = new PrecomputedTheos();
@@ -126,7 +96,7 @@ namespace mbts.spark {
_order_service.set_precomputed_theos(server_theos);
_timer.stop();
var pub_time = _timer.lastIntervalTime;
bts.Log.Gen.info($"InterpTheosServerPublisher._publish_data symbols: {all_theos.Count} " +
bts.Log.Gen.info($"InterpTheosServerPublisher._publish_data " +
$"size: {server_theos.Theos.Count} comp_time: {comp_time} msecs " +
$"pub_time: {pub_time}");
}
@@ -135,4 +105,4 @@ namespace mbts.spark {
_bb.data_callback -= _on_data;
}
}
}
}
@@ -32,7 +32,7 @@ namespace mbts.spark {
}
);
foreach (var sec_md in exp_secs) {
rv[sec_md.security.Id] = kv.Value;
rv.Add(sec_md.security.Id, kv.Value);
}
}
return rv;
@@ -12,7 +12,7 @@ namespace mbts.spark {
using Spark.Analytics.View;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using Spark.Core.Protobuf;
using System;
using System.Collections;
@@ -26,13 +26,13 @@ namespace mbts.spark {
_refresh = new(_is_dirty.refresh);
_committed_value.Changed += on_committed_changed;
_candidate_value.Changed += on_candidate_changed;
if (column.type.is_editable()) {
_is_dirty.Changed += (o, n) => {
Log.Ui.info(
$"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
$"commited: {committed_value}; candidate: {candidate_value}");
};
}
_is_dirty.Changed += (o, n) => {
Log.assert(o != n);
// 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) =>
_is_dirty.refresh();
@@ -29,7 +29,6 @@ namespace mbts.spark.VolSurface {
class VolSurfaceGridVM : DisposableViewModelBase {
readonly VolSurfaceVM _parent;
readonly UserTuple _user;
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
readonly DeferrableAction _invalidate_rows;
readonly ColumnsModel _columns_model;
@@ -42,12 +41,10 @@ namespace mbts.spark.VolSurface {
VolSurfaceVM vm,
VolSurfaceDisplayModel model,
ISet<string> hidden_columns,
ISet<VolSurfaceExpiration> hidden_expirations,
UserTuple user) {
ISet<VolSurfaceExpiration> hidden_expirations) {
Log.notnull(hidden_columns);
Log.notnull(hidden_expirations);
_parent = vm;
_user = user;
this.model = model;
_columns_model = new(create_exp_column_view());
_hidden_columns = hidden_columns;
@@ -86,7 +83,7 @@ namespace mbts.spark.VolSurface {
_columns_model);
VolSurfaceRowVM row_factory(VolSurfaceDisplayGridExpiration exp) =>
new(this, exp, _user);
new(this, exp);
IDisposable connect_row(VolSurfaceRowVM row) {
row.request_calculate += request_recalc;
@@ -254,7 +251,7 @@ namespace mbts.spark.VolSurface {
var new_hash = cols_new.aggregate_hash();
var old_hash = _columns_model.models.aggregate_hash();
if (new_hash != old_hash) {
_columns_model.models.sync_with(cols_new, allow_duplicates: false);
CollectionHelper.sync_with_never_duplicate(_columns_model.models, cols_new);
RaisePropertyChanged("super_headers");
}
// Add/remove rows too
@@ -1,6 +1,5 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.collections;
using mbts.spark.VolSurface;
@@ -10,7 +9,6 @@ namespace mbts.spark {
using mbts.ui.utility;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
@@ -24,10 +22,6 @@ namespace mbts.spark {
readonly VolSurfaceGridVM _parent;
readonly Property<VolSurfaceColumn?> _column;
readonly Property<DIYGridSuperHeaderVM?> _super_header;
readonly UserTuple _user;
readonly Property<bool> _is_open;
readonly DelegateProperty<string> _vs_manager;
readonly List<IDisposable> _resources = new();
ICommand? _revert_cmd;
ICommand? _shift_selection_cmd;
@@ -40,29 +34,21 @@ namespace mbts.spark {
ICommand? _copy_all_to_clipboard_cmd;
ICommand? _smart_copy_rolls_rates_cmd;
ICommand? _import_csv_cmd;
ObservantCommand? _acquire_ownership_cmd;
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row, UserTuple user) {
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row) {
_parent = parent;
_row = row;
_user = user;
_column = backing<VolSurfaceColumn?>(nameof(column));
_super_header = backing<DIYGridSuperHeaderVM?>(nameof(super_header));
_vs_manager = backing(
nameof(vs_manager),
() => _parent.model.get_active_settings()?.core_settings?.vs_manager ?? string.Empty);
_is_open = backing(nameof(is_open), false);
_resources.AddRange(
_dispose = Disposable.Create(
_column.invalidate_others_on_change(nameof(column_name)),
_super_header.invalidate_others_on_change(nameof(group_name)),
_is_open.Subscribe(_ => _vs_manager.refresh()),
_parent.visible_rows.ObserveSelf()
.BufferLatest(TimeSpan.FromSeconds(1))
.OnDispatcher()
.Subscribe(_ => sync_symbols()));
_dispose = Disposable.Create(() => _resources.DisposeAll(true));
void sync_symbols() {
var visible_exps = _parent.visible_rows.Map(r => r.expiration.symbol);
symbols.sync_with_models(
@@ -178,34 +164,6 @@ namespace mbts.spark {
_parent.model.csv_importing_enabled,
null);
public ICommand acquire_ownership_cmd {
get {
if (_acquire_ownership_cmd is null) {
_acquire_ownership_cmd = new(
() => {
var settings = _parent.model.get_active_settings();
if (settings is null) {
Log.Ui.error("Unable to acquire volsurface ownership: settings are null.");
return;
}
settings.core_settings.vs_manager = _user.name;
_parent.model.set_candidate_settings(settings);
});
_resources.Add(_vs_manager.observe_current(true)
.Subscribe(SelectorObserver.builder(_acquire_ownership_cmd).wrap<string>(
curr => curr != _user.name)));
}
return _acquire_ownership_cmd;
}
}
public bool is_open {
get => _is_open.Value;
set => _is_open.set(value);
}
public string vs_manager => _vs_manager.Value;
VolSurfaceDisplayGridColumn _assert_model() =>
column?.model ?? throw new InvalidOperationException();
@@ -1,7 +1,5 @@
#nullable enable
namespace mbts.spark.VolSurface {
using bts;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
@@ -18,16 +16,14 @@ namespace mbts.spark.VolSurface {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
readonly Dictionary<string, CellData> _cells = new();
readonly UserTuple _user;
readonly DeferrableAction _request_calculate;
VolSurfaceRowContextMenuVM? _context_menu;
bool _is_selected;
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp, UserTuple user) {
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_user = user;
_request_calculate = new(() => request_calculate?.Invoke());
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
@@ -53,7 +49,7 @@ namespace mbts.spark.VolSurface {
}
public VolSurfaceRowContextMenuVM context_menu =>
_context_menu ??= new(_parent, this, _user);
_context_menu ??= new(_parent, this);
public VolSurfaceCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
@@ -1,89 +0,0 @@
#nullable enable
namespace mbts.spark {
using bts.api.domain;
using mbts.analytics;
using mbts.ui.shell;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using VolCurveFitRegion = analytics.VolSurfaceEnums.VolCurveFitRegion;
public class VolSurfaceAutoFitSettingsVM : DisposableViewModelBase {
readonly Property<VolCurveFitRegion> _fit_region;
readonly Property<uint?> _period_secs;
readonly Property<double?> _driver_points_moved;
readonly Property<double?> _atm_points_moved;
readonly Property<bool> _is_auto_fit_enabled;
public VolSurfaceAutoFitSettingsVM() {
_fit_region = backing(nameof(fit_region), VolCurveFitRegion.None);
_is_auto_fit_enabled = backing(
nameof(is_auto_fit_enabled),
_fit_region.observe_current(true),
r => r != VolCurveFitRegion.None);
_period_secs = backing<uint?>(nameof(period_secs), 10);
_driver_points_moved = backing<double?>(nameof(driver_points_moved));
_atm_points_moved = backing<double?>(nameof(atm_points_moved));
_fit_region.Changed += (o, n) => RaisePropertyChanged(nameof(is_auto_fit_enabled));
}
public IEnumerable<VolCurveFitRegion> fit_regions =>
EnumHelper.get_values<VolCurveFitRegion>();
public VolCurveFitRegion fit_region {
get => _fit_region.Value;
set => _fit_region.set(value);
}
public bool is_auto_fit_enabled => _is_auto_fit_enabled.Value;
public uint? period_secs {
get => _period_secs.Value;
set => _period_secs.set(value);
}
public double? driver_points_moved {
get => _driver_points_moved.Value;
set => _driver_points_moved.set(value);
}
public TickDisplaySettingsImmutable? driver_points_display =>
user.settings.TickFactors.pennies.to_api_tick_display_settingsi();
public double? atm_points_moved {
get => _atm_points_moved.Value;
set => _atm_points_moved.set(value);
}
public TickDisplaySettingsImmutable? atm_points_display =>
user.settings.TickFactors.pennies.to_api_tick_display_settingsi();
public void load_from(VolSurfaceAutoFitSettings value) {
fit_region = value?.auto_fit_region ?? VolCurveFitRegion.None;
period_secs = value?.time_based_settings?.period_seconds;
driver_points_moved = value?.driver_move_based_settings?.points_moved;
atm_points_moved = value?.atm_implied_vol_based_settings?.points_moved;
}
public void assign_to(VolSurfaceAutoFitSettings value) {
if (value is null) {
throw new ArgumentNullException(nameof(value));
}
value.auto_fit_region = fit_region;
value.time_based_settings = new() {
period_seconds = period_secs
};
value.driver_move_based_settings = new() {
points_moved = driver_points_moved
};
value.atm_implied_vol_based_settings = new() {
points_moved = atm_points_moved
};
}
}
}
@@ -40,7 +40,6 @@ namespace mbts.spark {
vol_model_cubic_spline_vm.load_from(settings.spline_model_settings);
vol_model_dual_quadratic_vm.load_from(settings.dualquadratic_model_settings);
vol_path_parabolic_vm.load_from(settings.core_settings.volpath_settings.parabolic_vol_path_settings);
auto_fit_vm.load_from(settings.core_settings.market_fit_settings.vs_auto_fit_settings);
init_rotation_vms(call_rotations, _core_settings.call_rotation.strike_vol_movement_pairs);
init_rotation_vms(put_rotations, _core_settings.put_rotation.strike_vol_movement_pairs);
@@ -106,7 +105,6 @@ namespace mbts.spark {
}).ToList();
_core_settings.strangle.strike_vol_movement_pairs = strangles.SelectMany(r => new[] { Tuple.Create(r.target_put_strike, r.put_move), Tuple.Create(r.target_call_strike, r.call_move) }).ToList();
_core_settings.atm_shift.atm_strike_vol_movement = atm_shifts.Count == 1 ? atm_shifts[0].move : 0;
auto_fit_vm.assign_to(_core_settings.market_fit_settings.vs_auto_fit_settings);
commit(_settings);
}
@@ -235,7 +233,23 @@ namespace mbts.spark {
}
}
public VolSurfaceAutoFitSettingsVM auto_fit_vm { get; } = new();
public bool enable_auto_fit {
get => _core_settings.market_fit_settings.enable_auto_fit;
set {
using var _ = detect_property_change();
_core_settings.market_fit_settings.enable_auto_fit = value;
}
}
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region {
get => _core_settings.market_fit_settings.auto_fit_region;
set { _core_settings.market_fit_settings.auto_fit_region = value; }
}
public double auto_fit_time_ms {
get => _core_settings.market_fit_settings.auto_fit_time_ms;
set { _core_settings.market_fit_settings.auto_fit_time_ms = value; }
}
public bool auto_decay_vol_time {
get => _core_settings.time_settings.time_mode == VolSurfaceEnums.VolSurfaceTimeMode.AutoDecay;
+2 -10
View File
@@ -1,6 +1,5 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.api;
using bts.collections;
@@ -28,7 +27,6 @@ namespace mbts.spark {
readonly IBus _bus;
readonly string _request_id = Guid.NewGuid().ToString();
readonly VolSurfaceDisplayModel _model;
readonly UserTuple _user;
readonly IRaiseCanExecuteChangedCommand _revert_cmd;
readonly IRaiseCanExecuteChangedCommand _commit_cmd;
readonly IDialogCommand _main_settings_cmd;
@@ -40,16 +38,10 @@ namespace mbts.spark {
bool _ignore_implied_vol_settings;
public VolSurfaceVM(
VolSurfaceDisplayModel model,
int id,
IBus bus,
VolSurfaceWindowSettings startup_data,
UserTuple user
) {
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
_model = model;
_vs_id = id;
_bus = bus;
_user = user;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
@@ -57,7 +49,7 @@ namespace mbts.spark {
_grid_settings = startup_data.macro_grid_settings ?? new VolSurfaceMacroGridSettings();
var hidden_exps_set = startup_data.hidden_exps.empty_if_null().ToHashSet();
grid = new VolSurfaceGridVM(
this, _model, _grid_settings.hidden_cols(), hidden_exps_set, _user);
this, _model, _grid_settings.hidden_cols(), hidden_exps_set);
grid.on_selection_changed += _on_grid_selection_changed;
_model.publish_grid_settings(_grid_settings);
+1 -2
View File
@@ -162,8 +162,7 @@ namespace mbts.spark {
api_sec_exp.Exchange.to_venue(),
api_sec_exp.SecurityType.contract_case(),
api_sec_exp.Symbol,
api_sec_exp.HasExpiration ?
api_sec_exp.Expiration.date_time() : SecurityExpiration.empty.expiration);
api_sec_exp.Expiration.date_time());
public static SecurityExpiration to_sec_exp(this Security sec) =>
to_sec_exp(new SecurityImmutable(sec));
@@ -22,7 +22,7 @@ namespace mbts.spark {
// ii. IntepGreeks for each vs
public class VolSurfaceInterpGreeksMultiplexer : IDisposable {
private readonly ThreadedBlackboard _bb;
private readonly ITag<VolSurfaceUsageListImmutable?> _in_bb_vs_usage_tag;
private readonly ITag<VolSurfaceUsageListImmutable> _in_bb_vs_usage_tag;
private IDictionary<int, ITag<VSTheos>> _vs_theo_tags =
new Dictionary<int, ITag<VSTheos>>();
private VolSurfaceUsageListImmutable _vs_usage_map =
@@ -48,8 +48,8 @@ namespace mbts.spark {
}
private void _analyze_usages() {
_vs_usage_map = _bb.read_state(_in_bb_vs_usage_tag) ??
new VolSurfaceUsageList().immutable();
_vs_usage_map = _bb.read_state(_in_bb_vs_usage_tag,
new VolSurfaceUsageListImmutable(new VolSurfaceUsageList()));
bts.Log.Gen.info($"VolSurfaceInterpGreeksMultiplexer._analyze_usages " +
$"count: {_vs_usage_map.UsageList.Count()}");
foreach (int vs_id in _vs_usage_map.vss()) {
+12 -20
View File
@@ -6,7 +6,6 @@ using bts.collections;
using bts.utils;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
@@ -27,7 +26,6 @@ namespace mbts.spark {
: this(bus, service, user.Value) { }
AdminModel(IBus bus, AdminService service, UserTuple user) {
var bootstraps = new DisposableBuilder();
this.user = user;
// accounts
on_accounts = service.subscribei_admin_data()
@@ -43,30 +41,24 @@ namespace mbts.spark {
.RefCount();
// users
on_users = Observable.Return(DictionaryHelper.wrap_value(user.id, user.name));
if (user.permissions == UserTuple.Permissions.Admin) {
all_user_tuples = bootstraps.emplace(
service.subscribei_admin_data()
.Select(u => u.all.FirstOrNull())
.Where(ad => ad.HasValue)
.Select(ad => ad.Value.Users
.Where(u => user.can_access_user_data(u.Id))
.Select(u => new UserTuple(u.Id, u.Name))
.ToDictionary(UserTuple.key_fn))
.Table(UserTuple.key_fn)
.Cache()
.ToObservable());
} else {
all_user_tuples = Observable.Return(
TableUpdate<UserTuple, uint>.mk_empty(UserTuple.key_fn).with_added(new[] { user }));
}
all_user_tuples = user.permissions == UserTuple.Permissions.Admin ?
service.subscribei_admin_data()
.Select(u => u.all.FirstOrNull())
.Where(ad => ad.HasValue)
.Select(ad => ad.Value.Users
.Where(u => user.can_access_user_data(u.Id))
.Select(u => new UserTuple(u.Id, u.Name))
.ToDictionary(UserTuple.key_fn))
.Table(UserTuple.key_fn)
.Cache() :
Observable.Return(TableUpdate<UserTuple, uint>.mk_empty(UserTuple.key_fn).with_added(new[] { user }));
_dispose = Disposable.Create(
all_user_tuples.Subscribe(t => bus.post(SparkTags.Users, t.state)),
on_accounts.Subscribe(map => {
_account_map = map;
var account_tuple_map = MappedDictionary.create(map, (id, name) => new AccountTuple(id, name));
bus.post(SparkTags.AccountsTag, account_tuple_map);
}),
bootstraps);
}));
bus.post(SparkTags.CurrentUser, user);
}
@@ -1,15 +1,10 @@
using bts;
using bts.api;
using bts.api.core;
using bts.collections;
using mbts.spark.utilities;
using mbts.ui.utility;
using mbts.utils;
using Spark.Core.Data;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -21,18 +16,11 @@ using System.Text.RegularExpressions;
using AlgoType = bts.api.orderman.CustomOrderDefinition.CustomOneofCase;
namespace mbts.spark {
class AlgoProviderFactory : IDisposable {
IDisposable _dispose;
class AlgoProviderFactory {
[ImportingConstructor]
public AlgoProviderFactory(
IAlgoStudioModel studio_model,
OrderFactory order_factory,
ISecurityMetadataStore sec_meta_store
) {
public AlgoProviderFactory(IAlgoStudioModel studio_model, DynamicOrderHelper dynamic_helper, ISecurityAuxiliaryDataModel security_auxiliary_model) {
var from_conf = config.Configuration.get<bts.config.AlgoTypeRuleSet>();
var disposables = new List<IDisposable>();
if (from_conf.Rules.Count == 0) {
if (from_conf.rules.Count == 0) {
// There seems to be a config race bug, where the returned config values are empty, despite having entries in spark.conf.
// [John]I've only noticed it happen when attached to the debugger,
// but best to have a contingency plan in place anyways, to prevent any chance of regression.
@@ -50,18 +38,13 @@ namespace mbts.spark {
AlgoType.Tick,
AlgoType.Trigger,
AlgoType.QueueHolder)),
ImmutableHashSet.CreateRange(order_factory.dynamic_types()));
ImmutableHashSet.CreateRange(dynamic_helper.dynamic_types));
var rules = new[] {
// Glbx: Futures/Spreads
new SecurityAlgoTypeSetImmutable(
new SecurityCriteriaClause(
exchanges: new[] { Venue.Glbx },
security_types: new[] {
SecurityType.Spot,
SecurityType.Future,
SecurityType.Spread,
SecurityType.Option
}),
security_types: new[] { SecurityType.Future, SecurityType.Spread, SecurityType.Option }),
new AlgoTypeSetImmutable(
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader }),
full_algo_set.dynamic_types)),
@@ -69,12 +52,7 @@ namespace mbts.spark {
new SecurityAlgoTypeSetImmutable(
new SecurityCriteriaClause(
exchanges: EnumHelper.get_values_except(Venue.Glbx, Venue.Unset).ToArray(),
security_types: new[] {
SecurityType.Spot,
SecurityType.Future,
SecurityType.Spread,
SecurityType.Option
}),
security_types: new[] { SecurityType.Future, SecurityType.Spread, SecurityType.Option }),
new AlgoTypeSetImmutable(
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader, AlgoType.GlbxIceberg }),
full_algo_set.dynamic_types)),
@@ -122,35 +100,18 @@ namespace mbts.spark {
"\n\n\tAttachable\n" +
attachable_rules.fmt_diagnostic("\n\t\t"));
var security_algo_provider = new AlgoProvider(
rules, studio_model, order_factory, sec_meta_store);
var attachable_algo_provider = new AttachableAlgoProvider(
attachable_rules, studio_model, order_factory, sec_meta_store);
this.security_algo_provider = security_algo_provider;
this.attachable_algo_provider = attachable_algo_provider;
disposables.AddRange(security_algo_provider, attachable_algo_provider);
security_algo_provider = new AlgoProvider(rules, studio_model, dynamic_helper, security_auxiliary_model);
attachable_algo_provider = new AttachableAlgoProvider(attachable_rules, studio_model, dynamic_helper, security_auxiliary_model);
} else {
var algo_type_data =
EnumHelper.get_values_except(AlgoType.Dynamic, AlgoType.Composite, AlgoType.None)
.Select(t => _get_type_data(t))
.Concat(order_factory.dynamic_types().Select(dt => _get_type_data(AlgoType.Dynamic, dt)))
.Concat(dynamic_helper.dynamic_types.Select(dt => _get_type_data(AlgoType.Dynamic, dt)))
.ToListLazy();
var conf_sets = from_conf.Rules.Select(r => _to_security_algo_set(r, order_factory, algo_type_data)).ToList();
var security_algo_provider = new AlgoProvider(
conf_sets.Select(tup => tup.standard).ToList(),
studio_model,
order_factory,
sec_meta_store);
var attachable_algo_provider = new AttachableAlgoProvider(
conf_sets.Select(tup => tup.attachable).ToList(),
studio_model,
order_factory,
sec_meta_store);
this.security_algo_provider = security_algo_provider;
this.attachable_algo_provider = attachable_algo_provider;
disposables.AddRange(security_algo_provider, attachable_algo_provider);
var conf_sets = from_conf.rules.Select(r => _to_security_algo_set(r, dynamic_helper, algo_type_data)).ToList();
security_algo_provider = new AlgoProvider(conf_sets.Select(tup => tup.standard).ToList(), studio_model, dynamic_helper, security_auxiliary_model);
attachable_algo_provider = new AttachableAlgoProvider(conf_sets.Select(tup => tup.attachable).ToList(), studio_model, dynamic_helper, security_auxiliary_model);
}
_dispose = Disposable.Create(disposables);
}
[Export]
@@ -158,9 +119,6 @@ namespace mbts.spark {
[Export]
public IAttachableAlgoProvider attachable_algo_provider { get; }
public void Dispose() =>
Disposable.dispose(ref _dispose);
static (string name, AlgoType factory, string dynamic) _get_type_data(AlgoType type, string dynamic_type = null) {
string type_name = type.ToString();
return (type_name, type, dynamic_type ?? type_name);
@@ -170,42 +128,39 @@ namespace mbts.spark {
context == null ?
new SecurityCriteriaClause() :
new SecurityCriteriaClause(
exchanges: context.Exchanges?.Select(EnumHelper.parse<Venue>)?.ToArray(),
security_types: context.SecurityTypes?.Select(EnumHelper.parse<Security.ContractOneofCase>)?.Select(t => t.security_type())?.ToArray(),
symbols: context.Symbols?.ToArray());
exchanges: context.exchanges?.Select(EnumHelper.parse<Venue>)?.ToArray(),
security_types: context.security_types?.Select(EnumHelper.parse<Security.ContractOneofCase>)?.Select(t => t.security_type())?.ToArray(),
symbols: context.symbols?.ToArray());
static (SecurityAlgoTypeSetImmutable standard, SecurityAlgoTypeSetImmutable attachable) _to_security_algo_set(
bts.config.AlgoTypeRule rule,
OrderFactory order_factory,
DynamicOrderHelper dynamic_helper,
IEnumerable<(string name, AlgoType factory, string dynamic)> algo_type_data) {
//
var factory_types = ImmutableHashSet<AlgoType>.Empty.ToBuilder();
var dynamic_types = ImmutableHashSet<string>.Empty.ToBuilder();
var attachable_factory_types = ImmutableHashSet<AlgoType>.Empty.ToBuilder();
var attachable_dynamic_types = ImmutableHashSet<string>.Empty.ToBuilder();
foreach (var a in rule.Algos) {
if (Enum.TryParse(a.Name, out AlgoType sys_algo) && sys_algo != AlgoType.Composite && sys_algo != AlgoType.Dynamic) {
on_sys_match(sys_algo, a.IsAttachable);
continue;
}
var dyn_desc = order_factory.dynamic_descriptor(a.Name);
if (dyn_desc is not null) {
on_dyn_match(dyn_desc.DynamicOrderType, a.IsAttachable);
continue;
}
foreach (var (name, factory, dynamic) in algo_type_data) {
if (Regex.Match(name, a.Name).Success) {
switch (factory) {
case AlgoType.None:
case AlgoType.Composite:
// unexpected, but no need to crash
continue;
case AlgoType.Dynamic:
on_dyn_match(dynamic, a.IsAttachable);
break;
default:
on_sys_match(factory, a.IsAttachable);
break;
foreach (var a in rule.algos) {
if (Enum.TryParse(a.name, out AlgoType sys_algo) && sys_algo != AlgoType.Composite && sys_algo != AlgoType.Dynamic) {
on_sys_match(sys_algo, a.is_attachable);
} else if (dynamic_helper.try_parse(a.name, out var dyn_type)) {
on_dyn_match(dyn_type, a.is_attachable);
} else {
foreach (var (name, factory, dynamic) in algo_type_data) {
if (Regex.Match(name, a.name).Success) {
switch (factory) {
case AlgoType.None:
case AlgoType.Composite:
// unexpected, but no need to crash
continue;
case AlgoType.Dynamic:
on_dyn_match(dynamic, a.is_attachable);
break;
default:
on_sys_match(factory, a.is_attachable);
break;
}
}
}
}
@@ -213,13 +168,13 @@ namespace mbts.spark {
return (
// standard
new SecurityAlgoTypeSetImmutable(
_to_clause(rule.Context),
_to_clause(rule.context),
new AlgoTypeSetImmutable(
factory_types.ToImmutable(),
dynamic_types.ToImmutable())),
// attachable
new SecurityAlgoTypeSetImmutable(
_to_clause(rule.Context),
_to_clause(rule.context),
new AlgoTypeSetImmutable(
attachable_factory_types.ToImmutable(),
attachable_dynamic_types.ToImmutable())));
+4 -5
View File
@@ -80,7 +80,7 @@ namespace mbts.spark {
public static IEnumerable<AlgoData> define_algos(
this AlgoTypeSetImmutable algo_set,
Func<string, CustomOrderDefinitionImmutable> dynamic_order_factory,
DynamicOrderHelper dynamic_helper,
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
double display_qty_divisor = 1) =>
//
@@ -101,13 +101,13 @@ namespace mbts.spark {
}
return def;
})
.Concat(algo_set.dynamic_types.Select(dynamic_order_factory))
.Concat(algo_set.dynamic_types.Select(dynamic_helper.create_custom_defi))
.Select(AlgoData.from_custom_def);
public static ImmutableDictionary<AlgoKey, AlgoData> match_algos(
this IEnumerable<SecurityAlgoTypeSetImmutable> security_algo_sets,
SecurityCriteriaClause clause,
Func<string, CustomOrderDefinitionImmutable> dynamic_order_factory,
DynamicOrderHelper dynamic_helper,
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
double display_qty_divisor = 1) {
//
@@ -117,8 +117,7 @@ namespace mbts.spark {
continue;
} else if (rv == null) {
rv = ImmutableDictionary.CreateRange(
set.algo_type_set.define_algos(
dynamic_order_factory, fit_to_type, display_qty_divisor)
set.algo_type_set.define_algos(dynamic_helper, fit_to_type, display_qty_divisor)
.Select(a => new KeyValuePair<AlgoKey, AlgoData>(a.key, a)));
} else {
foreach (var kv in rv) {
+14 -36
View File
@@ -8,13 +8,6 @@ using mbts.spark.utilities;
using mbts.ui.utility;
using mbts.utils;
using Spark.Api.Orders;
using Spark.Core;
using Spark.Core.Data;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -34,28 +27,23 @@ namespace mbts.spark {
// from the standard one wrt MEF export/import.
interface IAttachableAlgoProvider : IAlgoProvider { }
class AlgoProvider : IAlgoProvider, IDisposable {
class AlgoProvider : IAlgoProvider {
readonly IEnumerable<SecurityAlgoTypeSetImmutable> _security_algo_types;
readonly IAlgoStudioModel _studio_model;
readonly ISecurityAuxiliaryDataModel _security_auxiliary_model;
readonly IObservable<TableUpdate<AlgoData, AlgoKey>> _studio_algos_source;
readonly OrderFactory _order_factory;
readonly ISecurityMetadataStore _sec_meta_store;
readonly DynamicOrderHelper _dynamic_helper;
readonly AlgoTypeSetImmutable _full_set;
IDisposable _dispose;
public AlgoProvider(
IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets,
IAlgoStudioModel studio_model,
OrderFactory order_factory,
ISecurityMetadataStore sec_meta_store) {
public AlgoProvider(IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets, IAlgoStudioModel studio_model, DynamicOrderHelper dynamic_helper, ISecurityAuxiliaryDataModel security_auxiliary_model) {
_security_algo_types = algo_sets;
_studio_model = studio_model;
_order_factory = order_factory;
_dynamic_helper = dynamic_helper;
_full_set = new AlgoTypeSetImmutable(
ImmutableHashSet.CreateRange(
EnumHelper.get_values_except(CustomOrderDefinition.CustomOneofCase.None, CustomOrderDefinition.CustomOneofCase.Dynamic, CustomOrderDefinition.CustomOneofCase.Composite)),
ImmutableHashSet.CreateRange(_order_factory.dynamic_types()));
_sec_meta_store = sec_meta_store;
ImmutableHashSet.CreateRange(dynamic_helper.dynamic_types));
_security_auxiliary_model = security_auxiliary_model;
/// initialize <see cref="_studio_algos_source"/> with an empty table, so the
/// <see cref="UpdateExtensions.AppendTable{T, TKey}(IObservable{TableUpdate{T, TKey}}, IEnumerable{T})"/>
/// calls made by the 'subscribe_algos' methods will fire at least once, even if the underlying
@@ -63,15 +51,9 @@ namespace mbts.spark {
/// <see cref="subscribe_algos"/>,
/// <see cref="subscribe_algos(SecurityCriteriaClause)"/>,
/// <see cref="subscribe_algos(SecurityImmutable)"/>
var bootstraps = new DisposableBuilder();
_studio_algos_source = bootstraps.emplace(studio_model.definitions.Cache().ToObservable());
_dispose = bootstraps;
_studio_algos_source = studio_model.definitions.Cache();
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
public AlgoTypeSetImmutable get_permitted_algos(SecurityImmutable security) =>
_security_algo_types.Where(p => p.security_criteria.includes(security))
.Select(sec_algos => sec_algos.algo_type_set)
@@ -88,12 +70,12 @@ namespace mbts.spark {
.AppendTable(_security_algo_types
.Select(s => s.algo_type_set)
.Aggregate(AlgoTypeSetImmutable.empty, (a, b) => a.union_with(b))
.define_algos(t => _order_factory.custom_defi(t).assert_value()));
.define_algos(_dynamic_helper));
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityCriteriaClause security_clause) {
var system_algos = _security_algo_types.match_algos(
security_clause,
t => _order_factory.custom_defi(t).assert_value(),
_dynamic_helper,
def => _fit_to_type(def, security_clause, _security_algo_types));
return _studio_algos_source
@@ -112,9 +94,9 @@ namespace mbts.spark {
// i.e., non-studio algos
var system_algos = _security_algo_types.match_algos(
clause,
t => _order_factory.custom_defi(t).assert_value(),
_dynamic_helper,
def => _fit_to_type(def, security, _security_algo_types),
_sec_meta_store.get_qty_display_divisor(security));
_security_auxiliary_model.get_display_quantity_divisor(security));
var filtered_studio_algos = _studio_algos_source
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
@@ -198,12 +180,8 @@ namespace mbts.spark {
}
class AttachableAlgoProvider : AlgoProvider, IAttachableAlgoProvider {
public AttachableAlgoProvider(
IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets,
IAlgoStudioModel studio_model,
OrderFactory order_factory,
ISecurityMetadataStore sec_meta_store)
: base(algo_sets, studio_model, order_factory, sec_meta_store) { }
public AttachableAlgoProvider(IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets, IAlgoStudioModel studio_model, DynamicOrderHelper dynamic_helper, ISecurityAuxiliaryDataModel security_auxiliary_model)
: base(algo_sets, studio_model, dynamic_helper, security_auxiliary_model) { }
// arbitrarily assign LimitOrderDefinition (this is just a placeholder; the real child is the attach target algo).
// Note: although 'None' might seem approrpriate, the server requires a valid definition (perhaps this will change in the future).
@@ -1,7 +1,7 @@
namespace mbts.analytics {
using System;
public readonly struct GreeksTuple : IEquatable<GreeksTuple> {
readonly struct GreeksTuple : IEquatable<GreeksTuple> {
public GreeksTuple(
double vol = double.NaN,
double driver = double.NaN,
@@ -58,7 +58,7 @@ namespace mbts.analytics {
public static bool operator !=(GreeksTuple a, GreeksTuple b) => !a.Equals(b);
}
public static class GreeksTupleExtensions {
static class GreeksTupleExtensions {
public static GreeksTuple with(
this GreeksTuple greeks_tuple,
double? vol = null,
@@ -3,7 +3,6 @@ namespace mbts {
using bts.api;
using bts.utils;
using mbts.spark;
using mbts.ui.utility;
using mbts.utils;
@@ -26,9 +25,6 @@ namespace mbts {
SecurityTuple.empty.security_name,
DateTime.MinValue);
public static bts.api.domain.SecurityExpirationImmutable empty_api_sec_expi =>
empty.to_api_sec_expi();
// for deserialization
SecurityExpiration() =>
security_tuple = SecurityTuple.empty;
@@ -131,14 +127,13 @@ namespace mbts {
public bool Equals(SecurityExpiration? other) =>
other is not null &&
security_tuple.safe_equals(other.security_tuple) &&
expiration == other.expiration &&
id == other.id;
expiration == other.expiration;
public override bool Equals(object? obj) =>
Equals(obj as SecurityExpiration);
public override int GetHashCode() =>
HashCode.Combine(security_tuple, expiration, id ?? 0);
HashCode.Combine(security_tuple, expiration);
object ICloneable.Clone() =>
Clone();
@@ -162,7 +157,7 @@ namespace mbts {
public double expiration_oa_date { get; set; }
public SecurityExpirationProto Clone() =>
new() { security = security, expiration_oa_date = expiration_oa_date };
new() { security = security, expiration_oa_date = expiration_oa_date};
public bool Equals(SecurityExpirationProto? other) =>
other is not null &&
@@ -4,11 +4,13 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.analytics {
namespace mbts.analytics
{
/// These are the VolSurface settings that are common
/// to any Vol Model
[ProtoBuf.ProtoContract(Name = "VolSurfaceCoreSettings")]
public class VolSurfaceCoreSettings {
public class VolSurfaceCoreSettings
{
[ProtoBuf.ProtoMember(1)]
public string vol_surface_name;
[ProtoBuf.ProtoMember(2)]
@@ -85,7 +87,5 @@ namespace mbts.analytics {
get => _time_settings ??= new();
set => _time_settings = value;
}
[ProtoBuf.ProtoMember(240)]
public string vs_manager { get; set; } = string.Empty;
}
}
@@ -75,7 +75,6 @@ namespace mbts.analytics {
if (core_settings.market_fit_settings == null) {
core_settings.market_fit_settings = new VolSurfaceMarketFitSettings();
}
core_settings.market_fit_settings.vs_auto_fit_settings ??= new();
if (core_settings.time_settings == null) {
core_settings.time_settings = new VolSurfaceTimeSettings();
}
@@ -141,7 +141,6 @@ namespace mbts.analytics
public enum VolCurveFitRegion
{
None,
ATM,
All
}
@@ -231,4 +230,4 @@ namespace mbts.analytics
USE_CALENDAR_FOR_BUSINESS
}
}
}
}
@@ -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;
@@ -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;
}
@@ -4,9 +4,11 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.analytics {
namespace mbts.analytics
{
[ProtoBuf.ProtoContract(Name = "VolSurfaceMarketFitSettings")]
public class VolSurfaceMarketFitSettings {
public class VolSurfaceMarketFitSettings
{
/// use one sided market or not
[ProtoBuf.ProtoMember(10)]
public bool ignore_one_sided_markets;
@@ -20,44 +22,19 @@ namespace mbts.analytics {
public double graph_update_period_ms = 2500;
/// If this is set to true a regression curve is drawn
/// and the vol model adheres to that
[ProtoBuf.ProtoMember(50)]
[ProtoBuf.ProtoMember(50)]
public bool use_weighted_regression_fit = false;
[ProtoBuf.ProtoMember(55)]
public uint regression_order = 4;
[ProtoBuf.ProtoMember(90)]
public VolSurfaceAutoFitSettings vs_auto_fit_settings { get; set; }
}
[ProtoBuf.ProtoContract(Name = "VolSurfaceAutoFitSettings")]
public class VolSurfaceAutoFitSettings {
// each of these settings can be enabled independently. if they are enabled
// then any of them being true will result in an autmatic fit
[ProtoBuf.ProtoContract(Name = "TimeBasedSettings")]
public class TimeBasedSettings {
[ProtoBuf.ProtoMember(10)]
public uint? period_seconds { get; set; }
}
[ProtoBuf.ProtoContract(Name = "DriverMoveBasedSettings")]
public class DriverMoveBasedSettings {
[ProtoBuf.ProtoMember(10)]
public double? points_moved { get; set; }
}
[ProtoBuf.ProtoContract(Name = "ATMImpliedVolBasedSettings")]
public class ATMImpliedVolBasedSettings {
[ProtoBuf.ProtoMember(20)]
public double? points_moved { get; set; }
// we can do price terms moved as well
}
[ProtoBuf.ProtoMember(5)]
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region;
[ProtoBuf.ProtoMember(10)]
public TimeBasedSettings time_based_settings = null;
[ProtoBuf.ProtoMember(20)]
public DriverMoveBasedSettings driver_move_based_settings = null;
[ProtoBuf.ProtoMember(30)]
public ATMImpliedVolBasedSettings atm_implied_vol_based_settings = null;
/// The system auto fits and saves vols if this is
/// set to true
[ProtoBuf.ProtoMember(60)]
public bool enable_auto_fit = false;
/// If enable_auto_fit = true, this governs
/// how often the system auto-fits
[ProtoBuf.ProtoMember(70)]
public double auto_fit_time_ms = 30000;
[ProtoBuf.ProtoMember(80)]
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region = VolSurfaceEnums.VolCurveFitRegion.ATM;
}
}
@@ -475,7 +475,6 @@ namespace mbts.analytics {
public static ResultMessage save_volsurface(
VolSurfaceInput vs_input, AnalyticsService service, string user = "") {
vs_input.saver_login = user;
vs_input.surface_settings.core_settings.vs_manager = user;
// convert to VolSurfaceEntry
var to_save = new VolSurfaceEntry();
var serialized_vs = ProtobufSerializationHelper.serialize(vs_input);
@@ -596,7 +595,7 @@ namespace mbts.analytics {
_greek_getter(g)(t, is_call);
public static IDictionary<double, IEnumerable<Theos>> hash_strikes(IEnumerable<Theos> theos) =>
theos.Map(t => t.strike);
theos.Map(t => t.strike);
static Func<Theos, bool, double> _greek_getter(VolSurfaceGreeks g) =>
g switch {
@@ -155,8 +155,7 @@ namespace mbts.analytics {
var master_exp_keys =
_exp_strikes_map.Keys.Select(k =>
new SecurityExpiration(Venue.Unset, SecurityType.Option, k.symbol, k.expiration));
// TODO: add exchange to key (so we don't have to 'Crush' the duplicate keys)
var exp_params_no_exch = _exp_params_map.ToDictionaryCrushed(
var exp_params_no_exch = _exp_params_map.ToDictionary(
kv => kv.Key.unset_exchange(), kv => kv.Value);
return exp_params_no_exch.sync(master_exp_keys, true,
exp => AnalyticsExpirationParameters.empty);
@@ -211,4 +210,4 @@ namespace mbts.analytics {
kv.Value.driver_price + max_move));
}
}
}
}
@@ -50,7 +50,9 @@ namespace mbts.analytics {
deliverable_security ??= SecurityExpiration.empty;
roll_schedule_expiration ??= SecurityExpiration.empty;
this.driver = driver ?? _default_driver;
this.driver = driver ?? new(new() {
TimeWeightedInterpolated = new()
});
_deliverable = deliverable_security.to_api_sec_expi();
_roll_schedule = roll_schedule_expiration.to_api_sec_expi();
this.roll_target = roll_target;
@@ -61,10 +63,10 @@ namespace mbts.analytics {
}
public AnalyticsExpirationParameters(ExpirationParameterEntryImmutable db_i) {
_security = db_i.HasSecurityExpiration ? db_i.SecurityExpiration : _default_api_sec_expi;
_deliverable = db_i.HasDeliverable ? db_i.Deliverable : _default_api_sec_expi;
_roll_schedule = db_i.HasRollSchedule ? db_i.RollSchedule : _default_api_sec_expi;
driver = db_i.HasDriver ? db_i.Driver : _default_driver;
_security = db_i.SecurityExpiration;
_deliverable = db_i.Deliverable;
_roll_schedule = db_i.RollSchedule;
driver = db_i.Driver;
roll_target = db_i.RollTarget;
riskless_rate = db_i.RisklessRate;
settlement_price = db_i.SettlementPrice;
@@ -72,12 +74,6 @@ namespace mbts.analytics {
vega_beta = db_i.VegaBeta;
}
static ExpirationDriverImmutable _default_driver =>
new(new() { TimeWeightedInterpolated = new() });
static bts.api.domain.SecurityExpirationImmutable _default_api_sec_expi =>
SecurityExpiration.empty_api_sec_expi;
public SecurityExpiration security => _security.to_sec_exp();
public SecurityExpiration driver_security => driver.HasSecurity ?
driver.Security.to_sec_exp() : SecurityExpiration.empty;
+47 -8
View File
@@ -5,10 +5,9 @@ namespace mbts.ui.shell {
using CommandLine;
using mbts.ui.native;
using Spark.Cli;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
@@ -22,7 +21,7 @@ namespace mbts.ui.shell {
static readonly Mutex _mutex;
ShellBootstrapper _runtime;
SparkCmdOpts _opts;
CLIOptions _opts;
Process _stunnel_process;
static App() {
@@ -44,13 +43,25 @@ namespace mbts.ui.shell {
#endif
public new int Run() {
var argv = SparkCmdOpts.conform_opts(Environment.GetCommandLineArgs());
var argv = Environment.GetCommandLineArgs().ToList();
// TODO: Add configserver arg to CLIOptions (for now, just strip it
// out before parsing)
for (int i = 0; i < argv.Count; i++) {
if (argv[i].ToLower() == "-configserver") {
argv.RemoveAt(i);
if (i < argv.Count) {
argv.RemoveAt(i);
}
break;
}
}
int exit_code = 1;
Parser.Default.ParseArguments<SparkCmdOpts>(argv).WithParsed(opts => {
Parser.Default.ParseArguments<CLIOptions>(argv).WithParsed(opts => {
_opts = opts;
var opt_desc = TableFormatter.fmt_table(
typeof(SparkCmdOpts).GetProperties()
typeof(CLIOptions).GetProperties()
.Select(p => (p.Name, p.GetValue(opts))), field_separator: "\n\t");
Log.Ui.info($"Running spark_client with options:\n\t{opt_desc}");
try {
@@ -83,8 +94,7 @@ namespace mbts.ui.shell {
CultureInfo.DefaultThreadCurrentUICulture = us_culture;
base.OnStartup(e);
_runtime = new ShellBootstrapper(
_opts?.user, _opts?.password, _opts?.sparkd, _opts?.restore_workspace);
_runtime = new ShellBootstrapper(_opts?.user, _opts?.password, _opts?.restore_workspace);
_runtime.Run();
// Select text on tab in
@@ -149,5 +159,34 @@ namespace mbts.ui.shell {
stunnel_job_error = "Error starting stunnel: " + ex.Message;
}
}
class CLIOptions {
[Option("multiple", HelpText = "Allow multple shells to run simultaneously")]
public bool allow_multiple_shells { get; set; }
[Option("stunnel", HelpText = "Use stunnel")]
public bool stunnel { get; set; }
[Option("no-stunnel", HelpText = "Don't use stunnel")]
public bool no_stunnel {
get => !stunnel;
set => stunnel = !value;
}
[Option("user", HelpText = "The user with which to login")]
public string user { get; set; }
[Option("password", HelpText = "The password with which to login")]
public string password { get; set; }
[Option("restore-workspace", HelpText = "Whether or not to restore the user's last workspace", Default = true)]
public bool restore_workspace { get; set; }
[Option("no-restore-workspace", HelpText = "Whether or not to restore the user's last workspace")]
public bool no_restore_workspace {
get => !restore_workspace;
set => restore_workspace = !value;
}
}
}
}
+1 -4
View File
@@ -38,10 +38,7 @@ namespace bts.ui {
Window about = Application.LoadComponent(new Uri("/view/Shell/About.xaml", UriKind.Relative)) as Window;
enable_crash_on_dblclick(about);
if (about != null) {
about.DataContext = new {
Version = Configuration.get<bts.config.SystemConfig>().Version,
User = _user
};
about.DataContext = new { Version = Configuration.get<bts.config.System>().version, User = _user };
about.Topmost = true;
about.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (a, b) => about.Close()));
about.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, (arg, e) => {
@@ -4,9 +4,7 @@ using bts.spark;
using mbts.spark;
using mbts.ui;
using Spark.Api.Orders;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
+1 -1
View File
@@ -104,7 +104,7 @@ namespace bts {
rv.ContractSpec.CashPerPoint = 50;
rv.ContractSpec.PriceMultiplier = 1.0;
// Currency
rv.Currency = "USD";
rv.Currency = Currency.Usd;
}
public static void fill_security_future(ref Security rv, DateTime exp) {
@@ -8,7 +8,6 @@ namespace bts.daemons {
using mbts.ui;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
@@ -9,7 +9,6 @@ using mbts.ui.spark;
using mbts.ui.utilities;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Composition;
+2 -6
View File
@@ -15,7 +15,6 @@ namespace bts {
using Spark.Core.Data;
using Spark.Core.Disposables;
using Spark.Core.Reactive;
using System;
using System.Collections.Concurrent;
@@ -51,7 +50,7 @@ namespace bts {
ss,
user,
security_metadata,
TimeSpan.FromMilliseconds(Configuration.get<RelayOptions>().NaggleMs),
TimeSpan.FromMilliseconds(Configuration.get<RelayOptions>().naggle_ms),
TimeSpan.FromSeconds(1)) { }
public MDDaemon(
@@ -136,10 +135,7 @@ namespace bts {
var meta = _security_metadata.get(smd.security);
if (meta.HasValue) {
exch_secs[smd.id] = new(
smd.security,
smd.md,
meta.Value.HasPriceDisplay ? meta.Value.PriceDisplay : null,
meta.Value.HasQuantityDisplay ? meta.Value.QuantityDisplay : null);
smd.security, smd.md, meta.Value.PriceDisplay, meta.Value.QuantityDisplay);
}
}
_bus.post(SparkTags.ServerSecuritiesTag, exch_secs);
+1 -7
View File
@@ -52,16 +52,10 @@ 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} ask: p: {ask.price} q: {ask.size} qf: {ask.size}" +
"\n";
$"k: {sec.Option.Strike} cp: {sec.Option.CallPut}" + "\n";
}
}
Log.Gen.info(rv);
+1 -1
View File
@@ -25,7 +25,7 @@ namespace bts.spark {
void handle_unclean_shutdown(ErrorReporter e, int oldpid) {
string extra = "";
try {
var conf = mbts.config.Configuration.get<bts.config.SystemConfig>();
var conf = mbts.config.Configuration.get<bts.config.System>();
extra = JsonConvert.SerializeObject(conf, Formatting.Indented);
} catch { }
Task.Run(() => e.report_silently(
+44 -36
View File
@@ -1,7 +1,7 @@
using bts.api;
using bts.api;
using bts.api.core;
using bts.api.orderman;
using bts.config;
using bts.spark;
using mbts;
using mbts.config;
@@ -10,9 +10,7 @@ using mbts.spark;
using mbts.ui;
using mbts.ui.spark;
using Spark.Api.Orders;
using Spark.Core.Disposables;
using Spark.Orders;
using System;
using System.Collections.Generic;
@@ -29,20 +27,21 @@ namespace bts.shell {
readonly IBus _bus;
readonly OrdersModel _model;
readonly UserSettingsHub _settings_hub;
readonly ErrorReporter _error_reporter;
readonly bool _close_on_send;
IReadOnlyDictionary<uint, AccountTuple> _accounts = new Dictionary<uint, AccountTuple>(0);
IReadOnlyDictionary<uint, SecurityMD> _md_map;
TableUpdate<OrderRecordTuple, uint> _orders;
TableUpdate<(SecurityImmutable? sec, OrderRecordImmutable order), uint> _orders;
IDisposable _dispose;
[ImportingConstructor]
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub)
: this(bus, model, settings_hub, Configuration.get<OrderTicketOptions>().CloseOnSend) { }
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub, ErrorReporter error_reporter)
: this(bus, model, settings_hub, error_reporter, Configuration.get<bts.config.OrderTicketOptions>().close_on_send) { }
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub, bool close_on_send) {
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub, ErrorReporter error_reporter, bool close_on_send) {
_bus = bus;
_model = model;
_settings_hub = settings_hub;
_error_reporter = error_reporter;
_close_on_send = close_on_send;
_dispose = Disposable.Create(
model.on_orders.OnDispatcher().Subscribe(o => _orders = o),
@@ -50,8 +49,7 @@ namespace bts.shell {
bus.subscribe(SparkTags.ShowOrderTicketFromSecurityTag).OnDispatcher().Subscribe(_show_order_ticket),
bus.subscribe(SparkTags.ShowOrderTicketTag).OnDispatcher().Subscribe(_show_order_ticket),
bus.subscribe(SparkTags.ShowOrderTicketAutoLookupTag).Subscribe(_show_order_tickets),
bus.subscribe(SparkTags.ShowModifyOrderTag).OnDispatcher().Subscribe(_show_modify_order),
bus.subscribe(SparkTags.AccountsTag).Subscribe(accs => _accounts = accs)
bus.subscribe(SparkTags.ShowModifyOrderTag).OnDispatcher().Subscribe(_show_modify_order)
);
}
@@ -72,25 +70,33 @@ namespace bts.shell {
void _show_order_ticket(SecurityMD smd) {
var settings_src = _settings_hub.subscribe_default_settings()
.Select(s => s.get_ladder_profile(smd.security)?.value ?? LadderSettings.Default);
var accounts_src = _bus.subscribe(SparkTags.AccountsTag);
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd, accounts_src, settings_src) {
DataContext = new NewOrderTicketVM(_model, smd, settings_src) {
close_on_send = _close_on_send
}
});
}
void _show_order_ticket(OrderTicketParams ot_params) {
if (!_md_map.TryGetValue(ot_params.definition.SecurityKey, out SecurityMD smd)) {
void _show_order_ticket((OrderDefinitionImmutable def, double price, uint size) ops) {
var (def, price, size) = ops;
if (!_md_map.TryGetValue(def.SecurityKey, out SecurityMD smd)) {
return;
}
var def = _model.factory.order(smd.security, _accounts.Values.FirstOrNull());
def.MergeFrom(ot_params.definition.CloneToMutable());
var accounts = _bus.subscribe(SparkTags.AccountsTag);
var calc_buttons = Observable.Return(LadderSettings.Default.calculator_buttons);
if (def.Account.is_null_or_empty() && def.AccountId == 0) {
var settings = _settings_hub.current.get_ladder_profile(smd.security);
var default_account = settings?.value?.default_account;
if (default_account.HasValue) {
var mdef = def.CloneToMutable();
// The order ticket will resolve AccountId to a name
mdef.AccountId = default_account.Value;
def = new(mdef);
}
}
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(
_model, smd, accounts, new(def), ot_params.price, ot_params.quantity, calc_buttons) {
DataContext = new NewOrderTicketVM(_model, smd, def, price, size,
Observable.Return(LadderSettings.Default.calculator_buttons)) {
close_on_send = _close_on_send
}
});
@@ -104,23 +110,25 @@ namespace bts.shell {
}
void _show_modify_order(uint order_key) {
if (!_orders.state.TryGetValue(order_key, out var ori) || !ori.security.HasValue) {
return;
if (_orders.state.TryGetValue(order_key, out var ori) && ori.sec.HasValue
&& (ori.order.HasDef && ori.order.Def.HasCustomDef && !(ori.order.Def.CustomDef.HasStop || ori.order.Def.CustomDef.HasStopLimit))) {
var md = _md_map.TryGetValue(ori.order.security_key());
_show_order_window(new OrderModificationDialog {
DataContext = new ExistingOrderTicketVM(_model,
Observable.Return((md, ori.order)),
Observable.Return(LadderSettings.Default.calculator_buttons)
)
});
}
switch (ori.order.order_type()) {
case CustomOrderDefinition.CustomOneofCase.Stop:
case CustomOrderDefinition.CustomOneofCase.StopLimit:
case CustomOrderDefinition.CustomOneofCase.None:
return;
}
LadderSettings _get_settings(SecurityImmutable sec) {
var settings = _settings_hub.current;
if (settings.ladder_profiles.TryGetFirst(
lsp => lsp.security_criteria.includes(sec), out var lsp)) {
return lsp.value;
}
var md = _md_map.TryGetValue(ori.order.security_key());
_show_order_window(new OrderModificationDialog {
DataContext = new ExistingOrderTicketVM(_model,
Observable.Return((md, ori.order)),
_bus.subscribe(SparkTags.AccountsTag),
Observable.Return(LadderSettings.Default.calculator_buttons),
md?.quantity_display)
});
return null;
}
}
}
+1 -2
View File
@@ -23,8 +23,7 @@ namespace mbts.ui {
[ImportingConstructor]
public RecenterDaemon(IBus bus) {
_bus = bus;
_time_to_center = TimeSpan.FromSeconds(
config.Configuration.get<bts.config.LadderKnobs>().SecondsToRecenter);
_time_to_center = TimeSpan.FromSeconds(config.Configuration.get<bts.config.LadderKnobs>().seconds_to_recenter);
_last_recenter = DateTime.UtcNow;
_dispose = _bus.subscribe(SparkTags.RequestRecenterLadder).Subscribe(_ => trigger_recenter(SparkTags.RecenterLadderNow));
+107 -113
View File
@@ -1,113 +1,107 @@
using bts.api.core;
using bts.metrics;
using mbts.config;
using mbts.ui;
using Spark.Core.Disposables;
using System;
using System.Composition;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
namespace bts.perf {
[Export, Export(typeof(IShellDaemon))]
class ShellLatencyDaemon : IShellDaemon, IDisposable {
readonly ShellLatencyService _service;
readonly string _hostname;
readonly string _version;
readonly string _username;
IDisposable _subs;
Ping _pinger = new Ping();
[ImportingConstructor]
public ShellLatencyDaemon(ShellLatencyService service, Lazy<UserTuple> user) {
_service = service;
_version = Configuration.get<bts.config.SystemConfig>().Version;
_username = user.Value.name;
_hostname = Environment.MachineName;
_forever_ping_host(_pinger);
_subs = Disposable.Create(
_pinger,
_service.subscribei_clock().Subscribe(on_tick)
);
}
void on_tick(Update<TickImmutable, int> update) {
if (update.added.Any()) {
var tick = update.added.Last();
_service.report_async(new Report() {
HostName = _hostname,
Version = _version,
User = _username,
Timestamp = tick.Timestamp
});
}
}
async void _forever_ping_host(Ping pinger) {
var config = Configuration.get<bts.config.ShellPingOptions>();
string server_ip = Configuration.get<bts.config.SystemConfig>().ConfigIp;
int delay = config.WorkloopMillisecondsInterval;
int _current_missed_ping_count = 0;
if (config.ShellPingIsEnabled && pinger != null) {
while (true) {
try {
await Task.Delay(delay);
var response = await pinger.SendPingAsync(server_ip, config.TimeoutMillisecondsThreshold);
if (response.Status == IPStatus.Success) {
_current_missed_ping_count = 0;
if (response.RoundtripTime > config.LoggingMillisecondsThreshold) {
Log.Ui.warn($"Ping response not received in a timely manner:\n" +
$"\tAddress:\t{response.Address}\n" +
$"\tRoundTrip:\t{response.RoundtripTime} ms");
}
// potentially reset delay to initial work period (no-op otherwise)
delay = config.WorkloopMillisecondsInterval;
} else {
_current_missed_ping_count++;
delay = _get_exp_delay(
_current_missed_ping_count,
config.WorkloopMillisecondsInterval,
config.MaximumBackoffMilliseconds);
Log.Ui.warn($"Ping was not successful. Ping response: {response.Status}. Missed ping count: {_current_missed_ping_count}. Backing off for {delay} milliseconds.");
}
} catch (PingException e) {
_current_missed_ping_count++;
delay = _get_exp_delay(
_current_missed_ping_count,
config.WorkloopMillisecondsInterval,
config.MaximumBackoffMilliseconds);
Log.Ui.error($"Ping exception. {e}\nBacking off for {delay} milliseconds.");
}
} // end while
}
// since we're returning milliseconds here up to a 1 minute delay
// we don't need to go crazy with the power, else we will get
// an ArgumentOutOfRangeExecption.
// Int.MaxValue = 2^31, so we need to be below that
// Also, even if we're under the 2^31 int.maxvalue, we don't want to be multed over it
// so that is why we have checked() here.
int _get_exp_delay(int retry_num, int min_interval, int max_delay) {
// add some jitter up to half the max delay so we don't
// have a ping spike from all clients at once
var jitter_amount = new Random().Next(max_delay / 2);
int power_factor = (int)Math.Pow(2, Math.Min(retry_num, 32) - 1);
try {
return Math.Min(checked(min_interval * power_factor + jitter_amount), max_delay + jitter_amount);
} catch (OverflowException) {
return max_delay + jitter_amount;
}
}
}
public void Dispose() {
Disposable.dispose(ref _subs);
}
}
}
using bts.api.core;
using bts.metrics;
using mbts.config;
using mbts.ui;
using Spark.Core.Disposables;
using System;
using System.Composition;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
namespace bts.perf {
[Export, Export(typeof(IShellDaemon))]
class ShellLatencyDaemon : IShellDaemon, IDisposable {
readonly ShellLatencyService _service;
readonly string _hostname;
readonly string _version;
readonly string _username;
IDisposable _subs;
Ping _pinger = new Ping();
[ImportingConstructor]
public ShellLatencyDaemon(ShellLatencyService service, Lazy<UserTuple> user) {
_service = service;
_version = Configuration.get<bts.config.System>().version;
_username = user.Value.name;
_hostname = Environment.MachineName;
_forever_ping_host(_pinger);
_subs = Disposable.Create(
_pinger,
_service.subscribei_clock().Subscribe(on_tick)
);
}
void on_tick(Update<TickImmutable, int> update) {
if (update.added.Any()) {
var tick = update.added.Last();
_service.report_async(new Report() {
HostName = _hostname,
Version = _version,
User = _username,
Timestamp = tick.Timestamp
});
}
}
async void _forever_ping_host(Ping pinger) {
var config = Configuration.get<bts.config.ShellPingOptions>();
string server_ip = Configuration.get<bts.config.System>().config_ip;
int delay = config.workloop_milliseconds_interval;
int _current_missed_ping_count = 0;
if (config.shell_ping_is_enabled && pinger != null) {
while (true) {
try {
await Task.Delay(delay);
var response = await pinger.SendPingAsync(server_ip, config.timeout_milliseconds_threshold);
if (response.Status == IPStatus.Success) {
_current_missed_ping_count = 0;
if (response.RoundtripTime > config.logging_milliseconds_threshold) {
Log.Ui.warn($"Ping response not received in a timely manner:\n" +
$"\tAddress:\t{response.Address}\n" +
$"\tRoundTrip:\t{response.RoundtripTime} ms");
}
// potentially reset delay to initial work period (no-op otherwise)
delay = config.workloop_milliseconds_interval;
} else {
_current_missed_ping_count++;
delay = _get_exp_delay(_current_missed_ping_count, config.workloop_milliseconds_interval, config.maximum_backoff_milliseconds);
Log.Ui.warn($"Ping was not successful. Ping response: {response.Status}. Missed ping count: {_current_missed_ping_count}. Backing off for {delay} milliseconds.");
}
} catch (PingException e) {
_current_missed_ping_count++;
delay = _get_exp_delay(_current_missed_ping_count, config.workloop_milliseconds_interval, config.maximum_backoff_milliseconds);
Log.Ui.error($"Ping exception. {e}\nBacking off for {delay} milliseconds.");
}
} // end while
}
// since we're returning milliseconds here up to a 1 minute delay
// we don't need to go crazy with the power, else we will get
// an ArgumentOutOfRangeExecption.
// Int.MaxValue = 2^31, so we need to be below that
// Also, even if we're under the 2^31 int.maxvalue, we don't want to be multed over it
// so that is why we have checked() here.
int _get_exp_delay(int retry_num, int min_interval, int max_delay) {
// add some jitter up to half the max delay so we don't
// have a ping spike from all clients at once
var jitter_amount = new Random().Next(max_delay / 2);
int power_factor = (int)Math.Pow(2, Math.Min(retry_num, 32) - 1);
try {
return Math.Min(checked(min_interval * power_factor + jitter_amount), max_delay + jitter_amount);
} catch (OverflowException) {
return max_delay + jitter_amount;
}
}
}
public void Dispose() {
Disposable.dispose(ref _subs);
}
}
}
+1 -4
View File
@@ -16,11 +16,8 @@ using System.Composition;
namespace Spark {
class ShellServices {
public ShellServices([Import("config_source")]string config_source) =>
context = new(config_source);
[Export]
public ServiceContext context { get; }
public ServiceContext context { get; } = new ServiceContext();
[Export("settings")]
public PersistenceService settings_service => context.locate<PersistenceService>("settings");
+1 -1
View File
@@ -28,7 +28,7 @@ namespace bts.shell {
}
}
bool check_version() {
string current = Configuration.get<bts.config.SystemConfig>().Version;
string current = Configuration.get<bts.config.System>().version;
if (!string.IsNullOrWhiteSpace(current) && current != "private") {
using (var key = Registry.CurrentUser.CreateSubKey(@"Software\BTS")) {
var value = key.GetValue("version");
Loaded 100 of 2003 files, more files were not shown because too many files have changed in this diff. Show more