Compare commits
75
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
caad455784 | ||
|
|
ac35c789ce | ||
|
|
1361d7cf5d | ||
|
|
7b30dbf6b4 | ||
|
|
7c96b54101 | ||
|
|
c6e4f090f5 | ||
|
|
dee847a30c | ||
|
|
b0c69f7a02 | ||
|
|
ae2e892311 | ||
|
|
99e9dbb886 | ||
|
|
a606a4749f | ||
|
|
fa22cbd386 | ||
|
|
6612a6d7e1 | ||
|
|
e6b2d6f0b8 | ||
|
|
b5828fbadc | ||
|
|
3844d9f3ee | ||
|
|
309b0e64b2 | ||
|
|
cfdca08cfe | ||
|
|
51c89fb8cc | ||
|
|
ded674d87c | ||
|
|
648e6206ab | ||
|
|
ef07463a7d | ||
|
|
124817d60d | ||
|
|
828afb6173 | ||
|
|
852782232c | ||
|
|
add0c3412c | ||
|
|
e20b7338c4 | ||
|
|
b5da4b3129 | ||
|
|
9f7bafa423 | ||
|
|
95e99f4855 | ||
|
|
4c4bc3d451 | ||
|
|
649be1e74e | ||
|
|
776c69d96c | ||
|
|
d371e09e72 | ||
|
|
c035befe7d | ||
|
|
be3bf93154 | ||
|
|
9ec5a2d394 | ||
|
|
0dbdc6cd62 | ||
|
|
0eeb37427f | ||
|
|
25cd86d44f | ||
|
|
bf6a232b5b | ||
|
|
47fdae4a71 | ||
|
|
32d1714cf6 | ||
|
|
df0018a8c0 | ||
|
|
200919d714 | ||
|
|
1a2a6b3fb2 | ||
|
|
ab5ec98d78 | ||
|
|
fd47c3aca9 | ||
|
|
24fb5d0041 | ||
|
|
74a4fa133c | ||
|
|
febba9b3f7 | ||
|
|
ad2bc86688 | ||
|
|
dd84ec6720 | ||
|
|
9d79490a20 | ||
|
|
24059df312 | ||
|
|
41862474e9 | ||
|
|
ccbb1dd5c9 | ||
|
|
e24c767c41 | ||
|
|
2b23c3d881 | ||
|
|
0306da2a58 | ||
|
|
511856f989 | ||
|
|
09ae3c23a5 | ||
|
|
9dddecbc06 | ||
|
|
02e31ecae6 | ||
|
|
8722d80f2d | ||
|
|
8360c3f63f | ||
|
|
c310544783 | ||
|
|
e9ca7748a4 | ||
|
|
83ee97419c | ||
|
|
b6a1dc61db | ||
|
|
4fb04aafd7 | ||
|
|
51cb7d91ba | ||
|
|
14dd9e0204 | ||
|
|
ee330fdf6d | ||
|
|
78b82db3e7 |
No files matched your search
@@ -7,24 +7,6 @@
|
||||
"commands": [
|
||||
"dotnet-format"
|
||||
]
|
||||
},
|
||||
"fable": {
|
||||
"version": "4.0.0-theta-018",
|
||||
"commands": [
|
||||
"fable"
|
||||
]
|
||||
},
|
||||
"fantomas": {
|
||||
"version": "5.2.2",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
]
|
||||
},
|
||||
"fake-cli": {
|
||||
"version": "6.0.0",
|
||||
"commands": [
|
||||
"fake"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Note installations that take a while (more than 10s)
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y ca-certificates
|
||||
RUN apt-get install -y ccache
|
||||
RUN apt-get install -y curl
|
||||
RUN apt-get install -y fish
|
||||
RUN apt-get install -y gdb
|
||||
# git-all: ~250s
|
||||
RUN apt-get install -y git-all
|
||||
RUN apt-get install -y gnupg
|
||||
# liblttng-ust-dev: ~30s
|
||||
RUN apt-get install -y liblttng-ust-dev
|
||||
RUN apt-get install -y libssh2-1-dev
|
||||
RUN apt-get install -y locales
|
||||
RUN apt-get install -y ninja-build
|
||||
# openssh-server: ~40s
|
||||
RUN apt-get install -y openssh-server
|
||||
RUN apt-get install -y pkg-config
|
||||
RUN apt-get install -y software-properties-common
|
||||
RUN apt-get install -y sudo
|
||||
RUN apt-get install -y tzdata
|
||||
RUN apt-get install -y vim
|
||||
RUN apt-get install -y zip
|
||||
|
||||
# Python: ~30s
|
||||
RUN apt-get install -y \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
&& python3 -m pip install --upgrade pip
|
||||
|
||||
# GCC
|
||||
ARG gcc_major=13
|
||||
RUN \
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y g++-$gcc_major
|
||||
|
||||
# Clang
|
||||
ARG clang_major=17
|
||||
RUN \
|
||||
curl -fsSL https://apt.llvm.org/llvm-snapshot.gpg.key 2> /dev/null \
|
||||
| gpg --dearmor - \
|
||||
| tee /usr/share/keyrings/llvm-snapshot.gpg > /dev/null \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-$clang_major main" \
|
||||
| tee -a "/etc/apt/sources.list.d/llvm.list" \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y \
|
||||
clang-$clang_major \
|
||||
clang-format-$clang_major \
|
||||
clangd-$clang_major
|
||||
|
||||
# CMake
|
||||
RUN \
|
||||
curl -fsSL https://apt.kitware.com/keys/kitware-archive-latest.asc 2> /dev/null \
|
||||
| gpg --dearmor - \
|
||||
| tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" \
|
||||
| tee /etc/apt/sources.list.d/kitware.list > /dev/null \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y cmake
|
||||
|
||||
# Dotnet
|
||||
RUN apt-get update && apt-get install -y dotnet7
|
||||
|
||||
# Node
|
||||
ARG node_major=18
|
||||
RUN mkdir -p /etc/apt/keyrings \
|
||||
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
|
||||
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
|
||||
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$node_major.x nodistro main" \
|
||||
| tee /etc/apt/sources.list.d/nodesource.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y nodejs
|
||||
|
||||
# Emumba (deps)
|
||||
RUN apt-get update && apt-get -y install rapidjson-dev
|
||||
# Emumba
|
||||
COPY emumba /emumba
|
||||
RUN dpkg -i /emumba/emumba-deribit-connector-3.3.1-Linux.LICENSE_DISABLED.deb \
|
||||
&& rm -r /emumba
|
||||
|
||||
# Pcap
|
||||
RUN apt-get update && apt-get install -y libpcap0.8-dev
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
docker.io \
|
||||
docker-compose \
|
||||
docker-compose-v2
|
||||
|
||||
# Set up default executables (update-alternatives)
|
||||
RUN \
|
||||
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-$clang_major 100; \
|
||||
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-$clang_major 100; \
|
||||
update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-$clang_major 100; \
|
||||
update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-$clang_major 100; \
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-$gcc_major 100; \
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-$gcc_major 100
|
||||
|
||||
# Add compiler symlinks for ccache
|
||||
RUN \
|
||||
ln -s /usr/bin/ccache /usr/local/bin/clang; \
|
||||
ln -s /usr/bin/ccache /usr/local/bin/clang++; \
|
||||
ln -s /usr/bin/ccache /usr/local/bin/clang-$clang_major; \
|
||||
ln -s /usr/bin/ccache /usr/local/bin/clang++-$clang_major; \
|
||||
ln -s /usr/bin/ccache /usr/local/bin/gcc; \
|
||||
ln -s /usr/bin/ccache /usr/local/bin/g++
|
||||
|
||||
RUN locale-gen en_US.UTF-8
|
||||
|
||||
ARG docker_user="bts"
|
||||
ARG docker_uid="1000"
|
||||
ARG docker_pass="bts"
|
||||
|
||||
RUN \
|
||||
groupadd -g "$docker_uid" "$docker_user" \
|
||||
&& useradd \
|
||||
-m \
|
||||
-u "$docker_uid" \
|
||||
-g "$docker_uid" \
|
||||
-G sudo \
|
||||
--password "$(openssl passwd -1 "$docker_pass")" \
|
||||
"$docker_user"
|
||||
|
||||
RUN usermod -aG docker "$docker_user"
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"dockerFile": "Dockerfile",
|
||||
// Creates local dir to mount to HOME in docker
|
||||
"initializeCommand": "mkdir -p ${localEnv:HOME}/.bts/devcontainer-mounts/${devcontainerId}",
|
||||
"hostRequirements": {
|
||||
"memory": "4gb",
|
||||
"storage": "6gb"
|
||||
},
|
||||
"postCreateCommand": "/home/bts/spark/docker/sparkd/dev/devcontainer_post_create.sh",
|
||||
"containerUser": "bts",
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/home/bts/spark,type=bind",
|
||||
"workspaceFolder": "/home/bts/spark",
|
||||
"updateRemoteUserUID": true,
|
||||
"shutdownAction": "none",
|
||||
// Note: If running multiple containers on the same host, each must use a
|
||||
// unique set of ports. Usually we just add 1000 to each port as needed. For
|
||||
// example, if 8000-8003 is taken, go with 9000-9003, then 10000-10003, etc.
|
||||
"runArgs": [
|
||||
"--shm-size",
|
||||
"2gb",
|
||||
"--network",
|
||||
"host"
|
||||
],
|
||||
"mounts": [
|
||||
"source=${localEnv:HOME}/.bts/devcontainer-mounts/${devcontainerId},target=/home/bts,type=bind",
|
||||
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"clangd.arguments": [
|
||||
"--compile-commands-dir=${workspaceFolder}/build/clang/debug"
|
||||
]
|
||||
},
|
||||
"extensions": [
|
||||
"eamodio.gitlens",
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"ms-vscode.cmake-tools",
|
||||
"ms-vscode.cpptools"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -42,7 +42,7 @@ trace_data/
|
||||
/.ignore
|
||||
*.rej
|
||||
.clangd/
|
||||
*CMakeDeps.cmake
|
||||
*CMakeDeps*.cmake
|
||||
/sniper.ipynb
|
||||
/src/.clang-format
|
||||
/src/server/sparkd/cmds/spartan/analysis/.ipynb_checkpoints
|
||||
|
||||
+3
-6
@@ -1,9 +1,6 @@
|
||||
[submodule "externals"]
|
||||
path = externals
|
||||
url = git@bitbucket.org:bluetradesys/externals.git
|
||||
[submodule "docker/linux"]
|
||||
path = docker/linux
|
||||
url = git@bitbucket.org:bluetradesys/linux_docker.git
|
||||
[submodule "docker/windows"]
|
||||
path = docker/windows
|
||||
url = git@bitbucket.org:bluetradesys/windows_docker.git
|
||||
[submodule "vcpkg"]
|
||||
path = vcpkg
|
||||
url = https://github.com/microsoft/vcpkg.git
|
||||
+25
-76
@@ -1,5 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(spark)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if(WIN32)
|
||||
set(platform "windows")
|
||||
@@ -13,101 +14,49 @@ set(
|
||||
CACHE
|
||||
STRING
|
||||
"External dependencies root folder (should contain folders: lib, bin, include")
|
||||
set(SPARK_PYTHON "${EXTERNALS_ROOT}/python")
|
||||
set(SPARK_BIN "${EXTERNALS_ROOT}/bin")
|
||||
set(SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
|
||||
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
|
||||
set(EXTERNALS_BIN "${EXTERNALS_ROOT}/bin")
|
||||
set(EXTERNALS_INCLUDE "${EXTERNALS_ROOT}/include")
|
||||
set(EXTERNALS_LIB "${EXTERNALS_ROOT}/lib/$<CONFIG>")
|
||||
set(BUILD_DOCS OFF CACHE BOOL "Build documentation")
|
||||
set(BUILD_SDK OFF CACHE BOOL "Build the sdk")
|
||||
set(BUILD_WEB ON CACHE BOOL "Build the web server")
|
||||
set(EXPORT_MD_CONSUMER OFF CACHE BOOL "Export (extern) C functions for MD consumer interop")
|
||||
if (WIN32)
|
||||
set(BUILD_SPARKD OFF CACHE BOOL "Build sparkd")
|
||||
set(BUILD_WEB OFF CACHE BOOL "Build the web server")
|
||||
else()
|
||||
set(BUILD_SPARKD ON CACHE BOOL "Build sparkd")
|
||||
set(BUILD_WEB ON CACHE BOOL "Build the web server")
|
||||
endif()
|
||||
|
||||
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
|
||||
link_directories(${SPARK_LIB})
|
||||
include_directories(BEFORE SYSTEM ${EXTERNALS_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
|
||||
link_directories(${EXTERNALS_LIB})
|
||||
|
||||
add_compile_definitions(EXPORT_MD_CONSUMER="${EXPORT_MD_CONSUMER}")
|
||||
if(WIN32)
|
||||
# flags
|
||||
set(
|
||||
CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
/MP \
|
||||
/WX /wd4251 /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 \
|
||||
/bigobj \
|
||||
/DCURL_STATICLIB \
|
||||
/D_WINSOCK_DEPRECATED_NO_WARNINGS \
|
||||
/D__TBB_NO_IMPLICIT_LINKAGE \
|
||||
/DBOOST_ALL_NO_LIB \
|
||||
/std:c++17 \
|
||||
/D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} /MT")
|
||||
set(
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELEASE
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_RELEASE} \
|
||||
/DEBUG \
|
||||
/OPT:REF \
|
||||
/OPT:ICF \
|
||||
/LTCG")
|
||||
|
||||
# subdirs
|
||||
add_subdirectory(src/lib)
|
||||
else()
|
||||
# make sparkd look for libspark.so in its directory
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH ".")
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install/${CMAKE_BUILD_TYPE}/sparkd")
|
||||
add_compile_definitions(SPARK_ENABLE_CCAPI)
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_FTX)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_DERIBIT)
|
||||
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
|
||||
|
||||
# flags
|
||||
set(
|
||||
CMAKE_CXX_FLAGS_DEBUG
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} \
|
||||
-fPIC \
|
||||
-Wall \
|
||||
-pedantic \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
-Wno-missing-braces \
|
||||
-Wno-ignored-qualifiers \
|
||||
--std=c++17 -fdiagnostics-color")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -DNDEBUG -O3")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wno-undef")
|
||||
|
||||
# subdirs
|
||||
add_subdirectory(src/server/sparkd)
|
||||
if (BUILD_SPARKD)
|
||||
add_subdirectory(src/server/sparkd)
|
||||
add_subdirectory(src/data_files)
|
||||
endif()
|
||||
add_subdirectory(src/lib)
|
||||
if (BUILD_WEB)
|
||||
add_subdirectory(src/web)
|
||||
endif()
|
||||
add_subdirectory(doc/user)
|
||||
if(BUILD_DOCS)
|
||||
add_subdirectory(doc/user)
|
||||
endif()
|
||||
if(BUILD_SDK)
|
||||
add_subdirectory(src/sdk)
|
||||
endif()
|
||||
add_subdirectory(src/data_files)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/server/sparkd/sparkd ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/web ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/data_files ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND
|
||||
ln ARGS -sf
|
||||
${EXTERNALS_ROOT}/lib/Release/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0
|
||||
${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libACE-5.7.5.so ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
|
||||
COMMENT "Creating server runtime layout"
|
||||
DEPENDS sparkd data_files_dir)
|
||||
|
||||
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
|
||||
|
||||
install(DIRECTORY "${CMAKE_BINARY_DIR}/server/plugins" DESTINATION bin)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libACE-5.7.5.so" DESTINATION bin)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0" DESTINATION bin)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/src/emumba/sparkd.lic" DESTINATION bin)
|
||||
endif()
|
||||
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"version": 4,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 23,
|
||||
"patch": 0
|
||||
},
|
||||
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "spark",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"environment": {
|
||||
"SPARK_CMAKE_CXX_FLAGS": "/MP /WX /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 /bigobj /EHsc /DCURL_STATICLIB /D_WINSOCK_DEPRECATED_NO_WARNINGS /D__TBB_NO_IMPLICIT_LINKAGE /DBOOST_ALL_NO_LIB /std:c++20 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "$env{SPARK_CMAKE_CXX_FLAGS}",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "$env{SPARK_CMAKE_CXX_FLAGS} /MTd",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "$env{SPARK_CMAKE_CXX_FLAGS} /MT",
|
||||
"CMAKE_CXX_STANDARD": "20",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
|
||||
"CMAKE_SHARED_LINKER_FLAGS_DEBUG": "/DEBUG",
|
||||
"CMAKE_SHARED_LINKER_FLAGS_RELEASE": "/OPT:REF /OPT:ICF /LTCG",
|
||||
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
||||
"EXTERNALS_ROOT": "${sourceDir}/externals/windows",
|
||||
"CONFIG_DEFAULTS_PATH": "config/defaults/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0;${sourceDir}/build/$<CONFIG>/bin/net7.0-windows",
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"hidden": true,
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"platform": "",
|
||||
"CMAKE_CXX_STANDARD": "20",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
|
||||
"CMAKE_EXE_LINKER_FLAGS": "-Wno-undef",
|
||||
"CONFIG_DEFAULTS_PATH": "config/defaults/*.conf",
|
||||
"EXTERNALS_ROOT": "${sourceDir}/externals/linux",
|
||||
"BUILD_SDK": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
},
|
||||
"BUILD_ADMIN_WEB_APP": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug",
|
||||
"inherits": "sparkd",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"CCAPI_LOG_LEVEL": "Info"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-release",
|
||||
"inherits": "sparkd",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CCAPI_LOG_LEVEL": "Warn"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug-clang",
|
||||
"inherits": "sparkd-debug",
|
||||
"displayName": "Sparkd (Debug | Clang)",
|
||||
"description": "Debug build compiled w/ clang",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -DDEBUG"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug-gcc",
|
||||
"inherits": "sparkd-debug",
|
||||
"displayName": "Sparkd (Debug | Gcc)",
|
||||
"description": "Debug build compiled w/ gcc",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "g++",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -Wno-stringop-overread -DDEBUG"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-release-clang",
|
||||
"inherits": "sparkd-release",
|
||||
"displayName": "Sparkd (Release | Clang)",
|
||||
"description": "Release build compiled w/ clang",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-release-gcc",
|
||||
"inherits": "sparkd-release",
|
||||
"displayName": "Sparkd (Release | Gcc)",
|
||||
"description": "Release build compiled w/ gcc",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "g++",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers -Wno-stringop-overflow --std=c++20 -fdiagnostics-color -Wno-stringop-overread -Wno-maybe-uninitialized -fno-omit-frame-pointer -DNDEBUG -O3"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "spark",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
{
|
||||
"name": "spark-debug",
|
||||
"displayName": "Spark (Debug)",
|
||||
"inherits": "spark",
|
||||
"configurePreset": "spark",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "spark-release",
|
||||
"displayName": "Spark (Release)",
|
||||
"inherits": "spark",
|
||||
"configurePreset": "spark",
|
||||
"configuration": "Release"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug-clang",
|
||||
"configurePreset": "sparkd-debug-clang",
|
||||
"displayName": "Sparkd (Debug | Clang)",
|
||||
"inherits": "sparkd"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug-clang-j6",
|
||||
"configurePreset": "sparkd-debug-clang",
|
||||
"displayName": "Sparkd (Debug | Clang | jobs=6)",
|
||||
"inherits": "sparkd",
|
||||
"jobs": 6
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-debug-gcc",
|
||||
"configurePreset": "sparkd-debug-gcc",
|
||||
"displayName": "Sparkd (Debug | Gcc)",
|
||||
"inherits": "sparkd"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-release-clang",
|
||||
"configurePreset": "sparkd-release-clang",
|
||||
"displayName": "Sparkd (Release | Clang)",
|
||||
"inherits": "sparkd"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sparkd-release-gcc",
|
||||
"configurePreset": "sparkd-release-gcc",
|
||||
"displayName": "Sparkd (Release | Gcc)",
|
||||
"inherits": "sparkd"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/PackBasic.cmake)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
function(install_basic)
|
||||
set(_options)
|
||||
set(_one_value_args)
|
||||
set(_multi_value_args HEADERS)
|
||||
cmake_parse_arguments(_ARGS "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
|
||||
if (_ARGS_HEADERS)
|
||||
set(${PROJECT_NAME}_HEADERS ${_ARGS_HEADERS})
|
||||
else()
|
||||
file(
|
||||
GLOB_RECURSE ${PROJECT_NAME}_HEADERS
|
||||
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
*.h
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
FILE_SET HEADERS FILES ${${PROJECT_NAME}_HEADERS})
|
||||
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}Targets
|
||||
FILE ${PROJECT_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
|
||||
pack_basic()
|
||||
endfunction()
|
||||
@@ -0,0 +1,36 @@
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
function(pack_basic)
|
||||
find_package(Git QUIET)
|
||||
|
||||
if(GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE PROJECT_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT GIT_FOUND OR PROJECT_VERSION STREQUAL "")
|
||||
set(PROJECT_VERSION "0.0.0")
|
||||
endif()
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
endfunction()
|
||||
@@ -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,5 +1,5 @@
|
||||
set(Protobuf_PROTOC_EXECUTABLE "${SPARK_BIN}/protoc")
|
||||
set(PROTOBUF_INCLUDE_DIRS "${SPARK_INCLUDE}")
|
||||
set(Protobuf_PROTOC_EXECUTABLE "${EXTERNALS_BIN}/protoc")
|
||||
set(PROTOBUF_INCLUDE_DIRS "${EXTERNALS_INCLUDE}")
|
||||
set(PROTOBUF_STATIC_LIB "libprotobuf")
|
||||
|
||||
function(Protobuf_Generate_Cpp SRCS HDRS)
|
||||
|
||||
File renamed without changes.
-1
Submodule docker/linux deleted from 6537812262.
Submodule docker/windows deleted from de7d40c09d.
+1
-1
Submodule externals updated: 4a3e40193e...800873c856.
@@ -4,8 +4,6 @@ VisualStudioVersion = 17.3.32922.545
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\sparkcmd\sparkcmd.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
|
||||
@@ -13,9 +11,6 @@ EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25} = {FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
EndProject
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace mbts.spark {
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
using bts.collections;
|
||||
using bts.reactive;
|
||||
using bts.utils;
|
||||
|
||||
using mbts;
|
||||
@@ -17,7 +18,6 @@ namespace mbts.spark {
|
||||
using Spark.Core;
|
||||
using Spark.Core.Collections;
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Reactive;
|
||||
using Spark.ViewModel.Commands;
|
||||
|
||||
using System;
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
|
||||
using mbts;
|
||||
using mbts.analytics;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
|
||||
// For each vs, it sends the vol surface calc request (_do_periodic_auto_fit)
|
||||
// and then commits the response
|
||||
public class SingleVolSurfaceAutoFitSource : IDisposable {
|
||||
private readonly ThreadedBlackboard _bb;
|
||||
private readonly int _vs_id;
|
||||
private readonly ITag<VolSurfaceInput> _vs_input_tag;
|
||||
private readonly ITag<VolSurfaceCalculationResponse> _vs_calc_response_tag;
|
||||
private DateTime _last_req_time = DateTime.MinValue;
|
||||
private TimeSpan _req_period = TimeSpan.MaxValue;
|
||||
private int _req_id = 0;
|
||||
public SingleVolSurfaceAutoFitSource(int vs_id, ThreadedBlackboard bb) {
|
||||
_bb = bb;
|
||||
_vs_id = vs_id;
|
||||
_vs_input_tag = SparkTags.VolSurfaceCommittedInputTag(vs_id);
|
||||
_vs_calc_response_tag = SparkTags.VolSurfaceAutoCalculationResponseTag(vs_id);
|
||||
_bb.subscribe(_vs_input_tag);
|
||||
_bb.subscribe(_vs_calc_response_tag);
|
||||
_bb.subscribe(SparkTags.CurrentUser);
|
||||
_bb.data_callback += _on_bb_data;
|
||||
_bb.timer_callback += _on_bb_timer;
|
||||
}
|
||||
|
||||
private void _on_bb_data(object tag, object data) {
|
||||
if (tag.Equals(_vs_input_tag))
|
||||
_possibly_autofit();
|
||||
else if (tag.Equals(_vs_calc_response_tag)) {
|
||||
VolSurfaceCalculationResponse calc_resp = data as VolSurfaceCalculationResponse;
|
||||
bts.Log.Gen.info($"SingleVolSurfaceAutoFitSource._on_bb_data vs_id: {_vs_id} " +
|
||||
$"received calculation response");
|
||||
_bb.post(SparkTags.VolSurfaceCommitTag(_vs_id),
|
||||
calc_resp.volsurface_calculation_output.volsurface_input);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _user_has_vs_control() {
|
||||
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
|
||||
string current_user = _bb.read_state(SparkTags.CurrentUser).name;
|
||||
return vs_input != null &&
|
||||
vs_input.surface_settings.core_settings.vs_manager == current_user;
|
||||
}
|
||||
|
||||
private void _on_bb_timer() {
|
||||
_possibly_autofit();
|
||||
}
|
||||
|
||||
private void _possibly_autofit() {
|
||||
var auto_fit_period = _get_auto_fit_periodic();
|
||||
if (!auto_fit_period.HasValue)
|
||||
return;
|
||||
if (DateTime.Now - _last_req_time <= auto_fit_period)
|
||||
return;
|
||||
if (!_user_has_vs_control())
|
||||
return;
|
||||
// auto fit here
|
||||
bts.Log.Gen.info($"SingleVolSurfaceAutoFitSource vs_id: {_vs_id} requesting fit " +
|
||||
$"last_req_time: {_last_req_time} period: {auto_fit_period.Value}");
|
||||
_send_request();
|
||||
}
|
||||
|
||||
private Nullable<TimeSpan> _get_auto_fit_periodic() {
|
||||
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
|
||||
if (vs_input == null)
|
||||
return null;
|
||||
var fit_settings =
|
||||
VolSurfaceDataFunctions.get_market_fit_settings(vs_input.surface_settings);
|
||||
if (fit_settings == null)
|
||||
return null;
|
||||
var auto_fit_setting = fit_settings.vs_auto_fit_settings;
|
||||
if (auto_fit_setting == null)
|
||||
return null;
|
||||
if (auto_fit_setting.auto_fit_region == VolSurfaceEnums.VolCurveFitRegion.None)
|
||||
return null;
|
||||
var time_based_fit_setting = auto_fit_setting.time_based_settings;
|
||||
if (time_based_fit_setting == null)
|
||||
return null;
|
||||
if (!time_based_fit_setting.period_seconds.HasValue)
|
||||
return null;
|
||||
return TimeSpan.FromSeconds(time_based_fit_setting.period_seconds.Value);
|
||||
}
|
||||
|
||||
private void _send_request() {
|
||||
VolSurfaceInput vs_input = _bb.read_state(_vs_input_tag);
|
||||
if (vs_input == null)
|
||||
return;
|
||||
VolCurveMarketFitAction mf_action = new VolCurveMarketFitAction(
|
||||
VolCurveMarketFitAction.ActionType.FitWholeCurve, null, false);
|
||||
VolCurveAction vc_action = new VolCurveAction(mf_action);
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
|
||||
vs_input.surface_parameters.curve_parameters_map.ToDictionary(
|
||||
i => i.Item1,
|
||||
i => vc_action
|
||||
);
|
||||
VolSurfaceCalculationRequest req = new VolSurfaceCalculationRequest(vs_input,
|
||||
_req_id++, action_map, true, true);
|
||||
_last_req_time = DateTime.Now;
|
||||
_bb.post(SparkTags.VolSurfaceAutoCalculationRequestTag(_vs_id), req);
|
||||
}
|
||||
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose() {
|
||||
_bb.data_callback -= _on_bb_data;
|
||||
_bb.timer_callback -= _on_bb_timer;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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,7 +4,6 @@
|
||||
using bts.api.analytics;
|
||||
|
||||
using mbts.analytics;
|
||||
using mbts.ui;
|
||||
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
@@ -14,7 +13,6 @@
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
// For a single VolSurface this class
|
||||
// 1. Listents to commmits and calls the service to persist data
|
||||
@@ -26,6 +24,7 @@
|
||||
private readonly ITag<VolSurfaceInput> _in_bb_committ_tag;
|
||||
private readonly AnalyticsService _analytics_service;
|
||||
private readonly HighPerformanceTimer _timer = new HighPerformanceTimer();
|
||||
private readonly string _user;
|
||||
private readonly List<IDisposable> _disposables = new List<IDisposable>();
|
||||
private IDictionary<UInt64, VolSurfaceInputSnapshot> _snp_shot_map = new
|
||||
Dictionary<UInt64, VolSurfaceInputSnapshot>();
|
||||
@@ -36,10 +35,10 @@
|
||||
volsurface_id));
|
||||
_volsurface_id = volsurface_id;
|
||||
_bb = threaded_bb;
|
||||
_user = "TEST_USER"; // TODO
|
||||
_in_bb_committ_tag = SparkTags.VolSurfaceCommitTag(volsurface_id);
|
||||
_analytics_service = analytics_service;
|
||||
_bb.subscribe(_in_bb_committ_tag);
|
||||
_bb.subscribe(SparkTags.CurrentUser);
|
||||
_bb.data_callback += _on_bb_data;
|
||||
var vs_sub = _analytics_service.subscribei_volsurfaces()
|
||||
.ObserveOn(SynchronizationContext.Current)
|
||||
@@ -55,10 +54,8 @@
|
||||
private void _on_vss(bts.api.core.Update<VolSurfaceEntryImmutable, UInt64> update) {
|
||||
IEnumerable<VolSurfaceEntryImmutable> all_vss = update.all;
|
||||
var this_vs_vss = all_vss.Where(vs => vs.VsId == _volsurface_id);
|
||||
bts.Log.Gen.info(
|
||||
$"SingleVolSurfaceGateway._on_vss vs_count: {this_vs_vss.Count()} " +
|
||||
$"all: {update.all.Count()} added: {update.added.Count()} " +
|
||||
$"updated: {update.changed.Count()} removed: {update.removed.Count()}");
|
||||
bts.Log.Gen.info(String.Format("SingleVolSurfaceGateway._on_vss count:{0} vs_count:{1}",
|
||||
all_vss.Count(), this_vs_vss.Count()));
|
||||
if (this_vs_vss.Count() == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -86,39 +83,22 @@
|
||||
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) =>
|
||||
ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs.Volsurface.ToByteArray());
|
||||
|
||||
// private void _show_save_error(string message) {
|
||||
// BTSMessageBox.Show(message, "Vol Save Error", BTSMessageBoxButtons.OK);
|
||||
// }
|
||||
|
||||
private void _on_bb_data(object tag, object data) {
|
||||
if (_in_bb_committ_tag.Equals(tag)) {
|
||||
try {
|
||||
_timer.start();
|
||||
VolSurfaceInput vs_input = data as VolSurfaceInput;
|
||||
var user_tup = _bb.read_state(SparkTags.CurrentUser);
|
||||
string current_user = user_tup.name;
|
||||
string vs_manager = vs_input.surface_settings.core_settings.vs_manager;
|
||||
if (current_user != vs_manager) {
|
||||
string msg = $"User {current_user} does not have the permission to save vols. " +
|
||||
$"Permission can be obtained via the grid context menu item 'Acquire ownership from {vs_manager}'";
|
||||
BTSMessageBox.Show(msg, "Vol Save Error", BTSMessageBoxButtons.OK);
|
||||
return;
|
||||
}
|
||||
_sanitize_input(ref vs_input);
|
||||
vs_input = VolSurfaceDataFunctions.unset_driver_overrides(vs_input);
|
||||
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, current_user);
|
||||
vs_input.saver_login = _user;
|
||||
VolSurfaceUtilityFunctions.save_volsurface(vs_input, _analytics_service, _user);
|
||||
_timer.stop();
|
||||
Log.Gen.info(String.Format(
|
||||
"SingleVolSurfaceGateway._on_bb_data Time to commit volsurface {0} {1} msecs",
|
||||
_volsurface_id, _timer.lastIntervalTime));
|
||||
var archived_theos = _get_theos();
|
||||
if (archived_theos != null) {
|
||||
_timer.start();
|
||||
if (archived_theos != null)
|
||||
_analytics_service.archive_theos(archived_theos);
|
||||
_timer.stop();
|
||||
Log.Gen.info($"SingleVolSurfaceGateway._on_bb_data archiving theos size: " +
|
||||
$"{archived_theos.SecTheo.Count} time: {_timer.lastIntervalTime} msecs");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.Gen.warn(ex.ToString());
|
||||
_bb.post(SparkTags.MessageDisplayTag,
|
||||
|
||||
@@ -36,11 +36,7 @@ namespace mbts.spark {
|
||||
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Committed, _vs_id, _bb,
|
||||
a_syms => new SingleVolSurfaceCommittedOutputRetriever(_vs_id, _bb, a_syms)),
|
||||
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Combined, _vs_id, _bb,
|
||||
a_syms => new SingleVolSurfaceRequestCalculator(
|
||||
SingleVolSurfaceRequestCalculator.RequestType.UI, _vs_id, a_syms, _bb)),
|
||||
new SingleVolSurfaceDataSource(SingleVolSurfaceDataSource.SymbolListType.Combined, _vs_id, _bb,
|
||||
a_syms => new SingleVolSurfaceRequestCalculator(
|
||||
SingleVolSurfaceRequestCalculator.RequestType.AUTO, _vs_id, a_syms, _bb)),
|
||||
a_syms => new SingleVolSurfaceRequestCalculator(_vs_id, a_syms, _bb)),
|
||||
new SingleVolSurfaceMarketImpliedVolSource(_vs_id, _bb),
|
||||
// new SingleVolSurfaceTheoSource(_vs_id, _bb),
|
||||
// TODO: suspending heatmaps for now (12/24/21)
|
||||
@@ -48,7 +44,6 @@ namespace mbts.spark {
|
||||
// server work that can optionally be done on the client
|
||||
new SingleVolSurfaceDataSource (SingleVolSurfaceDataSource.SymbolListType.Committed, _vs_id, _bb,
|
||||
a_syms => new SingleVolSurfaceInterpGreeksPublisher (_vs_id, _bb, a_syms)),
|
||||
new SingleVolSurfaceAutoFitSource(_vs_id, _bb),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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.diag($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
|
||||
bts.Log.Gen.info($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
|
||||
"publishing VolSurfaceNonVolData");
|
||||
_bb.post(_out_bb_vs_nonvol_data_tag,
|
||||
new VolSurfaceNonVolData(
|
||||
|
||||
@@ -18,16 +18,10 @@ namespace mbts.spark {
|
||||
// Pubs :
|
||||
// 1. Calc Resp
|
||||
public class SingleVolSurfaceRequestCalculator : IDisposable {
|
||||
public enum RequestType {
|
||||
UI = 0,
|
||||
AUTO
|
||||
}
|
||||
private readonly RequestType _request_type = RequestType.UI;
|
||||
private readonly int _vs_id;
|
||||
private readonly HashSet<string> _symbols;
|
||||
private readonly ThreadedBlackboard _bb;
|
||||
private readonly ITag<VolSurfaceCalculationRequest> _in_bb_request_tag;
|
||||
private readonly ITag<VolSurfaceCalculationRequest> _in_bb_auto_request_tag;
|
||||
private readonly ITag<VolSurfaceNonVolData> _in_bb_nonvol_data_tag;
|
||||
private readonly ITag<VolSurfaceStandardTime> _in_bb_vs_standard_time_tag;
|
||||
private readonly ITag<VolSurfaceEnums.MarketSide> _in_bb_market_impliedvol_side_tag;
|
||||
@@ -36,22 +30,18 @@ namespace mbts.spark {
|
||||
/// data
|
||||
private VolSurfaceOutput _last_output;
|
||||
|
||||
public SingleVolSurfaceRequestCalculator(RequestType request_type,
|
||||
int vs_id, IEnumerable<string> symbols,
|
||||
public SingleVolSurfaceRequestCalculator(int vs_id, IEnumerable<string> symbols,
|
||||
ThreadedBlackboard threaded_bb) {
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id} request_type: {request_type}");
|
||||
_request_type = request_type;
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id}");
|
||||
_vs_id = vs_id;
|
||||
_symbols = new HashSet<string>(symbols);
|
||||
_bb = threaded_bb;
|
||||
_in_bb_request_tag = SparkTags.VolSurfaceCalculationRequestTag(vs_id);
|
||||
_in_bb_auto_request_tag = SparkTags.VolSurfaceAutoCalculationRequestTag(vs_id);
|
||||
_in_bb_nonvol_data_tag = SparkTags.VolSurfaceNonVolDataTag(vs_id);
|
||||
_in_bb_vs_standard_time_tag = SparkTags.VolSurfaceStandardTimeTag(vs_id);
|
||||
_in_bb_market_impliedvol_side_tag = SparkTags.VolSurfaceMarketImpliedVolSide(vs_id);
|
||||
_in_bb_dirty_tag = SparkTags.VolSurfaceDirtyStateTag(vs_id);
|
||||
_bb.subscribe(_in_bb_request_tag);
|
||||
_bb.subscribe(_in_bb_auto_request_tag);
|
||||
_bb.subscribe(_in_bb_nonvol_data_tag);
|
||||
_bb.subscribe(_in_bb_vs_standard_time_tag);
|
||||
_bb.subscribe(_in_bb_vs_standard_time_tag);
|
||||
@@ -61,21 +51,11 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
private void _on_bb_data(object tag, object data) {
|
||||
switch (_request_type) {
|
||||
case RequestType.UI: {
|
||||
if (_in_bb_request_tag.Equals(tag) || _in_bb_dirty_tag.Equals(tag))
|
||||
_recompute_and_publish(true);
|
||||
else if (_in_bb_nonvol_data_tag.Equals(tag) || _in_bb_vs_standard_time_tag.Equals(tag))
|
||||
_recompute_and_publish(false);
|
||||
break;
|
||||
}
|
||||
case RequestType.AUTO: {
|
||||
if (tag.Equals(_in_bb_auto_request_tag)) {
|
||||
_serve_auto_request();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_in_bb_request_tag.Equals(tag) || _in_bb_dirty_tag.Equals(tag))
|
||||
_recompute_and_publish(true);
|
||||
else if (_in_bb_nonvol_data_tag.Equals(tag) || _in_bb_vs_standard_time_tag.Equals(tag))
|
||||
_recompute_and_publish(false);
|
||||
|
||||
}
|
||||
|
||||
private void _recompute_and_publish(bool is_new_request) {
|
||||
@@ -100,7 +80,7 @@ namespace mbts.spark {
|
||||
nonvol_data.driver_price_map,
|
||||
vs_standard_time, true);
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
|
||||
_post_process_action(_bb, _vs_id, effective_req, aux_data_map);
|
||||
_post_process_action(effective_req, aux_data_map);
|
||||
_last_output = GeneralVolSurfaceCalculator.compute(effective_req.volsurface_input,
|
||||
nonvol_data.contracts,
|
||||
aux_data_map,
|
||||
@@ -109,49 +89,16 @@ namespace mbts.spark {
|
||||
effective_req.cascade_up,
|
||||
effective_req.cascade_down);
|
||||
_timer.stop();
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish vs_id: {_vs_id} " +
|
||||
$"time: {_timer.lastIntervalTime}");
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time: " +
|
||||
$"{_timer.lastIntervalTime}");
|
||||
_bb.post(SparkTags.VolSurfaceCalculationResponseTag(_vs_id),
|
||||
new VolSurfaceCalculationResponse(_last_output, effective_req.request_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _serve_auto_request() {
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._serve_auto_request " +
|
||||
$"vs_id: {_vs_id} auto request received");
|
||||
bool is_dirty = _bb.read_state(_in_bb_dirty_tag, false);
|
||||
VolSurfaceNonVolData nonvol_data = _bb.read_state(_in_bb_nonvol_data_tag);
|
||||
VolSurfaceStandardTime vs_standard_time = _bb.read_state(_in_bb_vs_standard_time_tag);
|
||||
VolSurfaceCalculationRequest auto_req = _bb.read_state(_in_bb_auto_request_tag);
|
||||
if (is_dirty || nonvol_data == null || vs_standard_time == null || auto_req == null) {
|
||||
return;
|
||||
}
|
||||
_timer.start();
|
||||
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map =
|
||||
VolSurfaceUtilityFunctions.compute_aux_data(auto_req.volsurface_input,
|
||||
nonvol_data.input,
|
||||
nonvol_data.driver_price_map,
|
||||
vs_standard_time, true);
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map =
|
||||
_post_process_action(_bb, _vs_id, auto_req, aux_data_map);
|
||||
var vs_output = GeneralVolSurfaceCalculator.compute(auto_req.volsurface_input,
|
||||
nonvol_data.contracts,
|
||||
aux_data_map,
|
||||
action_map,
|
||||
null,
|
||||
auto_req.cascade_up,
|
||||
auto_req.cascade_down);
|
||||
_timer.stop();
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._serve_auto_request vs_id: {_vs_id} " +
|
||||
$"time: {_timer.lastIntervalTime}");
|
||||
_bb.post(SparkTags.VolSurfaceAutoCalculationResponseTag(_vs_id),
|
||||
new VolSurfaceCalculationResponse(vs_output, auto_req.request_id));
|
||||
}
|
||||
|
||||
/// Computes the impl vol if the action is fit to market
|
||||
private static IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
|
||||
ThreadedBlackboard bb, int vs_id,
|
||||
private IDictionary<VolSurfaceExpiration, VolCurveAction> _post_process_action(
|
||||
VolSurfaceCalculationRequest req,
|
||||
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map) {
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> rv = req.action_map;
|
||||
@@ -162,7 +109,7 @@ namespace mbts.spark {
|
||||
VolCurveAction rep_action = rv.ElementAt(0).Value;
|
||||
if (rep_action.action_type == VolCurveAction.ActionType.FitToMarket) {
|
||||
IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> impl_vol_map =
|
||||
_fill_in_implied_vols(bb, vs_id, req.volsurface_input, req.action_map, aux_data_map,
|
||||
_fill_in_implied_vols(req.volsurface_input, req.action_map, aux_data_map,
|
||||
req.cascade_up, req.cascade_down);
|
||||
rv = impl_vol_map.ToDictionary(kv => kv.Key, kv => new VolCurveAction(
|
||||
new VolCurveMarketFitAction(rep_action.market_fit_action.fit_action, kv.Value,
|
||||
@@ -172,8 +119,7 @@ namespace mbts.spark {
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
|
||||
ThreadedBlackboard bb, int vs_id,
|
||||
private IDictionary<VolSurfaceExpiration, VolCurveMarketImpliedVolData> _fill_in_implied_vols(
|
||||
VolSurfaceInput vs_inp,
|
||||
IDictionary<VolSurfaceExpiration, VolCurveAction> action_map,
|
||||
IDictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData> aux_data_map,
|
||||
@@ -194,15 +140,15 @@ namespace mbts.spark {
|
||||
applicable_exps = applicable_exps.Where(vs_exp => master_exps.Contains(vs_exp));
|
||||
|
||||
VolSurfaceEnums.MarketSide impliedvol_side =
|
||||
SingleVolSurfaceMarketImpliedVolSource._get_market_impliedvol_side(bb, vs_id);
|
||||
SingleVolSurfaceMarketImpliedVolSource._get_market_impliedvol_side(_bb, _vs_id);
|
||||
foreach (VolSurfaceExpiration vs_exp in applicable_exps) {
|
||||
VolSurfaceExpiration md_exp;
|
||||
VolCurveMarketImpliedVolData exp_impl_data =
|
||||
VolSurfaceCoreFunctions.compute_implied_vols(vs_inp, vs_exp, aux_data_map,
|
||||
arg_vs_exp => SingleVolSurfaceMarketImpliedVolSource.get_option_bbo(bb, arg_vs_exp),
|
||||
arg_vs_exp => SingleVolSurfaceMarketImpliedVolSource.get_option_bbo(_bb, arg_vs_exp),
|
||||
impliedvol_side,
|
||||
SingleVolSurfaceMarketImpliedVolSource._ignore_market_implied_vol_source_settings(
|
||||
bb, vs_id),
|
||||
_bb, _vs_id),
|
||||
out md_exp);
|
||||
rv[vs_exp] = exp_impl_data;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace mbts.analytics {
|
||||
output.Add(symbol, symbol_data);
|
||||
}
|
||||
IReadOnlyDictionary<string, TData> ro_output = output;
|
||||
bts.Log.Gen.diag($"SymbolAggregationPublisher._on_timer publishing " +
|
||||
bts.Log.Gen.info($"SymbolAggregationPublisher._on_timer publishing " +
|
||||
$"tag: {_out_tag} sz: {ro_output.Count}");
|
||||
_bb.post(_out_tag, ro_output);
|
||||
}
|
||||
|
||||
@@ -270,7 +270,6 @@ namespace mbts.spark {
|
||||
new mbts.analytics.VolSurfaceNonVolInput(exp_param_map.exp_map.ToDictionary()));
|
||||
} else if (_in_bb_req_vol.Equals(tag)) {
|
||||
ClientArchivedVolRequest client_req = _bb.read_state(_in_bb_req_vol);
|
||||
bts.Log.Ui.info($"VolSurfaceBusManager._on_bb_update ClientArchivedVolRequest: {client_req.ToString()}");
|
||||
ArchivedTheoRetrieval ret = client_req.ret;
|
||||
if (ret == null || ret.SecTup == null) {
|
||||
bts.Log.Ui.warn($"VolSurfaceBusManager malformed ArchivedTheoRetrieval");
|
||||
|
||||
@@ -5,7 +5,6 @@ using bts.api;
|
||||
using bts.collections;
|
||||
using System.Linq;
|
||||
using bts.api.orderman;
|
||||
using bts.api.analytics;
|
||||
using bts;
|
||||
|
||||
namespace mbts.spark {
|
||||
@@ -24,8 +23,6 @@ namespace mbts.spark {
|
||||
_order_service = order_service;
|
||||
_bb.subscribe(SparkTags.AllInterpGreeks);
|
||||
_bb.subscribe(SparkTags.SystemContractsTag);
|
||||
_bb.subscribe(SparkTags.CurrentUser);
|
||||
_bb.subscribe(SparkTags.VolSurfaceUsageTag);
|
||||
_bb.data_callback += _on_data;
|
||||
}
|
||||
|
||||
@@ -58,32 +55,10 @@ namespace mbts.spark {
|
||||
return rv;
|
||||
}
|
||||
|
||||
private IReadOnlyDictionary<string, OptionTheoInterpolationData>
|
||||
_filter_for_publish(IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos) {
|
||||
HashSet<string> syms = new HashSet<string>();
|
||||
VolSurfaceUsageListImmutable usage = _bb.read_state(SparkTags.VolSurfaceUsageTag);
|
||||
string current_user = _bb.read_state(SparkTags.CurrentUser).name;
|
||||
foreach (var u in usage.UsageList) {
|
||||
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.SymbolName);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 =
|
||||
_bb.read_state(SparkTags.AllInterpGreeks, null);
|
||||
all_theos = _filter_for_publish(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
|
||||
IReadOnlyDictionary<string, OptionDriverPriceMap> all_drivers =
|
||||
_bb.read_state(SparkTags.AllOptionDriverBBOTag, null);
|
||||
if (sc_data == null || all_theos == null || all_drivers == null)
|
||||
|
||||
@@ -26,13 +26,12 @@ namespace mbts.spark {
|
||||
_refresh = new(_is_dirty.refresh);
|
||||
_committed_value.Changed += on_committed_changed;
|
||||
_candidate_value.Changed += on_candidate_changed;
|
||||
if (column.type.is_editable()) {
|
||||
_is_dirty.Changed += (o, n) => {
|
||||
Log.Ui.info(
|
||||
$"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
|
||||
$"commited: {committed_value}; candidate: {candidate_value}");
|
||||
};
|
||||
}
|
||||
_is_dirty.Changed += (o, n) => {
|
||||
Log.assert(o != n);
|
||||
Log.Ui.info(
|
||||
$"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
|
||||
$"commited: {committed_value}; candidate: {candidate_value}");
|
||||
};
|
||||
|
||||
void on_committed_changed(object? oldval, object? newval) =>
|
||||
_is_dirty.refresh();
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace mbts.spark.VolSurface {
|
||||
|
||||
class VolSurfaceGridVM : DisposableViewModelBase {
|
||||
readonly VolSurfaceVM _parent;
|
||||
readonly UserTuple _user;
|
||||
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
|
||||
readonly DeferrableAction _invalidate_rows;
|
||||
readonly ColumnsModel _columns_model;
|
||||
@@ -42,12 +41,10 @@ namespace mbts.spark.VolSurface {
|
||||
VolSurfaceVM vm,
|
||||
VolSurfaceDisplayModel model,
|
||||
ISet<string> hidden_columns,
|
||||
ISet<VolSurfaceExpiration> hidden_expirations,
|
||||
UserTuple user) {
|
||||
ISet<VolSurfaceExpiration> hidden_expirations) {
|
||||
Log.notnull(hidden_columns);
|
||||
Log.notnull(hidden_expirations);
|
||||
_parent = vm;
|
||||
_user = user;
|
||||
this.model = model;
|
||||
_columns_model = new(create_exp_column_view());
|
||||
_hidden_columns = hidden_columns;
|
||||
@@ -86,7 +83,7 @@ namespace mbts.spark.VolSurface {
|
||||
_columns_model);
|
||||
|
||||
VolSurfaceRowVM row_factory(VolSurfaceDisplayGridExpiration exp) =>
|
||||
new(this, exp, _user);
|
||||
new(this, exp);
|
||||
|
||||
IDisposable connect_row(VolSurfaceRowVM row) {
|
||||
row.request_calculate += request_recalc;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using mbts.spark.VolSurface;
|
||||
@@ -10,7 +9,6 @@ namespace mbts.spark {
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Reactive;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -24,10 +22,6 @@ namespace mbts.spark {
|
||||
readonly VolSurfaceGridVM _parent;
|
||||
readonly Property<VolSurfaceColumn?> _column;
|
||||
readonly Property<DIYGridSuperHeaderVM?> _super_header;
|
||||
readonly UserTuple _user;
|
||||
readonly Property<bool> _is_open;
|
||||
readonly DelegateProperty<string> _vs_manager;
|
||||
readonly List<IDisposable> _resources = new();
|
||||
|
||||
ICommand? _revert_cmd;
|
||||
ICommand? _shift_selection_cmd;
|
||||
@@ -40,29 +34,21 @@ namespace mbts.spark {
|
||||
ICommand? _copy_all_to_clipboard_cmd;
|
||||
ICommand? _smart_copy_rolls_rates_cmd;
|
||||
ICommand? _import_csv_cmd;
|
||||
ObservantCommand? _acquire_ownership_cmd;
|
||||
|
||||
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row, UserTuple user) {
|
||||
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row) {
|
||||
_parent = parent;
|
||||
_row = row;
|
||||
_user = user;
|
||||
_column = backing<VolSurfaceColumn?>(nameof(column));
|
||||
_super_header = backing<DIYGridSuperHeaderVM?>(nameof(super_header));
|
||||
_vs_manager = backing(
|
||||
nameof(vs_manager),
|
||||
() => _parent.model.get_active_settings()?.core_settings?.vs_manager ?? string.Empty);
|
||||
_is_open = backing(nameof(is_open), false);
|
||||
|
||||
_resources.AddRange(
|
||||
_dispose = Disposable.Create(
|
||||
_column.invalidate_others_on_change(nameof(column_name)),
|
||||
_super_header.invalidate_others_on_change(nameof(group_name)),
|
||||
_is_open.Subscribe(_ => _vs_manager.refresh()),
|
||||
_parent.visible_rows.ObserveSelf()
|
||||
.BufferLatest(TimeSpan.FromSeconds(1))
|
||||
.OnDispatcher()
|
||||
.Subscribe(_ => sync_symbols()));
|
||||
|
||||
_dispose = Disposable.Create(() => _resources.DisposeAll(true));
|
||||
void sync_symbols() {
|
||||
var visible_exps = _parent.visible_rows.Map(r => r.expiration.symbol);
|
||||
symbols.sync_with_models(
|
||||
@@ -178,34 +164,6 @@ namespace mbts.spark {
|
||||
_parent.model.csv_importing_enabled,
|
||||
null);
|
||||
|
||||
public ICommand acquire_ownership_cmd {
|
||||
get {
|
||||
if (_acquire_ownership_cmd is null) {
|
||||
_acquire_ownership_cmd = new(
|
||||
() => {
|
||||
var settings = _parent.model.get_active_settings();
|
||||
if (settings is null) {
|
||||
Log.Ui.error("Unable to acquire volsurface ownership: settings are null.");
|
||||
return;
|
||||
}
|
||||
settings.core_settings.vs_manager = _user.name;
|
||||
_parent.model.set_candidate_settings(settings);
|
||||
});
|
||||
_resources.Add(_vs_manager.observe_current(true)
|
||||
.Subscribe(SelectorObserver.builder(_acquire_ownership_cmd).wrap<string>(
|
||||
curr => curr != _user.name)));
|
||||
}
|
||||
return _acquire_ownership_cmd;
|
||||
}
|
||||
}
|
||||
|
||||
public bool is_open {
|
||||
get => _is_open.Value;
|
||||
set => _is_open.set(value);
|
||||
}
|
||||
|
||||
public string vs_manager => _vs_manager.Value;
|
||||
|
||||
VolSurfaceDisplayGridColumn _assert_model() =>
|
||||
column?.model ?? throw new InvalidOperationException();
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark.VolSurface {
|
||||
using bts;
|
||||
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
@@ -18,16 +16,14 @@ namespace mbts.spark.VolSurface {
|
||||
readonly VolSurfaceGridVM _parent;
|
||||
readonly VolSurfaceDisplayGridExpiration _exp;
|
||||
readonly Dictionary<string, CellData> _cells = new();
|
||||
readonly UserTuple _user;
|
||||
readonly DeferrableAction _request_calculate;
|
||||
|
||||
VolSurfaceRowContextMenuVM? _context_menu;
|
||||
bool _is_selected;
|
||||
|
||||
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp, UserTuple user) {
|
||||
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
|
||||
_parent = parent;
|
||||
_exp = exp;
|
||||
_user = user;
|
||||
_request_calculate = new(() => request_calculate?.Invoke());
|
||||
_dispose = Disposable.Create(() => {
|
||||
_cells.Values.DisposeAll();
|
||||
@@ -53,7 +49,7 @@ namespace mbts.spark.VolSurface {
|
||||
}
|
||||
|
||||
public VolSurfaceRowContextMenuVM context_menu =>
|
||||
_context_menu ??= new(_parent, this, _user);
|
||||
_context_menu ??= new(_parent, this);
|
||||
|
||||
public VolSurfaceCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
|
||||
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
namespace mbts.spark {
|
||||
using bts.api.domain;
|
||||
|
||||
using mbts.analytics;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using VolCurveFitRegion = analytics.VolSurfaceEnums.VolCurveFitRegion;
|
||||
|
||||
public class VolSurfaceAutoFitSettingsVM : DisposableViewModelBase {
|
||||
readonly Property<VolCurveFitRegion> _fit_region;
|
||||
readonly Property<uint?> _period_secs;
|
||||
readonly Property<double?> _driver_points_moved;
|
||||
readonly Property<double?> _atm_points_moved;
|
||||
readonly Property<bool> _is_auto_fit_enabled;
|
||||
|
||||
public VolSurfaceAutoFitSettingsVM() {
|
||||
_fit_region = backing(nameof(fit_region), VolCurveFitRegion.None);
|
||||
_is_auto_fit_enabled = backing(
|
||||
nameof(is_auto_fit_enabled),
|
||||
_fit_region.observe_current(true),
|
||||
r => r != VolCurveFitRegion.None);
|
||||
_period_secs = backing<uint?>(nameof(period_secs), 10);
|
||||
_driver_points_moved = backing<double?>(nameof(driver_points_moved));
|
||||
_atm_points_moved = backing<double?>(nameof(atm_points_moved));
|
||||
_fit_region.Changed += (o, n) => RaisePropertyChanged(nameof(is_auto_fit_enabled));
|
||||
}
|
||||
|
||||
public IEnumerable<VolCurveFitRegion> fit_regions =>
|
||||
EnumHelper.get_values<VolCurveFitRegion>();
|
||||
|
||||
public VolCurveFitRegion fit_region {
|
||||
get => _fit_region.Value;
|
||||
set => _fit_region.set(value);
|
||||
}
|
||||
|
||||
public bool is_auto_fit_enabled => _is_auto_fit_enabled.Value;
|
||||
|
||||
public uint? period_secs {
|
||||
get => _period_secs.Value;
|
||||
set => _period_secs.set(value);
|
||||
}
|
||||
|
||||
public double? driver_points_moved {
|
||||
get => _driver_points_moved.Value;
|
||||
set => _driver_points_moved.set(value);
|
||||
}
|
||||
|
||||
public TickDisplaySettingsImmutable? driver_points_display =>
|
||||
user.settings.TickFactors.pennies.to_api_tick_display_settingsi();
|
||||
|
||||
public double? atm_points_moved {
|
||||
get => _atm_points_moved.Value;
|
||||
set => _atm_points_moved.set(value);
|
||||
}
|
||||
|
||||
public TickDisplaySettingsImmutable? atm_points_display =>
|
||||
user.settings.TickFactors.pennies.to_api_tick_display_settingsi();
|
||||
|
||||
public void load_from(VolSurfaceAutoFitSettings value) {
|
||||
fit_region = value?.auto_fit_region ?? VolCurveFitRegion.None;
|
||||
period_secs = value?.time_based_settings?.period_seconds;
|
||||
driver_points_moved = value?.driver_move_based_settings?.points_moved;
|
||||
atm_points_moved = value?.atm_implied_vol_based_settings?.points_moved;
|
||||
}
|
||||
|
||||
public void assign_to(VolSurfaceAutoFitSettings value) {
|
||||
if (value is null) {
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
value.auto_fit_region = fit_region;
|
||||
value.time_based_settings = new() {
|
||||
period_seconds = period_secs
|
||||
};
|
||||
value.driver_move_based_settings = new() {
|
||||
points_moved = driver_points_moved
|
||||
};
|
||||
value.atm_implied_vol_based_settings = new() {
|
||||
points_moved = atm_points_moved
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,6 @@ namespace mbts.spark {
|
||||
vol_model_cubic_spline_vm.load_from(settings.spline_model_settings);
|
||||
vol_model_dual_quadratic_vm.load_from(settings.dualquadratic_model_settings);
|
||||
vol_path_parabolic_vm.load_from(settings.core_settings.volpath_settings.parabolic_vol_path_settings);
|
||||
auto_fit_vm.load_from(settings.core_settings.market_fit_settings.vs_auto_fit_settings);
|
||||
|
||||
init_rotation_vms(call_rotations, _core_settings.call_rotation.strike_vol_movement_pairs);
|
||||
init_rotation_vms(put_rotations, _core_settings.put_rotation.strike_vol_movement_pairs);
|
||||
@@ -106,7 +105,6 @@ namespace mbts.spark {
|
||||
}).ToList();
|
||||
_core_settings.strangle.strike_vol_movement_pairs = strangles.SelectMany(r => new[] { Tuple.Create(r.target_put_strike, r.put_move), Tuple.Create(r.target_call_strike, r.call_move) }).ToList();
|
||||
_core_settings.atm_shift.atm_strike_vol_movement = atm_shifts.Count == 1 ? atm_shifts[0].move : 0;
|
||||
auto_fit_vm.assign_to(_core_settings.market_fit_settings.vs_auto_fit_settings);
|
||||
commit(_settings);
|
||||
}
|
||||
|
||||
@@ -235,7 +233,23 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public VolSurfaceAutoFitSettingsVM auto_fit_vm { get; } = new();
|
||||
public bool enable_auto_fit {
|
||||
get => _core_settings.market_fit_settings.enable_auto_fit;
|
||||
set {
|
||||
using var _ = detect_property_change();
|
||||
_core_settings.market_fit_settings.enable_auto_fit = value;
|
||||
}
|
||||
}
|
||||
|
||||
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region {
|
||||
get => _core_settings.market_fit_settings.auto_fit_region;
|
||||
set { _core_settings.market_fit_settings.auto_fit_region = value; }
|
||||
}
|
||||
|
||||
public double auto_fit_time_ms {
|
||||
get => _core_settings.market_fit_settings.auto_fit_time_ms;
|
||||
set { _core_settings.market_fit_settings.auto_fit_time_ms = value; }
|
||||
}
|
||||
|
||||
public bool auto_decay_vol_time {
|
||||
get => _core_settings.time_settings.time_mode == VolSurfaceEnums.VolSurfaceTimeMode.AutoDecay;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.collections;
|
||||
|
||||
@@ -28,7 +27,6 @@ namespace mbts.spark {
|
||||
readonly IBus _bus;
|
||||
readonly string _request_id = Guid.NewGuid().ToString();
|
||||
readonly VolSurfaceDisplayModel _model;
|
||||
readonly UserTuple _user;
|
||||
readonly IRaiseCanExecuteChangedCommand _revert_cmd;
|
||||
readonly IRaiseCanExecuteChangedCommand _commit_cmd;
|
||||
readonly IDialogCommand _main_settings_cmd;
|
||||
@@ -40,16 +38,10 @@ namespace mbts.spark {
|
||||
bool _ignore_implied_vol_settings;
|
||||
|
||||
public VolSurfaceVM(
|
||||
VolSurfaceDisplayModel model,
|
||||
int id,
|
||||
IBus bus,
|
||||
VolSurfaceWindowSettings startup_data,
|
||||
UserTuple user
|
||||
) {
|
||||
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
|
||||
_model = model;
|
||||
_vs_id = id;
|
||||
_bus = bus;
|
||||
_user = user;
|
||||
macro_actions = new VolSurfaceMacroActionsVM(_model);
|
||||
globals = new VolSurfaceGlobalParameterVM(_model);
|
||||
|
||||
@@ -57,7 +49,7 @@ namespace mbts.spark {
|
||||
_grid_settings = startup_data.macro_grid_settings ?? new VolSurfaceMacroGridSettings();
|
||||
var hidden_exps_set = startup_data.hidden_exps.empty_if_null().ToHashSet();
|
||||
grid = new VolSurfaceGridVM(
|
||||
this, _model, _grid_settings.hidden_cols(), hidden_exps_set, _user);
|
||||
this, _model, _grid_settings.hidden_cols(), hidden_exps_set);
|
||||
grid.on_selection_changed += _on_grid_selection_changed;
|
||||
_model.publish_grid_settings(_grid_settings);
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace mbts.analytics {
|
||||
namespace mbts.analytics
|
||||
{
|
||||
/// These are the VolSurface settings that are common
|
||||
/// to any Vol Model
|
||||
[ProtoBuf.ProtoContract(Name = "VolSurfaceCoreSettings")]
|
||||
public class VolSurfaceCoreSettings {
|
||||
public class VolSurfaceCoreSettings
|
||||
{
|
||||
[ProtoBuf.ProtoMember(1)]
|
||||
public string vol_surface_name;
|
||||
[ProtoBuf.ProtoMember(2)]
|
||||
@@ -85,7 +87,5 @@ namespace mbts.analytics {
|
||||
get => _time_settings ??= new();
|
||||
set => _time_settings = value;
|
||||
}
|
||||
[ProtoBuf.ProtoMember(240)]
|
||||
public string vs_manager { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,6 @@ namespace mbts.analytics {
|
||||
if (core_settings.market_fit_settings == null) {
|
||||
core_settings.market_fit_settings = new VolSurfaceMarketFitSettings();
|
||||
}
|
||||
core_settings.market_fit_settings.vs_auto_fit_settings ??= new();
|
||||
if (core_settings.time_settings == null) {
|
||||
core_settings.time_settings = new VolSurfaceTimeSettings();
|
||||
}
|
||||
|
||||
@@ -141,7 +141,6 @@ namespace mbts.analytics
|
||||
|
||||
public enum VolCurveFitRegion
|
||||
{
|
||||
None,
|
||||
ATM,
|
||||
All
|
||||
}
|
||||
@@ -231,4 +230,4 @@ namespace mbts.analytics
|
||||
USE_CALENDAR_FOR_BUSINESS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,16 @@
|
||||
using mbts.co2;
|
||||
|
||||
namespace mbts.analytics {
|
||||
using Size = System.Single;
|
||||
public class VolSurfaceMDUnit : IEquatable<VolSurfaceMDUnit> {
|
||||
public readonly double bid_price, ask_price;
|
||||
public readonly uint bid_size, ask_size;
|
||||
public readonly Size bid_size, ask_size;
|
||||
public readonly double mark_price = double.NaN;
|
||||
private static VolSurfaceMDUnit _empty =
|
||||
new VolSurfaceMDUnit(Double.NaN, 0, Double.NaN, 0, Double.NaN);
|
||||
|
||||
public VolSurfaceMDUnit(double this_bid_price, uint this_bid_size,
|
||||
double this_ask_price, uint this_ask_size,
|
||||
public VolSurfaceMDUnit(double this_bid_price, Size this_bid_size,
|
||||
double this_ask_price, Size this_ask_size,
|
||||
double this_mark_price) {
|
||||
bid_price = this_bid_price;
|
||||
bid_size = this_bid_size;
|
||||
@@ -28,7 +29,7 @@ namespace mbts.analytics {
|
||||
|
||||
public VolSurfaceMDUnit(NativePriceSize bid, NativePriceSize ask,
|
||||
double mark_price)
|
||||
: this(bid.price, bid.size, ask.price, ask.size, mark_price) {
|
||||
: this(bid.price, bid.size_f, ask.price, ask.size_f, mark_price) {
|
||||
}
|
||||
|
||||
public bool is_two_sided() { return bid_size != 0 && ask_size != 0; }
|
||||
@@ -41,7 +42,7 @@ namespace mbts.analytics {
|
||||
}
|
||||
|
||||
public double get_weighted_mid_price(bool get_one_sided_mid = true) {
|
||||
uint sum_q = bid_size + ask_size;
|
||||
Size sum_q = bid_size + ask_size;
|
||||
if (sum_q == 0) {
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace mbts.analytics {
|
||||
namespace mbts.analytics
|
||||
{
|
||||
[ProtoBuf.ProtoContract(Name = "VolSurfaceMarketFitSettings")]
|
||||
public class VolSurfaceMarketFitSettings {
|
||||
public class VolSurfaceMarketFitSettings
|
||||
{
|
||||
/// use one sided market or not
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public bool ignore_one_sided_markets;
|
||||
@@ -20,44 +22,19 @@ namespace mbts.analytics {
|
||||
public double graph_update_period_ms = 2500;
|
||||
/// If this is set to true a regression curve is drawn
|
||||
/// and the vol model adheres to that
|
||||
[ProtoBuf.ProtoMember(50)]
|
||||
[ProtoBuf.ProtoMember(50)]
|
||||
public bool use_weighted_regression_fit = false;
|
||||
[ProtoBuf.ProtoMember(55)]
|
||||
public uint regression_order = 4;
|
||||
|
||||
[ProtoBuf.ProtoMember(90)]
|
||||
public VolSurfaceAutoFitSettings vs_auto_fit_settings { get; set; }
|
||||
}
|
||||
|
||||
[ProtoBuf.ProtoContract(Name = "VolSurfaceAutoFitSettings")]
|
||||
public class VolSurfaceAutoFitSettings {
|
||||
// each of these settings can be enabled independently. if they are enabled
|
||||
// then any of them being true will result in an autmatic fit
|
||||
[ProtoBuf.ProtoContract(Name = "TimeBasedSettings")]
|
||||
public class TimeBasedSettings {
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public uint? period_seconds { get; set; }
|
||||
}
|
||||
|
||||
[ProtoBuf.ProtoContract(Name = "DriverMoveBasedSettings")]
|
||||
public class DriverMoveBasedSettings {
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public double? points_moved { get; set; }
|
||||
}
|
||||
|
||||
[ProtoBuf.ProtoContract(Name = "ATMImpliedVolBasedSettings")]
|
||||
public class ATMImpliedVolBasedSettings {
|
||||
[ProtoBuf.ProtoMember(20)]
|
||||
public double? points_moved { get; set; }
|
||||
// we can do price terms moved as well
|
||||
}
|
||||
[ProtoBuf.ProtoMember(5)]
|
||||
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region;
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public TimeBasedSettings time_based_settings = null;
|
||||
[ProtoBuf.ProtoMember(20)]
|
||||
public DriverMoveBasedSettings driver_move_based_settings = null;
|
||||
[ProtoBuf.ProtoMember(30)]
|
||||
public ATMImpliedVolBasedSettings atm_implied_vol_based_settings = null;
|
||||
/// The system auto fits and saves vols if this is
|
||||
/// set to true
|
||||
[ProtoBuf.ProtoMember(60)]
|
||||
public bool enable_auto_fit = false;
|
||||
/// If enable_auto_fit = true, this governs
|
||||
/// how often the system auto-fits
|
||||
[ProtoBuf.ProtoMember(70)]
|
||||
public double auto_fit_time_ms = 30000;
|
||||
[ProtoBuf.ProtoMember(80)]
|
||||
public VolSurfaceEnums.VolCurveFitRegion auto_fit_region = VolSurfaceEnums.VolCurveFitRegion.ATM;
|
||||
}
|
||||
}
|
||||
@@ -475,7 +475,6 @@ namespace mbts.analytics {
|
||||
public static ResultMessage save_volsurface(
|
||||
VolSurfaceInput vs_input, AnalyticsService service, string user = "") {
|
||||
vs_input.saver_login = user;
|
||||
vs_input.surface_settings.core_settings.vs_manager = user;
|
||||
// convert to VolSurfaceEntry
|
||||
var to_save = new VolSurfaceEntry();
|
||||
var serialized_vs = ProtobufSerializationHelper.serialize(vs_input);
|
||||
@@ -596,7 +595,7 @@ namespace mbts.analytics {
|
||||
_greek_getter(g)(t, is_call);
|
||||
|
||||
public static IDictionary<double, IEnumerable<Theos>> hash_strikes(IEnumerable<Theos> theos) =>
|
||||
theos.Map(t => t.strike);
|
||||
theos.Map(t => t.strike);
|
||||
|
||||
static Func<Theos, bool, double> _greek_getter(VolSurfaceGreeks g) =>
|
||||
g switch {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -135,10 +135,7 @@ namespace bts {
|
||||
var meta = _security_metadata.get(smd.security);
|
||||
if (meta.HasValue) {
|
||||
exch_secs[smd.id] = new(
|
||||
smd.security,
|
||||
smd.md,
|
||||
meta.Value.HasPriceDisplay ? meta.Value.PriceDisplay : null,
|
||||
meta.Value.HasQuantityDisplay ? meta.Value.QuantityDisplay : null);
|
||||
smd.security, smd.md, meta.Value.PriceDisplay, meta.Value.QuantityDisplay);
|
||||
}
|
||||
}
|
||||
_bus.post(SparkTags.ServerSecuritiesTag, exch_secs);
|
||||
|
||||
@@ -52,17 +52,23 @@ namespace bts {
|
||||
string rv = "MergedMDDaemon Options:\n";
|
||||
foreach (var kv in sec_map) {
|
||||
var sec = kv.Value.security;
|
||||
var md = kv.Value.md;
|
||||
ulong time = 0;
|
||||
NativePriceSize bid, ask;
|
||||
var has_md = md.get_bbo(ref time, out bid, out ask);
|
||||
if (sec.HasOption) {
|
||||
rv += $"id: {kv.Key} desc: {sec.security_desc()} sym: {sec.Symbol} " +
|
||||
$"exp: {sec.security_expiration()} " +
|
||||
$"k: {sec.Option.Strike} cp: {sec.Option.CallPut}" + "\n";
|
||||
$"k: {sec.Option.Strike} cp: {sec.Option.CallPut} " +
|
||||
$"bid: p: {bid.price} q: {bid.size} qf: {bid.size_f} ask: p: {ask.price} q: {ask.size} qf: {ask.size_f}" +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
Log.Gen.info(rv);
|
||||
}
|
||||
|
||||
private void _on_server_sec_map(IReadOnlyDictionary<uint, SecurityMD> sec_map) {
|
||||
//_log_options(sec_map);
|
||||
_log_options(sec_map);
|
||||
bts.Log.Gen.info(String.Format("MergedMDDaemon._on_server_sec_map sz: {0}", sec_map.Count()));
|
||||
_server_sec_map = new Dictionary<uint, SecurityMD>(sec_map);
|
||||
_merge_and_post();
|
||||
|
||||
@@ -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, user.Value),
|
||||
new VolSurfaceWindowFactory(this, bus),
|
||||
new AnalyticsExpirationParametersWindowFactory(this, bus),
|
||||
new SlideReportWindowFactory(this, bus, reports_demuxer.subscribe),
|
||||
new ComboReportWindowFactory(this, bus, reports_demuxer.subscribe),
|
||||
|
||||
@@ -793,106 +793,70 @@
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="4"
|
||||
DataContext="{Binding auto_fit_vm}"
|
||||
Header="Auto Fit"
|
||||
Margin="0,5,0,0"
|
||||
Padding="5">
|
||||
Padding="5"
|
||||
IsEnabled="False">
|
||||
<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"
|
||||
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" />
|
||||
Margin="12,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding auto_fit_region_choices}"
|
||||
SelectedValue="{Binding auto_fit_region}"
|
||||
IsEnabled="{Binding enable_auto_fit}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="0,5,0,0"
|
||||
Text="When Driver moves" />
|
||||
<c:TickUpDownNullableDouble
|
||||
<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
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
ToolTipService.ShowOnDisabled="True"
|
||||
c:TextBoxEx.Suffix="ms"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Margin="8,0,0,0"
|
||||
Width="60"
|
||||
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="%" />
|
||||
Margin="12,5,0,0"
|
||||
IsEnabled="{Binding enable_auto_fit}"
|
||||
Value="{Binding auto_fit_time_ms}"
|
||||
Template="{StaticResource SuffixTemplate}" />
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
@@ -1,20 +1,9 @@
|
||||
#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 IsOpen="{Binding is_open}">
|
||||
<ContextMenu>
|
||||
<MenuItem
|
||||
Header="Populate Empty Expirations"
|
||||
Command="{Binding populate_empty_exps_cmd}" />
|
||||
@@ -413,11 +413,6 @@
|
||||
</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.SetCurrentValue(ContextMenu.IsOpenProperty, false);
|
||||
cm.IsOpen = false;
|
||||
return;
|
||||
}
|
||||
var cgs = g.GetColumnGeometry().ToList();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.spark;
|
||||
|
||||
@@ -15,20 +14,14 @@
|
||||
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,
|
||||
UserTuple user
|
||||
) : base(vs_name, bus, factory, Icons.vol_surface) {
|
||||
VolSurfaceWindowFactory factory, IBus bus, string vs_name, VolSurfaceWindowSettings startup_data) :
|
||||
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));
|
||||
}
|
||||
@@ -44,7 +37,7 @@
|
||||
public override UIElement Content => _view;
|
||||
|
||||
public void thread_init() {
|
||||
_vm = new VolSurfaceVM(new (vs_id, _bus, true), vs_id, _bus, _startup_data, _user);
|
||||
_vm = new VolSurfaceVM(new VolSurfaceDisplayModel(vs_id, _bus, true), vs_id, _bus, _startup_data);
|
||||
_view = new VolSurfaceView {
|
||||
DataContext = _vm
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.shell;
|
||||
|
||||
@@ -11,12 +10,10 @@ namespace mbts.spark {
|
||||
|
||||
class VolSurfaceWindowFactory : ShellWindowFactory<VolSurfaceWindowSettings> {
|
||||
readonly IBus _bus;
|
||||
readonly UserTuple _user;
|
||||
|
||||
public VolSurfaceWindowFactory(IShellModule module, IBus bus, UserTuple user)
|
||||
public VolSurfaceWindowFactory(IShellModule module, IBus bus)
|
||||
: base(module, "VolSurface") {
|
||||
_bus = bus;
|
||||
_user = user;
|
||||
_dispose = bus.subscribe(SparkTags.ShowVolSurface).OnDispatcher().Subscribe(
|
||||
async state => _bus.post(SparkTags.ShowWindow, await _create(state)));
|
||||
}
|
||||
@@ -25,7 +22,7 @@ namespace mbts.spark {
|
||||
_create(state);
|
||||
|
||||
async Task<IShellWindow> _create(VolSurfaceWindowSettings state) =>
|
||||
new VolSurfaceWindow(this, _bus, await _lookup_vs_name(state.id), state, _user);
|
||||
new VolSurfaceWindow(this, _bus, await _lookup_vs_name(state.id), state);
|
||||
|
||||
async Task<string> _lookup_vs_name(int vs_id) {
|
||||
var (vol_surfaces, success) = await _bus.subscribe(SparkTags.VolSurfaceListTag).FirstAsyncTask(TimeSpan.FromSeconds(2));
|
||||
|
||||
@@ -176,11 +176,10 @@
|
||||
</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="{u:BTSColor ExecutionStrategy.expander_background}">
|
||||
<Grid Background="Transparent">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition/>
|
||||
@@ -191,7 +190,7 @@
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,5,0,0"
|
||||
SnapsToDevicePixels="False"
|
||||
Stroke="{u:BTSColor ExecutionStrategy.arrow_background}"
|
||||
Stroke="#77333333"
|
||||
StrokeThickness="2"
|
||||
VerticalAlignment="Top"
|
||||
/>
|
||||
@@ -200,7 +199,6 @@
|
||||
ContentSource="{TemplateBinding Content}"
|
||||
Margin="3,0,0,0"
|
||||
/>
|
||||
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
@@ -213,7 +211,7 @@
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="{u:BTSColor ExecutionStrategy.arrow_background_selected}"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
@@ -280,8 +278,7 @@
|
||||
<ColumnDefinition/>
|
||||
</SelectiveScrollingGrid.ColumnDefinitions>
|
||||
<DataGridRowHeader
|
||||
Foreground="{u:BTSColor ExecutionStrategy.expander_foreground}"
|
||||
Background="{u:BTSColor ExecutionStrategy.data_grid_row_header_background}"
|
||||
Background="Transparent"
|
||||
Padding="{Binding section_count, Converter={StaticResource RowHeaderGroupIndentConverter}}"
|
||||
FontWeight="{Binding font_weight, FallbackValue={u:FontWeight Normal}}"
|
||||
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
|
||||
@@ -320,17 +317,9 @@
|
||||
<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.immutable()).low_tick,
|
||||
tick_factors = TickUtils.get_regional_ticks(sec.ContractSpec).low_tick,
|
||||
name = sec.Synthetic.Name,
|
||||
parsed_synth = ps
|
||||
};
|
||||
|
||||
@@ -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).low_tick;
|
||||
_tick_factors = TickUtils.get_regional_ticks(synthetic.ContractSpec).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.immutable()).low_tick;
|
||||
_tick_factors = TickUtils.get_regional_ticks(_synthetic.ContractSpec).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.immutable()));
|
||||
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.ContractSpec));
|
||||
RaisePropertyChanged(nameof(tick_factors));
|
||||
}
|
||||
|
||||
|
||||
@@ -371,7 +371,6 @@
|
||||
<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.Value.tick_factors().to_api_tick_factors());
|
||||
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -218,10 +218,14 @@ namespace mbts.spark {
|
||||
background = buy_sell_background_fill_color;
|
||||
hoverbackground = _mk_hover_bg_brush(dark, _darkbg, 0);
|
||||
|
||||
(_num_root_orders, _filled, _quantity) = _root_nodes
|
||||
.Select(n => (1u, n.filled_quantity(), n.quantity()))
|
||||
.Sum();
|
||||
|
||||
_num_root_orders = 0;
|
||||
_filled = 0;
|
||||
_quantity = 0;
|
||||
foreach (var n in _root_nodes) {
|
||||
_num_root_orders++;
|
||||
_filled += n.filled_quantity();
|
||||
_quantity += n.quantity();
|
||||
}
|
||||
if (_num_root_orders == 1) {
|
||||
var order = _root_nodes.First();
|
||||
border = _owner.model.order_gateway.factory.get_metadata(order).Color.rgb_brush();
|
||||
@@ -241,7 +245,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public OrderBookVM? create_orderbook_vm() {
|
||||
var ticks = _owner.spec.count_ticks(real_price);
|
||||
var ticks = _owner.spec.full_ticks_from_zero(real_price);
|
||||
if (!ticks.HasValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -191,7 +191,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, ticks_per_row + i);
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, ticks_per_row + i);
|
||||
if (new_tpr != tpr) {
|
||||
ticks_per_row = new_tpr;
|
||||
break;
|
||||
@@ -201,7 +201,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, tpr - i);
|
||||
var new_tpr = TickUtils.fit_ticks_per_row_to_dollars(security.ContractSpec, tpr - i);
|
||||
if (new_tpr != tpr) {
|
||||
ticks_per_row = new_tpr;
|
||||
break;
|
||||
@@ -239,8 +239,7 @@ 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, ticks_per_row);
|
||||
public uint? rounded_ticks_per_row => TickUtils.fit_ticks_per_row_to_dollars(_security.ContractSpec, ticks_per_row);
|
||||
|
||||
public MarketSizeDisplayVM size_display { get; } = new MarketSizeDisplayVM();
|
||||
public SimpleGridSettingsVM mini_ob { get; } = new SimpleGridSettingsVM(OrderBookGridSettingsManager.hard_column_flags);
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace mbts.spark {
|
||||
IReadOnlyDictionary<uint, OrderSecurity> _cache = DictionaryHelper.empty<uint, OrderSecurity>();
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata> _favorite_algo_metadata_map =
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata>.Empty;
|
||||
RegionalTickFactors? _spec;
|
||||
ContractSpecificationImmutable? _spec;
|
||||
|
||||
LadderVM(
|
||||
IBus bus,
|
||||
@@ -243,9 +243,10 @@ namespace mbts.spark {
|
||||
|
||||
var orders_source = settings.Select(s => s.ticks_per_row).DistinctUntilChanged()
|
||||
.SelectSeries(tpr => {
|
||||
var spec = TickUtils.multiply_tick_size(security.regional_ticks(), tpr);
|
||||
var spec = TickUtils.multiply_tick_size(security.ContractSpec, tpr);
|
||||
var price_comp = Comparer<double>.Create((a, b) =>
|
||||
Comparer<long?>.Default.Compare(spec.count_ticks(a), spec.count_ticks(b)));
|
||||
Comparer<int?>.Default.Compare(
|
||||
spec.full_ticks_from_zero(a), spec.full_ticks_from_zero(b)));
|
||||
return _order_price_source(model.orders, price_comp, p => TickUtils.normalize_price(spec, p));
|
||||
});
|
||||
_day_change.Changed += (o, n) => RaisePropertyChanged(
|
||||
@@ -393,10 +394,9 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public SecurityImmutable security => _model.security;
|
||||
public RegionalTickFactors spec => _spec ?? (
|
||||
public ContractSpecificationImmutable spec => _spec ?? (
|
||||
_spec = TickUtils.multiply_tick_size(
|
||||
security.regional_ticks(), current_settings?.ticks_per_row ?? 1))
|
||||
?? RegionalTickFactors.Default;
|
||||
security.ContractSpec, current_settings?.ticks_per_row ?? 1)).Value;
|
||||
|
||||
public double display_quantity_divisor { get; }
|
||||
public LadderSettings current_settings { get; private set; }
|
||||
@@ -826,7 +826,7 @@ namespace mbts.spark {
|
||||
if (!price.is_real()) {
|
||||
msg = "not a real number";
|
||||
} else if (settlement.is_real()) {
|
||||
var ticks_from_settle = security.tickdiff(price, settlement);
|
||||
var ticks_from_settle = security.ContractSpec.tickdiff(price, settlement);
|
||||
if (ticks_from_settle.HasValue) {
|
||||
var max_cross = (current_settings?.ladder_order_limits?.max_settlement_cross_ticks)
|
||||
.as_nullable();
|
||||
@@ -858,7 +858,7 @@ namespace mbts.spark {
|
||||
} else {
|
||||
ulong _ = 0;
|
||||
_model.md.get_bbo(ref _, out var bid, out var ask);
|
||||
var mid = TickUtils.mid_tick(security.regional_ticks(), bid.price, ask.price);
|
||||
var mid = TickUtils.mid_tick(security.ContractSpec, bid.price, ask.price);
|
||||
_day_change.set(mid - md.settlement_price);
|
||||
}
|
||||
_volume.set(volume);
|
||||
|
||||
@@ -32,8 +32,6 @@ 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;
|
||||
@@ -85,6 +83,7 @@ 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;
|
||||
@@ -385,16 +384,16 @@ namespace mbts.spark {
|
||||
|
||||
Column[] _columns { get; set; } = Array.Empty<Column>();
|
||||
IEnumerable<Column> _visible_columns => _columns.Where(c => c.settings.show);
|
||||
RegionalTickFactors _spec_backing;
|
||||
RegionalTickFactors _spec {
|
||||
ContractSpecificationImmutable? _spec_backing;
|
||||
ContractSpecificationImmutable _spec {
|
||||
get {
|
||||
if (_spec_backing is not null) {
|
||||
return _spec_backing;
|
||||
if (_spec_backing.HasValue) {
|
||||
return _spec_backing.Value;
|
||||
} else if (_vm != null) {
|
||||
_spec_backing = TickUtils.multiply_tick_size(security.regional_ticks(), _settings?.ticks_per_row ?? 1);
|
||||
return _spec_backing;
|
||||
_spec_backing = TickUtils.multiply_tick_size(security.ContractSpec, _settings?.ticks_per_row ?? 1);
|
||||
return _spec_backing.Value;
|
||||
}
|
||||
return RegionalTickFactors.Default;
|
||||
return Security.Defaults.ContractSpecificationImmutable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,15 +447,6 @@ 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;
|
||||
@@ -470,23 +460,21 @@ 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.
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -756,12 +744,12 @@ namespace mbts.spark {
|
||||
internal double price_for_point(Point point) =>
|
||||
_price_for_row(_row_for_point(point));
|
||||
|
||||
static uint? _size_from_row(int row, IList<double> price_list, NativePriceSize[] depth, RegionalTickFactors spec) {
|
||||
static uint? _size_from_row(int row, IList<double> price_list, NativePriceSize[] depth, ContractSpecificationImmutable spec) {
|
||||
if (price_list == null || depth == null) return null;
|
||||
else return row <= price_list.Count ? _size_from_price(price_list[row], depth, spec) : null;
|
||||
}
|
||||
|
||||
static uint? _size_from_price(double price, NativePriceSize[] depth, RegionalTickFactors spec) {
|
||||
static uint? _size_from_price(double price, NativePriceSize[] depth, ContractSpecificationImmutable spec) {
|
||||
if (!double.IsNaN(price) && depth.TryGetFirst(nps => spec.tick_equals(price, nps.price), out NativePriceSize result))
|
||||
return result.size;
|
||||
return null;
|
||||
@@ -1111,16 +1099,10 @@ namespace mbts.spark {
|
||||
Log.assert(_price_dirty);
|
||||
_price_list = new LadderPriceList {
|
||||
length = _initial_row_count,
|
||||
security = security
|
||||
spec = security.ContractSpec
|
||||
};
|
||||
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));
|
||||
}
|
||||
var mid_tick = security.ContractSpec.tickdiff(_mkt_break_lines.origin, 0) ?? 0;
|
||||
_set_scrollbar_range(high_tick: mid_tick + (_price_list.Count << 1));
|
||||
_price_dirty = true;
|
||||
}
|
||||
if (_price_dirty) {
|
||||
@@ -1199,12 +1181,12 @@ namespace mbts.spark {
|
||||
_price_list, _vm.md.settlement_price,
|
||||
_settings.net_change == LadderSettings.NetChangeTerms.Ticks,
|
||||
_settings.row_height, _settings.price_column,
|
||||
_spec);
|
||||
security.ContractSpec);
|
||||
} else {
|
||||
LadderRender.render_prices(
|
||||
_price_vis_tup.visual, _price_vis_tup.glyph_context,
|
||||
_price_list, _settings.row_height,
|
||||
_settings.price_column, _spec,
|
||||
_settings.price_column, security.ContractSpec,
|
||||
_settings.price_display_format);
|
||||
}
|
||||
}
|
||||
@@ -1359,7 +1341,7 @@ namespace mbts.spark {
|
||||
return;
|
||||
if (_price_list is null) {
|
||||
_price_list = new LadderPriceList {
|
||||
security = security
|
||||
spec = security.ContractSpec
|
||||
};
|
||||
}
|
||||
_price_list.reset(null, null, _initial_row_count);
|
||||
@@ -1443,7 +1425,7 @@ namespace mbts.spark {
|
||||
_pending_scroll_to_origin |= _settings == null;
|
||||
_invalidate_spec();
|
||||
if (_price_list != null) {
|
||||
_price_list.security = security;
|
||||
_price_list.spec = _spec;
|
||||
}
|
||||
_bid_vis_tup.glyph_context = glyph_context(s.bid_column);
|
||||
_ask_vis_tup.glyph_context = glyph_context(s.ask_column);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using bts.api;
|
||||
|
||||
namespace mbts.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
class LadderPriceLineViewAdapter {
|
||||
public static double bid_line(
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (!double.IsNaN(bid)) {
|
||||
@@ -19,7 +17,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static double ask_line(
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (!double.IsNaN(ask)) {
|
||||
@@ -33,7 +31,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static double mid_line(
|
||||
double bid, double ask, double settlement, RegionalTickFactors spec) {
|
||||
double bid, double ask, double settlement, ContractSpecificationImmutable? spec) {
|
||||
return TickUtils.normalize_price(spec, impl());
|
||||
double impl() {
|
||||
if (double.IsNaN(bid)) {
|
||||
@@ -45,16 +43,16 @@ namespace mbts.spark {
|
||||
if (double.IsNaN(ask)) {
|
||||
return bid;
|
||||
}
|
||||
if (spec is not null) {
|
||||
return TickUtils.mid_tick(spec, bid, ask);
|
||||
if (spec.HasValue) {
|
||||
return TickUtils.mid_tick(spec.Value, bid, ask);
|
||||
}
|
||||
return bid;
|
||||
}
|
||||
}
|
||||
|
||||
static double _try_tick_down(RegionalTickFactors spec, double value) {
|
||||
if (spec is not null) {
|
||||
return spec.tickdown(value);
|
||||
static double _try_tick_down(ContractSpecificationImmutable? spec, double value) {
|
||||
if (spec.HasValue) {
|
||||
return spec.Value.tickdown(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
@@ -9,78 +8,52 @@ 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> {
|
||||
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);
|
||||
int _length;
|
||||
int _high_tick;
|
||||
|
||||
public LadderPriceList() { }
|
||||
|
||||
public LadderPriceList(LadderPriceList other) {
|
||||
_length = other._length;
|
||||
_high_tick = other._high_tick;
|
||||
_security = other._security;
|
||||
spec = other.spec;
|
||||
}
|
||||
|
||||
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 long high_tick {
|
||||
public int high_tick {
|
||||
get => _high_tick;
|
||||
set => _high_tick = value;
|
||||
}
|
||||
|
||||
public long low_tick {
|
||||
public int low_tick {
|
||||
get => high_tick - length;
|
||||
set => reset(null, value, null);
|
||||
}
|
||||
|
||||
public double start {
|
||||
get => _regional_tick.tickup<double>(0, (uint)high_tick);
|
||||
set => high_tick = _regional_tick.tickdiff(value, 0) ?? high_tick;
|
||||
get => spec.tickup(0, high_tick);
|
||||
set => high_tick = spec.tickdiff(value, 0) ?? high_tick;
|
||||
}
|
||||
|
||||
public long length {
|
||||
public int length {
|
||||
get => _length;
|
||||
set {
|
||||
if (value < 0 || value > _MAX_LENGTH) {
|
||||
throw new ArgumentException(
|
||||
$"Value 'v' must be >= 0 and < {_MAX_LENGTH} (actually {value})");
|
||||
if (value < 0) {
|
||||
throw new ArgumentException($"Value must be >= 0 (actually {value})");
|
||||
}
|
||||
_length = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
checked {
|
||||
return (int)length;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int Count => (int)length;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public double this[int idx] {
|
||||
get => _regional_tick.tick<double>(0, high_tick - idx);
|
||||
get => spec.tickup(0, high_tick - idx);
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -94,13 +67,11 @@ namespace mbts.spark {
|
||||
GetEnumerator();
|
||||
|
||||
public int IndexOf(double item) {
|
||||
var idx = _regional_tick.tickdiff(start, item) ?? -1;
|
||||
var idx = spec.tickdiff(start, item) ?? -1;
|
||||
if (idx < 0 || idx >= length) {
|
||||
return -1;
|
||||
}
|
||||
checked {
|
||||
return (int)idx;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
public void Insert(int index, double item) =>
|
||||
@@ -167,15 +138,15 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public void reset(long? high_tick = null, long? low_tick = null, long? length = null) {
|
||||
public void reset(int? high_tick = null, int? low_tick = null, int? 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));
|
||||
}
|
||||
long new_high_tick = 0;
|
||||
long new_length = 0;
|
||||
int new_high_tick = 0;
|
||||
int new_length = 0;
|
||||
if (high_tick.HasValue) {
|
||||
new_high_tick = high_tick.Value;
|
||||
if (low_tick.HasValue) {
|
||||
@@ -209,7 +180,8 @@ namespace mbts.spark {
|
||||
other != null &&
|
||||
_high_tick == other._high_tick &&
|
||||
_length == other._length &&
|
||||
_regional_tick.safe_equals(other._regional_tick);
|
||||
spec.LowTick.Equals(other.spec.LowTick) &&
|
||||
spec.PriceBreak.Equals(other.spec.PriceBreak);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
Equals(obj as LadderPriceList);
|
||||
@@ -217,10 +189,13 @@ namespace mbts.spark {
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(_high_tick, _length);
|
||||
|
||||
double _tick_to_price(long tick) =>
|
||||
_regional_tick.tick<double>(0, tick);
|
||||
double _tick_to_price(int tick) =>
|
||||
spec.tickup(0, tick);
|
||||
|
||||
void _add_tick(long tick) {
|
||||
int? _price_to_tick(double price) =>
|
||||
spec.tickdiff(price, 0);
|
||||
|
||||
void _add_tick(int tick) {
|
||||
int idx;
|
||||
if (length == 0) {
|
||||
_high_tick = tick;
|
||||
@@ -229,9 +204,7 @@ namespace mbts.spark {
|
||||
_high_tick = tick;
|
||||
idx = 0;
|
||||
} else if (tick == low_tick - 1) {
|
||||
checked {
|
||||
idx = (int)length;
|
||||
}
|
||||
idx = length;
|
||||
} else {
|
||||
throw new ArgumentException($"Must be == {nameof(high_tick)} ({high_tick}) + 1, or == {nameof(low_tick)} ({low_tick}) - 1)");
|
||||
}
|
||||
@@ -239,7 +212,7 @@ namespace mbts.spark {
|
||||
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, _tick_to_price(tick), idx));
|
||||
}
|
||||
|
||||
void _remove_tick(long tick) {
|
||||
void _remove_tick(int tick) {
|
||||
if (length == 0) {
|
||||
throw new InvalidOperationException("Cannot remove tick because length is 0");
|
||||
}
|
||||
@@ -248,9 +221,7 @@ namespace mbts.spark {
|
||||
_high_tick--;
|
||||
idx = 0;
|
||||
} else if (tick == low_tick) {
|
||||
checked {
|
||||
idx = (int)(length - 1);
|
||||
}
|
||||
idx = length - 1;
|
||||
} else {
|
||||
throw new ArgumentException(
|
||||
$"Can only remove {nameof(low_tick)} ({low_tick}) or " +
|
||||
|
||||
@@ -9,7 +9,6 @@ using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.utility.text;
|
||||
|
||||
using Spark.Core;
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
@@ -20,8 +19,6 @@ 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;
|
||||
@@ -76,16 +73,6 @@ 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;
|
||||
@@ -108,13 +95,30 @@ namespace mbts.spark {
|
||||
settings.font_size, settings.width, row_height, HorizontalAlignment.Right,
|
||||
-4, VerticalAlignment.Center, row * row_height, true);
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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, RegionalTickFactors spec, LadderSettings.PriceDisplayFormat price_display_format) {
|
||||
public static GlyphRun[] format_prices(IList<double> prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable 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));
|
||||
@@ -139,12 +143,12 @@ namespace mbts.spark {
|
||||
bool format_in_tick_terms,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
RegionalTickFactors tick) {
|
||||
ContractSpecificationImmutable spec) {
|
||||
if (price_list.IsNullOrEmpty()) {
|
||||
return;
|
||||
}
|
||||
render_prices(
|
||||
price, glyph_context, price_list, row_height, settings, tick,
|
||||
price, glyph_context, price_list, row_height, settings, spec,
|
||||
wrt_price, format_in_tick_terms);
|
||||
}
|
||||
|
||||
@@ -154,12 +158,12 @@ namespace mbts.spark {
|
||||
IList<double> dprices,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
RegionalTickFactors tick,
|
||||
ContractSpecificationImmutable spec,
|
||||
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, tick);
|
||||
var fprices = format_prices(dprices, wrt_price, format_in_tick_terms, row_height, settings, glyph_context, spec);
|
||||
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));
|
||||
@@ -174,11 +178,11 @@ namespace mbts.spark {
|
||||
IList<double> dprices,
|
||||
double row_height,
|
||||
LadderColumnSettings settings,
|
||||
RegionalTickFactors tick,
|
||||
ContractSpecificationImmutable spec,
|
||||
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, tick, price_display_format);
|
||||
var fprices = format_prices(dprices, row_height, settings, glyph_context, spec, 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));
|
||||
@@ -211,7 +215,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
NativePriceSize[] rungs,
|
||||
double row_height,
|
||||
RegionalTickFactors spec,
|
||||
ContractSpecificationImmutable spec,
|
||||
LadderColumnSettings settings,
|
||||
Func<NativePriceSize, string> fmt,
|
||||
bool lighten_market_cells,
|
||||
@@ -244,18 +248,17 @@ namespace mbts.spark {
|
||||
direct_size: aggr.direct_size + rung.direct_size,
|
||||
implied_size: aggr.implied_size + rung.implied_size),
|
||||
rung => {
|
||||
var ticks = spec.count_ticks(rung.price);
|
||||
//spec.round_to_tick(rung.price);
|
||||
var ticks = spec.full_ticks_from_zero(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.count_ticks(rung.price);
|
||||
var ticks = spec.full_ticks_from_zero(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
|
||||
var tick_diff = spec.tickdiff(curr_price, price).assert_value();
|
||||
checked {
|
||||
curr_index += (int)tick_diff;
|
||||
}
|
||||
int tick_diff = spec.tickdiff_unchecked(curr_price, price);
|
||||
curr_index += tick_diff;
|
||||
curr_price = price;
|
||||
if (curr_index >= 0 && curr_index < prices.Count) {
|
||||
if (market_cell_background_brush != null)
|
||||
@@ -275,7 +278,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
IEnumerable<VolumeAtPriceLevelImmutable> data,
|
||||
double row_height,
|
||||
RegionalTickFactors spec,
|
||||
ContractSpecificationImmutable spec,
|
||||
VolumeColumnSettings settings,
|
||||
int last_index,
|
||||
string last_size_and_direction,
|
||||
@@ -368,7 +371,7 @@ 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, RegionalTickFactors spec, RenderCell<T> render_cell) {
|
||||
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) {
|
||||
using (var dc = dv.RenderOpen())
|
||||
using (_draw_with_clip(dc, settings, row_height, prices.Count)) {
|
||||
if (data.is_null_or_empty())
|
||||
@@ -379,11 +382,8 @@ namespace mbts.spark {
|
||||
if (double.IsNaN(price))
|
||||
continue;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
var tick_diff = spec.tickdiff(curr_price, price) ?? 0;
|
||||
Log.assert(
|
||||
tick_diff > (int.MaxValue - curr_index),
|
||||
$"Unable to index ladder row for price {price}: tick count exceeds int.MaxValue");
|
||||
curr_index += (int)tick_diff;
|
||||
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);
|
||||
@@ -409,7 +409,7 @@ namespace mbts.spark {
|
||||
IList<double> prices,
|
||||
IEnumerable<(double price, uint piq)> pvp,
|
||||
double row_height,
|
||||
RegionalTickFactors spec,
|
||||
ContractSpecificationImmutable spec,
|
||||
LadderColumnSettings settings,
|
||||
Func<uint, string> fmt_value) {
|
||||
//
|
||||
@@ -425,10 +425,8 @@ namespace mbts.spark {
|
||||
foreach (var entry in pvp) {
|
||||
double price = entry.price;
|
||||
// prices are in descending order, so get diff from curr_price - price
|
||||
var tick_diff = spec.tickdiff(curr_price, price).assert_value();
|
||||
checked {
|
||||
curr_index += (int)tick_diff;
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -31,12 +31,10 @@
|
||||
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>
|
||||
@@ -125,12 +123,8 @@
|
||||
<!--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.Value.regional_ticks().low_tick.to_api_tick_factors());
|
||||
tick_factors: security.spec_or_default().tick_factors().to_api_tick_factors());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -769,7 +769,7 @@ namespace mbts.spark {
|
||||
return;
|
||||
}
|
||||
|
||||
var price_display = TickUtils.get_tick(row.security, price ?? 0).to_api_tick_display_settingsi();
|
||||
var price_display = row.contract_spec?.tick_factors()?.to_api_tick_display_settingsi();
|
||||
var update_desc = OrderUtils.update_description(
|
||||
row.order, price, quantity, price_display, row.quantity_display_settings);
|
||||
Log.Ui.info(
|
||||
|
||||
@@ -179,7 +179,8 @@ namespace mbts.spark {
|
||||
using var _ = detect_property_changes(
|
||||
nameof(spec),
|
||||
nameof(display_quantity_divisor),
|
||||
nameof(quantity_display));
|
||||
nameof(quantity_display),
|
||||
nameof(unit_quantity));
|
||||
_security_md = value;
|
||||
bbo.security_md = value;
|
||||
_payup_bid_cmd.RaiseCanExecuteChanged();
|
||||
@@ -209,6 +210,9 @@ 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; }
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using mbts.analytics;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace BCG {
|
||||
using Size = System.Single;
|
||||
public enum BidAskAlertZone { buy, sell, none }
|
||||
public class BBOPacket {
|
||||
public enum MarketSide {
|
||||
@@ -15,8 +13,8 @@ namespace BCG {
|
||||
|
||||
private double _bid_price => md.bid_price;
|
||||
private double _ask_price => md.ask_price;
|
||||
private UInt32 _bid_size => md.bid_size;
|
||||
private UInt32 _ask_size => md.ask_size;
|
||||
private Size _bid_size => md.bid_size;
|
||||
private Size _ask_size => md.ask_size;
|
||||
private static BBOPacket _null_pack = new BBOPacket(VolSurfaceMDUnit.empty);
|
||||
public readonly VolSurfaceMDUnit md;
|
||||
|
||||
@@ -24,21 +22,6 @@ namespace BCG {
|
||||
this.md = md;
|
||||
}
|
||||
|
||||
public static bool bid_through_theo(BBOPacket md, mbts.spark.TheoPoint tp, bool is_call) {
|
||||
return false;
|
||||
// if (tp != null && md != null && md._md_row != null)
|
||||
// return get_bid_price(md) > (is_call ? tp.call : tp.put);
|
||||
// else
|
||||
// return false;
|
||||
}
|
||||
|
||||
public static bool ask_through_theo(BBOPacket md, mbts.spark.TheoPoint tp, bool is_call) {
|
||||
// if (tp != null && md != null && md._md_row != null)
|
||||
// return get_ask_price(md) < (is_call ? tp.call : tp.put);
|
||||
// else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static double get_mid_price(BBOPacket md) {
|
||||
return (get_bid_price(md) + get_ask_price(md)) / 2.0;
|
||||
}
|
||||
@@ -47,21 +30,16 @@ namespace BCG {
|
||||
return md != null ? md._bid_price : Double.NaN;
|
||||
}
|
||||
|
||||
public static UInt32 get_bid_size(BBOPacket md) {
|
||||
return md != null ? md._bid_size : (UInt32)0;
|
||||
public static Size get_bid_size(BBOPacket md) {
|
||||
return md != null ? md._bid_size : (Size)0;
|
||||
}
|
||||
|
||||
public static double get_ask_price(BBOPacket md) {
|
||||
return md != null ? md._ask_price : Double.NaN;
|
||||
}
|
||||
|
||||
public static UInt32 get_ask_size(BBOPacket md) {
|
||||
return md != null ? md._ask_size : (UInt32)0;
|
||||
}
|
||||
public static Tuple<double, UInt32> get_md(BBOPacket md, bool is_bid) {
|
||||
double price = is_bid ? BBOPacket.get_bid_price(md) : BBOPacket.get_ask_price(md);
|
||||
UInt32 sz = is_bid ? BBOPacket.get_bid_size(md) : BBOPacket.get_ask_size(md);
|
||||
return Tuple.Create(price, sz);
|
||||
public static Size get_ask_size(BBOPacket md) {
|
||||
return md != null ? md._ask_size : (Size)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,15 +123,6 @@ 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,7 +18,6 @@ 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 {
|
||||
@@ -556,17 +555,6 @@ 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);
|
||||
@@ -578,20 +566,7 @@ namespace BCG {
|
||||
if (sc_data.sec_md_map.TryGetValue(key, out var smd)) {
|
||||
switch (window_type) {
|
||||
case OrderEntryWindow.Ticket:
|
||||
bool is_bid = NMSheetSettingColumnOrganization.get_column_info(cell.col).is_bid;
|
||||
bts.AccountTuple acc_tup = get_account("SMALL");
|
||||
Nullable<double> qty = _settings.setting_layout.DefaultQty;
|
||||
OrderDefinition od = new OrderDefinition() {
|
||||
SecurityKey = smd.id,
|
||||
TimeInForce = TimeInForce.Gtc,
|
||||
Account = acc_tup.name,
|
||||
AccountId = acc_tup.id
|
||||
};
|
||||
BBOPacket bbo = _sheet_data.get_bbo(smd.id);
|
||||
Tuple<double, UInt32> pr_sz = BBOPacket.get_md(bbo, is_bid);
|
||||
UInt32 effective_qty = qty.HasValue ? Convert.ToUInt32(Math.Abs(qty.Value)) : pr_sz.Item2;
|
||||
_threaded_bb.post(SparkTags.ShowOrderTicketTag,
|
||||
(new OrderDefinitionImmutable(od), pr_sz.Item1, effective_qty));
|
||||
_threaded_bb.post(SparkTags.ShowOrderTicketFromSecurityTag, smd);
|
||||
break;
|
||||
case OrderEntryWindow.Ladder:
|
||||
_threaded_bb.post(SparkTags.ShowLadderTag, smd);
|
||||
|
||||
@@ -11,8 +11,6 @@ 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;
|
||||
@@ -104,7 +102,6 @@ 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 double display_quantity_divisor {
|
||||
get => _display_quantity_divisor;
|
||||
|
||||
@@ -225,7 +225,10 @@ namespace bts.spark {
|
||||
var security = try_get_security(order.Def.SecurityKey);
|
||||
var change_descs = new List<string>(1);
|
||||
|
||||
var price_display = TickUtils.get_tick(security, price).to_api_tick_display_settingsi();
|
||||
TickDisplaySettingsImmutable? price_display =
|
||||
security.HasValue && security.Value.HasContractSpec ?
|
||||
security.Value.ContractSpec.tick_factors().to_api_tick_display_settingsi() : null;
|
||||
|
||||
var price_qty_change_desc = OrderUtils.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}}"
|
||||
RegionalTick="{Binding price_tick}"
|
||||
ContractSpec="{Binding security.ContractSpec}"
|
||||
Focusable="false"
|
||||
TickDefaultValue="{Binding current_price, Converter={StaticResource TickDefaultPriceConverter}, FallbackValue={u:Double 0}}"
|
||||
Value="{Binding price}"
|
||||
|
||||
@@ -254,14 +254,17 @@ namespace mbts.spark {
|
||||
$"{(order.HasDef ? order.Def.Side.ToString() : "(unknown-side)")} {(order.HasState ? ($@"{spec.format(order.State.Price)} @ {order.State.Quantity}") : "(unknown-price) @ (unknown-quantity)")}";
|
||||
|
||||
public static string short_description(
|
||||
SecurityImmutable security, Side side, double price, double quantity) {
|
||||
var price_display = TickUtils.get_tick(security, price).to_api_tick_display_settingsi();
|
||||
return new StringBuilderEx(
|
||||
SecurityImmutable security, Side side, double price, double quantity) =>
|
||||
new StringBuilderEx(
|
||||
security.ToString(), " ",
|
||||
side.ToString(), " ",
|
||||
price_quantity_description(price, quantity, price_display)
|
||||
price_quantity_description(price, quantity, security.spec_or_default())
|
||||
).ToString();
|
||||
}
|
||||
|
||||
public static string price_quantity_description(
|
||||
double price, double quantity, ContractSpecificationImmutable spec) =>
|
||||
price_quantity_description(
|
||||
price, quantity, spec.tick_factors().to_api_tick_display_settingsi());
|
||||
|
||||
public static string price_quantity_description(
|
||||
double price,
|
||||
|
||||
@@ -190,13 +190,24 @@ namespace mbts.analytics {
|
||||
}
|
||||
}
|
||||
|
||||
void _compute_swipe_sum() =>
|
||||
(swipe_sum_puts, swipe_sum_calls, swipe_sum_net) = _visible_selected_cells
|
||||
.SelectMany(tup =>
|
||||
tup.exps.Select(exp => {
|
||||
var (p, c, n) = tup.row.get_cell_values(exp);
|
||||
return (p.if_nan(0), c.if_nan(0), n.if_nan(0));
|
||||
}))
|
||||
.Sum();
|
||||
void _compute_swipe_sum() {
|
||||
swipe_sum_puts = 0;
|
||||
swipe_sum_calls = 0;
|
||||
swipe_sum_net = 0;
|
||||
foreach (var (row, exps) in _visible_selected_cells) {
|
||||
foreach (var exp in exps) {
|
||||
var (p, c, n) = row.get_cell_values(exp);
|
||||
if (!p.is_nan()) {
|
||||
swipe_sum_puts += p;
|
||||
}
|
||||
if (!c.is_nan()) {
|
||||
swipe_sum_calls += c;
|
||||
}
|
||||
if (!n.is_nan()) {
|
||||
swipe_sum_net += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ namespace mbts.analytics {
|
||||
timer.stop();
|
||||
Log.Ui.info($"PNLReportCalculator n_pos: {output.position_data.Count()} " +
|
||||
$"n_day_trades: {output.day_trades.Count()} time(msecs): {timer.lastIntervalTime}");
|
||||
//_log_before_posting(output.position_data);
|
||||
_log_before_posting(output.position_data);
|
||||
_bus.post(SparkTags.ReportBlackboardTags.PNL.PNLData, output);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,21 +115,21 @@ namespace mbts.analytics {
|
||||
}
|
||||
|
||||
private void _handle_nonvol_data(VolSurfaceNonVolData vs_nonvol_data) {
|
||||
// bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
|
||||
// _report.ReportName));
|
||||
bts.Log.Gen.info(String.Format("SlideReportCalculator._handle_nonvol_data report {0}",
|
||||
_report.ReportName));
|
||||
_vs_nonvol_data = vs_nonvol_data;
|
||||
}
|
||||
|
||||
private void _handle_future_prices(
|
||||
IReadOnlyDictionary<SecurityExpiration, FutureTheoStructure> future_prices_map) {
|
||||
// bts.Log.Gen.Diag(String.Format("SlideReportCalculator._handle_future_prices report {0}",
|
||||
// _report.ReportName));
|
||||
bts.Log.Gen.info(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;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
@@ -21,33 +22,39 @@
|
||||
<RootNamespace>bts</RootNamespace>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<Version>$(major).$(minor).$(patch)</Version>
|
||||
<Version Condition="'$(version)'=='..'">1.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
|
||||
<PackageReference Include="IronPython" Version="3.4.1" />
|
||||
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="NAudio" Version="2.0.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="OxyPlot.Core" Version="2.1.2" />
|
||||
<PackageReference Include="OxyPlot.Wpf" Version="2.1.2" />
|
||||
<PackageReference Include="protobuf-net" Version="3.2.26" />
|
||||
<PackageReference Include="System.Composition" Version="7.0.0-preview.2.22152.2" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" Version="7.0.0-preview.2.22152.2" />
|
||||
<PackageReference Include="System.Composition.Hosting" Version="7.0.0-preview.2.22152.2" />
|
||||
<PackageReference Include="System.Composition.TypedParts" Version="7.0.0-preview.2.22152.2" />
|
||||
<PackageReference Include="System.Reactive.Core" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reactive.Interfaces" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reactive.Linq" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reactive.PlatformServices" Version="5.0.0" />
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<ProjectReference Include="../spark_api/spark_api.csproj" />
|
||||
<ProjectReference Include="../spark_core/spark_core.csproj" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.21.4" />
|
||||
<PackageReference Include="IronPython" Version="2.7.12" />
|
||||
<PackageReference Include="NAudio" Version="2.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="protobuf-net" Version="3.1.17" />
|
||||
<PackageReference Include="OxyPlot.Core" Version="2.1.2" />
|
||||
<PackageReference Include="OxyPlot.Wpf" Version="2.1.2" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.0" />
|
||||
<PackageReference Include="System.Reactive.Core" Version="6.0.0" />
|
||||
<PackageReference Include="System.Reactive.Interfaces" Version="6.0.0" />
|
||||
<PackageReference Include="System.Reactive.Linq" Version="6.0.0" />
|
||||
<PackageReference Include="System.Reactive.PlatformServices" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\spark_api\spark_api.csproj" />
|
||||
<ProjectReference Include="..\spark_core\spark_core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -55,15 +62,20 @@
|
||||
<Resource Include="**/*.png" />
|
||||
<ConfigDefaults Include="../../lib/config/defaults/*.conf" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Remove="logo.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="logo.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Sounds/game_sound_correct.wav" />
|
||||
<EmbeddedResource Include="Sounds/whistle.wav" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="diagnostic" AfterTargets="PreBuildEvent" />
|
||||
|
||||
</Project>
|
||||
@@ -35,7 +35,7 @@ namespace bts.core {
|
||||
// TODO: for debugging purposes, remove it later
|
||||
if (tag != mbts.spark.SparkTags.SparkTimer) {
|
||||
var tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
//bts.Log.Ui.diag($"SimpleBus.post tag:{tag} tid:{tid}");
|
||||
bts.Log.Ui.diag($"SimpleBus.post tag:{tag} tid:{tid}");
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -45,7 +45,7 @@ namespace bts.core {
|
||||
|
||||
public IObservable<T> subscribe<T>(ITag<T> tag) {
|
||||
var tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
//bts.Log.Ui.info($"SimpleBus.subscribe tag:{tag} tid:{tid}");
|
||||
bts.Log.Ui.info($"SimpleBus.post tag:{tag} tid:{tid}");
|
||||
return subject<T>(tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace mbts.spark {
|
||||
public static ITag<int> CreateHeatmapTag { get; } = _mk_tag<int>();
|
||||
|
||||
// Publisher: VolSurfaceBlackboardManager
|
||||
// User: VolSurfaceModule
|
||||
// User: VoLSurfaceModule
|
||||
public static ITag<IDictionary<int, string>> VolSurfaceListTag { get; } =
|
||||
_mk_tag<IDictionary<int, string>>();
|
||||
|
||||
@@ -202,17 +202,11 @@ namespace mbts.spark {
|
||||
public static ITag<VolSurfaceCalculationRequest> VolSurfaceCalculationRequestTag(int vs_id) =>
|
||||
_mk_tag<VolSurfaceCalculationRequest, int>(vs_id);
|
||||
|
||||
public static ITag<VolSurfaceCalculationRequest> VolSurfaceAutoCalculationRequestTag(int vs_id) =>
|
||||
_mk_tag<VolSurfaceCalculationRequest, int>(vs_id);
|
||||
|
||||
// Publisher : SingleVolSurfaceRequestCalculator
|
||||
// Data : VolSurfaceCalculationResponse
|
||||
public static ITag<VolSurfaceCalculationResponse> VolSurfaceCalculationResponseTag(int vs_id) =>
|
||||
_mk_tag<VolSurfaceCalculationResponse, int>(vs_id);
|
||||
|
||||
public static ITag<VolSurfaceCalculationResponse> VolSurfaceAutoCalculationResponseTag(int vs_id) =>
|
||||
_mk_tag<VolSurfaceCalculationResponse, int>(vs_id);
|
||||
|
||||
// When the UI intends to save the vol surface (data or input)
|
||||
// Publisher: VolSurfaceDisplayModel
|
||||
public static ITag<VolSurfaceInput> VolSurfaceCommitTag(int vs_id) =>
|
||||
|
||||
@@ -591,9 +591,9 @@ namespace mbts.ui {
|
||||
|
||||
// Disabled
|
||||
public static BTSColor disabled_border => UI.input_disabled_border;
|
||||
public static BTSColor disabled_background => Button.disabled_background;
|
||||
public static BTSColor disabled_foreground => Button.disabled_foreground;
|
||||
public static BTSColor disabled_text => Button.disabled_foreground;
|
||||
public static BTSColor disabled_background => UI.input_disabled_background;
|
||||
public static BTSColor disabled_foreground => normal_foreground;
|
||||
public static BTSColor disabled_text => normal_text;
|
||||
public static BTSColor disabled_glyph => normal_glyph;
|
||||
public static BTSColor disabled_button_border => BTSCoreColors.transparent;
|
||||
public static BTSColor disabled_button_background => BTSCoreColors.transparent;
|
||||
@@ -647,7 +647,8 @@ namespace mbts.ui {
|
||||
public static BTSColor pressed_editable_button_background => pressed_button_background;
|
||||
public static BTSColor pressed_editable_button_border => pressed_button_border;
|
||||
|
||||
public static BTSColor disabled_editable_background => Core.transparent;
|
||||
public static BTSColor disabled_editable_background =>
|
||||
editable_background.blend(disabled_background);
|
||||
|
||||
public static BTSColor disabled_editable_border =>
|
||||
editable_border.blend(disabled_border);
|
||||
@@ -1041,21 +1042,6 @@ namespace mbts.ui {
|
||||
public static BTSColor foreground => UI.default_text;
|
||||
public static BTSColor footer_foreground => foreground;
|
||||
}
|
||||
public static class ExecutionStrategy {
|
||||
public static BTSColor expander_background => Core.transparent;//Grid.dark_column_background;
|
||||
public static BTSColor expander_foreground => UI.default_text;
|
||||
public static BTSColor data_grid_row_header_background => Core.transparent;
|
||||
public static BTSColor data_grid_row_header_foreground => UI.default_text;
|
||||
public static BTSColor data_grid_background => Grid.default_row_background;
|
||||
public static BTSColor default_column_background => Grid.default_row_background;
|
||||
public static BTSColor alternate_column_background => Grid.alternate_row_background;// 0xff494957;
|
||||
public static BTSColor arrow_background => UI.default_text;
|
||||
public static BTSColor arrow_background_selected => UI.alternate_text;
|
||||
|
||||
}
|
||||
public static class ManualFills {
|
||||
public static BTSColor background => UI.common_background;
|
||||
}
|
||||
public static class AlgoStudio {
|
||||
public static BTSColor background => UI.default_background;
|
||||
public static BTSColor foreground => UI.default_foreground;
|
||||
|
||||
@@ -76,11 +76,6 @@
|
||||
<Color x:Key="ComboBox.Pressed.Editable.BackgroundColor">#707070</Color>
|
||||
<Color x:Key="ComboBox.Pressed.Editable.Button.BackgroundColor">#FFC4E0FC</Color>
|
||||
|
||||
<Color x:Key="ComboBox.Disabled.Editable.BackgroundColor">#FFE5E5E5</Color>
|
||||
<Color x:Key="ComboBox.Disabled.Editable.BorderColor">#FFD9D9D9</Color>
|
||||
<Color x:Key="ComboBox.Disabled.Editable.Button.BackgroundColor">#FFE5E5E5</Color>
|
||||
<Color x:Key="ComboBox.Disabled.Editable.Button.BorderColor">#FFD9D9D9</Color>
|
||||
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Background" Color="{StaticResource ComboBox.Static.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Foreground" Color="{StaticResource ComboBox.Static.ForegroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Border" Color="{StaticResource ComboBox.Static.BorderColor}"/>
|
||||
@@ -103,7 +98,7 @@
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Border" Color="{StaticResource ComboBoxDisabledBorderColor}"/>
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Background" Color="{StaticResource ComboBox.Disabled.Editable.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Border" Color="{StaticResource ComboBox.Disabled.Editable.BorderColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Background" Color="{StaticResource ComboBox.Disabled.Editable.Button.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Background" Color="{StaticResource ComboBox.Disabled.Editable.BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Disabled.Editable.Button.Border" Color="{StaticResource ComboBox.Disabled.Editable.Button.BorderColor}" />
|
||||
<SolidColorBrush x:Key="ComboBox.Static.Glyph" Color="#FF606060"/>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<Setter Property="Focusable" Value="False"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="True"/>
|
||||
<Setter Property="Background" Value="{u:BTSColor UI.ScrollBar.thumb_pressed}"/>
|
||||
<Setter Property="Background" Value="{u:BTSColor ScrollBar.thumb_pressed}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
@@ -224,18 +224,18 @@
|
||||
<VisualState Name="Normal"/>
|
||||
<VisualState Name="MouseOver">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor UI.ScrollBar.thumb_mouse_over}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor ScrollBar.thumb_mouse_over}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="Pressed">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor UI.ScrollBar.thumb_pressed}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor ScrollBar.thumb_pressed}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Thumb.Background>
|
||||
<SolidColorBrush Color="{u:BTSColor UI.ScrollBar.thumb_static}"/>
|
||||
<SolidColorBrush Color="{u:BTSColor ScrollBar.thumb_static}"/>
|
||||
</Thumb.Background>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
@@ -380,18 +380,18 @@
|
||||
<VisualState Name="Normal"/>
|
||||
<VisualState Name="MouseOver">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{StaticResource u:BTSColor UI.ScrollBar.thumb_mouse_over}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{StaticResource u:BTSColor ScrollBar.thumb_mouse_over}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState Name="Pressed">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor UI.ScrollBar.thumb_presseds}"/>
|
||||
<ColorAnimation Storyboard.TargetProperty="Background.Color" BeginTime="0" Duration="0" To="{u:BTSColor ScrollBar.thumb_presseds}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Thumb.Background>
|
||||
<SolidColorBrush Color="{u:BTSColor UI.ScrollBar.thumb_static}"/>
|
||||
<SolidColorBrush Color="{u:BTSColor ScrollBar.thumb_static}"/>
|
||||
</Thumb.Background>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
|
||||
@@ -15,16 +15,12 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace mbts.ui.spark {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
using TickDisplaySettings = user.settings.TickDisplaySettings;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for PriceEntryControl.xaml
|
||||
/// </summary>
|
||||
class PriceEntryControl : Control {
|
||||
readonly PropertyUpdateGate _price_text_gate = new PropertyUpdateGate();
|
||||
ContractSpecificationImmutable? _spec;
|
||||
RegionalTickFactors _tick;
|
||||
TextBox _text;
|
||||
IDisposable _text_hooks;
|
||||
double? _raw_value;
|
||||
@@ -57,17 +53,16 @@ namespace mbts.ui.spark {
|
||||
(o, v) => o._update_text(v),
|
||||
(o, v) => {
|
||||
o._raw_value = v;
|
||||
if ((!o._spec.HasValue && o._tick is null) || DoubleHelper.IsNaNOrInfinity(v))
|
||||
if (!o._spec.HasValue || DoubleHelper.IsNaNOrInfinity(v))
|
||||
return v;
|
||||
// Note: the decimal cast here is important bc double-rounding errors can cause the keyboard text to conflict with poorly rounded result, and negate Tick Up/Down commands.
|
||||
// This happens bc the tick up/down commands flush the current text before inc/decrementing.
|
||||
var v_dec = (decimal)v;
|
||||
var rounded = (double)(o._tick?.round_to_tick(v_dec) ?? o._spec.Value.round_to_tick(v_dec));
|
||||
if (MathUtils.epsilon_equals(rounded, v)) {
|
||||
double tick = (double)o._spec.Value.round_to_tick((decimal)v);
|
||||
if (MathUtils.epsilon_equals(tick, v)) {
|
||||
// this value has already been rounded, don't make it re-enter the CoerceValueCallback delegate.
|
||||
return v;
|
||||
}
|
||||
return rounded;
|
||||
return tick;
|
||||
},
|
||||
double.NaN);
|
||||
|
||||
@@ -107,26 +102,6 @@ namespace mbts.ui.spark {
|
||||
public ContractSpecificationImmutable? ContractSpec { get => GetValue(ContractSpecProperty) as ContractSpecificationImmutable?; set => SetValue(ContractSpecProperty, value); }
|
||||
#endregion
|
||||
|
||||
#region RegionalTick
|
||||
public static readonly DependencyProperty RegionalTickProperty =
|
||||
WPFHelper.create_dp<RegionalTickFactors, PriceEntryControl>(
|
||||
nameof(RegionalTick),
|
||||
(o, v) => {
|
||||
o._tick = v;
|
||||
if (o._raw_value.HasValue) {
|
||||
o.SetCurrentValue(ValueProperty, o._raw_value.Value);
|
||||
if (o.AlwaysReformatOnSpecChange)
|
||||
o._update_text();
|
||||
}
|
||||
}, RegionalTickFactors.Default);
|
||||
|
||||
public RegionalTickFactors RegionalTick {
|
||||
get => GetValue(RegionalTickProperty) as RegionalTickFactors;
|
||||
set => SetValue(RegionalTickProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
/// TODO: verify that this control behaves correctly when <see cref="AlwaysReformatOnSpecChange"/> is true (ideally this prop will be removed, and this control will always behave is if the prop is true).
|
||||
/// Because this control is ubiquitious in our application, such verification will require careful, meticulous analysis.
|
||||
/// Until such verification is complete, this boolean property will be used to trigger the behavior, so unsuspecting instances of this control will not be affected.
|
||||
@@ -151,8 +126,6 @@ namespace mbts.ui.spark {
|
||||
double v = Value;
|
||||
if (double.IsNaN(v)) {
|
||||
SetCurrentValue(ValueProperty, TickDefaultValue);
|
||||
} else if (_tick is not null) {
|
||||
SetCurrentValue(ValueProperty, _tick.tickup(v));
|
||||
} else {
|
||||
var spec = ContractSpec;
|
||||
if (spec.HasValue) SetCurrentValue(ValueProperty, spec.Value.tickup(v));
|
||||
@@ -164,8 +137,6 @@ namespace mbts.ui.spark {
|
||||
double v = Value;
|
||||
if (double.IsNaN(v)) {
|
||||
SetCurrentValue(ValueProperty, TickDefaultValue);
|
||||
} else if (_tick is not null) {
|
||||
SetCurrentValue(ValueProperty, _tick.tickdown(v));
|
||||
} else {
|
||||
var spec = ContractSpec;
|
||||
if (spec.HasValue) SetCurrentValue(ValueProperty, spec.Value.tickdown(v));
|
||||
@@ -178,15 +149,7 @@ namespace mbts.ui.spark {
|
||||
|
||||
void _update_text(double v) {
|
||||
if (_text != null)
|
||||
_price_text_gate.try_update(() => {
|
||||
if (_tick is not null) {
|
||||
var settings = TickDisplaySettings.Default;
|
||||
settings.tick_factors = _tick.get_tick_for(v);
|
||||
_text.Text = _tick.format(v, settings);
|
||||
return;
|
||||
}
|
||||
_text.Text = _spec.HasValue ? _spec.Value.format(v, double.NaN, false, string.Empty) : v.ToString();
|
||||
});
|
||||
_price_text_gate.try_update(() => _text.Text = _spec.HasValue ? _spec.Value.format(v, double.NaN, false, string.Empty) : v.ToString());
|
||||
}
|
||||
|
||||
void _update_value() =>
|
||||
|
||||
@@ -485,10 +485,6 @@
|
||||
Width="{TemplateBinding Width}"
|
||||
MinWidth="{TemplateBinding MinWidth}"
|
||||
MaxWidth="{TemplateBinding MaxWidth}"
|
||||
TickUpCommand="{TemplateBinding TickUpCommand}"
|
||||
TickUpCommandParameter="{TemplateBinding TickUpCommandParameter}"
|
||||
TickDownCommand="{TemplateBinding TickDownCommand}"
|
||||
TickDownCommandParameter="{TemplateBinding TickDownCommandParameter}"
|
||||
>
|
||||
<TextBox
|
||||
Name="PART_TextBox"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
namespace mbts.ui.controls {
|
||||
using bts.api.domain;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.ui.extensions;
|
||||
using mbts.ui.utilities;
|
||||
@@ -229,12 +228,6 @@ namespace mbts.ui.controls {
|
||||
get => _explicit_props.value;
|
||||
set => _explicit_props.value = value;
|
||||
}
|
||||
|
||||
bool _has_valid_bounds =>
|
||||
Minimum < Maximum;
|
||||
|
||||
T _default_value =>
|
||||
_has_valid_bounds ? T.Zero.within_range(Minimum, Maximum) : T.Zero;
|
||||
|
||||
public override void OnApplyTemplate() {
|
||||
Disposable.dispose(ref _text_hooks);
|
||||
@@ -279,7 +272,7 @@ namespace mbts.ui.controls {
|
||||
var v = _value_d;
|
||||
if (!v.HasValue) {
|
||||
if (AllowNullTick) {
|
||||
SetCurrentValue(ValueProperty, _default_value);
|
||||
SetCurrentValue(ValueProperty, T.Zero);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -287,10 +280,6 @@ namespace mbts.ui.controls {
|
||||
TickUpDownHelper.nullable_tick_up(v, _increment_d, out var result_d, _maximum_d) :
|
||||
TickUpDownHelper.nullable_tick_down(v, _increment_d, out result_d, _minimum_d)) {
|
||||
var result = NumericCastOutConverter<T>.convert(result_d.assert_value());
|
||||
// Enforce min/max bounds (if bounds are valid)
|
||||
if (_has_valid_bounds) {
|
||||
result = result.within_range(Minimum, Maximum);
|
||||
}
|
||||
SetCurrentValue(ValueProperty, result);
|
||||
CoerceValue(ValueProperty);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace mbts.ui.converters {
|
||||
using RegionalTickFactors = user.settings.RegionalTickFactors;
|
||||
|
||||
class TickDisplayConverter : IMultiValueConverter {
|
||||
public static TickDisplayConverter Instance => new();
|
||||
|
||||
@@ -26,13 +24,10 @@ namespace mbts.ui.converters {
|
||||
if (values.Length == 2 && values[1] is bts.api.domain.TickDisplaySettingsImmutable tdsi) {
|
||||
return tdsi.to_tick_display_settings().format(price);
|
||||
}
|
||||
var spec = get_val<ContractSpecificationImmutable?>(values, 1);
|
||||
var spec = get_val<ContractSpecificationImmutable?>(values, 1) ??
|
||||
Security.Defaults.ContractSpecificationImmutable;
|
||||
var settings = get_val<mbts.user.settings.TickDisplaySettings>(values, 2);
|
||||
if (spec.HasValue) {
|
||||
return spec.Value.format(price, settings);
|
||||
}
|
||||
var rtick = get_val<RegionalTickFactors>(values, 1) ?? RegionalTickFactors.Default;
|
||||
return rtick.format(price, settings);
|
||||
return spec.format(price, settings);
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
|
||||
|
||||
@@ -34,8 +34,7 @@
|
||||
</Style>
|
||||
<Style x:Key="DisabledPlaceholderComboBox" TargetType="ComboBox">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.ComboBox.disabled_foreground}"/>
|
||||
<Setter Property="Background" Value="{u:BTSColor UI.ComboBox.disabled_button_background}"/>
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
<Setter Property="SelectedIndex" Value="0"/>
|
||||
<Setter Property="ItemsSource">
|
||||
<Setter.Value>
|
||||
|
||||
@@ -386,9 +386,9 @@
|
||||
<ControlTemplate x:Key="DataGridRowDefaultTemplate" TargetType="DataGridRow">
|
||||
<Border
|
||||
x:Name="DGR_Border"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"
|
||||
SnapsToDevicePixels="True">
|
||||
<u:StateManager.Groups>
|
||||
<u:StateGroupsManager AttachToMembers="True">
|
||||
@@ -408,9 +408,7 @@
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="DGR_Border" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{u:BTSColor ExecutionStrategy.default_column_background}" />
|
||||
<!-- <DiscreteObjectKeyFrame KeyTime="0" Value="{u:BTSColor Core.red}" /> -->
|
||||
<!-- <DiscreteObjectKeyFrame KeyTime="1" Value="{u:BTSColor Core.blue}" /> -->
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{u:BTSColor Grid.alternate_row_background}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
@@ -427,8 +425,7 @@
|
||||
HeadersVisibility,
|
||||
ConverterParameter={x:Static DataGridHeadersVisibility.Row},
|
||||
Converter={x:Static DataGrid.HeadersVisibilityConverter},
|
||||
RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
||||
Background="transparent"/>
|
||||
RelativeSource={RelativeSource AncestorType=DataGrid}}" />
|
||||
<DataGridCellsPresenter
|
||||
Grid.Column="1"
|
||||
ItemsPanel="{TemplateBinding ItemsPanel}"
|
||||
@@ -454,7 +451,7 @@
|
||||
<Style TargetType="{x:Type DataGrid}">
|
||||
<Setter Property="UseLayoutRounding" Value="True" />
|
||||
<Setter Property="ColumnHeaderStyle" Value="{StaticResource {x:Type DataGridColumnHeader}}" />
|
||||
<Setter Property="Background" Value="{uc:BTSColor Name=Core.transparent}" />
|
||||
<Setter Property="Background" Value="{uc:BTSColor Name=UI.default_background}" />
|
||||
<Setter Property="AlternationCount" Value="2" />
|
||||
<Setter Property="RowStyle" Value="{StaticResource {x:Type DataGridRow}}" />
|
||||
<Setter Property="AutoGenerateColumns" Value="False" />
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
|
||||
// Compare bids
|
||||
if (direct.int_price == implied.int_price) {
|
||||
bid[x] = new NativePriceSize(direct.int_price, direct.size, implied.size);
|
||||
bid[x] = new NativePriceSize(direct.int_price, direct.size_f, implied.size_f);
|
||||
dbid_idx++;
|
||||
ibid_idx++;
|
||||
}
|
||||
@@ -185,7 +185,7 @@
|
||||
|
||||
// Compare asks
|
||||
if (direct.int_price == implied.int_price) {
|
||||
ask[x] = new NativePriceSize(direct.int_price, direct.size, implied.size);
|
||||
ask[x] = new NativePriceSize(direct.int_price, direct.size_f, implied.size_f);
|
||||
dask_idx++;
|
||||
iask_idx++;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
namespace mbts.co2 {
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Size = System.Single;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public readonly struct NativePriceLevel {
|
||||
readonly IntPrice _bid;
|
||||
readonly IntPrice _ask;
|
||||
readonly uint _bid_size;
|
||||
readonly uint _ask_size;
|
||||
readonly Size _bid_size;
|
||||
readonly Size _ask_size;
|
||||
|
||||
public NativePriceLevel(IntPrice bid, uint bid_size, IntPrice ask, uint ask_size) {
|
||||
public NativePriceLevel(IntPrice bid, Size bid_size, IntPrice ask, Size ask_size) {
|
||||
_bid = bid;
|
||||
_bid_size = bid_size;
|
||||
_ask = ask;
|
||||
|
||||
@@ -5,27 +5,29 @@ namespace mbts.co2 {
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Size = System.Single;
|
||||
|
||||
public readonly struct NativePriceSize : IEquatable<NativePriceSize> {
|
||||
readonly IntPrice _price;
|
||||
readonly uint _size;
|
||||
readonly uint _direct_size;
|
||||
readonly Size _size;
|
||||
readonly Size _direct_size;
|
||||
|
||||
static NativePriceSize() =>
|
||||
Log.assert(Marshal.SizeOf<NativePriceSize>() == 16);
|
||||
|
||||
public NativePriceSize(IntPrice price, uint size) {
|
||||
public NativePriceSize(IntPrice price, Size size) {
|
||||
_price = price;
|
||||
_size = size;
|
||||
_direct_size = size;
|
||||
}
|
||||
|
||||
public NativePriceSize(long mantissa, sbyte exponent, uint size) {
|
||||
public NativePriceSize(long mantissa, sbyte exponent, Size size) {
|
||||
_price = new IntPrice(mantissa, exponent);
|
||||
_size = size;
|
||||
_direct_size = size;
|
||||
}
|
||||
|
||||
public NativePriceSize(IntPrice price, uint direct_size, uint implied_size) {
|
||||
public NativePriceSize(IntPrice price, Size direct_size, Size implied_size) {
|
||||
_price = price;
|
||||
_size = direct_size + implied_size;
|
||||
_direct_size = direct_size;
|
||||
@@ -36,15 +38,18 @@ namespace mbts.co2 {
|
||||
public IntPrice int_price => _price;
|
||||
public long mantissa => _price.mantissa;
|
||||
public sbyte exponent => _price.exponent;
|
||||
public uint size => _size;
|
||||
public uint direct_size => _direct_size;
|
||||
public uint implied_size => _size - _direct_size;
|
||||
public uint size => (uint)_size;
|
||||
public uint direct_size => (uint)_direct_size;
|
||||
public uint implied_size => (uint)(_size - _direct_size);
|
||||
public Size size_f => _size;
|
||||
public Size direct_size_f => _direct_size;
|
||||
public Size implied_size_f => _size - _direct_size;
|
||||
public double price => _price.price();
|
||||
public bool is_nan => _price.is_nan;
|
||||
|
||||
|
||||
public override string ToString() =>
|
||||
$"{price} {size} ({implied_size})";
|
||||
$"{price} {size_f} ({implied_size})";
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is NativePriceSize p ? Equals(p) : base.Equals(obj);
|
||||
|
||||
@@ -3,13 +3,14 @@ using mbts.co2;
|
||||
|
||||
namespace bts.md
|
||||
{
|
||||
using Size = System.Single;
|
||||
public class PriceSize
|
||||
{
|
||||
public uint size { get; }
|
||||
public uint direct_size { get; }
|
||||
public uint implied_size { get; }
|
||||
public Size size { get; }
|
||||
public Size direct_size { get; }
|
||||
public Size implied_size { get; }
|
||||
public double price { get; }
|
||||
public PriceSize(uint sz, uint direct_sz, uint implied_sz, double prx)
|
||||
public PriceSize(Size sz, Size direct_sz, Size implied_sz, double prx)
|
||||
{
|
||||
size = sz;
|
||||
direct_size = direct_sz;
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
#nullable enable
|
||||
namespace mbts {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.domain;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.co2;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
public readonly struct SecurityMD : IEquatable<SecurityMD> {
|
||||
public static readonly Func<SecurityMD, uint> key_fn = smd => smd.security.Id;
|
||||
@@ -19,28 +14,21 @@ namespace mbts {
|
||||
SecurityImmutable security,
|
||||
IMDConsumerHandle md,
|
||||
TickDisplaySettingsImmutable? price_display = null,
|
||||
TickDisplaySettingsImmutable? quantity_display = null,
|
||||
IEnumerable<TickDisplayRuleImmutable>? price_display_rules = null) {
|
||||
TickDisplaySettingsImmutable? quantity_display = null) {
|
||||
this.security = security;
|
||||
this.md = md;
|
||||
this.price_display = price_display ?? Security.Defaults.price_display_settingsi;
|
||||
this.quantity_display = quantity_display ??
|
||||
Security.Defaults.quantity_display_settingsi;
|
||||
this.price_display_rules = price_display_rules
|
||||
.empty_if_null()
|
||||
.OrderBy(r => r.MaxValue)
|
||||
.ToImmutableList();
|
||||
// Validate new 'price rules' config (be strict...this is a hotfix to prod)
|
||||
Log.assert(this.price_display_rules.All(r => r.MaxValue.is_real()));
|
||||
Log.assert(this.price_display_rules.Select(r => r.MaxValue).IsDistinct());
|
||||
unit_quantity = 1;
|
||||
}
|
||||
|
||||
public SecurityImmutable security { get; }
|
||||
public uint id => security.Id;
|
||||
public IMDConsumerHandle md { get; }
|
||||
public double unit_quantity { get; }
|
||||
public TickDisplaySettingsImmutable price_display { get; }
|
||||
public TickDisplaySettingsImmutable quantity_display { get; }
|
||||
public ImmutableList<TickDisplayRuleImmutable> price_display_rules { get; }
|
||||
|
||||
public override int GetHashCode() =>
|
||||
(int)security.Id;
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Spark.Core.Data {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.domain;
|
||||
using bts.collections;
|
||||
|
||||
using mbts;
|
||||
using mbts.config;
|
||||
@@ -56,21 +55,7 @@ namespace Spark.Core.Data {
|
||||
}
|
||||
// Can't possibly be null (the delegate above already checked for this)
|
||||
raw_meta = Log.notnull(raw_meta);
|
||||
var meta = convert_raw_metadata(raw_meta);
|
||||
if (sec.ContractCase == Security.ContractOneofCase.Spread
|
||||
&& meta.HasValue
|
||||
&& meta.Value.PriceRules.AtLeast(2)) {
|
||||
// This is a hack to force Deribit Combos to have uniform ticks
|
||||
var rules = meta.Value.PriceRules
|
||||
.Where(r => r.HasTickDisplay && r.TickDisplay.HasTickFactors);
|
||||
if (rules.TryGetMinElement(
|
||||
r => r.TickDisplay.TickFactors.tick_unit_frac(), out var min_tick_rule)) {
|
||||
var mutable_meta = meta.Value.CloneToMutable();
|
||||
mutable_meta.PriceRules.SetItems(new[] { min_tick_rule.CloneToMutable() });
|
||||
meta = mutable_meta.immutable();
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
return convert_raw_metadata(raw_meta);
|
||||
});
|
||||
|
||||
SecurityMetadataImmutable? convert_raw_metadata(SecurityMetadataItem raw_meta) {
|
||||
@@ -81,8 +66,8 @@ namespace Spark.Core.Data {
|
||||
/// Don't mutate the actual object stored in <see cref="_security_metadata"/>
|
||||
var meta = raw_meta.Value.Clone();
|
||||
meta.PriceDisplay ??= Security.Defaults.price_display_settings;
|
||||
// meta.PriceDisplay.TickFactors = sec.spec_or_default()
|
||||
// .tick_factors().to_api_tick_factorsi().CloneToMutable();
|
||||
meta.PriceDisplay.TickFactors = sec.spec_or_default()
|
||||
.tick_factors().to_api_tick_factorsi().CloneToMutable();
|
||||
return new(meta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@ namespace mbts.user.settings {
|
||||
_low_tick_inclusive_end = low_tick_inclusive_end;
|
||||
}
|
||||
|
||||
public static RegionalTickFactors Default =>
|
||||
new(new(10000, 1), new(10000, 1), double.MaxValue);
|
||||
|
||||
public TickFactors low_tick => _low_tick;
|
||||
public TickFactors high_tick => _high_tick;
|
||||
public double low_tick_inclusive_end => _low_tick_inclusive_end;
|
||||
|
||||
@@ -55,16 +55,9 @@ namespace mbts {
|
||||
this TickFactors tick_factors) =>
|
||||
new(tick_factors.to_api_tick_display_settings());
|
||||
|
||||
public static bool is_valid(this TickFactors tick) {
|
||||
if (!tick.tick_unit.is_real_positive() && !tick.tick_base.is_real_positive()) {
|
||||
return false;
|
||||
}
|
||||
var ticks_per_base = tick.tick_base / tick.tick_unit;
|
||||
if (ticks_per_base.is_int()) {
|
||||
return true;
|
||||
}
|
||||
return tick.tick_unit > tick.tick_base && tick.tick_base == 1;
|
||||
}
|
||||
public static bool is_valid(this TickFactors tick) =>
|
||||
(tick.tick_unit > 0 && tick.tick_unit <= (tick.tick_base * 0.5)) ||
|
||||
tick.tick_unit == tick.tick_base;
|
||||
|
||||
public static bool is_valid(this RegionalTickFactors regional_tick) =>
|
||||
regional_tick.low_tick.is_valid() && regional_tick.high_tick.is_valid();
|
||||
@@ -72,10 +65,6 @@ namespace mbts {
|
||||
public static bool is_integer(this TickFactors tick) =>
|
||||
tick.tick_unit == tick.tick_base;
|
||||
|
||||
public static TickFactors tick_factors(this RegionalTickFactors regional_tick, double value) =>
|
||||
value > regional_tick.low_tick_inclusive_end ?
|
||||
regional_tick.high_tick : regional_tick.low_tick;
|
||||
|
||||
public static double tick_unit_frac(this TickFactors tick) =>
|
||||
tick.tick_unit / tick.tick_base;
|
||||
|
||||
@@ -87,21 +76,6 @@ namespace mbts {
|
||||
|
||||
public static double reduced_base(this TickFactors tick) => MathUtils.factor_out(tick.tick_base, 10);
|
||||
|
||||
public static bool tick_equals(this RegionalTickFactors regional_tick, double x, double y) {
|
||||
if (x.is_nan()) {
|
||||
return y.is_nan();
|
||||
}
|
||||
if (y.is_nan()) {
|
||||
return false;
|
||||
}
|
||||
var xtick = regional_tick.tick_factors(x);
|
||||
var ytick = regional_tick.tick_factors(y);
|
||||
return xtick is not null
|
||||
&& ytick is not null
|
||||
&& xtick.Equals(ytick)
|
||||
&& xtick.tick_equals(x, y);
|
||||
}
|
||||
|
||||
public static bool tick_equals(this TickFactors tick, double x, double y) {
|
||||
if (x.is_nan()) {
|
||||
return y.is_nan();
|
||||
@@ -118,35 +92,27 @@ namespace mbts {
|
||||
}
|
||||
var x_units = MathUtils.round_fractional_units(x, tick.tick_unit_frac<T>());
|
||||
var y_units = MathUtils.round_fractional_units(y, tick.tick_unit_frac<T>());
|
||||
return NumericCastConverter<T, long>.convert(x_units) ==
|
||||
NumericCastConverter<T, long>.convert(y_units);
|
||||
return NumericCastConverter<T, int>.convert(x_units) ==
|
||||
NumericCastConverter<T, int>.convert(y_units);
|
||||
}
|
||||
|
||||
public static IEqualityComparer<T> tick_equality_comparer<T>(this TickFactors tick)
|
||||
where T : IFloatingPoint<T> =>
|
||||
EqualityComparer.Create<T>(
|
||||
(a, b) => tick_equals(tick, a, b),
|
||||
x => NumericCastConverter<T, int>.convert(
|
||||
MathUtils.round_fractional_units(x, tick.tick_unit_frac<T>())));
|
||||
x => NumericCastConverter<T, int>.convert(MathUtils.round_fractional_units(x, tick.tick_unit_frac<T>())));
|
||||
|
||||
public static IEqualityComparer<double> tick_equality_comparer(this TickFactors tick) =>
|
||||
EqualityComparer.Create<double>(
|
||||
(a, b) => tick_equals(tick, a, b),
|
||||
x => (int)MathUtils.round_fractional_units(x, tick.tick_unit_frac()));
|
||||
|
||||
public static TickFactors get_tick_for(this RegionalTickFactors rtick, double value) =>
|
||||
value > rtick.low_tick_inclusive_end ? rtick.high_tick : rtick.low_tick;
|
||||
|
||||
public static string format_without_decimal_part(this TickFactors tick, double value) =>
|
||||
format(tick, value, double.NaN, false, _nan_text, true);
|
||||
|
||||
public static string format<T>(this TickFactors tick, T value) where T : IFloatingPointIeee754<T> =>
|
||||
format(tick, value, T.NaN, false, _nan_text);
|
||||
|
||||
public static string format<T>(this RegionalTickFactors regional_tick, T value, bool show_commas)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
format(regional_tick, value, T.NaN, show_commas, _nan_text);
|
||||
|
||||
public static string format<T>(this TickFactors tick, T value, bool show_commas)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
format(tick, value, T.NaN, show_commas, _nan_text);
|
||||
@@ -177,19 +143,6 @@ namespace mbts {
|
||||
value, settings.display_multiplier.as_type<double, T>(), settings.show_commas);
|
||||
}
|
||||
|
||||
public static string format<T>(
|
||||
this RegionalTickFactors regional_tick,
|
||||
T value,
|
||||
T display_multiplier,
|
||||
bool show_commas,
|
||||
string nan_text,
|
||||
bool show_decimal_part = true
|
||||
) where T : IFloatingPointIeee754<T> {
|
||||
var value_d = NumericCastConverter<T, double>.convert(value);
|
||||
return regional_tick.tick_factors(value_d)
|
||||
.format(value, display_multiplier, show_commas, nan_text, show_decimal_part);
|
||||
}
|
||||
|
||||
public static string format<T>(
|
||||
this TickFactors tick,
|
||||
T value,
|
||||
@@ -278,44 +231,33 @@ namespace mbts {
|
||||
_parse(regional_tick, text, display_multiplier, nan_text) :
|
||||
_parse_no_tick(text, display_multiplier, nan_text);
|
||||
|
||||
public static T tick<T>(this TickFactors tick, T value, long count)
|
||||
public static T tick<T>(this TickFactors tick, T value, int count)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
count < 0 ? tick.tickdown(value, (uint)-count) : tick.tickup(value, (ulong)count);
|
||||
count < 0 ? tick.tickdown(value, (uint)-count) : tick.tickup(value, (uint)count);
|
||||
|
||||
public static T tick<T>(this bts.api.domain.TickFactorsImmutable tick, T value, long count)
|
||||
public static T tick<T>(this bts.api.domain.TickFactorsImmutable tick, T value, int count)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
tick.to_tick_factors().tick(value, count);
|
||||
|
||||
public static T tick<T>(
|
||||
this bts.api.domain.TickDisplaySettingsImmutable settings, T value, long count)
|
||||
this bts.api.domain.TickDisplaySettingsImmutable settings, T value, int count)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
settings.HasTickFactors ?
|
||||
settings.TickFactors.tick(value, count) :
|
||||
throw new ArgumentException(
|
||||
"Can't tick because 'settings.HasTickFactors' is false", nameof(settings));
|
||||
|
||||
public static double tick(
|
||||
this RegionalTickFactors regional_tick, double input, long count) =>
|
||||
tick<double>(regional_tick, input, count);
|
||||
|
||||
public static T tick<T>(
|
||||
this RegionalTickFactors regional_tick, T input, long count)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
count > 0 ?
|
||||
tickup(regional_tick, input, (ulong)count) :
|
||||
tickdown(regional_tick, input, (ulong)-count);
|
||||
|
||||
public static T tickup<T>(this TickFactors tick, T input, ulong count = 1)
|
||||
public static T tickup<T>(this TickFactors tick, T input, uint count = 1)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
tickup(tick, input, count, TickUtils.precision_const<T>());
|
||||
|
||||
public static T tickup<T>(this TickFactors tick, T input, ulong count, T precision)
|
||||
public static T tickup<T>(this TickFactors tick, T input, uint count, T precision)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
tickup<T, NumericCastOutConverter<T>>(tick, input, count, precision);
|
||||
|
||||
public static T tickup<T, TFromUInt64>(this TickFactors tick, T input, ulong count, T precision)
|
||||
public static T tickup<T, TFromUInt32>(this TickFactors tick, T input, uint count, T precision)
|
||||
where T : IFloatingPointIeee754<T>
|
||||
where TFromUInt64 : IConverter<ulong, T> {
|
||||
where TFromUInt32 : IConverter<uint, T> {
|
||||
if (!precision.is_real_positive()) {
|
||||
throw new ArgumentException("Must be a real positive number.", nameof(precision));
|
||||
}
|
||||
@@ -328,33 +270,21 @@ namespace mbts {
|
||||
if (ieeer < -precision) {
|
||||
count--;
|
||||
}
|
||||
var result = input + tuf * TFromUInt64.convert(count);
|
||||
var result = input + tuf * TFromUInt32.convert(count);
|
||||
return _round_tick(tuf, result);
|
||||
}
|
||||
|
||||
public static double tickup(
|
||||
this RegionalTickFactors regional_tick, double input, long count = 1) =>
|
||||
count switch {
|
||||
> 0 => tickup<double>(regional_tick, input, (ulong)count),
|
||||
< 0 => tickdown<double>(regional_tick, input, (ulong)-count),
|
||||
0 => input,
|
||||
};
|
||||
|
||||
public static double tickup(
|
||||
this RegionalTickFactors regional_tick, double input, ulong count) =>
|
||||
tickup<double>(regional_tick, input, count);
|
||||
|
||||
public static T tickup<T>(
|
||||
this RegionalTickFactors regional_tick, T input) where T : IFloatingPointIeee754<T> =>
|
||||
regional_tick.tickup(input, 1);
|
||||
|
||||
public static T tickup<T>(
|
||||
this RegionalTickFactors regional_tick, T input, ulong count)
|
||||
this RegionalTickFactors regional_tick, T input, uint count)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
regional_tick.tickup(input, count, TickUtils.precision_const<T>());
|
||||
|
||||
public static T tickup<T>(
|
||||
this RegionalTickFactors regional_tick, T input, ulong count, T precision)
|
||||
this RegionalTickFactors regional_tick, T input, uint count, T precision)
|
||||
where T : IFloatingPointIeee754<T> {
|
||||
if (!precision.is_real_positive()) {
|
||||
throw new ArgumentException("Must be a real positive number.", nameof(precision));
|
||||
@@ -371,33 +301,33 @@ namespace mbts {
|
||||
var ieeer = T.Ieee754Remainder(input, tuf);
|
||||
input -= ieeer;
|
||||
if (ieeer < -precision) count--;
|
||||
val = input + tuf * count.as_type<ulong, T>();
|
||||
val = input + tuf * count.as_type<uint, T>();
|
||||
if (val > ltie) {
|
||||
count -= MathUtils.round_up((ltie - input) / tuf, precision).as_type<T, ulong>();
|
||||
count -= MathUtils.round_up((ltie - input) / tuf, precision).as_type<T, uint>();
|
||||
tuf = regional_tick.high_tick.tick_unit_frac<T>();
|
||||
val = ltie + tuf * count.as_type<ulong, T>();
|
||||
val = ltie + tuf * count.as_type<uint, T>();
|
||||
}
|
||||
} else {
|
||||
tuf = regional_tick.high_tick.tick_unit_frac<T>();
|
||||
var ieeer = T.Ieee754Remainder(input, tuf);
|
||||
input -= ieeer;
|
||||
if (ieeer < -precision) count--;
|
||||
val = input + tuf * count.as_type<ulong, T>();
|
||||
val = input + tuf * count.as_type<uint, T>();
|
||||
}
|
||||
return _round_tick(tuf, val);
|
||||
}
|
||||
|
||||
public static T tickdown<T>(this TickFactors tick, T input, ulong count = 1)
|
||||
public static T tickdown<T>(this TickFactors tick, T input, uint count = 1)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
tickdown(tick, input, count, TickUtils.precision_const<T>());
|
||||
|
||||
public static T tickdown<T>(this TickFactors tick, T input, ulong count, T precision)
|
||||
public static T tickdown<T>(this TickFactors tick, T input, uint count, T precision)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
tickdown<T, NumericCastOutConverter<T>>(tick, input, count, precision);
|
||||
|
||||
public static T tickdown<T, TFromUInt64>(this TickFactors tick, T input, ulong count, T precision)
|
||||
public static T tickdown<T, TFromUInt32>(this TickFactors tick, T input, uint count, T precision)
|
||||
where T : IFloatingPointIeee754<T>
|
||||
where TFromUInt64 : IConverter<ulong, T> {
|
||||
where TFromUInt32 : IConverter<uint, T> {
|
||||
if (!input.is_real()) {
|
||||
return input;
|
||||
}
|
||||
@@ -407,42 +337,30 @@ namespace mbts {
|
||||
if (ieeer > precision) {
|
||||
count--;
|
||||
}
|
||||
var result = input - tuf * TFromUInt64.convert(count);
|
||||
var result = input - tuf * TFromUInt32.convert(count);
|
||||
return _round_tick(tuf, result);
|
||||
}
|
||||
|
||||
public static double tickdown(
|
||||
this RegionalTickFactors regional_tick, double input, long count = 1) =>
|
||||
count switch {
|
||||
> 0 => tickdown<double>(regional_tick, input, (ulong)count),
|
||||
< 0 => tickup<double>(regional_tick, input, (ulong)count),
|
||||
0 => input,
|
||||
};
|
||||
|
||||
public static double tickdown(
|
||||
this RegionalTickFactors regional_tick, double input, ulong count) =>
|
||||
tickdown<double>(regional_tick, input, count);
|
||||
|
||||
public static T tickdown<T>(this RegionalTickFactors regional_tick, T input)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
regional_tick.tickdown(input, 1);
|
||||
|
||||
public static T tickdown<T>(this RegionalTickFactors regional_tick, T input, ulong count)
|
||||
public static T tickdown<T>(this RegionalTickFactors regional_tick, T input, uint count)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
tickdown(regional_tick, input, count, TickUtils.precision_const<T>());
|
||||
|
||||
public static T tickdown<T>(
|
||||
this RegionalTickFactors regional_tick, T input, ulong count, T precision)
|
||||
this RegionalTickFactors regional_tick, T input, uint count, T precision)
|
||||
where T : IFloatingPointIeee754<T> =>
|
||||
tickdown<T, NumericCastOutConverter<T>, NumericCastOutConverter<T>, NumericCastInConverter<T>>(
|
||||
regional_tick, input, count, precision);
|
||||
|
||||
public static T tickdown<T, TFromUInt32, TFromDouble, TToUInt16>(
|
||||
this RegionalTickFactors regional_tick, T input, ulong count, T precision)
|
||||
this RegionalTickFactors regional_tick, T input, uint count, T precision)
|
||||
where T : IFloatingPointIeee754<T>
|
||||
where TFromDouble : IConverter<double, T>
|
||||
where TFromUInt32 : IConverter<ulong, T>
|
||||
where TToUInt16 : IConverter<T, ulong> {
|
||||
where TFromUInt32 : IConverter<uint, T>
|
||||
where TToUInt16 : IConverter<T, uint> {
|
||||
if (!precision.is_real_positive()) {
|
||||
throw new ArgumentException("Must be a real positive number.", nameof(precision));
|
||||
}
|
||||
@@ -505,6 +423,16 @@ namespace mbts {
|
||||
CashPerPoint = 1
|
||||
};
|
||||
|
||||
public static bool try_get_tickdiff(this RegionalTickFactors regional_tick, double minuend, double subtrahend, out int n_low, out int n_high) {
|
||||
if (DoubleHelper.IsNaNOrInfinity(minuend) || DoubleHelper.IsNaNOrInfinity(subtrahend)) {
|
||||
n_low = default;
|
||||
n_high = default;
|
||||
return false;
|
||||
}
|
||||
(n_low, n_high) = tickdiff_unchecked(regional_tick, minuend, subtrahend);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the difference, in tick units, between <paramref name="minuend"/> and <paramref name="subtrahend"/>
|
||||
/// </summary>
|
||||
@@ -513,14 +441,31 @@ namespace mbts {
|
||||
/// </remarks>
|
||||
/// <param name="minuend">The minuend</param>
|
||||
/// <param name="subtrahend">The subtrahend</param>
|
||||
public static long? tickdiff(this RegionalTickFactors regional_tick, double minuend, double subtrahend) {
|
||||
if (!minuend.is_real() || !subtrahend.is_real()) {
|
||||
return null;
|
||||
internal static (int n_low, int n_high) tickdiff_unchecked(this RegionalTickFactors regional_tick, double minuend, double subtrahend) {
|
||||
Log.assert(minuend.is_real() && subtrahend.is_real());
|
||||
|
||||
double ltie = regional_tick.low_tick_inclusive_end;
|
||||
double raw_diff = minuend - subtrahend;
|
||||
|
||||
if (minuend < ltie) {
|
||||
if (subtrahend < ltie) {
|
||||
return ((int)MathUtils.round_fractional_units(raw_diff, regional_tick.low_tick.tick_unit_frac()), 0);
|
||||
}
|
||||
double low_diff = ltie - minuend;
|
||||
double high_diff = raw_diff - low_diff;
|
||||
int n_low = (int)MathUtils.round_fractional_units(low_diff, regional_tick.low_tick.tick_unit_frac());
|
||||
int n_high = (int)MathUtils.round_fractional_units(high_diff, regional_tick.high_tick.tick_unit_frac());
|
||||
return (n_low, n_high);
|
||||
}
|
||||
var minuend_n = TickUtils.count_ticks(regional_tick, minuend);
|
||||
var subtrahend_n = TickUtils.count_ticks(regional_tick, subtrahend);
|
||||
var n = minuend_n - subtrahend_n;
|
||||
return n;
|
||||
|
||||
if (subtrahend < ltie) {
|
||||
double high_diff = minuend - ltie;
|
||||
double low_diff = raw_diff - high_diff;
|
||||
int n_low = (int)MathUtils.round_fractional_units(low_diff, regional_tick.high_tick.tick_unit_frac());
|
||||
int n_high = (int)MathUtils.round_fractional_units(high_diff, regional_tick.high_tick.tick_unit_frac());
|
||||
return (n_low, n_high);
|
||||
}
|
||||
return (0, (int)MathUtils.round_fractional_units(raw_diff, regional_tick.high_tick.tick_unit_frac()));
|
||||
}
|
||||
|
||||
public static double round(this TickFactors tick, double input) =>
|
||||
@@ -557,10 +502,6 @@ namespace mbts {
|
||||
new(tick_base ?? tick_factors.tick_base, tick_unit ?? tick_factors.tick_unit);
|
||||
|
||||
static char _separator(TickFactors tick) {
|
||||
if (tick.tick_base == 1 && tick.tick_unit > tick.tick_base &&
|
||||
MathUtils.is_int(tick.tick_unit / tick.tick_base)) {
|
||||
return '.';
|
||||
}
|
||||
double tb_log10 = Math.Log10(tick.tick_base);
|
||||
return tb_log10 >= 1 && tb_log10 % 1 == 0 ? '.' : '-';
|
||||
}
|
||||
|
||||
@@ -1,62 +1,34 @@
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts;
|
||||
using mbts.spark;
|
||||
using mbts.user.settings;
|
||||
|
||||
using Spark.Core.Data;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace bts.data.ticks {
|
||||
class TickFactorsFactory {
|
||||
static readonly RegionalTickFactors _default_rtf = new RegionalTickFactors(new TickFactors(1000, 1), new TickFactors(1000, 1), double.MaxValue);
|
||||
readonly Dictionary<uint, RegionalTickFactors> _sec_ticks = new();
|
||||
readonly Dictionary<SpecKey, RegionalTickFactors> _spec_ticks = new();
|
||||
readonly Dictionary<SpecKey, RegionalTickFactors> _exchange_ticks = new Dictionary<SpecKey, RegionalTickFactors>();
|
||||
|
||||
public RegionalTickFactors default_rtf => _default_rtf;
|
||||
|
||||
public RegionalTickFactors get(ContractSpecification spec) =>
|
||||
_spec_ticks.GetOrAdd(new SpecKey(spec), _create_rtf);
|
||||
_exchange_ticks.GetOrAdd(new SpecKey(spec), _create_rtf);
|
||||
|
||||
public RegionalTickFactors get(ContractSpecificationImmutable spec) =>
|
||||
_spec_ticks.GetOrAdd(new SpecKey(spec), _create_rtf);
|
||||
_exchange_ticks.GetOrAdd(new SpecKey(spec), _create_rtf);
|
||||
|
||||
public RegionalTickFactors get(SecurityImmutable security) =>
|
||||
security.HasContractSpec ? get(security.ContractSpec) : _default_rtf;
|
||||
|
||||
public RegionalTickFactors get(SecurityImmutable? security) =>
|
||||
security.HasValue ?
|
||||
_sec_ticks.GetOrAdd(security.Value.Id, _ => _create_rtf(security.Value)) :
|
||||
_default_rtf;
|
||||
|
||||
static RegionalTickFactors _create_rtf(SecurityImmutable? security) {
|
||||
var meta = SecurityMetadataStore.instance.get(security.Value);
|
||||
return meta?.PriceRules?.Any() ?? false ?
|
||||
_create_rtf(meta.Value.PriceRules.ToList()) :
|
||||
_create_rtf(new SpecKey(security.Value.spec_or_default()));
|
||||
}
|
||||
|
||||
static RegionalTickFactors _create_rtf(
|
||||
IList<api.domain.TickDisplayRuleImmutable> rules) {
|
||||
if (rules.is_null_or_empty()) {
|
||||
throw new ArgumentException("Rules is null or empty", nameof(rules));
|
||||
}
|
||||
if (rules.Count > 2) {
|
||||
throw new ArgumentException("Rules cannot have more than 2 items (backwards compatibility)");
|
||||
}
|
||||
var low_tick = rules[0].TickDisplay.TickFactors;
|
||||
var high_tick_idx = rules.Count > 1 ? 1 : 0;
|
||||
var high_tick = rules[high_tick_idx].TickDisplay.TickFactors;
|
||||
var low_tick_end = rules.Count > 1 ? rules[0].MaxValue : double.MaxValue;
|
||||
return new(low_tick.to_tick_factors(), high_tick.to_tick_factors(), low_tick_end);
|
||||
}
|
||||
security.HasValue ? get(security.Value) : _default_rtf;
|
||||
|
||||
static RegionalTickFactors _create_rtf(SpecKey key) {
|
||||
double tick_base = key.denominator;
|
||||
if (tick_base == 0) {
|
||||
// Tick in pennies if units are < 1 (i.e., fractional)
|
||||
tick_base = key.low_tick > 1 && key.high_tick > 1 ? 1 : 100;
|
||||
// indicates tick is a decimal
|
||||
tick_base = 100;
|
||||
}
|
||||
return _create_rtf(key.low_tick, key.high_tick, key.price_break, tick_base, key.display_digits);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.data.ticks;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.co2;
|
||||
using mbts.user.settings;
|
||||
|
||||
using Spark.Core;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
@@ -38,9 +36,6 @@ namespace mbts.spark {
|
||||
public static IComparer<double> price_comparer(this ContractSpecificationImmutable spec) =>
|
||||
MathUtils.epsilon_comparer.wrap<double, double>(p => spec.round_to_tick(p));
|
||||
|
||||
public static IComparer<double> price_comparer(this RegionalTickFactors rtick) =>
|
||||
MathUtils.epsilon_comparer.wrap<double, double>(p => rtick.round_to_tick(p));
|
||||
|
||||
public static double ticksize(this ContractSpecificationImmutable spec, double price) {
|
||||
if (!spec.LowTick.is_real_positive()) {
|
||||
return spec.HighTick;
|
||||
@@ -53,23 +48,8 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public static double ticksize(this RegionalTickFactors rtick, double price) {
|
||||
var low_tick = rtick.low_tick.tick_unit_frac();
|
||||
var high_tick = rtick.high_tick.tick_unit_frac();
|
||||
var price_break = rtick.low_tick_inclusive_end;
|
||||
if (!low_tick.is_real_positive()) {
|
||||
return high_tick;
|
||||
} else if (!high_tick.is_real_positive()) {
|
||||
return low_tick;
|
||||
} else if (!price.is_real() || !price_break.is_real()) {
|
||||
return low_tick;
|
||||
} else {
|
||||
return price > price_break ? high_tick : low_tick;
|
||||
}
|
||||
}
|
||||
|
||||
public static string format(this ContractSpecificationImmutable spec, double price, bool in_tick_terms) =>
|
||||
in_tick_terms ?
|
||||
in_tick_terms ?
|
||||
_get(spec).format_without_decimal_part(price / spec.ticksize(price)) :
|
||||
_get(spec).format(price);
|
||||
|
||||
@@ -107,13 +87,18 @@ namespace mbts.spark {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static long? tickdiff(this ContractSpecificationImmutable spec, double x, double y) =>
|
||||
get_regional_ticks(spec).tickdiff(x, y);
|
||||
public static int? tickdiff(this ContractSpecificationImmutable spec, double x, double y) {
|
||||
if (get_regional_ticks(spec).try_get_tickdiff(x, y, out int n_low, out int n_high))
|
||||
return n_low + n_high;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long? tickdiff(this SecurityImmutable sec, double x, double y) =>
|
||||
get_regional_ticks(sec).tickdiff(x, y);
|
||||
public static int tickdiff_unchecked(this ContractSpecificationImmutable spec, double x, double y) {
|
||||
(int n_low, int n_high) = get_regional_ticks(spec).tickdiff_unchecked(x, y);
|
||||
return n_low + n_high;
|
||||
}
|
||||
|
||||
public static double mid_tick(RegionalTickFactors spec, double bid, double ask) {
|
||||
public static double mid_tick(ContractSpecificationImmutable spec, double bid, double ask) {
|
||||
double raw_mid;
|
||||
if (double.IsNaN(bid)) {
|
||||
if (double.IsNaN(ask)) return double.NaN;
|
||||
@@ -129,8 +114,8 @@ namespace mbts.spark {
|
||||
raw_mid - (raw_mid % tick_size);
|
||||
}
|
||||
|
||||
public static TickFactors deduce_ticks(IEnumerable<SecurityImmutable> securities) {
|
||||
var ticks = new HashSet<TickFactors>(securities.Select(_get).SelectMany(rtf => new[] { rtf.low_tick, rtf.high_tick }));
|
||||
public static TickFactors deduce_ticks(IEnumerable<ContractSpecification> contract_specs) {
|
||||
var ticks = new HashSet<TickFactors>(contract_specs.Select(_get).SelectMany(rtf => new[] { rtf.low_tick, rtf.high_tick }));
|
||||
switch (ticks.Count) {
|
||||
case 0: return _exchange_ticks.default_rtf.low_tick;
|
||||
case 1: return ticks.First();
|
||||
@@ -141,27 +126,30 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public static TickFactors tick_factors(this SecurityImmutable sec) =>
|
||||
_get(sec).low_tick;
|
||||
public static RegionalTickFactors get_tick_factors(ContractSpecificationImmutable spec) =>
|
||||
_get(spec);
|
||||
|
||||
public static TickFactors tick_factors(this ContractSpecificationImmutable spec) =>
|
||||
_get(spec).low_tick;
|
||||
|
||||
public static double tickup(this ContractSpecificationImmutable spec, double value) =>
|
||||
_get(spec).tickup(value);
|
||||
|
||||
public static double tickup(this ContractSpecificationImmutable spec, double value, long count) {
|
||||
public static double tickup(this ContractSpecificationImmutable spec, double value, int count) {
|
||||
uint bl = 3;
|
||||
var res = value * bl;
|
||||
if (count == 0) return value;
|
||||
if (count < 0) return _get(spec).tickdown(value, (ulong)-count);
|
||||
else return _get(spec).tickup(value, (ulong)count);
|
||||
if (count < 0) return _get(spec).tickdown(value, (uint)(-count));
|
||||
else return _get(spec).tickup(value, (uint)count);
|
||||
}
|
||||
|
||||
public static double tickdown(this ContractSpecificationImmutable spec, double value) =>
|
||||
_get(spec).tickdown(value);
|
||||
|
||||
public static double tickdown(this ContractSpecificationImmutable spec, double value, long count) {
|
||||
public static double tickdown(this ContractSpecificationImmutable spec, double value, int count) {
|
||||
if (count == 0) return value;
|
||||
if (count < 0) return _get(spec).tickup(value, (ulong)-count);
|
||||
else return _get(spec).tickdown(value, (ulong)count);
|
||||
if (count < 0) return _get(spec).tickup(value, (uint)(-count));
|
||||
else return _get(spec).tickdown(value, (uint)count);
|
||||
}
|
||||
|
||||
public static bool tick_equals<T>(
|
||||
@@ -180,7 +168,7 @@ namespace mbts.spark {
|
||||
x => (int)MathUtils.round_fractional_units(x, contract.LowTick));
|
||||
|
||||
public static IEqualityComparer<T> tick_equality_comparer<T>(
|
||||
this ContractSpecificationImmutable contract) where T : IFloatingPoint<T> =>
|
||||
this ContractSpecificationImmutable contract) where T : IFloatingPoint<T> =>
|
||||
EqualityComparer.Create<T>(
|
||||
(a, b) => tick_equals(contract, a, b),
|
||||
x => (int)MathUtils.round_fractional_units(
|
||||
@@ -189,107 +177,85 @@ namespace mbts.spark {
|
||||
public static int compare_tick_fallback_to_double(this ContractSpecificationImmutable contract, double x, double y) =>
|
||||
tick_equals(contract, x, y) ? 0 : x.CompareTo(y);
|
||||
|
||||
public static double round_to_tick(this ContractSpecificationImmutable spec, double value) =>
|
||||
round_to_tick(spec.ticksize(value), value);
|
||||
|
||||
public static decimal round_to_tick(this ContractSpecificationImmutable spec, decimal value) =>
|
||||
round_to_tick((decimal)spec.ticksize((double)value), value);
|
||||
|
||||
public static double round_to_tick(this RegionalTickFactors rtick, double value) =>
|
||||
round_to_tick(rtick.ticksize(value), value);
|
||||
|
||||
public static decimal round_to_tick(this RegionalTickFactors rtick, decimal value) =>
|
||||
round_to_tick((decimal)rtick.ticksize((double)value), value);
|
||||
|
||||
public static double round_to_tick(double tick_size, double value) {
|
||||
public static double round_to_tick(this ContractSpecificationImmutable spec, double value) {
|
||||
double intpart = (long)value;
|
||||
double floatpart = value % 1;
|
||||
floatpart = ((int)Math.Round(floatpart / tick_size)) * tick_size;
|
||||
double tick = spec.ticksize(value);
|
||||
floatpart = ((int)Math.Round(floatpart / tick)) * tick;
|
||||
return intpart + floatpart;
|
||||
}
|
||||
|
||||
public static decimal round_to_tick(decimal tick_size, decimal value) {
|
||||
public static decimal round_to_tick(this ContractSpecificationImmutable spec, decimal value) {
|
||||
decimal intpart = (long)value;
|
||||
decimal floatpart = value % 1;
|
||||
floatpart = ((int)(floatpart / tick_size)) * tick_size;
|
||||
decimal tick = (decimal)spec.ticksize((double)value);
|
||||
floatpart = ((int)(floatpart / tick)) * tick;
|
||||
return intpart + floatpart;
|
||||
}
|
||||
|
||||
public static long? count_ticks(this RegionalTickFactors rtick, double value) {
|
||||
if (!rtick.is_valid()) {
|
||||
public static int? full_ticks_from_zero(this ContractSpecificationImmutable spec, double value) =>
|
||||
full_ticks_from(spec, 0, value);
|
||||
|
||||
public static int? full_ticks_from(this ContractSpecificationImmutable spec, double origin, double value) {
|
||||
if (!value.is_real() || !origin.is_real())
|
||||
return null;
|
||||
if (value < origin) {
|
||||
if (spec.LowTick.is_real_positive()) {
|
||||
if (spec.HighTick.is_real_positive() && spec.PriceBreak < origin && spec.PriceBreak > value) {
|
||||
var ticks_to_break = MathUtils.round_up((spec.PriceBreak - origin) / spec.HighTick, _precision_const);
|
||||
var low_ticks_remainder = MathUtils.round_up((value - spec.PriceBreak) / spec.LowTick, _precision_const);
|
||||
return (int)(ticks_to_break + low_ticks_remainder);
|
||||
} else {
|
||||
return (int)MathUtils.round_up((value - origin) / spec.LowTick, _precision_const);
|
||||
}
|
||||
} else if (spec.HighTick.is_real_positive()) {
|
||||
return (int)MathUtils.round_up((value - origin) / spec.HighTick, _precision_const);
|
||||
}
|
||||
} else {
|
||||
if (spec.HighTick.is_real_positive()) {
|
||||
if (spec.LowTick.is_real_positive() && spec.PriceBreak > origin && spec.PriceBreak < value) {
|
||||
var ticks_to_break = MathUtils.round_down((spec.PriceBreak - origin) / spec.LowTick, _precision_const);
|
||||
var high_ticks_remainder = MathUtils.round_down((value - spec.PriceBreak) / spec.HighTick, _precision_const);
|
||||
return (int)(ticks_to_break + high_ticks_remainder);
|
||||
} else {
|
||||
return (int)MathUtils.round_down(value / spec.HighTick, _precision_const);
|
||||
}
|
||||
} else if (spec.LowTick.is_real_positive()) {
|
||||
return (int)MathUtils.round_down(value / spec.LowTick, _precision_const);
|
||||
}
|
||||
}
|
||||
var n = _count_ticks(
|
||||
rtick.low_tick.tick_unit_frac(),
|
||||
rtick.low_tick_inclusive_end,
|
||||
rtick.high_tick.tick_unit_frac(),
|
||||
0,
|
||||
value);
|
||||
var orig_n = n;
|
||||
// Enforce proper rounding
|
||||
var rounded_val = rtick.round_to_tick(value);
|
||||
var half_tick = rtick.get_tick_for(value).tick_unit_frac() / 2;
|
||||
if (n < 0 && (value - rounded_val) > half_tick) {
|
||||
++n;
|
||||
} else if (n > 0 && (rounded_val - value) > half_tick) {
|
||||
--n;
|
||||
}
|
||||
Log.assert(n == orig_n);
|
||||
return n;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static RegionalTickFactors get_regional_ticks(ContractSpecificationImmutable? spec) =>
|
||||
spec.HasValue ? _get(spec.Value) : _exchange_ticks.default_rtf;
|
||||
|
||||
public static RegionalTickFactors regional_ticks(this SecurityImmutable security) =>
|
||||
_exchange_ticks.get(security);
|
||||
public static RegionalTickFactors get_regional_ticks(SecurityImmutable security) =>
|
||||
get_regional_ticks(security.spec_or_default());
|
||||
|
||||
public static RegionalTickFactors get_regional_ticks(SecurityImmutable? security) =>
|
||||
_exchange_ticks.get(security);
|
||||
|
||||
public static TickFactors get_tick(SecurityImmutable? security, double value) {
|
||||
var rtick = get_regional_ticks(security);
|
||||
var tick = rtick.low_tick_inclusive_end > value ? rtick.high_tick : rtick.low_tick;
|
||||
return tick;
|
||||
public static ContractSpecificationImmutable multiply_tick_size(ContractSpecificationImmutable spec, uint factor) {
|
||||
factor = fit_ticks_per_row_to_dollars(spec, factor);
|
||||
return spec.with(low_tick: spec.LowTick * factor, high_tick: spec.HighTick * factor);
|
||||
}
|
||||
|
||||
public static RegionalTickFactors multiply_tick_size(RegionalTickFactors spec, uint factor) {
|
||||
factor = _fit_ticks_per_row_to_dollars(spec, factor) ?? 1;
|
||||
return new(
|
||||
new(spec.low_tick.tick_base, spec.low_tick.tick_unit * factor),
|
||||
new(spec.high_tick.tick_base, spec.high_tick.tick_unit * factor),
|
||||
spec.low_tick_inclusive_end);
|
||||
public static double normalize_price(ContractSpecificationImmutable spec, double price) {
|
||||
var ticks = spec.full_ticks_from_zero(price);
|
||||
return ticks.HasValue ? spec.tickup(0, ticks.Value) : price;
|
||||
}
|
||||
|
||||
public static double normalize_price(RegionalTickFactors rtick, double price) {
|
||||
if (!price.is_real()) {
|
||||
return price;
|
||||
}
|
||||
var ticks = rtick.count_ticks(price);
|
||||
if (!ticks.HasValue) {
|
||||
return price;
|
||||
}
|
||||
var normalized = rtick.tick(0, ticks.Value);
|
||||
var tick = price > rtick.low_tick_inclusive_end ? rtick.high_tick : rtick.low_tick;
|
||||
// Diff should always be < 1/2 tick
|
||||
Log.assert((normalized - price).abs() < tick.tick_unit_frac() * 0.5);
|
||||
return normalized;
|
||||
public static double normalize_price(ContractSpecificationImmutable? spec, double price) {
|
||||
return spec.HasValue ? normalize_price(spec.Value, price) : price;
|
||||
}
|
||||
|
||||
public static uint fit_ticks_per_row_to_dollars(SecurityImmutable sec, uint ticks_per_row) =>
|
||||
_fit_ticks_per_row_to_dollars(sec, ticks_per_row) ?? 1;
|
||||
public static uint fit_ticks_per_row_to_dollars(ContractSpecificationImmutable spec, uint ticks_per_row) =>
|
||||
_fit_ticks_per_row_to_dollars(spec, ticks_per_row) ?? 1;
|
||||
|
||||
public static uint fit_ticks_per_row_to_dollars(RegionalTickFactors rtick, uint ticks_per_row) =>
|
||||
_fit_ticks_per_row_to_dollars(rtick, ticks_per_row) ?? 1;
|
||||
|
||||
static uint? _fit_ticks_per_row_to_dollars(SecurityImmutable sec, uint ticks_per_row) =>
|
||||
_fit_ticks_per_row_to_dollars(sec.regional_ticks(), ticks_per_row);
|
||||
|
||||
static uint? _fit_ticks_per_row_to_dollars(RegionalTickFactors tf, uint ticks_per_row) {
|
||||
static uint? _fit_ticks_per_row_to_dollars(ContractSpecificationImmutable spec, uint ticks_per_row) {
|
||||
if (ticks_per_row == 0)
|
||||
return null;
|
||||
// it is assumed that low tick will be the same as high tick;
|
||||
// however, best to double check - return null if this isn't the case (let the caller decide what to do).
|
||||
var tf = get_tick_factors(spec);
|
||||
if (!tf.low_tick.Equals(tf.high_tick) || !tf.is_valid() || tf.low_tick.is_integer())
|
||||
return null;
|
||||
var ticks_per_dollar = (uint)(tf.low_tick.tick_base / tf.low_tick.tick_unit);
|
||||
@@ -317,61 +283,7 @@ namespace mbts.spark {
|
||||
return null;
|
||||
}
|
||||
|
||||
static long? _count_ticks(
|
||||
double low_tick, double price_break, double high_tick, double from, double to) {
|
||||
if (!from.is_real() || !to.is_real()) {
|
||||
return null;
|
||||
}
|
||||
var has_low = low_tick.is_real_positive();
|
||||
var has_high = high_tick.is_real_positive();
|
||||
if (!has_low) {
|
||||
if (!has_high) {
|
||||
return null;
|
||||
}
|
||||
low_tick = high_tick;
|
||||
} else if (!has_high) {
|
||||
high_tick = low_tick;
|
||||
}
|
||||
if (price_break.is_nan()) {
|
||||
// Take price_break out of play
|
||||
price_break = double.PositiveInfinity;
|
||||
}
|
||||
// Allow core impl to assume: 'from <= to'
|
||||
(from, to) = (from, to).ordered(out var negate);
|
||||
var n_ticks = _count_asc_ticks(low_tick, high_tick, from, to, price_break);
|
||||
return negate ? -n_ticks : n_ticks;
|
||||
}
|
||||
|
||||
static long _count_asc_ticks(
|
||||
double low_tick, double high_tick, double from, double to, double price_break) {
|
||||
Contract.Requires(from <= to);
|
||||
Contract.Requires(low_tick.is_real_positive() && high_tick.is_real_positive());
|
||||
Log.assert(from <= to);
|
||||
checked {
|
||||
if (to <= price_break) {
|
||||
// All ticks are below price_break
|
||||
return count_single_tick_sz(low_tick, from, to);
|
||||
}
|
||||
if (from >= price_break) {
|
||||
// All ticks are above price_break
|
||||
return count_single_tick_sz(high_tick, from, to);
|
||||
}
|
||||
// Ticks cross the price break. Compute low and high ticks separately
|
||||
var low_ticks = count_single_tick_sz(low_tick, from, price_break);
|
||||
var high_ticks = count_single_tick_sz(high_tick, price_break, to);
|
||||
var total_ticks = low_ticks + high_ticks;
|
||||
return total_ticks;
|
||||
|
||||
static long count_single_tick_sz(
|
||||
double tick_sz, double from, double to) {
|
||||
var from_n = (long)MathUtils.round_fractional_units(from, tick_sz);
|
||||
var to_n = (long)MathUtils.round_fractional_units(to, tick_sz);
|
||||
return to_n - from_n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static RegionalTickFactors _get(SecurityImmutable sec) => _exchange_ticks.get(sec);
|
||||
static RegionalTickFactors _get(ContractSpecification spec) => _exchange_ticks.get(spec);
|
||||
static RegionalTickFactors _get(ContractSpecificationImmutable spec) => _exchange_ticks.get(spec);
|
||||
|
||||
public static class CompareUtils {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
namespace bts.api {
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
public static class SecurityExtensions {
|
||||
public static Security.ContractOneofCase contract_case(this SecurityType type) =>
|
||||
@@ -96,6 +97,8 @@ namespace bts.api {
|
||||
return security.Ice.SecurityDesc;
|
||||
} else if (security.HasDeribit) {
|
||||
return security.Deribit.SecurityDesc;
|
||||
} else if (security.HasFtx) {
|
||||
return security.Ftx.SecurityDesc;
|
||||
}
|
||||
Log.assert(false, "security_desc not implemented for exchange");
|
||||
return null;
|
||||
@@ -136,6 +139,7 @@ namespace bts.api {
|
||||
domain.Venue.Bts => Venue.Bts,
|
||||
domain.Venue.Sim => Venue.Sim,
|
||||
domain.Venue.Deribit => Venue.Deribit,
|
||||
domain.Venue.Ftx => Venue.Ftx,
|
||||
domain.Venue.Glbx => Venue.Glbx,
|
||||
domain.Venue.None => Venue.Unset,
|
||||
_ => throw new NotImplementedException(),
|
||||
@@ -146,6 +150,7 @@ namespace bts.api {
|
||||
Venue.Bts => domain.Venue.Bts,
|
||||
Venue.Sim => domain.Venue.Sim,
|
||||
Venue.Deribit => domain.Venue.Deribit,
|
||||
Venue.Ftx => domain.Venue.Ftx,
|
||||
Venue.Glbx => domain.Venue.Glbx,
|
||||
Venue.Unset => domain.Venue.None,
|
||||
_ => throw new NotImplementedException(),
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
string.IsNullOrEmpty(exch_desc) ? format_option(symbol, option) : exch_desc;
|
||||
|
||||
static string _format(SecurityImmutable? security) =>
|
||||
security.HasValue ? _format(security.Value) : "Unknown-security";
|
||||
security.HasValue ? _format(security.Value) : "Unknown-security1";
|
||||
|
||||
static string _format(SecurityImmutable security, bool exchange_specific_formatting = true) {
|
||||
switch (security.ContractCase) {
|
||||
@@ -71,8 +71,10 @@
|
||||
return string.Join("", _format_legs(new ContractLegEnumerable(security.Spread.Legs, 1)));
|
||||
case Security.ContractOneofCase.Synthetic:
|
||||
return security.Synthetic.Name;
|
||||
case Security.ContractOneofCase.Spot:
|
||||
return security.security_desc();
|
||||
default:
|
||||
return "Unknown-security";
|
||||
return "Unknown-security2";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Spark.Core.Reactive {
|
||||
namespace bts.reactive {
|
||||
using System;
|
||||
|
||||
public static class ObserverExtensions {
|
||||
|
||||
Loaded 100 of 459 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user