Compare commits
276
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5b79b3dae | ||
|
|
5180d13fb0 | ||
|
|
4065b8b4c4 | ||
|
|
a28070713e | ||
|
|
83cf96d254 | ||
|
|
56b3eb60d5 | ||
|
|
c30e09a6eb | ||
|
|
be96cbb57d | ||
|
|
d26b818939 | ||
|
|
6f0e0e5172 | ||
|
|
b2d5ab5e03 | ||
|
|
c3e098e27d | ||
|
|
a930d2165a | ||
|
|
05cdfce9ce | ||
|
|
61c9d6b2d6 | ||
|
|
7545d3fd5c | ||
|
|
04e0297e86 | ||
|
|
562706b968 | ||
|
|
4195207a71 | ||
|
|
71eb89b6a1 | ||
|
|
94e4a0b725 | ||
|
|
40d1fe20e3 | ||
|
|
2ed23159ca | ||
|
|
faa8438adf | ||
|
|
0b35c2ccde | ||
|
|
98eea0ef09 | ||
|
|
4bf237aebe | ||
|
|
da927adef4 | ||
|
|
cf587e26d5 | ||
|
|
9e4354fb55 | ||
|
|
e6bb4c73a8 | ||
|
|
e43a2a4818 | ||
|
|
cde0f44b7d | ||
|
|
b07a1e2c74 | ||
|
|
8376fce5fe | ||
|
|
d9e5c846c2 | ||
|
|
65736c13ef | ||
|
|
071c28e925 | ||
|
|
8355e3e1be | ||
|
|
f9a6e0963c | ||
|
|
b2879837c6 | ||
|
|
0d03ddb009 | ||
|
|
a6dfa4ae80 | ||
|
|
e66ec82ba8 | ||
|
|
9ce5e971c6 | ||
|
|
3e7cc49ebb | ||
|
|
d07e68b6e2 | ||
|
|
619ece2313 | ||
|
|
1dda9566f3 | ||
|
|
3704d1ed16 | ||
|
|
a524ca02a5 | ||
|
|
3c97f2552b | ||
|
|
15b1d55ef1 | ||
|
|
4e42c9f01b | ||
|
|
76775f821a | ||
|
|
e7088f6b1c | ||
|
|
f2c3ff4be6 | ||
|
|
1fb42ade59 | ||
|
|
129650e9d4 | ||
|
|
170a44ac04 | ||
|
|
7e04f02327 | ||
|
|
abda2dbf97 | ||
|
|
ad1a45cf49 | ||
|
|
e9abdd0ff2 | ||
|
|
9254002318 | ||
|
|
596780b7f4 | ||
|
|
7ba061ac20 | ||
|
|
f8e6b73714 | ||
|
|
c01593d119 | ||
|
|
dd53c149c0 | ||
|
|
04b4efe1e1 | ||
|
|
81bafbe68d | ||
|
|
7ee95c55ab | ||
|
|
87d67feff4 | ||
|
|
d21ceddbb6 | ||
|
|
4434df3d09 | ||
|
|
35916881c8 | ||
|
|
5230d6bab5 | ||
|
|
68c3418c04 | ||
|
|
7bce9f8a7f | ||
|
|
a5b988738f | ||
|
|
53a4b61884 | ||
|
|
7be111dc36 | ||
|
|
0c5bd66cca | ||
|
|
b699c5a310 | ||
|
|
af8850f4c0 | ||
|
|
10e359d6b5 | ||
|
|
b360881b8b | ||
|
|
b250dc31d3 | ||
|
|
995df189ae | ||
|
|
93739e7010 | ||
|
|
bc42498d61 | ||
|
|
2b95507c49 | ||
|
|
ca8c3a18d7 | ||
|
|
e49066ffa7 | ||
|
|
e3cd910acd | ||
|
|
cb47177b8e | ||
|
|
fba00c9d51 | ||
|
|
af0b7d9146 | ||
|
|
e0a8c476f6 | ||
|
|
5acb8100de | ||
|
|
1c133e87e7 | ||
|
|
8a8419576d | ||
|
|
4a28723adb | ||
|
|
e482408f29 | ||
|
|
4dcc98ab1f | ||
|
|
ace0fc35a2 | ||
|
|
c7d1eb00dc | ||
|
|
949c8e0a32 | ||
|
|
c2419b491a | ||
|
|
786322f397 | ||
|
|
09e2a1764f | ||
|
|
a780668bce | ||
|
|
5b79aeaa14 | ||
|
|
049c006b5f | ||
|
|
6fdc344472 | ||
|
|
cb09b93553 | ||
|
|
21447d32e5 | ||
|
|
28b03e1cd2 | ||
|
|
a7acb89c15 | ||
|
|
35289710ba | ||
|
|
4677acfb39 | ||
|
|
ac05d0d69e | ||
|
|
25a9b6b433 | ||
|
|
b78713ad0d | ||
|
|
1f3d0e879c | ||
|
|
baad4dc68e | ||
|
|
ef7c0c7a30 | ||
|
|
3b3c4a2a35 | ||
|
|
ef9fc66a31 | ||
|
|
212d9c853b | ||
|
|
7815b18b6b | ||
|
|
05126074d4 | ||
|
|
3611d2c1f3 | ||
|
|
b5ad4b8104 | ||
|
|
43d7c0a2b5 | ||
|
|
12e361cec7 | ||
|
|
a4b0f026f4 | ||
|
|
59f65c32d8 | ||
|
|
ccec77f7d1 | ||
|
|
1deeb85d22 | ||
|
|
648a32147a | ||
|
|
806ddfc156 | ||
|
|
05b5f22204 | ||
|
|
4f09d2cff1 | ||
|
|
e1234fe583 | ||
|
|
aa64dacd65 | ||
|
|
10b062ebce | ||
|
|
e057057173 | ||
|
|
82cec2672a | ||
|
|
50184cd6ff | ||
|
|
e64dc49a64 | ||
|
|
010bd53723 | ||
|
|
50ae7ca7f9 | ||
|
|
995bbef878 | ||
|
|
8c325e30be | ||
|
|
6bb9b24210 | ||
|
|
df1c558c33 | ||
|
|
357d245a4c | ||
|
|
d43863ab59 | ||
|
|
89188acc7d | ||
|
|
86a9fc0c83 | ||
|
|
15579acd2a | ||
|
|
411009c996 | ||
|
|
17a4cce68b | ||
|
|
adb36795a8 | ||
|
|
691545b71a | ||
|
|
31c7fa4f2c | ||
|
|
86009c3cdb | ||
|
|
c9392dd306 | ||
|
|
ac8a6094fb | ||
|
|
6dbe497013 | ||
|
|
274aa9b17d | ||
|
|
d47e61ca57 | ||
|
|
3078b918d2 | ||
|
|
95e9a6e8aa | ||
|
|
1a3cf1dbea | ||
|
|
0d705eed1f | ||
|
|
1d28526792 | ||
|
|
3ecf3dd048 | ||
|
|
64ff79a38d | ||
|
|
aba478f3dc | ||
|
|
1025881ec8 | ||
|
|
6d95a645e3 | ||
|
|
4769f66eea | ||
|
|
82c126362d | ||
|
|
fd2ba70031 | ||
|
|
ab410c339f | ||
|
|
9093c72646 | ||
|
|
3a220b8320 | ||
|
|
ac20f7c9dd | ||
|
|
578146905e | ||
|
|
7f07f5a69b | ||
|
|
3dd7d0999e | ||
|
|
5076770d15 | ||
|
|
791446c514 | ||
|
|
66370bd541 | ||
|
|
cce8973e87 | ||
|
|
37dcd32c6b | ||
|
|
d772958272 | ||
|
|
c85e221e9f | ||
|
|
28e95df5c6 | ||
|
|
8d84355d57 | ||
|
|
5c25f9a3e5 | ||
|
|
c0980809c5 | ||
|
|
e946c6427e | ||
|
|
58ccbe2b19 | ||
|
|
7519c0b63a | ||
|
|
947c071cee | ||
|
|
54018fcce7 | ||
|
|
4b85eb33f8 | ||
|
|
592cf54e94 | ||
|
|
b8368bf9fa | ||
|
|
7d19ea84ab | ||
|
|
14651341c4 | ||
|
|
681fbc6915 | ||
|
|
37d7f51d19 | ||
|
|
48eb0a2c9b | ||
|
|
6d2cd54deb | ||
|
|
2ec956b430 | ||
|
|
4f22ae04fe | ||
|
|
7da82d8444 | ||
|
|
d8611536ee | ||
|
|
c94ffd1a56 | ||
|
|
cddf081e19 | ||
|
|
94071b4889 | ||
|
|
d7518cffe1 | ||
|
|
fa26ecaf67 | ||
|
|
c2eaf00aaa | ||
|
|
74be3ec9b9 | ||
|
|
967e3100d2 | ||
|
|
b1d1243eae | ||
|
|
72edd99cb0 | ||
|
|
a512460396 | ||
|
|
48ff593c2e | ||
|
|
d8fc99bca4 | ||
|
|
6a04759fe8 | ||
|
|
2cc07b71bd | ||
|
|
40bf117f6c | ||
|
|
20209ef429 | ||
|
|
c30a7a29fd | ||
|
|
c6ae2ea038 | ||
|
|
f95715beec | ||
|
|
0e85f4b9d5 | ||
|
|
c0bb26e56f | ||
|
|
1e3e57b990 | ||
|
|
0b50d5b5f0 | ||
|
|
9e3f16d8bc | ||
|
|
a3f194d708 | ||
|
|
bf87c46fcd | ||
|
|
222d4b266e | ||
|
|
d593eaf058 | ||
|
|
eaa6493ce1 | ||
|
|
9fd0df2a13 | ||
|
|
d272612c6c | ||
|
|
77408c8c5e | ||
|
|
09958eb333 | ||
|
|
fdb7bbdac2 | ||
|
|
a7f24e84e4 | ||
|
|
7e5c71f337 | ||
|
|
bed6feae3f | ||
|
|
d508d34a3a | ||
|
|
5904bab03e | ||
|
|
fc9519cde3 | ||
|
|
2dc823a6ac | ||
|
|
ae9366f44a | ||
|
|
db344656e5 | ||
|
|
ac31deed5b | ||
|
|
55d021ccb1 | ||
|
|
60cde0712f | ||
|
|
c20f017069 | ||
|
|
5122038d21 | ||
|
|
3039df56a0 | ||
|
|
4dc675eb9c | ||
|
|
cc8c181728 | ||
|
|
dde8524ecb |
No files matched your search
@@ -9,7 +9,7 @@
|
||||
]
|
||||
},
|
||||
"fable": {
|
||||
"version": "4.0.0-theta-018",
|
||||
"version": "4.0.6",
|
||||
"commands": [
|
||||
"fable"
|
||||
]
|
||||
@@ -27,4 +27,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-10
@@ -1,5 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(spark)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if(WIN32)
|
||||
set(platform "windows")
|
||||
@@ -19,16 +20,21 @@ 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(BUILD_SDK OFF CACHE BOOL "Build the sdk")
|
||||
set(BUILD_ADMIN_WEB_APP ON CACHE BOOL "Build the Admin WebApp")
|
||||
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()
|
||||
|
||||
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(
|
||||
@@ -41,7 +47,7 @@ if(WIN32)
|
||||
/D_WINSOCK_DEPRECATED_NO_WARNINGS \
|
||||
/D__TBB_NO_IMPLICIT_LINKAGE \
|
||||
/DBOOST_ALL_NO_LIB \
|
||||
/std:c++17 \
|
||||
/std:c++20 \
|
||||
/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")
|
||||
@@ -65,7 +71,6 @@ else()
|
||||
set(SPARK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/$<CONFIG>")
|
||||
|
||||
if(BUILD_API_SERVER)
|
||||
add_compile_definitions(SPARK_ENABLE_API_SERVER)
|
||||
add_compile_definitions(APP_DATA_DIR="\$\{HOME\}/spark_api/")
|
||||
add_compile_definitions(SHARED_MEMORY_PREFIX="spark_api")
|
||||
elseif(BUILD_SPARKD)
|
||||
@@ -80,17 +85,17 @@ else()
|
||||
# config (i.e., resolved at runtime rather than compile-time)
|
||||
add_compile_definitions(CCAPI_EXPOSE_INTERNAL)
|
||||
|
||||
# Enable ccapi exchanges/services
|
||||
# Enable ccapi services
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_FTX)
|
||||
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_BINANCE_COIN_FUTURES)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_HUOBI)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_HUOBI_USDT_SWAP)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_HUOBI_COIN_SWAP)
|
||||
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"
|
||||
@@ -112,6 +117,20 @@ else()
|
||||
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()
|
||||
|
||||
# subdirs
|
||||
|
||||
+133
-17
@@ -17,14 +17,17 @@
|
||||
"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++17 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
|
||||
"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_SHARED_LINKER_FLAGS_RELEASE": "/DEBUG /OPT:REF /OPT:ICF /LTCG",
|
||||
"EXTERNALS_ROOT": "${sourceDir}/externals/windows"
|
||||
"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"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -44,11 +47,11 @@
|
||||
"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",
|
||||
"CMAKE_CXX_STANDARD": "17",
|
||||
"BUILD_SDK": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
@@ -70,7 +73,8 @@
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"CCAPI_LOG_LEVEL": "Debug"
|
||||
"CCAPI_LOG_LEVEL": "Info",
|
||||
"CONFIG_DEFAULTS_PATH": "config/profiles/md_dev/*.conf;config/profiles/default/*.conf"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -80,7 +84,8 @@
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CCAPI_LOG_LEVEL": "Warn"
|
||||
"CCAPI_LOG_LEVEL": "Warn",
|
||||
"CONFIG_DEFAULTS_PATH": "config/profiles/md_prod/*.conf;config/profiles/default/*.conf"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -93,7 +98,7 @@
|
||||
"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++17 -fdiagnostics-color -DDEBUG",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
@@ -107,7 +112,7 @@
|
||||
"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++17 -fdiagnostics-color -Wno-stringop-overread -DDEBUG",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
@@ -121,7 +126,7 @@
|
||||
"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++17 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
@@ -135,16 +140,72 @@
|
||||
"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++17 -fdiagnostics-color -Wno-stringop-overread -Wno-maybe-uninitialized -fno-omit-frame-pointer -DNDEBUG -O3",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -156,21 +217,20 @@
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"hidden": true,
|
||||
"jobs": 4
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
{
|
||||
"name": "spark-dev",
|
||||
"displayName": "Development",
|
||||
"name": "spark-debug",
|
||||
"displayName": "Debug",
|
||||
"inherits": "spark",
|
||||
"configurePreset": "spark",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "spark-prod",
|
||||
"displayName": "Production",
|
||||
"name": "spark-release",
|
||||
"displayName": "Release",
|
||||
"inherits": "spark",
|
||||
"configurePreset": "spark",
|
||||
"configuration": "Release"
|
||||
@@ -184,7 +244,6 @@
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"hidden": true,
|
||||
"jobs": 4,
|
||||
"targets": [
|
||||
"data_files_dir",
|
||||
"admin_web_app_bundle",
|
||||
@@ -224,12 +283,69 @@
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
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()
|
||||
@@ -1,12 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# add protos to the library to facilitate source_group
|
||||
target_sources(libspark PUBLIC ${Config_Protos} ${NonConfig_Protos} ${Service_Protos})
|
||||
|
||||
# Explicitly set policy to convert relative paths to absolute (although this is a default policy,
|
||||
# setting it explicitly prevents a compile-warning)
|
||||
cmake_policy(SET CMP0076 NEW)
|
||||
|
||||
# add protos to the library to facilitate source_group
|
||||
target_sources(libspark PUBLIC ${Config_Protos} ${NonConfig_Protos} ${Service_Protos})
|
||||
|
||||
function(assign_source_group)
|
||||
foreach(_source IN ITEMS ${ARGN})
|
||||
if(IS_ABSOLUTE "${_source}")
|
||||
+188
-41
@@ -1,8 +1,15 @@
|
||||
[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**
|
||||
@@ -30,47 +37,187 @@
|
||||
* *The **Clang** presets may work best with the **Clangd** extension*
|
||||
* *Intellisense won't work for generated files/types until you build libspark*
|
||||
|
||||
# Build Sparkd on Linux
|
||||
# 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)
|
||||
|
||||
**Notes**
|
||||
* Sparkd is built using **[CMakePresets][cmake presets]**
|
||||
### 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*
|
||||
|
||||
**Steps**
|
||||
1. Set up the **[Python virtual environment][py venv]**<br>
|
||||
* *Run commands from the repo root dir unless otherwise noted*
|
||||
1. Create the virtual environment
|
||||
```
|
||||
python3 -m venv .venv
|
||||
```
|
||||
2. Activate the virtual environment
|
||||
```
|
||||
. .venv/bin/activate
|
||||
```
|
||||
3. Verify `python` in the venv is first in the path<br>
|
||||
* ***Expected:** output shows the absolute path to `.venv/bin/python`*
|
||||
```
|
||||
which python
|
||||
```
|
||||
4. Update `pip`<br>
|
||||
* *The venv module initializes virtual environments with its own version
|
||||
of pip, rather than the system's version. Even if the latter is up-to-date, the
|
||||
former may not be.*
|
||||
```
|
||||
python -m pip install --upgrade pip
|
||||
```
|
||||
5. Install the packages listed `requirements.txt`
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
2. Build **Sparkd**<br>
|
||||
* From the terminal
|
||||
```
|
||||
tools/build_sparkd.sh
|
||||
```
|
||||
* *Run with `--help` to see available options*
|
||||
* From VS Code
|
||||
1. Install the **[CMake extension][cmake ext]**
|
||||
2. In the VS Code Command Palette, run **CMake: Select Configure
|
||||
Preset**, then select the **[preset][cmake presets]** you wish to
|
||||
build from the dropdown
|
||||
3. Run **CMake: Build** in the command palette.
|
||||
```
|
||||
# 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
|
||||
```
|
||||
@@ -116,4 +116,8 @@ if ! shopt -oq posix; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -v XDG_CONFIG_HOME ]]; then
|
||||
export XDG_CONFIG_HOME="$HOME/.config"
|
||||
fi
|
||||
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
@@ -1,3 +1,6 @@
|
||||
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"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{
|
||||
"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",
|
||||
@@ -11,6 +15,8 @@
|
||||
// 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",
|
||||
|
||||
+1
-1
Submodule externals updated: 4aaae5b1eb...9a41237fc0.
+5
-1
@@ -1,7 +1,9 @@
|
||||
astroid==2.7.3
|
||||
autopep8==1.5.7
|
||||
cffi==1.14.6
|
||||
certifi==2023.5.7
|
||||
charset-normalizer==3.1.0
|
||||
colorama==0.4.4
|
||||
idna==3.4
|
||||
isort==5.9.3
|
||||
lazy-object-proxy==1.6.0
|
||||
mccabe==0.6.1
|
||||
@@ -12,7 +14,9 @@ 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
|
||||
@@ -793,7 +793,10 @@ let venueToString (venue:bts.api.Venue) =
|
||||
| bts.api.Venue.GLBX -> "GLBX"
|
||||
| bts.api.Venue.DERIBIT -> "DERIBIT"
|
||||
| bts.api.Venue.ICE -> "ICE"
|
||||
// | bts.api.Venue.DERIBIT -> "DERIBIT"
|
||||
| bts.api.Venue.BINANCE -> "BINANCE"
|
||||
| bts.api.Venue.BinanceUs -> "BinanceUs"
|
||||
| bts.api.Venue.BinanceUsdsFutures -> "BinanceUsdsFutures"
|
||||
| bts.api.Venue.FTX -> "FTX"
|
||||
|
||||
let exchange_display expirationNameList =
|
||||
let s = sprintf "%O" expirationNameList.product.exchange
|
||||
|
||||
@@ -60,23 +60,30 @@
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<!--
|
||||
Each .proto 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
|
||||
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:
|
||||
<Proto3 Include="foo_bar.proto" CSName="FooBar" />
|
||||
<ProtoService Include="foo_bar.proto" CSName="FooBar" />
|
||||
-->
|
||||
<Proto3>
|
||||
<Proto>
|
||||
<OutDir>$(ProtoOutputPath)/</OutDir>
|
||||
<CSName>%(FileName)</CSName>
|
||||
</Proto3>
|
||||
</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>
|
||||
@@ -6,39 +6,76 @@
|
||||
passes wipes out the additional compile includes that we add.
|
||||
-->
|
||||
<Target
|
||||
Name="CompileProto3"
|
||||
Name="CompileProtos"
|
||||
AfterTargets="GetAssemblyVersion"
|
||||
Condition="'@(Proto3)'!=''"
|
||||
Condition="'@(Proto)'!=''"
|
||||
Inputs="$(protoc);
|
||||
%(Proto3.Identity);$(ProtocPluginBase)/plugin.py;
|
||||
%(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="protoc-gen-spark-csharp=$(ProtocPlugin)"</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="
|
||||
%(Proto3.OutDir)/%(Proto3.CSName).cs;
|
||||
%(Proto3.OutDir)/%(Proto3.FileName).client.pb.cs;
|
||||
%(Proto3.OutDir)/%(Proto3.FileName).server.pb.cs;
|
||||
%(Proto3.OutDir)/%(Proto3.FileName).immutable.pb.cs">
|
||||
<MakeDir Directories="%(Proto3.OutDir)" />
|
||||
%(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 service %(Proto3.FileName)" />
|
||||
Text="Generating ProtoService %(ProtoService.FileName)" />
|
||||
|
||||
<PropertyGroup>
|
||||
<GenProtosCmd>$(protoc) %(Proto3.FullPath)</GenProtosCmd>
|
||||
<GenProtosCmd>$(protoc) %(ProtoService.FullPath)</GenProtosCmd>
|
||||
<GenProtosCmd>$(GenProtosCmd) --error_format=msvs</GenProtosCmd>
|
||||
<GenProtosCmd>$(GenProtosCmd) --proto_path=$(SourceRoot)</GenProtosCmd>
|
||||
<GenProtosCmd>$(GenProtosCmd) --plugin="protoc-gen-service=$(ProtocPlugin)"</GenProtosCmd>
|
||||
<GenProtosCmd>$(GenProtosCmd) --service_out=lang=c#,strip_out_path=1:%(Proto3.OutDir)</GenProtosCmd>
|
||||
<GenProtosCmd>$(GenProtosCmd) --csharp_out=%(Proto3.OutDir)</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="%(Proto3.RelativeDir)" />
|
||||
<Exec Command="$(GenProtosCmd)" WorkingDirectory="%(ProtoService.RelativeDir)" />
|
||||
<ItemGroup>
|
||||
<Compile Include="%(Proto3.OutDir)/%(Proto3.CSName).cs" />
|
||||
<Compile Include="%(Proto3.OutDir)/%(Proto3.FileName).client.pb.cs" />
|
||||
<Compile Include="%(Proto3.OutDir)/%(Proto3.FileName).server.pb.cs" />
|
||||
<Compile Include="%(Proto3.OutDir)/%(Proto3.FileName).immutable.pb.cs" />
|
||||
<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>
|
||||
|
||||
@@ -53,12 +90,17 @@
|
||||
</Target>
|
||||
|
||||
<Target
|
||||
Name="AfterClean"
|
||||
Name="CleanProtos"
|
||||
AfterTargets="Clean">
|
||||
<Delete Files="%(Proto3.OutDir)/%(Proto3.CSName).cs" />
|
||||
<Delete Files="%(Proto3.OutDir)/%(Proto3.FileName).client.pb.cs" />
|
||||
<Delete Files="%(Proto3.OutDir)/%(Proto3.FileName).server.pb.cs" />
|
||||
<Delete Files="%(Proto3.OutDir)/%(Proto3.FileName).immutable.pb.cs" />
|
||||
<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
|
||||
|
||||
@@ -8,10 +8,7 @@ namespace Spark.Console {
|
||||
|
||||
class ConfigCommand {
|
||||
public static int run(ConfigCommandOptions opts) {
|
||||
if (opts.sparkd is not null) {
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
BTS.set_config_arg(args, opts.sparkd);
|
||||
}
|
||||
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(
|
||||
|
||||
@@ -19,7 +19,9 @@ namespace Spark.Console {
|
||||
if (o.type == TestType.Unit) {
|
||||
// Skip loading any local config
|
||||
Configuration.initialize_for_test();
|
||||
} else Configuration.initialize();
|
||||
} else {
|
||||
Configuration.initialize(o.sparkd);
|
||||
}
|
||||
|
||||
ConsoleEx.WriteLine(JsonConvert.SerializeObject(o), ConsoleColor.DarkGray);
|
||||
|
||||
|
||||
@@ -21,5 +21,8 @@ namespace Spark.Console {
|
||||
|
||||
[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; }
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ namespace Spark.Console {
|
||||
var security = new Security {
|
||||
Symbol = "ES",
|
||||
Exchange = Venue.Bts,
|
||||
Currency = Currency.Usd,
|
||||
Currency = "USD",
|
||||
Synthetic = new SyntheticContract {
|
||||
Name = "Synthetic1",
|
||||
PriceCalc = SyntheticContract.Types.PriceCalc.Standard,
|
||||
|
||||
@@ -3,7 +3,6 @@ namespace mbts.spark {
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
using bts.collections;
|
||||
using bts.reactive;
|
||||
using bts.utils;
|
||||
|
||||
using mbts;
|
||||
@@ -18,6 +17,7 @@ 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.Stock);
|
||||
driver_exp.security_tuple.security_type == SecurityType.Spot);
|
||||
}
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -63,9 +63,9 @@ namespace mbts.spark {
|
||||
vs_input, vs_nonvol_data.contracts, aux_data_map);
|
||||
_timer.stop();
|
||||
var tag_str = tag == null ? "Null" : tag.ToString();
|
||||
bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
|
||||
$"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
|
||||
$"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
|
||||
// bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
|
||||
// $"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
|
||||
// $"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
|
||||
_logger.log(_log_id, _log_id, _timer.lastIntervalTime);
|
||||
_bb.post(_out_bb_computed_vol_tag, vs_output);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using bts.api.analytics;
|
||||
|
||||
using mbts.analytics;
|
||||
using mbts.ui;
|
||||
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
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
|
||||
@@ -24,7 +26,6 @@
|
||||
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>();
|
||||
@@ -35,10 +36,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)
|
||||
@@ -54,8 +55,10 @@
|
||||
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(String.Format("SingleVolSurfaceGateway._on_vss count:{0} vs_count:{1}",
|
||||
all_vss.Count(), this_vs_vss.Count()));
|
||||
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()}");
|
||||
if (this_vs_vss.Count() == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -83,22 +86,39 @@
|
||||
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);
|
||||
vs_input.saver_login = _user;
|
||||
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, _user);
|
||||
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, current_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)
|
||||
if (archived_theos != null) {
|
||||
_timer.start();
|
||||
_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,7 +36,11 @@ 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(_vs_id, a_syms, _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)),
|
||||
new SingleVolSurfaceMarketImpliedVolSource(_vs_id, _bb),
|
||||
// new SingleVolSurfaceTheoSource(_vs_id, _bb),
|
||||
// TODO: suspending heatmaps for now (12/24/21)
|
||||
@@ -44,6 +48,7 @@ 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),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace mbts.spark {
|
||||
var exp_price_map = OptionDriverPriceMap.get_vs_price_map(
|
||||
all_sym_price_map, (s) => _option_symbols.Contains(s));
|
||||
if (sc_data != null && vs_nonvol_input != null && exp_price_map != null) {
|
||||
bts.Log.Gen.info($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
|
||||
bts.Log.Gen.diag($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
|
||||
"publishing VolSurfaceNonVolData");
|
||||
_bb.post(_out_bb_vs_nonvol_data_tag,
|
||||
new VolSurfaceNonVolData(
|
||||
|
||||
@@ -18,10 +18,16 @@ 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;
|
||||
@@ -30,18 +36,22 @@ namespace mbts.spark {
|
||||
/// data
|
||||
private VolSurfaceOutput _last_output;
|
||||
|
||||
public SingleVolSurfaceRequestCalculator(int vs_id, IEnumerable<string> symbols,
|
||||
public SingleVolSurfaceRequestCalculator(RequestType request_type,
|
||||
int vs_id, IEnumerable<string> symbols,
|
||||
ThreadedBlackboard threaded_bb) {
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id}");
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id} request_type: {request_type}");
|
||||
_request_type = request_type;
|
||||
_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);
|
||||
@@ -51,11 +61,21 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
private void _on_bb_data(object tag, object data) {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _recompute_and_publish(bool is_new_request) {
|
||||
@@ -80,7 +100,7 @@ namespace mbts.spark {
|
||||
nonvol_data.driver_price_map,
|
||||
vs_standard_time, true);
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
|
||||
_post_process_action(effective_req, aux_data_map);
|
||||
_post_process_action(_bb, _vs_id, effective_req, aux_data_map);
|
||||
_last_output = GeneralVolSurfaceCalculator.compute(effective_req.volsurface_input,
|
||||
nonvol_data.contracts,
|
||||
aux_data_map,
|
||||
@@ -89,16 +109,49 @@ namespace mbts.spark {
|
||||
effective_req.cascade_up,
|
||||
effective_req.cascade_down);
|
||||
_timer.stop();
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time: " +
|
||||
$"{_timer.lastIntervalTime}");
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish vs_id: {_vs_id} " +
|
||||
$"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 IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
|
||||
private static IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
|
||||
ThreadedBlackboard bb, int vs_id,
|
||||
VolSurfaceCalculationRequest req,
|
||||
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map) {
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> rv = req.action_map;
|
||||
@@ -109,7 +162,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(req.volsurface_input, req.action_map, aux_data_map,
|
||||
_fill_in_implied_vols(bb, vs_id, 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,
|
||||
@@ -119,7 +172,8 @@ namespace mbts.spark {
|
||||
return rv;
|
||||
}
|
||||
|
||||
private IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
|
||||
private static IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
|
||||
ThreadedBlackboard bb, int vs_id,
|
||||
VolSurfaceInput vs_inp,
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map,
|
||||
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map,
|
||||
@@ -140,15 +194,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) {
|
||||
VolSurfaceUsageListImmutable vs_usage_list = bb.read_state(SparkTags.VolSurfaceUsageTag);
|
||||
return vs_usage_list.get_sectups(vs_id);
|
||||
var vs_usage_list = bb.read_state(SparkTags.VolSurfaceUsageTag);
|
||||
return (vs_usage_list?.get_sectups(vs_id)).empty_if_null();
|
||||
}
|
||||
|
||||
|
||||
@@ -242,4 +242,4 @@ namespace mbts.spark {
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ namespace mbts.analytics {
|
||||
output.Add(symbol, symbol_data);
|
||||
}
|
||||
IReadOnlyDictionary<string, TData> ro_output = output;
|
||||
bts.Log.Gen.info($"SymbolAggregationPublisher._on_timer publishing " +
|
||||
bts.Log.Gen.diag($"SymbolAggregationPublisher._on_timer publishing " +
|
||||
$"tag: {_out_tag} sz: {ro_output.Count}");
|
||||
_bb.post(_out_tag, ro_output);
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@ 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,6 +5,7 @@ using bts.api;
|
||||
using bts.collections;
|
||||
using System.Linq;
|
||||
using bts.api.orderman;
|
||||
using bts.api.analytics;
|
||||
using bts;
|
||||
|
||||
namespace mbts.spark {
|
||||
@@ -23,6 +24,8 @@ 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;
|
||||
}
|
||||
|
||||
@@ -55,6 +58,27 @@ 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 =
|
||||
@@ -64,6 +88,11 @@ 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
|
||||
@@ -86,6 +115,7 @@ 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();
|
||||
@@ -96,7 +126,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 " +
|
||||
bts.Log.Gen.info($"InterpTheosServerPublisher._publish_data symbols: {all_theos.Count} " +
|
||||
$"size: {server_theos.Theos.Count} comp_time: {comp_time} msecs " +
|
||||
$"pub_time: {pub_time}");
|
||||
}
|
||||
@@ -105,4 +135,4 @@ namespace mbts.spark {
|
||||
_bb.data_callback -= _on_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace mbts.spark {
|
||||
}
|
||||
);
|
||||
foreach (var sec_md in exp_secs) {
|
||||
rv.Add(sec_md.security.Id, kv.Value);
|
||||
rv[sec_md.security.Id] = kv.Value;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
|
||||
@@ -26,12 +26,13 @@ namespace mbts.spark {
|
||||
_refresh = new(_is_dirty.refresh);
|
||||
_committed_value.Changed += on_committed_changed;
|
||||
_candidate_value.Changed += on_candidate_changed;
|
||||
_is_dirty.Changed += (o, n) => {
|
||||
Log.assert(o != n);
|
||||
Log.Ui.info(
|
||||
$"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
|
||||
$"commited: {committed_value}; candidate: {candidate_value}");
|
||||
};
|
||||
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}");
|
||||
};
|
||||
}
|
||||
|
||||
void on_committed_changed(object? oldval, object? newval) =>
|
||||
_is_dirty.refresh();
|
||||
|
||||
@@ -29,6 +29,7 @@ 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;
|
||||
@@ -41,10 +42,12 @@ namespace mbts.spark.VolSurface {
|
||||
VolSurfaceVM vm,
|
||||
VolSurfaceDisplayModel model,
|
||||
ISet<string> hidden_columns,
|
||||
ISet<VolSurfaceExpiration> hidden_expirations) {
|
||||
ISet<VolSurfaceExpiration> hidden_expirations,
|
||||
UserTuple user) {
|
||||
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;
|
||||
@@ -83,7 +86,7 @@ namespace mbts.spark.VolSurface {
|
||||
_columns_model);
|
||||
|
||||
VolSurfaceRowVM row_factory(VolSurfaceDisplayGridExpiration exp) =>
|
||||
new(this, exp);
|
||||
new(this, exp, _user);
|
||||
|
||||
IDisposable connect_row(VolSurfaceRowVM row) {
|
||||
row.request_calculate += request_recalc;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using mbts.spark.VolSurface;
|
||||
@@ -23,6 +24,10 @@ 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;
|
||||
@@ -35,21 +40,29 @@ 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) {
|
||||
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row, UserTuple user) {
|
||||
_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);
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
_resources.AddRange(
|
||||
_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(
|
||||
@@ -165,6 +178,34 @@ 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,5 +1,7 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark.VolSurface {
|
||||
using bts;
|
||||
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
@@ -16,14 +18,16 @@ 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) {
|
||||
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp, UserTuple user) {
|
||||
_parent = parent;
|
||||
_exp = exp;
|
||||
_user = user;
|
||||
_request_calculate = new(() => request_calculate?.Invoke());
|
||||
_dispose = Disposable.Create(() => {
|
||||
_cells.Values.DisposeAll();
|
||||
@@ -49,7 +53,7 @@ namespace mbts.spark.VolSurface {
|
||||
}
|
||||
|
||||
public VolSurfaceRowContextMenuVM context_menu =>
|
||||
_context_menu ??= new(_parent, this);
|
||||
_context_menu ??= new(_parent, this, _user);
|
||||
|
||||
public VolSurfaceCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
|
||||
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#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,6 +40,7 @@ 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);
|
||||
@@ -105,6 +106,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -233,23 +235,7 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
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 VolSurfaceAutoFitSettingsVM auto_fit_vm { get; } = new();
|
||||
|
||||
public bool auto_decay_vol_time {
|
||||
get => _core_settings.time_settings.time_mode == VolSurfaceEnums.VolSurfaceTimeMode.AutoDecay;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.collections;
|
||||
|
||||
@@ -27,6 +28,7 @@ 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;
|
||||
@@ -38,10 +40,16 @@ namespace mbts.spark {
|
||||
bool _ignore_implied_vol_settings;
|
||||
|
||||
public VolSurfaceVM(
|
||||
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
|
||||
VolSurfaceDisplayModel model,
|
||||
int id,
|
||||
IBus bus,
|
||||
VolSurfaceWindowSettings startup_data,
|
||||
UserTuple user
|
||||
) {
|
||||
_model = model;
|
||||
_vs_id = id;
|
||||
_bus = bus;
|
||||
_user = user;
|
||||
macro_actions = new VolSurfaceMacroActionsVM(_model);
|
||||
globals = new VolSurfaceGlobalParameterVM(_model);
|
||||
|
||||
@@ -49,7 +57,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);
|
||||
this, _model, _grid_settings.hidden_cols(), hidden_exps_set, _user);
|
||||
grid.on_selection_changed += _on_grid_selection_changed;
|
||||
_model.publish_grid_settings(_grid_settings);
|
||||
|
||||
|
||||
@@ -162,7 +162,8 @@ namespace mbts.spark {
|
||||
api_sec_exp.Exchange.to_venue(),
|
||||
api_sec_exp.SecurityType.contract_case(),
|
||||
api_sec_exp.Symbol,
|
||||
api_sec_exp.Expiration.date_time());
|
||||
api_sec_exp.HasExpiration ?
|
||||
api_sec_exp.Expiration.date_time() : SecurityExpiration.empty.expiration);
|
||||
|
||||
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 VolSurfaceUsageListImmutable(new VolSurfaceUsageList()));
|
||||
_vs_usage_map = _bb.read_state(_in_bb_vs_usage_tag) ??
|
||||
new VolSurfaceUsageList().immutable();
|
||||
bts.Log.Gen.info($"VolSurfaceInterpGreeksMultiplexer._analyze_usages " +
|
||||
$"count: {_vs_usage_map.UsageList.Count()}");
|
||||
foreach (int vs_id in _vs_usage_map.vss()) {
|
||||
|
||||
@@ -56,7 +56,12 @@ namespace mbts.spark {
|
||||
new SecurityAlgoTypeSetImmutable(
|
||||
new SecurityCriteriaClause(
|
||||
exchanges: new[] { Venue.Glbx },
|
||||
security_types: new[] { SecurityType.Future, SecurityType.Spread, SecurityType.Option }),
|
||||
security_types: new[] {
|
||||
SecurityType.Spot,
|
||||
SecurityType.Future,
|
||||
SecurityType.Spread,
|
||||
SecurityType.Option
|
||||
}),
|
||||
new AlgoTypeSetImmutable(
|
||||
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader }),
|
||||
full_algo_set.dynamic_types)),
|
||||
@@ -64,7 +69,12 @@ namespace mbts.spark {
|
||||
new SecurityAlgoTypeSetImmutable(
|
||||
new SecurityCriteriaClause(
|
||||
exchanges: EnumHelper.get_values_except(Venue.Glbx, Venue.Unset).ToArray(),
|
||||
security_types: new[] { SecurityType.Future, SecurityType.Spread, SecurityType.Option }),
|
||||
security_types: new[] {
|
||||
SecurityType.Spot,
|
||||
SecurityType.Future,
|
||||
SecurityType.Spread,
|
||||
SecurityType.Option
|
||||
}),
|
||||
new AlgoTypeSetImmutable(
|
||||
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader, AlgoType.GlbxIceberg }),
|
||||
full_algo_set.dynamic_types)),
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace mbts {
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.spark;
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
|
||||
@@ -25,6 +26,9 @@ 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;
|
||||
@@ -127,13 +131,14 @@ namespace mbts {
|
||||
public bool Equals(SecurityExpiration? other) =>
|
||||
other is not null &&
|
||||
security_tuple.safe_equals(other.security_tuple) &&
|
||||
expiration == other.expiration;
|
||||
expiration == other.expiration &&
|
||||
id == other.id;
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
Equals(obj as SecurityExpiration);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(security_tuple, expiration);
|
||||
HashCode.Combine(security_tuple, expiration, id ?? 0);
|
||||
|
||||
object ICloneable.Clone() =>
|
||||
Clone();
|
||||
@@ -157,7 +162,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,13 +4,11 @@ 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)]
|
||||
@@ -87,5 +85,7 @@ namespace mbts.analytics
|
||||
get => _time_settings ??= new();
|
||||
set => _time_settings = value;
|
||||
}
|
||||
[ProtoBuf.ProtoMember(240)]
|
||||
public string vs_manager { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ 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,6 +141,7 @@ namespace mbts.analytics
|
||||
|
||||
public enum VolCurveFitRegion
|
||||
{
|
||||
None,
|
||||
ATM,
|
||||
All
|
||||
}
|
||||
@@ -230,4 +231,4 @@ namespace mbts.analytics
|
||||
USE_CALENDAR_FOR_BUSINESS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,9 @@ 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;
|
||||
@@ -22,19 +20,44 @@ 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;
|
||||
/// 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;
|
||||
|
||||
[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;
|
||||
}
|
||||
}
|
||||
@@ -475,6 +475,7 @@ 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);
|
||||
@@ -595,7 +596,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 {
|
||||
|
||||
@@ -88,8 +88,8 @@ namespace mbts.analytics {
|
||||
|
||||
public void set_driver_price(
|
||||
IDictionary<VolSurfaceExpiration, double> driver_price_map) {
|
||||
Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_driver_price " +
|
||||
$"vs_id: {_vs_id} exp_count: {driver_price_map.Count}");
|
||||
// Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_driver_price " +
|
||||
// $"vs_id: {_vs_id} exp_count: {driver_price_map.Count}");
|
||||
_driver_price_map = new Dictionary<VolSurfaceExpiration, double>(driver_price_map);
|
||||
_compute_and_fire(InputType.DriverPrice);
|
||||
}
|
||||
|
||||
@@ -50,9 +50,7 @@ namespace mbts.analytics {
|
||||
deliverable_security ??= SecurityExpiration.empty;
|
||||
roll_schedule_expiration ??= SecurityExpiration.empty;
|
||||
|
||||
this.driver = driver ?? new(new() {
|
||||
TimeWeightedInterpolated = new()
|
||||
});
|
||||
this.driver = driver ?? _default_driver;
|
||||
_deliverable = deliverable_security.to_api_sec_expi();
|
||||
_roll_schedule = roll_schedule_expiration.to_api_sec_expi();
|
||||
this.roll_target = roll_target;
|
||||
@@ -63,10 +61,10 @@ namespace mbts.analytics {
|
||||
}
|
||||
|
||||
public AnalyticsExpirationParameters(ExpirationParameterEntryImmutable db_i) {
|
||||
_security = db_i.SecurityExpiration;
|
||||
_deliverable = db_i.Deliverable;
|
||||
_roll_schedule = db_i.RollSchedule;
|
||||
driver = db_i.Driver;
|
||||
_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;
|
||||
roll_target = db_i.RollTarget;
|
||||
riskless_rate = db_i.RisklessRate;
|
||||
settlement_price = db_i.SettlementPrice;
|
||||
@@ -74,6 +72,12 @@ 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;
|
||||
|
||||
@@ -5,9 +5,10 @@ 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;
|
||||
@@ -21,7 +22,7 @@ namespace mbts.ui.shell {
|
||||
static readonly Mutex _mutex;
|
||||
|
||||
ShellBootstrapper _runtime;
|
||||
CLIOptions _opts;
|
||||
SparkCmdOpts _opts;
|
||||
Process _stunnel_process;
|
||||
|
||||
static App() {
|
||||
@@ -43,25 +44,13 @@ namespace mbts.ui.shell {
|
||||
#endif
|
||||
|
||||
public new int Run() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
var argv = SparkCmdOpts.conform_opts(Environment.GetCommandLineArgs());
|
||||
|
||||
int exit_code = 1;
|
||||
Parser.Default.ParseArguments<CLIOptions>(argv).WithParsed(opts => {
|
||||
Parser.Default.ParseArguments<SparkCmdOpts>(argv).WithParsed(opts => {
|
||||
_opts = opts;
|
||||
var opt_desc = TableFormatter.fmt_table(
|
||||
typeof(CLIOptions).GetProperties()
|
||||
typeof(SparkCmdOpts).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 {
|
||||
@@ -94,7 +83,8 @@ namespace mbts.ui.shell {
|
||||
CultureInfo.DefaultThreadCurrentUICulture = us_culture;
|
||||
|
||||
base.OnStartup(e);
|
||||
_runtime = new ShellBootstrapper(_opts?.user, _opts?.password, _opts?.restore_workspace);
|
||||
_runtime = new ShellBootstrapper(
|
||||
_opts?.user, _opts?.password, _opts?.sparkd, _opts?.restore_workspace);
|
||||
_runtime.Run();
|
||||
|
||||
// Select text on tab in
|
||||
@@ -159,34 +149,5 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ namespace bts {
|
||||
rv.ContractSpec.CashPerPoint = 50;
|
||||
rv.ContractSpec.PriceMultiplier = 1.0;
|
||||
// Currency
|
||||
rv.Currency = Currency.Usd;
|
||||
rv.Currency = "USD";
|
||||
}
|
||||
|
||||
public static void fill_security_future(ref Security rv, DateTime exp) {
|
||||
|
||||
@@ -136,7 +136,10 @@ namespace bts {
|
||||
var meta = _security_metadata.get(smd.security);
|
||||
if (meta.HasValue) {
|
||||
exch_secs[smd.id] = new(
|
||||
smd.security, smd.md, meta.Value.PriceDisplay, meta.Value.QuantityDisplay);
|
||||
smd.security,
|
||||
smd.md,
|
||||
meta.Value.HasPriceDisplay ? meta.Value.PriceDisplay : null,
|
||||
meta.Value.HasQuantityDisplay ? meta.Value.QuantityDisplay : null);
|
||||
}
|
||||
}
|
||||
_bus.post(SparkTags.ServerSecuritiesTag, exch_secs);
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace bts {
|
||||
}
|
||||
|
||||
private void _on_server_sec_map(IReadOnlyDictionary<uint, SecurityMD> sec_map) {
|
||||
_log_options(sec_map);
|
||||
//_log_options(sec_map);
|
||||
bts.Log.Gen.info(String.Format("MergedMDDaemon._on_server_sec_map sz: {0}", sec_map.Count()));
|
||||
_server_sec_map = new Dictionary<uint, SecurityMD>(sec_map);
|
||||
_merge_and_post();
|
||||
|
||||
@@ -16,8 +16,11 @@ using System.Composition;
|
||||
|
||||
namespace Spark {
|
||||
class ShellServices {
|
||||
public ShellServices([Import("config_source")]string config_source) =>
|
||||
context = new(config_source);
|
||||
|
||||
[Export]
|
||||
public ServiceContext context { get; } = new ServiceContext();
|
||||
public ServiceContext context { get; }
|
||||
|
||||
[Export("settings")]
|
||||
public PersistenceService settings_service => context.locate<PersistenceService>("settings");
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace mbts.spark {
|
||||
r => new ReportImmutable?(r),
|
||||
r => r?.Id ?? throw new ArgumentNullException(nameof(r)));
|
||||
_window_factories = new() {
|
||||
new VolSurfaceWindowFactory(this, bus),
|
||||
new VolSurfaceWindowFactory(this, bus, user.Value),
|
||||
new AnalyticsExpirationParametersWindowFactory(this, bus),
|
||||
new SlideReportWindowFactory(this, bus, reports_demuxer.subscribe),
|
||||
new ComboReportWindowFactory(this, bus, reports_demuxer.subscribe),
|
||||
|
||||
@@ -793,70 +793,106 @@
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="4"
|
||||
DataContext="{Binding auto_fit_vm}"
|
||||
Header="Auto Fit"
|
||||
Margin="0,5,0,0"
|
||||
Padding="5"
|
||||
IsEnabled="False">
|
||||
Padding="5">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox
|
||||
Grid.ColumnSpan="2" Content="Enabled" IsChecked="{Binding enable_auto_fit}" />
|
||||
|
||||
<TextBlock Grid.Row="1" Text="Region" Margin="16,5,0,0">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<DataTrigger
|
||||
Binding="{Binding enable_auto_fit}"
|
||||
Value="False">
|
||||
<Setter
|
||||
Property="Foreground"
|
||||
Value="Gray" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Fit Region" />
|
||||
<ComboBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding fit_regions}"
|
||||
SelectedItem="{Binding fit_region}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={x:Static shell:VolSurfaceSettingsEditor.AutoFitRegionDisplayTextConverter}}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,5,0,0"
|
||||
Text="Every" />
|
||||
<c:TickUpDownNullableUInt32
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="12,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding auto_fit_region_choices}"
|
||||
SelectedValue="{Binding auto_fit_region}"
|
||||
IsEnabled="{Binding enable_auto_fit}" />
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Minimum="30"
|
||||
Margin="8,0,0,0"
|
||||
Width="60"
|
||||
Value="{Binding period_secs}"
|
||||
IsEnabled="{Binding is_auto_fit_enabled}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="3,5,0,0"
|
||||
Text="secs" />
|
||||
|
||||
<TextBlock Grid.Row="2" Text="Fit Time" Margin="16,5,0,0">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding enable_auto_fit}" Value="False">
|
||||
<Setter Property="Foreground" Value="Gray" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<c:TextBoxDouble
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="0,5,0,0"
|
||||
Text="When Driver moves" />
|
||||
<c:TickUpDownNullableDouble
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
c:TextBoxEx.Suffix="ms"
|
||||
ToolTipService.ShowOnDisabled="True"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Margin="8,0,0,0"
|
||||
Width="60"
|
||||
Margin="12,5,0,0"
|
||||
IsEnabled="{Binding enable_auto_fit}"
|
||||
Value="{Binding auto_fit_time_ms}"
|
||||
Template="{StaticResource SuffixTemplate}" />
|
||||
Value="{Binding driver_points_moved}"
|
||||
Increment="0.01"
|
||||
TickDisplaySettings="{Binding driver_points_display}"
|
||||
IsEnabled="False"
|
||||
ToolTip="Not yet supported (coming soon)" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="3,5,0,0"
|
||||
Text="%" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Margin="0,5,0,0"
|
||||
Text="When ATM moves" />
|
||||
<c:TickUpDownNullableDouble
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
ToolTipService.ShowOnDisabled="True"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="8,0,0,0"
|
||||
Width="60"
|
||||
Value="{Binding atm_points_moved}"
|
||||
Increment="0.01"
|
||||
TickDisplaySettings="{Binding atm_points_display}"
|
||||
IsEnabled="False"
|
||||
ToolTip="Not yet supported (coming soon)" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="3,5,0,0"
|
||||
Text="%" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
#nullable enable
|
||||
namespace mbts.ui.shell {
|
||||
using mbts.analytics;
|
||||
using mbts.ui.converters;
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
partial class VolSurfaceSettingsEditor : Window {
|
||||
public VolSurfaceSettingsEditor() =>
|
||||
InitializeComponent();
|
||||
|
||||
public static IValueConverter AutoFitRegionDisplayTextConverter =>
|
||||
ValueConverter.create<VolSurfaceEnums.VolCurveFitRegion, string>(fr =>
|
||||
fr switch {
|
||||
VolSurfaceEnums.VolCurveFitRegion.None => "Disabled",
|
||||
_ => fr.ToString()
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -262,7 +262,7 @@
|
||||
IsDragAdornerEnabled="False"
|
||||
ContextMenuOpening="_on_context_menu_opening">
|
||||
<c:DIYGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<ContextMenu IsOpen="{Binding is_open}">
|
||||
<MenuItem
|
||||
Header="Populate Empty Expirations"
|
||||
Command="{Binding populate_empty_exps_cmd}" />
|
||||
@@ -413,6 +413,11 @@
|
||||
</MenuItem.ItemContainerStyle>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Import CSV..." Command="{Binding import_csv_cmd}" />
|
||||
<MenuItem Command="{Binding acquire_ownership_cmd}">
|
||||
<MenuItem.Header>
|
||||
<TextBlock Text="{Binding vs_manager, StringFormat='Acquire ownership from \'{0}\''}" />
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</c:DIYGrid.ContextMenu>
|
||||
<c:DIYGrid.RowStyle>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
}
|
||||
var mouse_pos = Mouse.GetPosition(this);
|
||||
if (!this.ChildAtPoint<VolSurfaceRowView>(mouse_pos, out var row)) {
|
||||
cm.IsOpen = false;
|
||||
cm.SetCurrentValue(ContextMenu.IsOpenProperty, false);
|
||||
return;
|
||||
}
|
||||
var cgs = g.GetColumnGeometry().ToList();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.spark;
|
||||
|
||||
@@ -14,14 +15,20 @@
|
||||
public const string WINDOW_TYPE = "VolSurface";
|
||||
|
||||
readonly VolSurfaceWindowSettings _startup_data;
|
||||
readonly UserTuple _user;
|
||||
|
||||
VolSurfaceVM _vm;
|
||||
VolSurfaceView _view;
|
||||
|
||||
public VolSurfaceWindow(
|
||||
VolSurfaceWindowFactory factory, IBus bus, string vs_name, VolSurfaceWindowSettings startup_data) :
|
||||
base(vs_name, bus, factory, Icons.vol_surface) {
|
||||
VolSurfaceWindowFactory factory,
|
||||
IBus bus,
|
||||
string vs_name,
|
||||
VolSurfaceWindowSettings startup_data,
|
||||
UserTuple user
|
||||
) : base(vs_name, bus, factory, Icons.vol_surface) {
|
||||
_startup_data = startup_data ?? throw new ArgumentNullException(nameof(startup_data));
|
||||
_user = user;
|
||||
this.vs_name = vs_name;
|
||||
_dispose = Disposable.Create(() => Disposable.dispose(ref _vm));
|
||||
}
|
||||
@@ -37,7 +44,7 @@
|
||||
public override UIElement Content => _view;
|
||||
|
||||
public void thread_init() {
|
||||
_vm = new VolSurfaceVM(new VolSurfaceDisplayModel(vs_id, _bus, true), vs_id, _bus, _startup_data);
|
||||
_vm = new VolSurfaceVM(new (vs_id, _bus, true), vs_id, _bus, _startup_data, _user);
|
||||
_view = new VolSurfaceView {
|
||||
DataContext = _vm
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.shell;
|
||||
|
||||
@@ -12,10 +13,12 @@ namespace mbts.spark {
|
||||
|
||||
class VolSurfaceWindowFactory : ShellWindowFactory<VolSurfaceWindowSettings> {
|
||||
readonly IBus _bus;
|
||||
readonly UserTuple _user;
|
||||
|
||||
public VolSurfaceWindowFactory(IShellModule module, IBus bus)
|
||||
public VolSurfaceWindowFactory(IShellModule module, IBus bus, UserTuple user)
|
||||
: base(module, "VolSurface") {
|
||||
_bus = bus;
|
||||
_user = user;
|
||||
_dispose = bus.subscribe(SparkTags.ShowVolSurface).OnDispatcher().Subscribe(
|
||||
async state => _bus.post(SparkTags.ShowWindow, await _create(state)));
|
||||
}
|
||||
@@ -24,7 +27,7 @@ namespace mbts.spark {
|
||||
_create(state);
|
||||
|
||||
async Task<IShellWindow> _create(VolSurfaceWindowSettings state) =>
|
||||
new VolSurfaceWindow(this, _bus, await _lookup_vs_name(state.id), state);
|
||||
new VolSurfaceWindow(this, _bus, await _lookup_vs_name(state.id), state, _user);
|
||||
|
||||
async Task<string> _lookup_vs_name(int vs_id) {
|
||||
var (vol_surfaces, success) = await _bus.subscribe(SparkTags.VolSurfaceListTag).FirstAsyncTask(TimeSpan.FromSeconds(2));
|
||||
|
||||
@@ -176,10 +176,11 @@
|
||||
</usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
|
||||
</usp:DataGridParameterCellTemplateConverter>
|
||||
<Style x:Key="ExpanderToggleButton" TargetType="ToggleButton">
|
||||
<Setter Property="Foreground" Value="{u:BTSColor ExecutionStrategy.expander_foreground}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Grid Background="Transparent">
|
||||
<Grid Background="{u:BTSColor ExecutionStrategy.expander_background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition/>
|
||||
@@ -190,7 +191,7 @@
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,5,0,0"
|
||||
SnapsToDevicePixels="False"
|
||||
Stroke="#77333333"
|
||||
Stroke="{u:BTSColor ExecutionStrategy.arrow_background}"
|
||||
StrokeThickness="2"
|
||||
VerticalAlignment="Top"
|
||||
/>
|
||||
@@ -199,6 +200,7 @@
|
||||
ContentSource="{TemplateBinding Content}"
|
||||
Margin="3,0,0,0"
|
||||
/>
|
||||
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
@@ -211,7 +213,7 @@
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="{u:BTSColor ExecutionStrategy.arrow_background_selected}"/>
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
@@ -278,7 +280,8 @@
|
||||
<ColumnDefinition/>
|
||||
</SelectiveScrollingGrid.ColumnDefinitions>
|
||||
<DataGridRowHeader
|
||||
Background="Transparent"
|
||||
Foreground="{u:BTSColor ExecutionStrategy.expander_foreground}"
|
||||
Background="{u:BTSColor ExecutionStrategy.data_grid_row_header_background}"
|
||||
Padding="{Binding section_count, Converter={StaticResource RowHeaderGroupIndentConverter}}"
|
||||
FontWeight="{Binding font_weight, FallbackValue={u:FontWeight Normal}}"
|
||||
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
|
||||
@@ -317,9 +320,17 @@
|
||||
<Style x:Key="DataGridRowStyle" TargetType="DataGridRow">
|
||||
<Setter Property="BorderThickness" Value="1,0"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Background" Value="{u:BTSColor ExecutionStrategy.alternate_column_background}"/>
|
||||
<Setter Property="Template" Value="{StaticResource DataGridRowTemplate}"/>
|
||||
<Setter Property="usp:ExecutionStrategyEditor.RowHasErrors" Value="{Binding has_errors}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="ListBox.AlternationIndex" Value="1">
|
||||
<Setter Property="Background" Value="{u:BTSColor ExecutionStrategy.data_grid_background}"/>
|
||||
</Trigger>
|
||||
<!-- <Trigger Property="ListBox.AlternationIndex" Value="2">
|
||||
<Setter Property="Background" Value="LightBlue"/>
|
||||
<Setter Property="Foreground" Value="Navy"/>
|
||||
</Trigger> -->
|
||||
<DataTrigger Binding="{Binding read_only}" Value="True">
|
||||
<Setter Property="TextElement.Foreground" Value="{u:BTSColor UI.input_disabled_text_dark}"/>
|
||||
<Setter Property="ToolTip">
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace mbts.spark {
|
||||
main_vm.rows.AddRange(parsed_synths.Select(ps => {
|
||||
var sec = ps.result;
|
||||
var r = new SyntheticImportRowVM(orders_model.admin_model.user.id, used_names.Contains) {
|
||||
tick_factors = TickUtils.get_regional_ticks(sec.ContractSpec).low_tick,
|
||||
tick_factors = TickUtils.get_regional_ticks(sec.immutable()).low_tick,
|
||||
name = sec.Synthetic.Name,
|
||||
parsed_synth = ps
|
||||
};
|
||||
|
||||
@@ -45,17 +45,17 @@ namespace mbts.spark {
|
||||
SecurityMD.key_fn,
|
||||
UserTuple.key_fn,
|
||||
smd => smd.security.Synthetic.UserId,
|
||||
(smd, sid, ut, uid) => new SyntheticTuple(smd.security, ut.name, null),
|
||||
(smd, sid, uid) => new SyntheticTuple(smd.security, null, null),
|
||||
SyntheticTuple.key_fn);
|
||||
(smd, sid, ut, uid) => new SyntheticSecurityTuple(smd.security, ut.name, null),
|
||||
(smd, sid, uid) => new SyntheticSecurityTuple(smd.security, null, null),
|
||||
SyntheticSecurityTuple.key_fn);
|
||||
|
||||
synthetic_tuples = synthetic_user_join.LeftJoin(
|
||||
strategy_source,
|
||||
SyntheticTuple.key_fn,
|
||||
SyntheticSecurityTuple.key_fn,
|
||||
tup => tup.security_id,
|
||||
(synth_tup, id, strat_tup) => new SyntheticTuple(synth_tup.security, synth_tup.user_name, strat_tup.strategy),
|
||||
(synth_tup, id, strat_tup) => new SyntheticSecurityTuple(synth_tup.security, synth_tup.user_name, strat_tup.strategy),
|
||||
(synth_tup, id) => synth_tup,
|
||||
SyntheticTuple.key_fn);
|
||||
SyntheticSecurityTuple.key_fn);
|
||||
}
|
||||
|
||||
public IObservable<IReadOnlyDictionary<uint, ExecutionStrategyImmutable>> strategy => _bus.subscribe(SparkTags.SyntheticstrategiesTag);
|
||||
@@ -69,7 +69,7 @@ namespace mbts.spark {
|
||||
.LeftJoin(strategies, (security, strategy) => (new ExecutionStrategyImmutable?(strategy), security), security => (new ExecutionStrategyImmutable?(), security))
|
||||
);
|
||||
|
||||
public IObservable<TableUpdate<SyntheticTuple, uint>> synthetic_tuples { get; }
|
||||
public IObservable<TableUpdate<SyntheticSecurityTuple, uint>> synthetic_tuples { get; }
|
||||
|
||||
public IObservable<ExecutionStrategyImmutable> security_strategy(uint security_key) =>
|
||||
strategy.TrySelect(s => {
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace mbts.spark {
|
||||
public SyntheticEditorVM(SpreaderModel model, SecurityImmutable synthetic, ExecutionStrategyImmutable strategy, IObservable<bool> security_has_working_orders)
|
||||
: this(synthetic, strategy, false) {
|
||||
ExceptionAssert.InvalidOperation.That(synthetic.Id != 0, "This constructor may only be used for already-existing synthetic securities (id must be non-zero).");
|
||||
_tick_factors = TickUtils.get_regional_ticks(synthetic.ContractSpec).low_tick;
|
||||
_tick_factors = TickUtils.get_regional_ticks(synthetic).low_tick;
|
||||
if (TickUtils.is_integer_tick(synthetic.ContractSpec)) {
|
||||
_use_fractional_ticks = false;
|
||||
_integer_tick_size = DoubleHelper.to_optional_int32(synthetic.ContractSpec.LowTick) ?? 0;
|
||||
@@ -112,7 +112,7 @@ namespace mbts.spark {
|
||||
_set_ticks_automatically = false;
|
||||
_set_quantities_automatically = false;
|
||||
_set_price_mults_automatically = false;
|
||||
_tick_factors = TickUtils.get_regional_ticks(_synthetic.ContractSpec).low_tick;
|
||||
_tick_factors = TickUtils.get_regional_ticks(_synthetic.immutable()).low_tick;
|
||||
} else {
|
||||
_deduce_name();
|
||||
_deduce_ticks();
|
||||
@@ -411,7 +411,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
void _deduce_ticks() {
|
||||
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.ContractSpec));
|
||||
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.immutable()));
|
||||
RaisePropertyChanged(nameof(tick_factors));
|
||||
}
|
||||
|
||||
|
||||
@@ -148,12 +148,12 @@ namespace mbts.spark {
|
||||
};
|
||||
|
||||
public class Row : DisposableViewModelBase, IEquatable<Row>, IRowVM, IActionableRowVM {
|
||||
public readonly SyntheticTuple synthetic_tuple;
|
||||
public readonly SyntheticSecurityTuple synthetic_tuple;
|
||||
|
||||
readonly IBus _bus;
|
||||
readonly Property<uint> _n_working_orders;
|
||||
|
||||
public Row(IBus bus, SyntheticTuple synthetic_tuple, OrdersModel orders_model) {
|
||||
public Row(IBus bus, SyntheticSecurityTuple synthetic_tuple, OrdersModel orders_model) {
|
||||
_bus = bus;
|
||||
this.synthetic_tuple = synthetic_tuple;
|
||||
_n_working_orders = backing(nameof(n_working_orders),
|
||||
|
||||
@@ -371,6 +371,7 @@
|
||||
<usp:AlgoEditorView
|
||||
DataContext="{Binding selected_definition}"
|
||||
Background="Transparent"
|
||||
Foreground="{u:BTSColor UI.default_text}"
|
||||
BorderBrush="{Binding algo_root, Converter={StaticResource OrderTypeBrushConverter}}"
|
||||
Padding="12,8" />
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Spark.Trading {
|
||||
meta.Value.Value.PriceDisplay : Security.Defaults.price_display_settingsi;
|
||||
if (security.HasValue) {
|
||||
rv = rv.with(
|
||||
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
|
||||
tick_factors: security.Value.tick_factors().to_api_tick_factors());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public OrderBookVM? create_orderbook_vm() {
|
||||
var ticks = _owner.spec.full_ticks_from_zero(real_price);
|
||||
var ticks = _owner.spec.count_ticks(real_price);
|
||||
if (!ticks.HasValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace mbts.spark {
|
||||
void increment_ticks_per_row() {
|
||||
var tpr = ticks_per_row;
|
||||
for (uint i = 1; i < 100; i++) {
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, ticks_per_row + i);
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security, ticks_per_row + i);
|
||||
if (new_tpr != tpr) {
|
||||
ticks_per_row = new_tpr;
|
||||
break;
|
||||
@@ -204,7 +204,7 @@ namespace mbts.spark {
|
||||
void decrement_ticks_per_row() {
|
||||
var tpr = ticks_per_row;
|
||||
for (uint i = 1; i < tpr; i++) {
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, tpr - i);
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security, tpr - i);
|
||||
if (new_tpr != tpr) {
|
||||
ticks_per_row = new_tpr;
|
||||
break;
|
||||
@@ -242,7 +242,8 @@ namespace mbts.spark {
|
||||
// since settings profiles may be shared among ladders
|
||||
// of different securities/tick sizes, the ticks per row setting
|
||||
// may need to be rounded to a number that is a factor of $1.00
|
||||
public uint? rounded_ticks_per_row => TickUtils.fit_ticks_per_row_to_dollars(_security.ContractSpec, ticks_per_row);
|
||||
public uint? rounded_ticks_per_row =>
|
||||
TickUtils.fit_ticks_per_row_to_dollars(_security, ticks_per_row);
|
||||
|
||||
public MarketSizeDisplayVM size_display { get; } = new MarketSizeDisplayVM();
|
||||
public SimpleGridSettingsVM mini_ob { get; } = new SimpleGridSettingsVM(OrderBookGridSettingsManager.hard_column_flags);
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace mbts.spark {
|
||||
IReadOnlyDictionary<uint, OrderRecordTuple> _cache = DictionaryHelper.empty<uint, OrderRecordTuple>();
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata> _favorite_algo_metadata_map =
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata>.Empty;
|
||||
ContractSpecificationImmutable? _spec;
|
||||
RegionalTickFactors? _spec;
|
||||
|
||||
LadderVM(
|
||||
IBus bus,
|
||||
@@ -245,10 +245,9 @@ namespace mbts.spark {
|
||||
|
||||
var orders_source = settings.Select(s => s.ticks_per_row).DistinctUntilChanged()
|
||||
.SelectSeries(tpr => {
|
||||
var spec = TickUtils.multiply_tick_size(security.ContractSpec, tpr);
|
||||
var spec = TickUtils.multiply_tick_size(security.regional_ticks(), tpr);
|
||||
var price_comp = Comparer<double>.Create((a, b) =>
|
||||
Comparer<int?>.Default.Compare(
|
||||
spec.full_ticks_from_zero(a), spec.full_ticks_from_zero(b)));
|
||||
Comparer<long?>.Default.Compare(spec.count_ticks(a), spec.count_ticks(b)));
|
||||
return _order_price_source(model.orders, price_comp, p => TickUtils.normalize_price(spec, p));
|
||||
});
|
||||
_day_change.Changed += (o, n) => RaisePropertyChanged(
|
||||
@@ -397,9 +396,10 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public SecurityImmutable security => _model.security;
|
||||
public ContractSpecificationImmutable spec => _spec ?? (
|
||||
public RegionalTickFactors spec => _spec ?? (
|
||||
_spec = TickUtils.multiply_tick_size(
|
||||
security.ContractSpec, current_settings?.ticks_per_row ?? 1)).Value;
|
||||
security.regional_ticks(), current_settings?.ticks_per_row ?? 1))
|
||||
?? RegionalTickFactors.Default;
|
||||
|
||||
public double display_quantity_divisor { get; }
|
||||
public LadderSettings current_settings { get; private set; }
|
||||
@@ -829,7 +829,7 @@ namespace mbts.spark {
|
||||
if (!price.is_real()) {
|
||||
msg = "not a real number";
|
||||
} else if (settlement.is_real()) {
|
||||
var ticks_from_settle = security.ContractSpec.tickdiff(price, settlement);
|
||||
var ticks_from_settle = security.tickdiff(price, settlement);
|
||||
if (ticks_from_settle.HasValue) {
|
||||
var max_cross = (current_settings?.ladder_order_limits?.max_settlement_cross_ticks)
|
||||
.as_nullable();
|
||||
@@ -861,7 +861,7 @@ namespace mbts.spark {
|
||||
} else {
|
||||
ulong _ = 0;
|
||||
_model.md.get_bbo(ref _, out var bid, out var ask);
|
||||
var mid = TickUtils.mid_tick(security.ContractSpec, bid.price, ask.price);
|
||||
var mid = TickUtils.mid_tick(security.regional_ticks(), bid.price, ask.price);
|
||||
_day_change.set(mid - md.settlement_price);
|
||||
}
|
||||
_volume.set(volume);
|
||||
|
||||
@@ -32,6 +32,8 @@ using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
partial class LadderGridHost : Control {
|
||||
static readonly int _initial_row_count;
|
||||
static readonly bool _show_scrollbar;
|
||||
@@ -83,7 +85,6 @@ namespace mbts.spark {
|
||||
bool _price_dirty = false, _piq_dirty = false;
|
||||
LadderPriceList _price_list = new() {
|
||||
length = _initial_row_count,
|
||||
spec = Security.Defaults.ContractSpecificationImmutable
|
||||
};
|
||||
LadderPriceList _pending_price_list = null;
|
||||
IComparer<double> _price_comparer;
|
||||
@@ -386,16 +387,16 @@ namespace mbts.spark {
|
||||
|
||||
Column[] _columns { get; set; } = Array.Empty<Column>();
|
||||
IEnumerable<Column> _visible_columns => _columns.Where(c => c.settings.show);
|
||||
ContractSpecificationImmutable? _spec_backing;
|
||||
ContractSpecificationImmutable _spec {
|
||||
RegionalTickFactors _spec_backing;
|
||||
RegionalTickFactors _spec {
|
||||
get {
|
||||
if (_spec_backing.HasValue) {
|
||||
return _spec_backing.Value;
|
||||
if (_spec_backing is not null) {
|
||||
return _spec_backing;
|
||||
} else if (_vm != null) {
|
||||
_spec_backing = TickUtils.multiply_tick_size(security.ContractSpec, _settings?.ticks_per_row ?? 1);
|
||||
return _spec_backing.Value;
|
||||
_spec_backing = TickUtils.multiply_tick_size(security.regional_ticks(), _settings?.ticks_per_row ?? 1);
|
||||
return _spec_backing;
|
||||
}
|
||||
return Security.Defaults.ContractSpecificationImmutable;
|
||||
return RegionalTickFactors.Default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,6 +450,15 @@ namespace mbts.spark {
|
||||
return _price_list.high_tick + tick_diff;
|
||||
}
|
||||
|
||||
public bool scroll_to_tick(long tick) {
|
||||
if (tick > int.MaxValue) {
|
||||
Log.Ui.error(
|
||||
$"Unable to scroll to tick {tick} because it exceeds int.MaxValue");
|
||||
return false;
|
||||
}
|
||||
return scroll_to_tick((int)tick);
|
||||
}
|
||||
|
||||
public bool scroll_to_tick(int tick) {
|
||||
if (_vm is null || _settings is null || _scroll_viewer is null) {
|
||||
return false;
|
||||
@@ -462,21 +472,23 @@ namespace mbts.spark {
|
||||
|
||||
// The scrollbar's vertical offset won't change. Find the 'top tick' that will put the
|
||||
// target `tick` in the center of the viewport.
|
||||
var top_tick = (int)_get_target_top_tick(tick);
|
||||
if (_settings.animate_recenter) {
|
||||
var anim = new Int32Animation {
|
||||
From = _price_list.high_tick,
|
||||
To = top_tick,
|
||||
Duration = TimeSpan.FromSeconds(0.15)
|
||||
};
|
||||
var sb = new Storyboard();
|
||||
sb.Children.Add(anim);
|
||||
Storyboard.SetTarget(anim, this);
|
||||
Storyboard.SetTargetProperty(anim, new PropertyPath(TopTickProperty));
|
||||
sb.Begin();
|
||||
} else {
|
||||
_set_scrollbar_range(high_tick: top_tick);
|
||||
_refresh_prices();
|
||||
checked {
|
||||
var top_tick = (int)_get_target_top_tick(tick);
|
||||
if (_settings.animate_recenter) {
|
||||
var anim = new Int32Animation {
|
||||
From = (int)_price_list.high_tick,
|
||||
To = top_tick,
|
||||
Duration = TimeSpan.FromSeconds(0.15)
|
||||
};
|
||||
var sb = new Storyboard();
|
||||
sb.Children.Add(anim);
|
||||
Storyboard.SetTarget(anim, this);
|
||||
Storyboard.SetTargetProperty(anim, new PropertyPath(TopTickProperty));
|
||||
sb.Begin();
|
||||
} else {
|
||||
_set_scrollbar_range(high_tick: top_tick);
|
||||
_refresh_prices();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -747,15 +759,11 @@ namespace mbts.spark {
|
||||
_price_for_row(_row_for_point(point));
|
||||
|
||||
static double _size_from_row(
|
||||
int row,
|
||||
IList<double> price_list,
|
||||
NativePriceSize[] depth,
|
||||
ContractSpecificationImmutable spec) =>
|
||||
int row, IList<double> price_list, NativePriceSize[] depth, RegionalTickFactors spec) =>
|
||||
price_list is null || depth is null || row >= price_list.Count ?
|
||||
double.NaN : _size_from_price(price_list[row], depth, spec);
|
||||
|
||||
static double _size_from_price(
|
||||
double price, NativePriceSize[] depth, ContractSpecificationImmutable spec) {
|
||||
static double _size_from_price(double price, NativePriceSize[] depth, RegionalTickFactors spec) {
|
||||
if (!double.IsNaN(price) && depth.TryGetFirst(nps => spec.tick_equals(price, nps.price), out NativePriceSize result))
|
||||
return result.size;
|
||||
return double.NaN;
|
||||
@@ -1105,10 +1113,16 @@ namespace mbts.spark {
|
||||
Log.assert(_price_dirty);
|
||||
_price_list = new LadderPriceList {
|
||||
length = _initial_row_count,
|
||||
spec = security.ContractSpec
|
||||
security = security
|
||||
};
|
||||
var mid_tick = security.ContractSpec.tickdiff(_mkt_break_lines.origin, 0) ?? 0;
|
||||
_set_scrollbar_range(high_tick: mid_tick + (_price_list.Count << 1));
|
||||
var mid_tick = security.tickdiff(_mkt_break_lines.origin, 0) ?? 0;
|
||||
if (mid_tick > int.MaxValue) {
|
||||
Log.Ui.error(
|
||||
$"Unable to set scrollbar range about mid_tick {mid_tick}: " +
|
||||
$"tick count exceeds int.MaxValue");
|
||||
} else {
|
||||
_set_scrollbar_range(high_tick: (int)mid_tick + (_price_list.Count << 1));
|
||||
}
|
||||
_price_dirty = true;
|
||||
}
|
||||
if (_price_dirty) {
|
||||
@@ -1187,12 +1201,12 @@ namespace mbts.spark {
|
||||
_price_list, _vm.md.settlement_price,
|
||||
_settings.net_change == LadderSettings.NetChangeTerms.Ticks,
|
||||
_settings.row_height, _settings.price_column,
|
||||
security.ContractSpec);
|
||||
_spec);
|
||||
} else {
|
||||
LadderRender.render_prices(
|
||||
_price_vis_tup.visual, _price_vis_tup.glyph_context,
|
||||
_price_list, _settings.row_height,
|
||||
_settings.price_column, security.ContractSpec,
|
||||
_settings.price_column, _spec,
|
||||
_settings.price_display_format);
|
||||
}
|
||||
}
|
||||
@@ -1269,7 +1283,7 @@ namespace mbts.spark {
|
||||
if (!_settings.piq_column.show)
|
||||
return;
|
||||
int origin_index = LadderRender.index_of(_price_list, _mkt_break_lines.origin, _price_comparer);
|
||||
LadderRender.render_piqs(_piq_vis_tup.visual, _last_vis_tup.glyph_context, origin_index, _price_list, _vm.price_vs_piq, _settings.row_height, _spec, _settings.piq_column, _fmt_mkt_quantity);
|
||||
LadderRender.render_piqs(_piq_vis_tup.visual, _last_vis_tup.glyph_context, _price_list, _vm.price_vs_piq, _settings.row_height, _spec, _settings.piq_column, _fmt_mkt_quantity);
|
||||
}
|
||||
|
||||
void _refresh_sizes() {
|
||||
@@ -1347,7 +1361,7 @@ namespace mbts.spark {
|
||||
return;
|
||||
if (_price_list is null) {
|
||||
_price_list = new LadderPriceList {
|
||||
spec = security.ContractSpec
|
||||
security = security
|
||||
};
|
||||
}
|
||||
_price_list.reset(null, null, _initial_row_count);
|
||||
@@ -1431,7 +1445,7 @@ namespace mbts.spark {
|
||||
_pending_scroll_to_origin |= _settings == null;
|
||||
_invalidate_spec();
|
||||
if (_price_list != null) {
|
||||
_price_list.spec = _spec;
|
||||
_price_list.security = security;
|
||||
}
|
||||
_bid_vis_tup.glyph_context = glyph_context(s.bid_column);
|
||||
_ask_vis_tup.glyph_context = glyph_context(s.ask_column);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using bts.api;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
class LadderPriceLineViewAdapter {
|
||||
public static double bid_line(
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (!double.IsNaN(bid)) {
|
||||
@@ -17,7 +19,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static double ask_line(
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (!double.IsNaN(ask)) {
|
||||
@@ -31,7 +33,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static double mid_line(
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (double.IsNaN(bid)) {
|
||||
@@ -43,16 +45,16 @@ namespace mbts.spark {
|
||||
if (double.IsNaN(ask)) {
|
||||
return bid;
|
||||
}
|
||||
if (spec.HasValue) {
|
||||
return TickUtils.mid_tick(spec.Value, bid, ask);
|
||||
if (spec is not null) {
|
||||
return TickUtils.mid_tick(spec, bid, ask);
|
||||
}
|
||||
return bid;
|
||||
}
|
||||
}
|
||||
|
||||
static double _try_tick_down(ContractSpecificationImmutable? spec, double value) {
|
||||
if (spec.HasValue) {
|
||||
return spec.Value.tickdown(value);
|
||||
static double _try_tick_down(RegionalTickFactors spec, double value) {
|
||||
if (spec is not null) {
|
||||
return spec.tickdown(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
@@ -8,52 +9,78 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
public class LadderPriceList : IReadOnlyList<double>, IList<double>, INotifyCollectionChanged, IEquatable<LadderPriceList> {
|
||||
int _length;
|
||||
int _high_tick;
|
||||
const long _MAX_LENGTH = int.MaxValue;
|
||||
|
||||
long _length;
|
||||
long _high_tick;
|
||||
SecurityImmutable? _security;
|
||||
RegionalTickFactors _regional_tick_backing;
|
||||
RegionalTickFactors _regional_tick =>
|
||||
_regional_tick_backing ??= TickUtils.get_regional_ticks(_security);
|
||||
|
||||
public LadderPriceList() { }
|
||||
|
||||
public LadderPriceList(LadderPriceList other) {
|
||||
_length = other._length;
|
||||
_high_tick = other._high_tick;
|
||||
spec = other.spec;
|
||||
_security = other._security;
|
||||
}
|
||||
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
|
||||
public SecurityImmutable? security {
|
||||
get => _security;
|
||||
set {
|
||||
if (value == _security) {
|
||||
return;
|
||||
}
|
||||
_security = value;
|
||||
_regional_tick_backing = null;
|
||||
}
|
||||
}
|
||||
|
||||
public ContractSpecificationImmutable spec { get; set; }
|
||||
|
||||
public int high_tick {
|
||||
public long high_tick {
|
||||
get => _high_tick;
|
||||
set => _high_tick = value;
|
||||
}
|
||||
|
||||
public int low_tick {
|
||||
public long low_tick {
|
||||
get => high_tick - length;
|
||||
set => reset(null, value, null);
|
||||
}
|
||||
|
||||
public double start {
|
||||
get => spec.tickup(0, high_tick);
|
||||
set => high_tick = spec.tickdiff(value, 0) ?? high_tick;
|
||||
get => _regional_tick.tickup<double>(0, (uint)high_tick);
|
||||
set => high_tick = _regional_tick.tickdiff(value, 0) ?? high_tick;
|
||||
}
|
||||
|
||||
public int length {
|
||||
public long length {
|
||||
get => _length;
|
||||
set {
|
||||
if (value < 0) {
|
||||
throw new ArgumentException($"Value must be >= 0 (actually {value})");
|
||||
if (value < 0 || value > _MAX_LENGTH) {
|
||||
throw new ArgumentException(
|
||||
$"Value 'v' must be >= 0 and < {_MAX_LENGTH} (actually {value})");
|
||||
}
|
||||
_length = value;
|
||||
}
|
||||
}
|
||||
public int Count => (int)length;
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
checked {
|
||||
return (int)length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public double this[int idx] {
|
||||
get => spec.tickup(0, high_tick - idx);
|
||||
get => _regional_tick.tick<double>(0, high_tick - idx);
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -67,11 +94,13 @@ namespace mbts.spark {
|
||||
GetEnumerator();
|
||||
|
||||
public int IndexOf(double item) {
|
||||
var idx = spec.tickdiff(start, item) ?? -1;
|
||||
var idx = _regional_tick.tickdiff(start, item) ?? -1;
|
||||
if (idx < 0 || idx >= length) {
|
||||
return -1;
|
||||
}
|
||||
return idx;
|
||||
checked {
|
||||
return (int)idx;
|
||||
}
|
||||
}
|
||||
|
||||
public void Insert(int index, double item) =>
|
||||
@@ -138,15 +167,15 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public void reset(int? high_tick = null, int? low_tick = null, int? length = null) {
|
||||
public void reset(long? high_tick = null, long? low_tick = null, long? length = null) {
|
||||
if (!high_tick.HasValue && !low_tick.HasValue && !length.HasValue) {
|
||||
return;
|
||||
}
|
||||
if (length.HasValue && length.Value < 0) {
|
||||
throw new ArgumentException("Must be >= 0", nameof(length));
|
||||
}
|
||||
int new_high_tick = 0;
|
||||
int new_length = 0;
|
||||
long new_high_tick = 0;
|
||||
long new_length = 0;
|
||||
if (high_tick.HasValue) {
|
||||
new_high_tick = high_tick.Value;
|
||||
if (low_tick.HasValue) {
|
||||
@@ -180,8 +209,7 @@ namespace mbts.spark {
|
||||
other != null &&
|
||||
_high_tick == other._high_tick &&
|
||||
_length == other._length &&
|
||||
spec.LowTick.Equals(other.spec.LowTick) &&
|
||||
spec.PriceBreak.Equals(other.spec.PriceBreak);
|
||||
_regional_tick.safe_equals(other._regional_tick);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
Equals(obj as LadderPriceList);
|
||||
@@ -189,13 +217,10 @@ namespace mbts.spark {
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(_high_tick, _length);
|
||||
|
||||
double _tick_to_price(int tick) =>
|
||||
spec.tickup(0, tick);
|
||||
double _tick_to_price(long tick) =>
|
||||
_regional_tick.tick<double>(0, tick);
|
||||
|
||||
int? _price_to_tick(double price) =>
|
||||
spec.tickdiff(price, 0);
|
||||
|
||||
void _add_tick(int tick) {
|
||||
void _add_tick(long tick) {
|
||||
int idx;
|
||||
if (length == 0) {
|
||||
_high_tick = tick;
|
||||
@@ -204,7 +229,9 @@ namespace mbts.spark {
|
||||
_high_tick = tick;
|
||||
idx = 0;
|
||||
} else if (tick == low_tick - 1) {
|
||||
idx = length;
|
||||
checked {
|
||||
idx = (int)length;
|
||||
}
|
||||
} else {
|
||||
throw new ArgumentException($"Must be == {nameof(high_tick)} ({high_tick}) + 1, or == {nameof(low_tick)} ({low_tick}) - 1)");
|
||||
}
|
||||
@@ -212,7 +239,7 @@ namespace mbts.spark {
|
||||
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, _tick_to_price(tick), idx));
|
||||
}
|
||||
|
||||
void _remove_tick(int tick) {
|
||||
void _remove_tick(long tick) {
|
||||
if (length == 0) {
|
||||
throw new InvalidOperationException("Cannot remove tick because length is 0");
|
||||
}
|
||||
@@ -221,7 +248,9 @@ namespace mbts.spark {
|
||||
_high_tick--;
|
||||
idx = 0;
|
||||
} else if (tick == low_tick) {
|
||||
idx = length - 1;
|
||||
checked {
|
||||
idx = (int)(length - 1);
|
||||
}
|
||||
} else {
|
||||
throw new ArgumentException(
|
||||
$"Can only remove {nameof(low_tick)} ({low_tick}) or " +
|
||||
|
||||
@@ -10,6 +10,7 @@ using mbts.ui.controls;
|
||||
using mbts.ui.utility.text;
|
||||
|
||||
using Spark.Api.Orders;
|
||||
using Spark.Core;
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
@@ -20,6 +21,8 @@ using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
static class BadgeRender {
|
||||
// IMPORTANT: the return values for this method MUST BE IN SYNC with the "format" method, else "measure_height" and "LadderRender.measure_row_height" will be broken.
|
||||
static int _line_count_for_style(LadderSettings.BadgeStyle badge_style) => badge_style == LadderSettings.BadgeStyle.Alternate ? 2 : 1;
|
||||
@@ -74,6 +77,16 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static int index_of(IList<double> prices, double price, IComparer<double> comparer, bool relative_idx) {
|
||||
for (int i = 1; i < prices.Count; i++) {
|
||||
Log.assert(prices[i - 1] > prices[i]);
|
||||
var c = comparer.Compare(prices[i - 1], prices[i]);
|
||||
if (c >= 0) {
|
||||
c = comparer.Compare(prices[i - 1], prices[i]);
|
||||
} else {
|
||||
c = comparer.Compare(prices[i - 1], prices[i]);
|
||||
}
|
||||
Log.assert(c < 0);
|
||||
}
|
||||
var idx = CollectionHelper.binary_search(prices, price, comparer);
|
||||
if (relative_idx && idx < 0) {
|
||||
idx = ~idx;
|
||||
@@ -96,30 +109,13 @@ namespace mbts.spark {
|
||||
settings.font_size, settings.width, row_height, HorizontalAlignment.Right,
|
||||
-4, VerticalAlignment.Center, row * row_height, true);
|
||||
|
||||
public static IList<double> gen_prices(double mid, int row_count, ContractSpecificationImmutable spec) {
|
||||
bool is_odd = row_count % 2 == 1;
|
||||
var result = new double[row_count];
|
||||
int range = row_count / 2;
|
||||
int middle = row_count / 2;
|
||||
result[middle] = mid;
|
||||
double up = mid, down = mid;
|
||||
// Starting from the middle iterate out to the edges
|
||||
for (int x = 1; x <= range; ++x) {
|
||||
up = spec.tickup(up);
|
||||
down = spec.tickdown(down);
|
||||
result[middle - x] = up;
|
||||
result[middle + x] = down;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double reference_price, bool format_in_tick_terms, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec) {
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double reference_price, bool format_in_tick_terms, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, RegionalTickFactors spec) {
|
||||
var result = new GlyphRun[prices.Count];
|
||||
Parallel.For(0, prices.Count, i =>
|
||||
result[i] = format_text(spec.format(prices[i] - reference_price, format_in_tick_terms), i, row_height, settings, glyph_context));
|
||||
return result;
|
||||
}
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec, LadderSettings.PriceDisplayFormat price_display_format) {
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, RegionalTickFactors spec, LadderSettings.PriceDisplayFormat price_display_format) {
|
||||
var result = new GlyphRun[prices.Count];
|
||||
Parallel.For(0, prices.Count, i =>
|
||||
result[i] = format_text(spec.format(prices[i]), i, row_height, settings, glyph_context, price_display_format));
|
||||
@@ -144,12 +140,12 @@ namespace mbts.spark {
|
||||
bool format_in_tick_terms,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
ContractSpecificationImmutable spec) {
|
||||
RegionalTickFactors tick) {
|
||||
if (price_list.IsNullOrEmpty()) {
|
||||
return;
|
||||
}
|
||||
render_prices(
|
||||
price, glyph_context, price_list, row_height, settings, spec,
|
||||
price, glyph_context, price_list, row_height, settings, tick,
|
||||
wrt_price, format_in_tick_terms);
|
||||
}
|
||||
|
||||
@@ -159,12 +155,12 @@ namespace mbts.spark {
|
||||
IList<double> dprices,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors tick,
|
||||
double wrt_price,
|
||||
bool format_in_tick_terms) {
|
||||
var foreground = settings.foreground.rgb_brush();
|
||||
//var background = new SolidColorBrush(settings.background.rgb_color());
|
||||
var fprices = format_prices(dprices, wrt_price, format_in_tick_terms, row_height, settings, glyph_context, spec);
|
||||
var fprices = format_prices(dprices, wrt_price, format_in_tick_terms, row_height, settings, glyph_context, tick);
|
||||
using (var dc = price.RenderOpen())
|
||||
using (_draw_with_clip(dc, settings, row_height, dprices.Count)) {
|
||||
//dc.DrawRectangle(background, null, new Rect(0, 0, settings.width, row_count * row_height));
|
||||
@@ -179,11 +175,11 @@ namespace mbts.spark {
|
||||
IList<double> dprices,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors tick,
|
||||
LadderSettings.PriceDisplayFormat price_display_format) {
|
||||
var foreground = settings.foreground.rgb_brush();
|
||||
//var background = new SolidColorBrush(settings.background.rgb_color());
|
||||
var fprices = format_prices(dprices, row_height, settings, glyph_context, spec, price_display_format);
|
||||
var fprices = format_prices(dprices, row_height, settings, glyph_context, tick, price_display_format);
|
||||
using (var dc = price.RenderOpen())
|
||||
using (_draw_with_clip(dc, settings, row_height, dprices.Count)) {
|
||||
//dc.DrawRectangle(background, null, new Rect(0, 0, settings.width, row_count * row_height));
|
||||
@@ -216,7 +212,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
NativePriceSize[] rungs,
|
||||
double row_height,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors spec,
|
||||
LadderColumnSettings settings,
|
||||
Func<NativePriceSize, string> fmt,
|
||||
bool lighten_market_cells,
|
||||
@@ -249,17 +245,18 @@ namespace mbts.spark {
|
||||
direct_size: aggr.direct_size + rung.direct_size,
|
||||
implied_size: aggr.implied_size + rung.implied_size),
|
||||
rung => {
|
||||
//spec.round_to_tick(rung.price);
|
||||
var ticks = spec.full_ticks_from_zero(rung.price);
|
||||
var ticks = spec.count_ticks(rung.price);
|
||||
return ticks.HasValue ? spec.tickup(0, ticks.Value) : rung.price;
|
||||
});
|
||||
foreach (var rung in row_tick_groups) {
|
||||
//double price = spec.round_to_tick(rung.price);
|
||||
var ticks = spec.full_ticks_from_zero(rung.price);
|
||||
var ticks = spec.count_ticks(rung.price);
|
||||
var price = ticks.HasValue ? spec.tickup(0, ticks.Value) : rung.price;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
int tick_diff = spec.tickdiff_unchecked(curr_price, price);
|
||||
curr_index += tick_diff;
|
||||
var tick_diff = spec.tickdiff(curr_price, price).assert_value();
|
||||
checked {
|
||||
curr_index += (int)tick_diff;
|
||||
}
|
||||
curr_price = price;
|
||||
if (curr_index >= 0 && curr_index < prices.Count) {
|
||||
if (market_cell_background_brush != null)
|
||||
@@ -279,7 +276,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
IEnumerable<VolumeAtPriceLevelImmutable> data,
|
||||
double row_height,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors spec,
|
||||
VolumeColumnSettings settings,
|
||||
int last_index,
|
||||
string last_size_and_direction,
|
||||
@@ -371,23 +368,27 @@ namespace mbts.spark {
|
||||
|
||||
public delegate void RenderCell<T>(DrawingContext dc, int row, T data_item);
|
||||
|
||||
static void _render_cells<T>(DrawingVisual dv, double row_height, IEnumerable<(double price, T value)> data, LadderColumnSettings settings, IList<double> prices, ContractSpecificationImmutable spec, RenderCell<T> render_cell) {
|
||||
static void _render_cells<T>(DrawingVisual dv, double row_height, IEnumerable<(double price, T value)> cells, LadderColumnSettings settings, IList<double> prices, RegionalTickFactors spec, RenderCell<T> render_cell) {
|
||||
using (var dc = dv.RenderOpen())
|
||||
using (_draw_with_clip(dc, settings, row_height, prices.Count)) {
|
||||
if (data.is_null_or_empty())
|
||||
if (prices.is_null_or_empty() || cells.is_null_or_empty()) {
|
||||
return;
|
||||
int curr_index = 0;
|
||||
double curr_price = prices[curr_index];
|
||||
foreach (var (price, value) in data) {
|
||||
if (double.IsNaN(price))
|
||||
continue;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
int tick_diff = spec.tickdiff(curr_price, price) ?? 0;
|
||||
curr_index += tick_diff;
|
||||
curr_price = price;
|
||||
if (curr_index >= 0 && curr_index < prices.Count) {
|
||||
render_cell(dc, curr_index, value);
|
||||
} else break;
|
||||
}
|
||||
var min_price = prices[prices.Count - 1];
|
||||
var max_price = prices[0];
|
||||
Log.assert(min_price.is_real() && max_price.is_real() && min_price <= max_price);
|
||||
var indexed_cells = cells
|
||||
.Where(item => item.price.is_real() && item.price.is_within_range(min_price, max_price))
|
||||
.Select(row => {
|
||||
checked {
|
||||
return (row.price, row.value, (int)spec.tickdiff(max_price, row.price));
|
||||
}
|
||||
});
|
||||
foreach (var (price, value, idx) in indexed_cells) {
|
||||
var check_price = spec.tickdown(max_price, idx);
|
||||
Log.assert(spec.tick_equals(price, check_price));
|
||||
Log.assert(idx >= 0 && idx < prices.Count);
|
||||
render_cell(dc, idx, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -411,35 +412,18 @@ namespace mbts.spark {
|
||||
internal static void render_piqs(
|
||||
DrawingVisual dv,
|
||||
GlyphContext glyph_context,
|
||||
int origin_index,
|
||||
IList<double> prices,
|
||||
IEnumerable<(double price, uint piq)> pvp,
|
||||
double row_height,
|
||||
ContractSpecificationImmutable spec,
|
||||
RegionalTickFactors spec,
|
||||
LadderColumnSettings settings,
|
||||
Func<double, string> fmt_value) {
|
||||
//
|
||||
using (var dc = dv.RenderOpen()) {
|
||||
using (_draw_with_clip(dc, settings, row_height, prices.Count)) {
|
||||
if (!prices.within_range(origin_index) || pvp.is_null_or_empty())
|
||||
return;
|
||||
fmt_value ??= FormattingDelegates.default_string<double>();
|
||||
var foreground = settings.foreground.rgb_brush();
|
||||
int curr_index = origin_index;
|
||||
double curr_price = prices[curr_index];
|
||||
foreach (var entry in pvp) {
|
||||
double price = entry.price;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
int tick_diff = spec.tickdiff_unchecked(curr_price, price);
|
||||
curr_index += tick_diff;
|
||||
curr_price = price;
|
||||
if (curr_index >= 0 && curr_index < prices.Count) {
|
||||
var gr = format_text(fmt_value(entry.piq), curr_index, row_height, settings, glyph_context);
|
||||
dc.DrawGlyphRun(foreground, gr);
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Func<double, string> fmt_value
|
||||
) {
|
||||
fmt_value ??= FormattingDelegates.default_string<double>();
|
||||
var fg = settings.foreground.rgb_brush();
|
||||
_render_cells(dv, row_height, pvp, settings, prices, spec, (dc, row, piq) =>
|
||||
dc.DrawGlyphRun(
|
||||
fg, format_text(fmt_value(piq), row, row_height, settings, glyph_context)));
|
||||
}
|
||||
|
||||
public static void render_mkt_break(DrawingVisual dv, int index, double row_height, uint color) =>
|
||||
|
||||
@@ -59,7 +59,9 @@ namespace bts.shell.manual_fills {
|
||||
nameof(quantity_display),
|
||||
() => {
|
||||
var sec_meta = security.HasValue ? _sec_meta_store.get(security.Value) : null;
|
||||
return sec_meta?.QuantityDisplay ?? Security.Defaults.quantity_display_settingsi;
|
||||
return sec_meta?.HasQuantityDisplay ?? false ?
|
||||
sec_meta.Value.QuantityDisplay :
|
||||
Security.Defaults.quantity_display_settingsi;
|
||||
});
|
||||
// TODO (prob): remove conversion_data. Replace get_qty_display_divisor delegates w/
|
||||
// TickDisplaySettingsImmutable for qty, obtained via ISecurityMetadataStore.
|
||||
|
||||
@@ -31,10 +31,12 @@
|
||||
ItemsSource="{Binding rows_view}"
|
||||
MinRowHeight="17"
|
||||
RowHeaderWidth="22"
|
||||
Background="{u:BTSColor ManualFills.background}"
|
||||
>
|
||||
<!--Row Header Style-->
|
||||
<DataGrid.RowHeaderStyle>
|
||||
<Style TargetType="DataGridRowHeader">
|
||||
<Setter Property="Background" Value="transparent"/>
|
||||
<Setter Property="Content" Value="{Binding}"/>
|
||||
<Setter Property="ContentTemplate">
|
||||
<Setter.Value>
|
||||
@@ -123,8 +125,12 @@
|
||||
<!--Row Style-->
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Background" Value="{u:BTSColor Grid.default_row_background}"/>
|
||||
<Setter Property="IsSelected" Value="{Binding is_selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="DataGridRow.AlternationIndex" Value="1">
|
||||
<Setter Property="Background" Value="{u:BTSColor Grid.alternate_row_background}"/>
|
||||
</Trigger>
|
||||
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource SelectedRowBackground}"/>
|
||||
</DataTrigger>
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Spark.Trading {
|
||||
meta.Value.Value.PriceDisplay : Security.Defaults.price_display_settingsi;
|
||||
if (security.HasValue) {
|
||||
rv = rv.with(
|
||||
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
|
||||
tick_factors: security.Value.regional_ticks().low_tick.to_api_tick_factors());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -779,7 +779,7 @@ namespace mbts.spark {
|
||||
return;
|
||||
}
|
||||
|
||||
var price_display = row.contract_spec?.tick_factors()?.to_api_tick_display_settingsi();
|
||||
var price_display = TickUtils.get_tick(row.security, price ?? 0).to_api_tick_display_settingsi();
|
||||
var update_desc = OrderUtils.update_description(
|
||||
row.order, price, quantity, price_display, row.quantity_display_settings);
|
||||
Log.Ui.info(
|
||||
|
||||
@@ -185,8 +185,7 @@ namespace mbts.spark {
|
||||
using var _ = detect_property_changes(
|
||||
nameof(spec),
|
||||
nameof(display_quantity_divisor),
|
||||
nameof(quantity_display),
|
||||
nameof(unit_quantity));
|
||||
nameof(quantity_display));
|
||||
_security_md = value;
|
||||
bbo.security_md = value;
|
||||
_payup_bid_cmd.RaiseCanExecuteChanged();
|
||||
@@ -216,9 +215,6 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public double unit_quantity =>
|
||||
(security?.ContractSpec)?.tick_factors()?.tick_unit_frac() ?? 1;
|
||||
|
||||
public AlgoDefinitionVM algo_vm { get; }
|
||||
public IReadOnlyObservableCollection<AlgoParamRowVM> param_rows { get; }
|
||||
public BBOVM bbo { get; }
|
||||
|
||||
@@ -507,7 +507,7 @@ namespace bts.shell.pnl {
|
||||
|
||||
static class PNLDataExtensions {
|
||||
public static string pnl_symbol(this SecurityImmutable security) {
|
||||
return bts.api.ExchangeSpecificUitlities.get_pnl_symbol(security);
|
||||
return bts.api.ExchangeSpecificUtilities.get_pnl_symbol(security);
|
||||
}
|
||||
|
||||
// while override_cpp could use double.NaN to indicate the lack of an override,
|
||||
@@ -519,7 +519,7 @@ namespace bts.shell.pnl {
|
||||
|
||||
public static (double default_cpp, double? override_cpp) pnl_cpp_tuple(this PNLUnitImmutable pnl_unit, SecurityImmutable security) {
|
||||
// TODO: actual impl
|
||||
double calced_pnl = bts.api.ExchangeSpecificUitlities.get_cpp(pnl_unit, security);
|
||||
double calced_pnl = bts.api.ExchangeSpecificUtilities.get_cpp(pnl_unit, security);
|
||||
return (calced_pnl, pnl_unit.HasCppOverride ? pnl_unit.CppOverride.Value : (double?)null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,9 +233,12 @@ namespace BCG {
|
||||
private IDictionary<DateTime, ATMData> _get_atm_data(ExpStrikeKeyedData<mbts.spark.TheoPoint> theo_data) {
|
||||
NMSheetSettings sheet_settings = _threaded_bb.read_state(_in_bb_sheet_settings_tag) ?? new NMSheetSettings();
|
||||
VolSurfaceNonVolInput vs_nvinp = _threaded_bb.read_state(_in_exp_param_tag);
|
||||
IDictionary<DateTime, double> option_exp_roll_data = vs_nvinp != null ?
|
||||
vs_nvinp.get_roll_map((exp) => exp.symbol == _nmsheet_symbol.option_name && exp.security_type == SecurityType.Option).ToDictionary(kv => kv.Key.expiration, kv => kv.Value) :
|
||||
new Dictionary<DateTime, double>();
|
||||
var option_exp_roll_data = vs_nvinp
|
||||
?.get_roll_map(exp =>
|
||||
exp.symbol == _nmsheet_symbol.option_name &&
|
||||
exp.security_type == SecurityType.Option)
|
||||
?.ToDictionary(kv => kv.Key.expiration, kv => kv.Value)
|
||||
?? new();
|
||||
IDictionary<DateTime, ATMData> atm_data = OptionATMDataSource.compute_atm_data(_nmsheet_symbol.option_name, _get_onefive(), theo_data, option_exp_roll_data);
|
||||
if (sheet_settings.setting_atm.select_atm_nearest_strike_only)
|
||||
foreach (ATMData exp_atm_data in atm_data.Values)
|
||||
@@ -306,4 +309,4 @@ namespace BCG {
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,5 +41,10 @@ namespace BCG {
|
||||
public static Size get_ask_size(BBOPacket md) {
|
||||
return md != null ? md._ask_size : (Size)0;
|
||||
}
|
||||
public static Tuple<double, Size> get_md(BBOPacket md, bool is_bid) {
|
||||
double price = is_bid ? BBOPacket.get_bid_price(md) : BBOPacket.get_ask_price(md);
|
||||
Size sz = is_bid ? BBOPacket.get_bid_size(md) : BBOPacket.get_ask_size(md);
|
||||
return Tuple.Create(price, sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace BCG {
|
||||
// return _fut_map.Select(e => Tuple.Create(e.Key.exchange, e.Key.symbol, e.Key.expiration, e.Key));
|
||||
// }
|
||||
|
||||
public IEnumerable<Tuple<Venue, string, uint>> get_stocks() { return new List<Tuple<Venue, string, uint>>(); }
|
||||
public IEnumerable<Tuple<Venue, string, uint>> get_spots() { return new List<Tuple<Venue, string, uint>>(); }
|
||||
|
||||
public Security get_o2_security(uint sec_key) {
|
||||
Security rv = _key_sec_map.TryGetValue(sec_key, out rv) ? rv : null;
|
||||
|
||||
@@ -123,6 +123,15 @@ namespace BCG {
|
||||
|
||||
#endregion
|
||||
|
||||
#region Orders
|
||||
[System.ComponentModel.Category("Orders / Algo")]
|
||||
[System.ComponentModel.DisplayName("Default Account")]
|
||||
public string Account { get; set; }
|
||||
[System.ComponentModel.Category("Orders / Algo")]
|
||||
[System.ComponentModel.DisplayName("Default Qty")]
|
||||
public Nullable<double> DefaultQty { get; set; }
|
||||
#endregion
|
||||
|
||||
public NMSheetSettingLayout() {
|
||||
show_settings_header = false;
|
||||
show_exp_navigator = false;
|
||||
|
||||
@@ -18,6 +18,7 @@ using mbts.spark.filters;
|
||||
using System.Collections;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using bts.api.orderman;
|
||||
|
||||
namespace BCG {
|
||||
public partial class NMSheetControl : UserControl {
|
||||
@@ -555,6 +556,17 @@ namespace BCG {
|
||||
}
|
||||
private void _launch_order_entry_window(NMSheetTheoGrid.GridCell cell,
|
||||
OrderEntryWindow window_type) {
|
||||
Func<string, bts.AccountTuple> get_account = (string default_acc) => {
|
||||
string account = _settings.setting_layout.Account;
|
||||
if (String.IsNullOrEmpty(account)) {
|
||||
account = default_acc;
|
||||
}
|
||||
Nullable<uint> id = _get_account_id(account);
|
||||
if (!id.HasValue) {
|
||||
id = 0;
|
||||
}
|
||||
return new bts.AccountTuple(id.Value, account);
|
||||
};
|
||||
uint key;
|
||||
var found = _sheet_data.get_security_key(cell.expiration,
|
||||
cell.strike, cell.call_selected, out key);
|
||||
@@ -566,7 +578,19 @@ namespace BCG {
|
||||
if (sc_data.sec_md_map.TryGetValue(key, out var smd)) {
|
||||
switch (window_type) {
|
||||
case OrderEntryWindow.Ticket:
|
||||
_threaded_bb.post(SparkTags.ShowOrderTicketFromSecurityTag, smd);
|
||||
bool is_bid = NMSheetSettingColumnOrganization.get_column_info(cell.col).is_bid;
|
||||
bts.AccountTuple acc_tup = get_account("SMALL");
|
||||
Nullable<double> qty = _settings.setting_layout.DefaultQty;
|
||||
OrderDefinition od = new OrderDefinition() {
|
||||
SecurityKey = smd.id,
|
||||
TimeInForce = TimeInForce.Gtc,
|
||||
Account = acc_tup.name,
|
||||
AccountId = acc_tup.id
|
||||
};
|
||||
BBOPacket bbo = _sheet_data.get_bbo(smd.id);
|
||||
var pr_sz = BBOPacket.get_md(bbo, is_bid);
|
||||
_threaded_bb.post(SparkTags.ShowOrderTicketTag,
|
||||
new(new(od), pr_sz.Item1, qty ?? pr_sz.Item2));
|
||||
break;
|
||||
case OrderEntryWindow.Ladder:
|
||||
_threaded_bb.post(SparkTags.ShowLadderTag, smd);
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace bts.shell {
|
||||
|
||||
void _on_orders(TableUpdate<OrderRecordTuple, uint> update) {
|
||||
// must update notification_service_data_cache first, some of the predicate/triggers (esp. ToastNotifications) will use the notification_service_data_cache to lookup order-history
|
||||
_data_cache.update(update.as_iincremental());
|
||||
_data_cache.update(update);
|
||||
foreach (var o in update.added.Concat(update.changed))
|
||||
_order_notifications.process_item(o);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using bts.api;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
|
||||
using mbts.spark;
|
||||
@@ -8,6 +9,7 @@ using Spark.Api.Orders;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace bts.shell {
|
||||
// Any predicate-sound/notifications that need to reference previous data (i.e. notifications based on change/time, or state changes) should use the INotificationServiceDataCache.
|
||||
@@ -17,7 +19,6 @@ namespace bts.shell {
|
||||
// --------------------------------------------------------------------------------------------------------------------------------------------
|
||||
// IMPOARTANT!!! The current implementation of this interface is NOT INTENDED FOR GENERAL USE - order_history is NOT THREAD-SAFE
|
||||
interface INotificationServiceDataCache {
|
||||
DateTime last_order_reset_time { get; }
|
||||
bool is_first_order_update { get; }
|
||||
IReadOnlyDictionary<uint, List<TimeStampedData<OrderRecordTuple>>> order_history { get; }
|
||||
}
|
||||
@@ -45,45 +46,113 @@ namespace bts.shell {
|
||||
|
||||
partial class NotificationService : INotificationService, IDisposable {
|
||||
class DataCache : INotificationServiceDataCache {
|
||||
const int _buffer_size = 10;
|
||||
const int _ORDER_HISTORY_BUFFER_SIZE = 10;
|
||||
const int _TABLE_HISTORY_BUFFER_SIZE = 5;
|
||||
|
||||
readonly Dictionary<uint, OrderRecordTuple> _order_cache = new();
|
||||
readonly Dictionary<uint, List<TimeStampedData<OrderRecordTuple>>> _order_history = new();
|
||||
readonly List<(TableUpdate<OrderRecordTuple, uint>, DateTime)> _table_history = new(_TABLE_HISTORY_BUFFER_SIZE);
|
||||
readonly object _lock = new();
|
||||
|
||||
public IReadOnlyDictionary<uint, List<TimeStampedData<OrderRecordTuple>>> order_history => _order_history;
|
||||
|
||||
public DateTime last_order_reset_time { get; private set; }
|
||||
public bool is_first_order_update { get; private set; }
|
||||
|
||||
internal void update(IIncrementalUpdate<OrderRecordTuple, uint> data) {
|
||||
internal void update(TableUpdate<OrderRecordTuple, uint> table) {
|
||||
// First, try processing the update per usual (incrementally). If it throws,
|
||||
// then log the exception and reset the state.
|
||||
DateTime now = DateTime.Now;
|
||||
if (data.removed.Count == _order_cache.Count) {
|
||||
last_order_reset_time = now;
|
||||
_order_cache.Clear();
|
||||
lock (_lock) {
|
||||
_circular_buffer_add(_table_history, (table, now), _TABLE_HISTORY_BUFFER_SIZE);
|
||||
try {
|
||||
impl();
|
||||
return;
|
||||
} catch (Exception ex) {
|
||||
var table_history_desc = _fmt_order_table_history_safe();
|
||||
Log.Ui.error(
|
||||
$"Error processing order update in NotificationService: {ex}.\n" +
|
||||
$"***Last table updates below***\n" +
|
||||
table_history_desc);
|
||||
}
|
||||
// This is the 'escape' path. It really shouldn't throw.
|
||||
reset();
|
||||
}
|
||||
is_first_order_update = _order_cache.Count == 0 && data.added.Count > 0;
|
||||
foreach (var kv in data.removed) {
|
||||
if (data.added.ContainsKey(kv.Key)) {
|
||||
_order_cache[kv.Key] = kv.Value;
|
||||
_order_history[kv.Key].Add(new TimeStampedData<OrderRecordTuple>(kv.Value, now));
|
||||
} else {
|
||||
_order_cache.Remove(kv.Key);
|
||||
// TODO: maybe these shouldn't be removed?
|
||||
// if we add delta/time predicates that need to refer to order history, we might need to keep them around
|
||||
// although, if the server is telling us to remove them, perhaps we shouldn't consider such data.
|
||||
_order_history.Remove(kv.Key);
|
||||
|
||||
void impl() {
|
||||
if (table.state.Count == 0) {
|
||||
_order_cache.Clear();
|
||||
}
|
||||
is_first_order_update = _order_cache.Count == 0 && table.state.Count > 0;
|
||||
foreach (var order in table.removed) {
|
||||
var k = table.key(order);
|
||||
_order_cache.Remove(k);
|
||||
_order_history.Remove(k);
|
||||
}
|
||||
foreach (var ch in table.changes) {
|
||||
var k = table.key(ch.New);
|
||||
_order_cache[k] = ch.New;
|
||||
_order_history[k].Add(new(ch.New, now));
|
||||
}
|
||||
foreach (var order in table.added) {
|
||||
var k = table.key(order);
|
||||
_order_cache[k] = order;
|
||||
var hist = _order_history.GetOrAdd(k, _ => new());
|
||||
_circular_buffer_add(hist, new(order, now), _ORDER_HISTORY_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
foreach (var kv in data.added) {
|
||||
if (data.removed.ContainsKey(kv.Key))
|
||||
continue;
|
||||
_order_cache.Add(kv.Key, kv.Value);
|
||||
_order_history.AddOrUpdate(kv.Key,
|
||||
k => new List<TimeStampedData<OrderRecordTuple>> { new(kv.Value, now) },
|
||||
(k, l) => {
|
||||
l.Add(new TimeStampedData<OrderRecordTuple>(kv.Value, now));
|
||||
if (l.Count >= 10)
|
||||
l.RemoveAt(0);
|
||||
});
|
||||
|
||||
void reset() {
|
||||
_order_cache.Clear();
|
||||
_order_history.Clear();
|
||||
_table_history.Clear();
|
||||
foreach (var (k, order) in table.state) {
|
||||
_order_cache[k] = order;
|
||||
_order_history.GetOrAdd(k, _ => new()).Add(new(order, now));
|
||||
}
|
||||
is_first_order_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void _circular_buffer_add<T>(List<T> list, T item, int buffer_size) {
|
||||
Log.assert(buffer_size > 0);
|
||||
if (list.Count > buffer_size - 1) {
|
||||
// Remove oldest items (trim front)
|
||||
list.RemoveRange(
|
||||
0, list.Count - (buffer_size - 1));
|
||||
}
|
||||
list.Add(item);
|
||||
}
|
||||
|
||||
string _fmt_order_table_history_safe() {
|
||||
return _fmt_table_history_safe(_table_history, fmt_order_tup);
|
||||
|
||||
static string fmt_order_tup(OrderRecordTuple order_tup) {
|
||||
var sec = order_tup.security;
|
||||
var order = order_tup.order;
|
||||
var order_desc = OrderUtils.short_description(order, sec.spec_or_default());
|
||||
var sec_desc = sec?.ToString() ?? ("sid=" + order_tup.security_id.ToString());
|
||||
return $"{sec_desc} {order_desc}";
|
||||
}
|
||||
}
|
||||
|
||||
static string _fmt_table_history_safe<T, TKey>(
|
||||
List<(TableUpdate<T, TKey>, DateTime)> table_history, Func<T, string> fmt_value) where TKey : IEquatable<TKey> {
|
||||
var table_history_desc = new System.Text.StringBuilder();
|
||||
for (int i = 0; i < table_history.Count; i++) {
|
||||
var (table, time_stamp) = table_history[i];
|
||||
table_history_desc.AppendLine(
|
||||
$"Update - {table_history.Count - i}, at {time_stamp:yyyy-MM-dd hh:mm:ss.ffffff}");
|
||||
table_history_desc.AppendLine(_fmt_table_safe(table, fmt_value));
|
||||
}
|
||||
return table_history_desc.ToString();
|
||||
}
|
||||
|
||||
static string _fmt_table_safe<T, TKey>(
|
||||
TableUpdate<T, TKey> table, Func<T, string> fmt_value) where TKey : IEquatable<TKey> {
|
||||
try {
|
||||
return table.description(fmt_value);
|
||||
} catch (Exception ex) {
|
||||
return $"Exception while formatting TableUpdate: ${ex}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
class InlineOrderTicketProperties {
|
||||
public readonly InlineUserProperty<double> price;
|
||||
public readonly InlineUserProperty<double> size;
|
||||
@@ -128,6 +130,7 @@ namespace mbts.spark {
|
||||
|
||||
public SecurityImmutable security => _security.Value;
|
||||
public double price { get; set; }
|
||||
public RegionalTickFactors price_tick => security.regional_ticks();
|
||||
public CalculatorLogic<double> size_calculator { get; }
|
||||
|
||||
public TickDisplaySettingsImmutable qty_display {
|
||||
|
||||
@@ -225,10 +225,7 @@ namespace bts.spark {
|
||||
var security = try_get_security(order.Def.SecurityKey);
|
||||
var change_descs = new List<string>(1);
|
||||
|
||||
TickDisplaySettingsImmutable? price_display =
|
||||
security.HasValue && security.Value.HasContractSpec ?
|
||||
security.Value.ContractSpec.tick_factors().to_api_tick_display_settingsi() : null;
|
||||
|
||||
var price_display = TickUtils.get_tick(security, price).to_api_tick_display_settingsi();
|
||||
var price_qty_change_desc = OrdersExtensions.update_description(
|
||||
order, price, size, price_display);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<usp:PriceEntryControl
|
||||
Grid.ColumnSpan="2"
|
||||
usp:OrderModificationControl.IsDirty="{Binding price_dirty, FallbackValue={x:Null}}"
|
||||
ContractSpec="{Binding security.ContractSpec}"
|
||||
RegionalTick="{Binding price_tick}"
|
||||
Focusable="false"
|
||||
TickDefaultValue="{Binding current_price, Converter={StaticResource TickDefaultPriceConverter}, FallbackValue={u:Double 0}}"
|
||||
Value="{Binding price}"
|
||||
|
||||
@@ -127,9 +127,9 @@
|
||||
<TextBlock.Inlines>
|
||||
<Run FontWeight="Bold" Text="{Binding security, Mode=OneWay}" />
|
||||
<Run Foreground="{u:BTSColor MarketData.bid}" FontSize="10">
|
||||
<MultiBinding Converter="{x:Static cv:DynamicDoubleDivisorConverter.Instance}" Mode="OneWay" StringFormat="({0})">
|
||||
<MultiBinding Converter="{x:Static cv:TickDisplayConverter.Instance}" StringFormat="({0})">
|
||||
<Binding Path="bid_size" Mode="OneWay"/>
|
||||
<Binding Path="DataContext.display_quantity_divisor" RelativeSource="{RelativeSource AncestorType=usp:OrderTicket}"/>
|
||||
<Binding Path="DataContext.qty_display" RelativeSource="{RelativeSource AncestorType=usp:OrderTicket}"/>
|
||||
</MultiBinding>
|
||||
</Run>
|
||||
<Run Foreground="{u:BTSColor MarketData.bid}" FontWeight="Bold">
|
||||
@@ -149,9 +149,9 @@
|
||||
</Run.Text>
|
||||
</Run>
|
||||
<Run Foreground="{u:BTSColor MarketData.ask}" FontSize="10">
|
||||
<MultiBinding Converter="{x:Static cv:DynamicDoubleDivisorConverter.Instance}" Mode="OneWay" StringFormat="({0})">
|
||||
<MultiBinding Converter="{x:Static cv:TickDisplayConverter.Instance}" StringFormat="({0})">
|
||||
<Binding Path="ask_size" Mode="OneWay"/>
|
||||
<Binding Path="DataContext.display_quantity_divisor" RelativeSource="{RelativeSource AncestorType=usp:OrderTicket}"/>
|
||||
<Binding Path="DataContext.qty_display" RelativeSource="{RelativeSource AncestorType=usp:OrderTicket}"/>
|
||||
</MultiBinding>
|
||||
</Run>
|
||||
</TextBlock.Inlines>
|
||||
|
||||
@@ -91,7 +91,8 @@ namespace mbts {
|
||||
}
|
||||
var sec = order.security;
|
||||
var sec_meta = sec.HasValue ? _sec_meta_store.get(sec.Value) : null;
|
||||
var qty_display = sec_meta?.QuantityDisplay ??
|
||||
var qty_display = sec_meta?.HasQuantityDisplay ?? false ?
|
||||
sec_meta.Value.QuantityDisplay :
|
||||
Security.Defaults.quantity_display_settingsi;
|
||||
return ToastNotifications.order_completed(order, qty_display);
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace mbts.analytics {
|
||||
timer.stop();
|
||||
Log.Ui.info($"PNLReportCalculator n_pos: {output.position_data.Count()} " +
|
||||
$"n_day_trades: {output.day_trades.Count()} time(msecs): {timer.lastIntervalTime}");
|
||||
_log_before_posting(output.position_data);
|
||||
//_log_before_posting(output.position_data);
|
||||
_bus.post(SparkTags.ReportBlackboardTags.PNL.PNLData, output);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -116,21 +116,21 @@ namespace mbts.analytics {
|
||||
}
|
||||
|
||||
private void _handle_nonvol_data(VolSurfaceNonVolData vs_nonvol_data) {
|
||||
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
|
||||
_report.ReportName));
|
||||
// bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
|
||||
// _report.ReportName));
|
||||
_vs_nonvol_data = vs_nonvol_data;
|
||||
}
|
||||
|
||||
private void _handle_future_prices(
|
||||
IReadOnlyDictionary<SecurityExpiration, FutureTheoStructure> future_prices_map) {
|
||||
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_future_prices report {0}",
|
||||
_report.ReportName));
|
||||
// bts.Log.Gen.Diag(String.Format("SlideReportCalculator._handle_future_prices report {0}",
|
||||
// _report.ReportName));
|
||||
_future_prices_map = future_prices_map.ToDictionary(kv => kv.Key, kv => kv.Value.theo);
|
||||
}
|
||||
|
||||
private void _handle_trades(IEnumerable<ITradeLogRow> trades) {
|
||||
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_trades report {0}",
|
||||
_report.ReportName));
|
||||
// bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_trades report {0}",
|
||||
// _report.ReportName));
|
||||
_all_trades = trades.Where(t => t.is_active);
|
||||
if (_report.CalcMode == Report.Types.ReportCalculationMode.PositionOrTheoChange) {
|
||||
_compute_dirty = true;
|
||||
|
||||
@@ -555,7 +555,7 @@ namespace mbts.analytics {
|
||||
var rv = new HashSet<bts.api.SecurityTuple>();
|
||||
foreach (var c in sc.Clauses)
|
||||
foreach (var s in c.Symbols)
|
||||
foreach (var e in c.Exchanges)
|
||||
foreach (var e in c.Venues)
|
||||
foreach (var st in c.SecurityTypes) {
|
||||
var st_i = new bts.api.SecurityTuple();
|
||||
st_i.Symbol = s;
|
||||
@@ -568,4 +568,4 @@ namespace mbts.analytics {
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace mbts {
|
||||
if (!is_unexpired(l.Security))
|
||||
return false;
|
||||
return true;
|
||||
case bts.api.SecurityType.Stock:
|
||||
case bts.api.SecurityType.Spot:
|
||||
return true;
|
||||
case bts.api.SecurityType.Synthetic:
|
||||
foreach (var l in sec.Synthetic.Legs)
|
||||
@@ -68,4 +68,4 @@ namespace mbts {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,14 @@
|
||||
class ShellBootstrapper : BTSApplicationBootstrapper {
|
||||
Window _login;
|
||||
|
||||
public ShellBootstrapper(string user = null, string password = null, bool? restore_workspace = null) {
|
||||
public ShellBootstrapper(
|
||||
string user = null,
|
||||
string password = null,
|
||||
string config_source = null,
|
||||
bool? restore_workspace = null
|
||||
) : base(config_source) {
|
||||
// Get the LoginModel instance on this thread to make sure it performs syncronous config initialization.
|
||||
var login_model = LoginModel.instance;
|
||||
var login_model = LoginModel.init(config_source);
|
||||
// Show the dialog on a background thread so animations aren't blocked during the main application startup
|
||||
var thread = new Thread(thread_start) {
|
||||
IsBackground = true,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#nullable enable
|
||||
namespace Spark.Cli {
|
||||
using CommandLine;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
class SparkCmdOpts {
|
||||
const string _SPARKD_OPT_NAME = "sparkd";
|
||||
|
||||
[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", MetaValue = "USER", HelpText = "The user to login with")]
|
||||
public string? user { get; set; }
|
||||
|
||||
[Option("password", MetaValue = "PASS", HelpText = "The password to login with")]
|
||||
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;
|
||||
}
|
||||
|
||||
[Option(_SPARKD_OPT_NAME, MetaValue = "URL", HelpText = "The config server url")]
|
||||
public string? sparkd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Conform opts to modern cli for backwards compatibility
|
||||
/// </summary>
|
||||
public static IEnumerable<string> conform_opts(IEnumerable<string> opts) {
|
||||
using var en = opts.GetEnumerator();
|
||||
while (en.MoveNext()) {
|
||||
if (en.Current.ToLower() == "-configserver") {
|
||||
yield return $"--{_SPARKD_OPT_NAME}";
|
||||
continue;
|
||||
}
|
||||
yield return en.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ using MathNet.Numerics.Distributions;
|
||||
namespace BCG {
|
||||
public class ContractUtilities {
|
||||
public static bool is_strock(string sec_type) {
|
||||
return String.Compare(sec_type, SecurityType.Stock.ToString(), true) == 0;
|
||||
return String.Compare(sec_type, SecurityType.Spot.ToString(), true) == 0;
|
||||
// return String.Compare(sec_type, SecurityType.Stock.ToString(), true) == 0 ||
|
||||
// String.Compare(sec_type, SecurityType.Equity.ToString(), true) == 0 ||
|
||||
// String.Compare(sec_type, SecurityType.ETF.ToString(), true) == 0 ||
|
||||
@@ -18,8 +18,8 @@ namespace BCG {
|
||||
}
|
||||
|
||||
//also see SecurityType.cs extension method
|
||||
public static SecurityType default_aw_stock_type {
|
||||
get { return SecurityType.Stock; }
|
||||
public static SecurityType default_aw_spot_type {
|
||||
get { return SecurityType.Spot; }
|
||||
}
|
||||
|
||||
public static string case_correct_symbol(string sym_type, SecurityType default_type = SecurityType.Future) {
|
||||
|
||||
Loaded 100 of 1176 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user