Compare commits

..
1629 changed files with 42015 additions and 94968 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
IndentWidth: 3
-11
View File
@@ -1,7 +1,4 @@
nohup.out
build/
cmake-build-debug/
.idea/
.dir-locals.el
*.pyc
.vscode/*
@@ -9,15 +6,7 @@ cmake-build-debug/
.vs
obj/
*.csproj.user
*.vspx
*.psess
msbuild.log
*.orig
vcxproj.user
src/client/spark/Properties/launchSettings.json
compile_commands.json
.cquery_cached_index/
src/client/sparkcmd/Properties/launchSettings.json
node_modules
paket-files
project.lock.json
+65 -101
View File
@@ -1,102 +1,66 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"cStandard": "c11",
"cppStandard": "c++17"
},
{
"name": "Windows",
"intelliSenseMode": "clang-x64",
"includePath": [
"${workspaceRoot}/src",
"${workspaceRoot}/build/src",
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
"${workspaceRoot}/externals/windows/vscode/usr/include"
],
"defines": [
"__linux__",
"__x86_64__"
],
"browse": {
"path": [
"${workspaceRoot}/src",
"${workspaceRoot}/build/src",
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
"${workspaceRoot}/externals/windows/vscode/usr/include/*"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"cStandard": "c11",
"cppStandard": "c++17"
},
{
"name": "WindowsQuick",
"intelliSenseMode": "clang-x64",
"includePath": [
"${workspaceRoot}/src",
"${workspaceRoot}/build/src",
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
"${workspaceRoot}/externals/windows/vscode/usr/include"
],
"defines": [
"__linux__",
"__x86_64__"
],
"browse": {
"path": [
"${workspaceRoot}/src"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "${workspaceRoot}/.vscode/browse.vc.db"
},
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
{
"configurations": [
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "Windows",
"intelliSenseMode": "clang-x64",
"includePath": [
"${workspaceRoot}/src",
"${workspaceRoot}/build/src",
"${workspaceRoot}/build/gcc_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
"${workspaceRoot}/externals/windows/vscode/usr/include"
],
"defines": [
"__linux__",
"__x86_64__"
],
"browse": {
"path": [
"${workspaceRoot}/src",
"${workspaceRoot}/build/src",
"${workspaceRoot}/build/gcc_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
"${workspaceRoot}/externals/windows/vscode/usr/include/*"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
}
],
"version": 3
}
+163 -314
View File
@@ -1,315 +1,164 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/build/ninja_debug/src/server/sparkd/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "${workspaceRoot}/build/ninja_debug/src/server/sparkd",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
{
"name": "Client Launch",
"type": "clr",
"request": "launch",
"program": "${workspaceRoot}/build/Debug/bin/net471/spark.exe",
"args": [],
"cwd": "${workspaceRoot}",
"stopAtEntry": false,
"externalConsole": true,
"requireExactSource": false
},
{
"name": "SDK Launch",
"type": "clr",
"request": "launch",
"program": "${workspaceRoot}/build/Debug/bin/net471/spark_sdk.exe",
"args": ["md","GLBX","Future","ES","ESM8"],
"cwd": "${workspaceRoot}",
"stopAtEntry": false,
"externalConsole": true,
"requireExactSource": false
},
{
"name": "Client Attach",
"type": "clr",
"request": "attach",
"processId":"${command:pickProcess}"
},
{
"name": "SparkVM Launch",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
},
{
"description": "Skip STL",
"text": "skip -gfi /usr/include/c++/7/bits/*.h",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@sparkvm"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Spreader Tests",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"args": ["test", "[spreader]"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@sparkvm"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Admin Service Tests",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"args": ["test", "[admin_service]"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@sparkvm"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Limiter Tests",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"args": ["test", "[limiter]"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@sparkvm"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "MD Tests",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"args": ["test", "[md]"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Skip STL",
"text": "skip -gfi /usr/include/c++/7/bits/*.h",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@sparkvm"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "SparkVM attach",
"type": "cppdbg",
"request": "attach",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"processId": "${command:pickRemoteProcess}",
"MIMode": "gdb",
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@sparkvm"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Python",
"type": "python",
"request": "launch",
"stopOnEntry": false,
"pythonPath": "${config:python.pythonPath}",
"program": "${file}",
"cwd": "${workspaceRoot}",
"env": {},
"envFile": "${workspaceRoot}/.env",
"args": [ "DEBUG" ],
"debugOptions": [
"WaitOnAbnormalExit",
"WaitOnNormalExit",
"RedirectOutput"
]
},
{
"name": "edge-asp051",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@edge-asp051"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/bts/": "${workspaceRoot}"
}
},
{
"name": "Docker Launch",
"type": "cppdbg",
"request": "launch",
"program": "/bts/build/gcc_debug/src/server/sparkd/sparkd",
"args": ["test"],
"stopAtEntry": false,
"cwd": "/bts/build/gcc_debug/src/server/sparkd",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["-p 2000","root@localhost"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/bts/": "${workspaceRoot}"
}
}
]
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/build/gcc_debug/src/server/sparkd/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "${workspaceRoot}/build/gcc_debug/src/server/sparkd",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
{
"name": "Client Launch",
"type": "clr",
"request": "launch",
"program": "${workspaceRoot}/build/Debug/bin/net462/spark.exe",
"args": [],
"cwd": "${workspaceRoot}",
"stopAtEntry": false,
"externalConsole": true
},
{
"name": "Client Attach",
"type": "clr",
"request": "attach",
"processId":"${command:pickProcess}"
},
{
"name": "SparkVM Launch",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
"args": ["configcheck", "System"],
"stopAtEntry": true,
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@sparkvm"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Docker Launch",
"type": "cppdbg",
"request": "launch",
"program": "/bts/build/gcc_debug/src/server/sparkd/sparkd",
"args": ["test"],
"stopAtEntry": false,
"cwd": "/bts/build/gcc_debug/src/server/sparkd",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["-p 2000","root@localhost"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/bts/": "${workspaceRoot}"
}
},
{
"name": "Docker attach",
"type": "cppdbg",
"request": "attach",
"program": "/bts/build/gcc_debug/src/server/sparkd/sparkd",
"processId": "${command:pickRemoteProcess}",
"MIMode": "gdb",
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["-p 2000","root@localhost"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/bts/": "${workspaceRoot}"
}
},
{
"name": "Python",
"type": "python",
"request": "launch",
"stopOnEntry": false,
"pythonPath": "${config:python.pythonPath}",
"program": "${file}",
"cwd": "${workspaceRoot}",
"env": {},
"envFile": "${workspaceRoot}/.env",
"args": [ "DEBUG" ],
"debugOptions": [
"WaitOnAbnormalExit",
"WaitOnNormalExit",
"RedirectOutput"
]
},
{
"name": "edge-asp051",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "/home/bts/spark/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": ["bts@edge-asp051"],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/bts/": "${workspaceRoot}"
}
}
]
}
+10 -18
View File
@@ -4,9 +4,9 @@
"version": "2.0.0",
"tasks": [
{
"label": "client_build",
"taskName": "client_build",
"type": "shell",
"command": ".\\tools\\buildspark.cmd",
"command": ".\\tools\\clientbuild.cmd",
"problemMatcher":"$msCompile",
"presentation": {
"echo": true,
@@ -20,30 +20,22 @@
}
},
{
"label": "server_build",
"taskName": "server_build",
"type": "shell",
"command": ".\\tools\\buildsparkd.cmd",
"problemMatcher": {
"base": "$gcc",
"owner": "cpp",
"command": ".\\tools\\ssh_serverbuild.cmd",
"problemMatcher": {
"base": "$gcc",
"fileLocation": [
"relative",
"${workspaceFolder}"
],
"pattern": {
"regexp": "(.?)(home)(.?)(bts)(.?)(spark)(.?)(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)",
"file": 8,
"line": 9,
"column": 10,
"severity": 11,
"message": 12
}
"${workspaceFolder}"
]
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new"
"panel": "shared"
},
"group": {
"kind": "build",
+3 -3
View File
@@ -28,14 +28,14 @@ if (WIN32)
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")
add_subdirectory(src/lib)
else ()
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} \
-Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++14 -fdiagnostics-color")
-Wall -pedantic -Wextra -Werror -Wno-missing-braces --std=c++14 -fdiagnostics-color")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -DNDEBUG -O3")
add_subdirectory(src/lib)
add_subdirectory(src/server/sparkd)
add_subdirectory(src/web)
endif()
+35 -63
View File
@@ -1,10 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2024
VisualStudioVersion = 15.0.26730.12
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}") = "spark_lib", "build\src\lib\spark_lib.vcxproj", "{502FD050-679A-3B50-B438-098500700919}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spark_lib", "build\src\lib\spark_lib.vcxproj", "{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
EndProject
@@ -12,12 +12,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\spar
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{2256015B-E7D5-3614-8F39-814CA68A4444}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
ProjectSection(ProjectDependencies) = postProject
{502FD050-679A-3B50-B438-098500700919} = {502FD050-679A-3B50-B438-098500700919}
EndProjectSection
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -55,22 +50,22 @@ Global
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.Build.0 = Release|x64
{502FD050-679A-3B50-B438-098500700919}.Debug|Any CPU.ActiveCfg = Debug|x64
{502FD050-679A-3B50-B438-098500700919}.Debug|x64.ActiveCfg = Debug|x64
{502FD050-679A-3B50-B438-098500700919}.Debug|x64.Build.0 = Debug|x64
{502FD050-679A-3B50-B438-098500700919}.Debug|x86.ActiveCfg = Debug|x64
{502FD050-679A-3B50-B438-098500700919}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{502FD050-679A-3B50-B438-098500700919}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{502FD050-679A-3B50-B438-098500700919}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{502FD050-679A-3B50-B438-098500700919}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{502FD050-679A-3B50-B438-098500700919}.Release|Any CPU.ActiveCfg = Release|x64
{502FD050-679A-3B50-B438-098500700919}.Release|x64.ActiveCfg = Release|x64
{502FD050-679A-3B50-B438-098500700919}.Release|x64.Build.0 = Release|x64
{502FD050-679A-3B50-B438-098500700919}.Release|x86.ActiveCfg = Release|x64
{502FD050-679A-3B50-B438-098500700919}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{502FD050-679A-3B50-B438-098500700919}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{502FD050-679A-3B50-B438-098500700919}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{502FD050-679A-3B50-B438-098500700919}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Debug|Any CPU.ActiveCfg = Debug|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Debug|x64.ActiveCfg = Debug|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Debug|x64.Build.0 = Debug|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Debug|x86.ActiveCfg = Debug|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Release|Any CPU.ActiveCfg = Release|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Release|x64.ActiveCfg = Release|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Release|x64.Build.0 = Release|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.Release|x86.ActiveCfg = Release|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{9186D3A8-1C5C-372A-A4EE-E1045BCCB0C7}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|Any CPU.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
@@ -131,42 +126,22 @@ Global
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.Build.0 = Release|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|Any CPU.ActiveCfg = Debug|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|x64.ActiveCfg = Debug|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|x64.Build.0 = Debug|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|x86.ActiveCfg = Debug|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|Any CPU.ActiveCfg = Release|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|x64.ActiveCfg = Release|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|x64.Build.0 = Release|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|x86.ActiveCfg = Release|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|Any CPU.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x86.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|Any CPU.Build.0 = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.Build.0 = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x86.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x86.Build.0 = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|Any CPU.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.Build.0 = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x86.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.Build.0 = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x86.Build.0 = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|Any CPU.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.Build.0 = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x86.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|Any CPU.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.Build.0 = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x86.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -174,7 +149,4 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal
-17
View File
@@ -1,17 +0,0 @@
{
"files.associations": {
"chrono": "cpp",
"future": "cpp",
"system_error": "cpp",
"ios": "cpp",
"utility": "cpp",
"iosfwd": "cpp",
"xhash": "cpp",
"xstring": "cpp",
"xtree": "cpp",
"xutility": "cpp",
"exception": "cpp",
"bitset": "cpp",
"xlocale": "cpp"
}
}
+1 -1
View File
@@ -15,7 +15,7 @@
</PropertyGroup>
<PropertyGroup Label="Output">
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)</BaseOutputPath>
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)\$(SolutionName)</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\bin</OutputPath>
<BaseIntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</IntermediateOutputPath>
-30
View File
@@ -1,30 +0,0 @@
using bts.api;
using bts.api.admin;
using bts.api.core;
using bts.spark;
using mbts.spark.utilities;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace mbts.spark {
[Export]
class AdminModel {
readonly AdminService _service;
[ImportingConstructor]
private AdminModel(AdminService service) {
_service = service;
on_admin_data = _service.subscribei_admin_data().Table().Replay(1).RefCount();
}
public IObservable<TableUpdate<AdminDataImmutable, int>> on_admin_data { get; }
}
}
-65
View File
@@ -1,65 +0,0 @@
using bts.api;
using mbts;
using mbts.config;
using mbts.spark;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace bts.ui {
[Export, Export(typeof(IShellDaemon))]
class AboutDaemon : IShellDaemon, IDisposable {
readonly string _user;
readonly IBrowserWindowManager _browser;
IDisposable _dispose;
[ImportingConstructor]
public AboutDaemon(IBus bus, [Import("username")]string username, IBrowserWindowManager browser) {
_user = username;
_browser = browser;
_dispose = bus.subscribe(SparkTags.About).ObserveOnDispatcher().Subscribe(_ => show_about());
}
[Conditional("DEBUG")]
private void enable_crash_on_dblclick(Window w) {
w.MouseDoubleClick += (o,e) => {
throw new DebugException("Too many or too few clicks on BTS logo.");
};
}
void show_about() {
Window about = Application.LoadComponent(new Uri("/view/Shell/About.xaml", UriKind.Relative)) as Window;
enable_crash_on_dblclick(about);
if (about != null) {
about.DataContext = new { Version = Configuration.get<bts.config.System>().version, User = _user };
about.Topmost = true;
about.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (a, b) => about.Close()));
about.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, (arg, e) => {
if (e.Parameter != null) {
string param = e.Parameter.ToString();
if (!string.IsNullOrEmpty(param) && param.IndexOf("http") == 0) {
Process.Start(param);
}
else if (!string.IsNullOrEmpty(param)) {
Uri address = new Uri("bts://" + param);
_browser.Pages.Add(address);
}
}
}));
about.Show();
}
}
public void Dispose() {
Disposable.dispose(ref _dispose);
}
}
}
@@ -1,43 +0,0 @@
using bts.api;
using bts.log;
using mbts;
using mbts.spark;
using mbts.ui;
using System;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reactive.Linq;
namespace bts {
[Export, Export(typeof(IShellDaemon))]
class DeleteSyntheticDaemon : IShellDaemon, IDisposable {
readonly OrdersModel _orders_model;
IDisposable _dispose;
[ImportingConstructor]
public DeleteSyntheticDaemon(IBus bus, OrdersModel orders_model) {
_orders_model = orders_model;
_dispose = bus.subscribe(SparkTags.SyntheticDeleteTag)
.ObserveOnDispatcher()
.Subscribe(_delete_synthetic);
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
async void _delete_synthetic(uint id) {
var (orders, orders_success) = await _orders_model.on_orders.FirstAsyncTask(SparkUtils.DefaultTimeOut);
if (!orders_success) {
Logger.warn(Subsystem.Ui, $"Ignoring request to delete synthetic security ({id}) because the orders lookup timed out (must confirm no working orders).");
} else if (orders.state.Values.Any(o => o.Def.SecurityKey == id && o.is_non_terminal())) {
Logger.warn(Subsystem.Ui, $"Ignoring request to delete synthetic security ({id}) because non-terminal-orders were detected.");
} else {
var (strategy, strategy_success) = await _orders_model.spreader.lookup_strategy_async(id);
if (strategy_success) {
var deleted_strategy = strategy.with(deleted: true);
await _orders_model.spreader.save_strategy(id, deleted_strategy);
}
}
}
}
}
@@ -1,21 +0,0 @@
using bts.api.core;
using bts.api.diagnostic;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bts.spark {
[Export(typeof(IShellDaemon))]
class DiagnosticDaemon : IShellDaemon {
readonly ShellDiagnosticsServiceServer _service;
[ImportingConstructor]
public DiagnosticDaemon(ServiceContext context, CompositionContainer container) {
_service = new ShellDiagnosticsServiceServer(container, context);
}
}
}
-82
View File
@@ -1,82 +0,0 @@
using bts.api;
using bts.api.core;
using bts.support;
using mbts;
using mbts.spark;
using mbts.ui;
using System;
using System.ComponentModel.Composition;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace bts.spark
{
[Export, Export(typeof(IShellDaemon))]
public class ErrorReporter : IShellDaemon, IDisposable {
readonly ErrorReportService _svc;
readonly string _username;
IDisposable _dispose;
[ImportingConstructor]
public ErrorReporter(ErrorReportService svc, IBus bus, [Import("username")] string username) {
_svc = svc;
_username = username;
_dispose = bus.subscribe(SparkTags.Support).ObserveOnDispatcher().Subscribe(msg => show_support_window(msg, "Report a problem"));
}
public void Dispose() {
Disposable.dispose(ref _dispose);
}
public async Task report_error(string message, string title = null, MessageBoxImage? image = null) {
var result = await BTSMessageBox.ShowAsync(message, title = "Error", BTSMessageBoxButtons.OK | BTSMessageBoxButtons.Support, image ?? MessageBoxImage.Error);
if (result == BTSMessageBoxButtons.Support) {
show_support_window(message, title);
}
}
public void show_support_window(string message, string title) {
view.controls.SupportRequestWindow.Show(_svc, new ErrorReport() {
User = _username,
ErrorTitle = title,
ErrorMessage = message,
});
}
}
static class ErrorReporterExtensions
{
public static bool handle_error<T, TError>(this ErrorReporter error_reporter, Result<T> result, string template, TError error, bool error_ok) =>
handle_error(error_reporter, result, template, error, error_ok, false, true);
public static TRV handle_error<T, TError, TRV>(this ErrorReporter error_reporter, Result<T> result, string template, TError error, bool error_ok, TRV successful_rv, TRV unsuccessful_rv = default) =>
handle_error(error_reporter, result, template, _ => error, _ => error_ok, _ => successful_rv, () => unsuccessful_rv).result;
public static bool handle_error<T, TError>(this ErrorReporter error_reporter, Result<T> result, string template, Func<T, TError> get_error, Func<TError, bool> get_error_ok) =>
handle_error(error_reporter, result, template, get_error, get_error_ok, _ => true, () => false).result;
public static (TRV result, string error) handle_error<T, TError, TRV>(this ErrorReporter error_reporter, Result<T> result, string template, Func<T, TError> get_error, Func<TError, bool> get_error_ok, Func<T, TRV> get_successful_rv) =>
handle_error(error_reporter, result, template, get_error, get_error_ok, get_successful_rv, () => default);
public static (TRV result, string error) handle_error<T, TError, TRV>(
this ErrorReporter error_reporter, Result<T> result, string template,
Func<T, TError> get_error, Func<TError, bool> get_error_ok,
Func<T, TRV> get_successful_rv, Func<TRV> get_unsuccessful_rv
) {
if (result.success) {
TError error = get_error(result.value);
if (get_error_ok(error))
return (get_successful_rv(result.value), string.Empty);
else {
string error_msg = template.fmt(error);
error_reporter.report_error(error_msg).ignore();
return (get_unsuccessful_rv(), error_msg);
}
} else {
error_reporter.report_error(result.error_message).ignore();
return (get_unsuccessful_rv(), result.error_message);
}
}
}
}
-80
View File
@@ -1,80 +0,0 @@
using bts.api;
using bts.api.synthetic;
using bts.log;
using mbts;
using mbts.co2;
using mbts.spark;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Linq;
using SecurityKey = System.UInt32;
namespace bts {
[Export(typeof(IShellDaemon))]
class MDSource : IObserver<List<SecurityAndHandle>>, IShellDaemon, IDisposable {
readonly IBus _bus;
readonly MDConsumer _consumer = new MDConsumer();
readonly Co2RelayControl _relay;
HashSet<SecurityKey> _deleted_synthetics = new HashSet<SecurityKey>();
List<IDisposable> _dispose = new List<IDisposable>();
IReadOnlyDictionary<SecurityKey, SecurityMD> _exchange_sec_map = new Dictionary<SecurityKey, SecurityMD>();
[ImportingConstructor]
public MDSource(IBus bus, SyntheticSecurityService ss) {
_bus = bus;
_relay = new Co2RelayControl(_consumer);
_relay.preload_securities((co2.MDRequest.Types.Flags)0xff).ignore();
_dispose.Add(_consumer.on_security.Subscribe(this));
_dispose.Add(
ss.subscribei_metadata()
.Select(upd => upd.all.ToDictionary(i => i.SecurityKey, i => i.Strategy))
.Subscribe(t => {
_deleted_synthetics = new HashSet<uint>(t.Where(kv => kv.Value.Deleted).Select(kv => kv.Key));
_bus.post(SparkTags.SyntheticstrategiesTag, t);
}));
new DataPersistor(_bus);
Task.Run(run);
}
[Export]
MDConsumer consumer => _consumer;
public void OnCompleted() { }
public void OnError(Exception error) => Logger.error(Subsystem.gen, error.ToString());
public void OnNext(List<SecurityAndHandle> values) {
if (values.Count > 0) {
var temp = _exchange_sec_map.ToDictionary(k => k.Key, k => k.Value);
foreach (var v in values) {
temp.Add(v.security.Id, new SecurityMD(v.security, v.handle));
}
_exchange_sec_map = temp;
}
}
public void Dispose() => Disposable.dispose(_dispose);
async Task run() {
int exch_sec_count = 0, deleted_synth_count = 0;
while (true) {
var exch = _exchange_sec_map;
var deleted_synths = _deleted_synthetics;
if (exch.Count > exch_sec_count || deleted_synths.Count != deleted_synth_count) {
exch_sec_count = exch.Count;
deleted_synth_count = deleted_synths.Count;
exch = exch.Where(kv => !deleted_synths.Contains(kv.Key)).ToDictionary();
try {
Logger.log(Level.Info, Subsystem.gen, String.Format("MDSource publishing {0} securities", exch.Count));
_bus.post(SparkTags.SecuritiesTag, exch);
} catch (Exception e) {
Logger.error(Subsystem.md, $"Error in publish_securities: {e}");
}
}
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
}
}
@@ -1,39 +0,0 @@
using mbts;
using mbts.ui;
using System;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bts.api;
using mbts.spark;
using bts.spark;
using bts.api.orderman;
using System.Windows;
namespace bts
{
[Export, Export(typeof(IShellDaemon))]
class ModifyOrderDaemon : IShellDaemon, IDisposable {
readonly IBus _bus;
IDisposable _dispose;
[ImportingConstructor]
public ModifyOrderDaemon(IBus bus) {
_bus = bus;
//_dispose = Disposable.Create(
// bus.subscribe(SparkTags.ShowModifyOrderTag).Subscribe(show_modify_order)
//);
_dispose = null;
}
void show_modify_order(OrderRecordImmutable record) {
// lauch the order ticket
}
public void Dispose() {
Disposable.dispose(ref _dispose);
}
}
}
@@ -1,70 +0,0 @@
using bts.api;
using bts.api.core;
using bts.api.orderman;
using bts.spark;
using mbts;
using mbts.spark;
using mbts.ui;
using mbts.ui.spark;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Reactive.Linq;
using System.Windows;
namespace bts.shell {
[Export(typeof(IShellDaemon))]
class OrderTicketDaemon : IShellDaemon {
readonly IBus _bus;
readonly OrdersModel _model;
readonly ErrorReporter _error_reporter;
IReadOnlyDictionary<uint, SecurityMD> _md_map;
TableUpdate<OrderRecordImmutable, uint> _orders;
IDisposable _dispose;
[ImportingConstructor]
public OrderTicketDaemon(IBus bus, OrdersModel model, ErrorReporter error_reporter) {
_bus = bus;
_model = model;
_error_reporter = error_reporter;
_dispose = Disposable.Create(
model.on_orders.ObserveOnDispatcher().Subscribe(o => _orders = o),
bus.subscribe(SparkTags.SecuritiesTag).ObserveOnDispatcher().Subscribe(m =>_md_map = m),
bus.subscribe(SparkTags.ShowOrderTicketFromSecurityTag).ObserveOnDispatcher().Subscribe(_show_order_ticket),
bus.subscribe(SparkTags.ShowOrderTicketTag).ObserveOnDispatcher().Subscribe(_show_order_ticket),
bus.subscribe(SparkTags.ShowModifyOrderTag).ObserveOnDispatcher().Subscribe(_show_modify_order)
);
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
static void _show_order_window(Window window) =>
window.Show(-200, -160, true);
void _show_order_ticket(SecurityMD smd) =>
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd,
Observable.Return(_model.factory.default_ladder_settings(smd.security)))
});
void _show_order_ticket((OrderDefinitionImmutable def, double price, uint size) ops) {
if (_md_map.TryGetValue(ops.def.SecurityKey, out SecurityMD smd))
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd, ops.def, ops.price, ops.size,
Observable.Return(_model.factory.default_ladder_settings(smd.security).calculator_buttons))
});
}
void _show_modify_order(uint order_key) {
if (_orders.state.TryGetValue(order_key, out OrderRecordImmutable ori) && _md_map.TryGetValue(ori.Def.SecurityKey, out SecurityMD smd)
&& (ori.HasDef && ori.Def.HasCustomDef && !(ori.Def.CustomDef.HasStop || ori.Def.CustomDef.HasStopLimit)))
_show_order_window(new OrderModificationDialog {
DataContext = new ExistingOrderTicketVM(_model,
Observable.Return(new OrderRecordTuple(ori, smd)),
Observable.Return(_model.factory.default_ladder_settings(smd.security).calculator_buttons)
)
});
}
}
}
@@ -1,130 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bts.api;
using mbts.spark;
using mbts.ui;
using System.ComponentModel.Composition;
using mbts;
using System.Windows;
using System.Windows.Input;
using bts.spark;
using System.Reactive.Linq;
namespace bts {
[Export, Export(typeof(IShellDaemon))]
class SecurityPickerDaemon : IShellDaemon, IDisposable {
readonly IBus _bus;
IDisposable _dispose;
[ImportingConstructor]
public SecurityPickerDaemon(IBus bus) {
_bus = bus;
_dispose = Disposable.Create(
bus.subscribe(SparkTags.ShowPickOne).ObserveOnDispatcher().Subscribe(show_pick_one),
bus.subscribe(SparkTags.FilterPickOne).ObserveOnDispatcher().Subscribe(show_filtered_pick_one),
bus.subscribe(SparkTags.ShowPickMultiple).ObserveOnDispatcher().Subscribe(show_pick_multiple),
bus.subscribe(SparkTags.ShowAndEditPickMultiple).ObserveOnDispatcher().Subscribe(show_and_edit_pick_multiple)
);
}
void show_pick_one(PartialCommand<SecurityMD> message) {
var vm = new ContractPickerModel(_bus, false, null);
var view = new ContractPickerView(vm);
Window picker = new Window {
Content = view,
Title = $"Select a Security for {message.title}",
Icon = message.icon,
Height = view.Height,
Width = view.Width
};
picker.Style = picker.TryFindResource("BTSWindow") as Style;
view.Height = Double.NaN;
view.Width = Double.NaN;
vm.ok_action = () => {
picker.Close();
message.complete(vm.result).execute(_bus);
};
picker.move_to_mouse();
picker.Show();
}
void show_filtered_pick_one((PartialCommand<SecurityMD> message, SecurityCriteria global_filter) message_and_filter) {
var vm = new ContractPickerModel(_bus, false, null, message_and_filter.global_filter);
var view = new ContractPickerView(vm);
Window picker = new Window {
Content = view,
Title = $"Select a Security for {message_and_filter.message.title}",
Icon = message_and_filter.message.icon,
Height = view.Height,
Width = view.Width
};
picker.Style = picker.TryFindResource("BTSWindow") as Style;
view.Height = Double.NaN;
view.Width = Double.NaN;
vm.ok_action = () => {
picker.Close();
message_and_filter.message.complete(vm.result).execute(_bus);
};
picker.move_to_mouse();
picker.Show();
}
void show_pick_multiple(PartialCommand<SecurityCriteria> message) {
var vm = new ContractPickerModel(_bus, true, null);
var view = new ContractPickerView(vm);
Window picker = new Window
{
Content = view,
Title = $"Select Securities for {message.title}",
Icon = message.icon,
Height = view.Height,
Width = view.Width,
};
picker.Style = picker.TryFindResource("BTSWindow") as Style;
view.Height = Double.NaN;
view.Width = Double.NaN;
vm.ok_action = () => {
picker.Close();
message.complete(vm.result_criteria).execute(_bus);
};
picker.move_to_mouse();
picker.Show();
}
void show_and_edit_pick_multiple((PartialCommand<SecurityCriteria> message, SecurityCriteria existing_criteria) message_and_data) {
var vm = new ContractPickerModel(_bus, true, message_and_data.existing_criteria);
var view = new ContractPickerView(vm);
Window picker = new Window {
Content = view,
Title = $" {message_and_data.message.title} security selection",
Icon = message_and_data.message.icon,
Height = view.Height,
Width = view.Width,
};
picker.Style = picker.TryFindResource("BTSWindow") as Style;
view.Height = Double.NaN;
view.Width = Double.NaN;
vm.ok_action = () => {
picker.Close();
message_and_data.message.complete(vm.result_criteria).execute(_bus);
};
picker.move_to_mouse();
picker.Show();
}
public void Dispose() {
Disposable.dispose(ref _dispose);
}
}
}
-38
View File
@@ -1,38 +0,0 @@
using mbts.ui.shell;
using System.Windows.Input;
using System.Windows.Media;
namespace mbts.ui {
interface IMenuItemVM {
string name { get; }
string group { get; }
ImageSource icon { get; }
ICommand command { get; }
object parameter { get; }
}
class MenuItemVM : ViewModelBase, IMenuItemVM {
object _parameter;
public MenuItemVM(string name, ICommand command, ImageSource icon = null, string group = null, object parameter = null) {
this.name = name;
this.group = group;
this.command = command;
this.icon = icon;
_parameter = parameter;
}
public string name { get; }
public string group { get; }
public ImageSource icon { get; }
public ICommand command { get; }
public object parameter {
get => _parameter;
set {
_parameter = value;
command.TryRaiseCanExecuteChanged();
RaisePropertyChanged();
}
}
}
}
-778
View File
@@ -1,778 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mbts="clr-namespace:mbts.ui">
<DrawingImage x:Key="FavoritesGold">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M1540.22,2082.07L1546.95,2102.78 1568.73,2102.78 1551.11,2115.58 1557.84,2136.29 1540.22,2123.49 1522.6,2136.29 1529.33,2115.58 1511.71,2102.78 1533.49,2102.78 1540.22,2082.07z">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>
<GeometryDrawing.Brush>
<SolidColorBrush Color="#ffd932" />
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="FavoritesWhite">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M1540.22,2082.07L1546.95,2102.78 1568.73,2102.78 1551.11,2115.58 1557.84,2136.29 1540.22,2123.49 1522.6,2136.29 1529.33,2115.58 1511.71,2102.78 1533.49,2102.78 1540.22,2082.07z">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>
<GeometryDrawing.Brush>
<SolidColorBrush Color="#ffd932" />
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Window">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="
M 32.868601,3.8869994 C31.026201,3.8869996 29.534,5.3791947 29.534,7.2190399 29.534,9.0588851 31.026201,10.553 32.868601,10.553 34.7085,10.553 36.202,9.0588851 36.202,7.2190399 36.202,5.3791947 34.7085,3.8869996 32.868601,3.8869994z
M 42.868601,3.8869994 C41.026201,3.8869996 39.534,5.3791947 39.534,7.2190399 39.534,9.0588851 41.026201,10.553 42.868601,10.553 44.7085,10.553 46.202,9.0588851 46.202,7.2190399 46.202,5.3791947 44.7085,3.8869996 42.868601,3.8869994z
M 52.868601,3.8869994 C51.026201,3.8869996 49.534,5.3791947 49.534,7.2190399 49.534,9.0588851 51.026201,10.553 52.868601,10.553 54.7085,10.553 56.202,9.0588851 56.202,7.2190399 56.202,5.3791947 54.7085,3.8869996 52.868601,3.8869994z
M5.2010002,14.812L5.2010002,43.573997 56.098,43.573997 56.098,14.812z
M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ActiveWindow">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="
M 32.868601,3.8869994 C31.026201,3.8869996 29.534,5.3791947 29.534,7.2190399 29.534,9.0588851 31.026201,10.553 32.868601,10.553 34.7085,10.553 36.202,9.0588851 36.202,7.2190399 36.202,5.3791947 34.7085,3.8869996 32.868601,3.8869994z
M 42.868601,3.8869994 C41.026201,3.8869996 39.534,5.3791947 39.534,7.2190399 39.534,9.0588851 41.026201,10.553 42.868601,10.553 44.7085,10.553 46.202,9.0588851 46.202,7.2190399 46.202,5.3791947 44.7085,3.8869996 42.868601,3.8869994z
M 52.868601,3.8869994 C51.026201,3.8869996 49.534,5.3791947 49.534,7.2190399 49.534,9.0588851 51.026201,10.553 52.868601,10.553 54.7085,10.553 56.202,9.0588851 56.202,7.2190399 56.202,5.3791947 54.7085,3.8869996 52.868601,3.8869994z
M5.2010002,14.812L5.2010002,43.573997 56.098,43.573997 56.098,14.812z
M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Trash">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M33.978,27.679999L33.978,58.098995 41.374,58.098995 41.374,27.679999z M14.841001,27.679999L14.841001,58.098995 22.237,58.098995 22.237,27.679999z M4.0320003,22.430001L52.183002,22.430001 52.183002,63.995998 4.0320003,63.995998z M15.974001,0L40.194999,0 40.194999,7.7200003 56.166999,7.7200003 56.166999,15.995 0,15.995 0,7.7200003 15.974001,7.7200003z">
<!--<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>-->
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Trash2">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Transparent" Geometry="M0,12.568994L23.662999,12.568994 20.910989,31.999999 2.7520113,31.999999z M8.0689915,1.6269979L8.0689915,4.6679968 15.594984,4.6679968 15.594984,1.6269979z M6.4420097,0L17.221997,0 17.221997,4.6679968 23.662999,4.6679968 23.662999,8.7949938 0,8.7949938 0,4.6679968 6.4420097,4.6679968z">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="2"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Undo">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="F1M-198.67,4280.19C-197.609,4277.78 -197.035,4275.17 -197.035,4272.46 -197.035,4267.33 -199.032,4262.51 -202.665,4258.88 -206.286,4255.25 -211.107,4253.26 -216.235,4253.26 -221.365,4253.26 -226.186,4255.25 -229.811,4258.88 -232.498,4261.57 -234.282,4264.92 -235.032,4268.56L-225.835,4278.86 -252.503,4278.86 -250.373,4251.38 -241.577,4261.22C-240.214,4258.14 -238.303,4255.3 -235.844,4252.85 -230.61,4247.61 -223.644,4244.72 -216.235,4244.72 -208.822,4244.72 -201.861,4247.61 -196.627,4252.85 -191.39,4258.08 -188.503,4265.05 -188.503,4272.46 -188.503,4275.11 -188.894,4277.71 -189.617,4280.19L-198.67,4280.19z">
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Crucible">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="m 430.4375 225.625 c -1.92352 0.0276 -3.82501 0.82944 -5.1875 2.1875 L 330.0625 323 288 280.9375 c -1.38915 -1.39371 -3.34472 -2.2056 -5.3125 -2.2056 -1.96778 0 -3.92335 0.81189 -5.3125 2.2056 l -23.9375 23.9375 c -1.3844 1.38804 -2.18997 3.33646 -2.18997 5.29687 0 1.96042 0.80557 3.90884 2.18997 5.29688 l 71.3125 71.3125 c 1.38804 1.3844 3.33646 2.18997 5.29687 2.18997 1.96042 0 3.90884 -0.80557 5.29688 -2.18997 l 4.34375 -4.34375 19.59375 -19.59375 100.5 -100.5 c 1.3844 -1.38804 2.18997 -3.33646 2.18997 -5.29688 0 -1.96041 -0.80557 -3.90883 -2.18997 -5.29687 l -23.9375 -23.9375 c -1.41413 -1.40955 -3.40982 -2.21706 -5.40625 -2.1875 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Cube">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M37.063741,37.405188L33.240929,50.771959 33.345182,50.829412C33.743126,51.061163,34.109612,51.337603,34.437061,51.651468L34.468327,51.682901 44.707291,44.003126 44.641921,43.880777C44.347813,43.295671,44.183001,42.63962,44.183001,41.946699L44.185978,41.833834z M24.591099,31.982382L10.519234,39.24213 10.504738,39.424831C10.479679,39.661278,10.436295,39.892527,10.375957,40.117252L10.337856,40.24584 10.451912,40.307037C10.495525,40.332783,10.538376,40.360497,10.58033,40.390192L26.361021,51.547636 26.448517,51.467699C27.339916,50.69132,28.485014,50.17779,29.750544,50.054647L30.015249,50.035364 34.145618,35.590685 29.192999,32.51112C29.04261,32.417593,28.908485,32.31176,28.79232,32.197899L28.716364,32.117622 28.685419,32.139805C28.132467,32.49791 27.465902,32.706999 26.748449,32.706999 26.030621,32.706999 25.363836,32.49791 24.810755,32.139805z M28.780092,24.040133L28.448082,26.492748 28.685419,26.630915C29.607006,27.227547 30.212999,28.238197 30.212999,29.385599 30.212999,29.614918 30.188759,29.838802 30.142603,30.055031L30.080193,30.287708 30.111809,30.297695C30.268356,30.353413,30.424189,30.42791,30.574446,30.521399L34.837221,33.172018 35.327473,31.457518C35.410911,31.165865,35.525216,30.895145,35.662153,30.652515L35.756067,30.497255 35.710442,30.474535C33.991901,29.570229,32.844,27.933699,32.844,26.065052L32.845716,26.006275z M53.770291,20.119031L44.688253,25.319921 44.720247,25.537884C44.740581,25.711212 44.750998,25.887079 44.750998,26.065052 44.750998,28.912514 42.084275,31.221001 38.797749,31.221001L38.67025,31.218208 38.672958,31.305962C38.671358,31.615515,38.625373,31.944508,38.53014,32.277802L37.755445,34.986586 44.966217,39.470285 44.977812,39.451984C45.814164,38.264851 47.230547,37.483999 48.837201,37.483999 49.078189,37.483999 49.314904,37.501568 49.546028,37.535442L49.656656,37.554392 54.505396,20.597714 54.402527,20.541037C54.290171,20.475618,54.180146,20.40689,54.0726,20.334991z M9.6452522,14.786494L9.5807686,14.857854C9.0475883,15.420187,8.3894768,15.871748,7.6484566,16.172216L7.5149994,16.222663 7.5149994,34.615192 7.5420074,34.625397C8.4930382,35.010883,9.2904701,35.676405,9.8216705,36.51416L9.9140587,36.668142 23.306246,29.758877 23.300888,29.725224C23.289059,29.61356 23.282999,29.500257 23.282999,29.385599 23.282999,27.893976 24.307062,26.633465 25.717823,26.213213L26.001564,26.143343 26.439465,22.908201z M25.594164,6.962996L10.989891,11.757046 10.982574,11.849259C10.963779,12.026639,10.935814,12.201424,10.899147,12.373173L10.896881,12.382581 26.821791,20.083639 28.28179,9.2974239 28.12504,9.2381914C27.074772,8.8124379,26.207533,8.0535914,25.667171,7.0996943z M34.637348,6.8116302L34.599276,6.8923512C33.894737,8.2938632,32.502018,9.3174334,30.841724,9.5606082L30.738474,9.5731842 29.162455,21.21555 33.69524,23.407539 33.705906,23.391473C34.750082,21.903184 36.639784,20.909001 38.797749,20.909001 40.441011,20.909001 41.929324,21.486123 43.006821,22.41919L43.020344,22.431472 51.760321,17.426437 51.737371,17.368303C51.521266,16.762437 51.403998,16.112631 51.403998,15.436536 51.403998,14.921415 51.472072,14.421554 51.600069,13.944759L51.681425,13.670171z M30.077951,0C32.588049,0,34.668222,1.7676992,35.036192,4.0752702L35.064489,4.2886443 52.961684,11.489869 53.021899,11.423252C54.161165,10.222043 55.804663,9.4679997 57.631995,9.4679992 61.070987,9.4680003 63.858998,12.139764 63.858998,15.436536 63.858998,18.733305 61.070987,21.405001 57.631995,21.405001L57.456546,21.40075 52.402265,39.080206 52.428996,39.108406C53.093061,39.879898 53.492,40.868822 53.492,41.946699 53.492,44.410421 51.407745,46.407999 48.837201,46.407999 48.033874,46.407999 47.278115,46.212923 46.618644,45.869505L46.615751,45.867823 35.872695,53.925859 35.950705,54.189234C36.069708,54.632677 36.132998,55.097586 36.132998,55.5767 36.132998,58.641745 33.540598,61.126001 30.342699,61.126001 27.144098,61.126001 24.550999,58.641745 24.550999,55.5767 24.550999,55.193407 24.591516,54.819208 24.668669,54.457815L24.711109,54.281561 8.605793,42.894129C8.5577812,42.860109,8.5120659,42.824305,8.4686737,42.786901L8.4553757,42.77429 8.3729744,42.833338C7.5921974,43.338846 6.6510086,43.634001 5.6380043,43.634001 2.935627,43.634001 0.74499893,41.535135 0.74499893,38.9454 0.74499893,36.841322 2.1911545,35.061296 4.1829567,34.467758L4.2889977,34.438908 4.2889977,16.456114 4.1295319,16.420828C1.7547989,15.835048 0,13.768469 0,11.309781 0,8.3958501 2.4649048,6.0340006 5.5053978,6.0339997 7.5959015,6.0340006 9.4142189,7.1503434 10.346516,8.7949429L10.425873,8.9434187 25.113558,4.1221313 25.119768,4.0752702C25.48749,1.7676992,27.566404,0,30.077951,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Risk">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M3.3500004,28.921999L16.410999,28.921999 16.410999,29.396999 16.410999,32.959999 16.410999,38.421999 25.514,38.421999 25.514,42.458 25.495,42.458 25.495,47.602999 34.698,47.602999 34.698,51.640999 25.495,51.640999 25.495,51.671 21.458,51.671 21.458,42.458 16.410999,42.458 12.453001,42.458 12.374001,42.458 12.374001,32.959999 3.3500004,32.959999z M54.794001,20.069L59.39695,23.324425 64,26.580851 59.39695,29.837375 54.794001,33.094 54.794001,30.650999 33.583,30.650999 33.583,22.698998 54.794001,22.698998z M14.7162,0.3409996L24.9141,0.3409996C25.97705,0.3409996,26.865667,1.1746159,27.071213,2.1986313L27.086924,2.3030968 27.124624,2.3546333C27.940995,3.4717503 29.881758,6.1571293 30.565413,7.3636971 30.565413,7.3636971 34.096944,13.338465 34.877442,15.061705L34.890623,15.092 40.170837,15.092C41.324416,15.092 42.257998,16.195044 42.257998,17.396999 42.257998,18.600256 41.324416,19.702 40.170837,19.702L33.450961,19.702C32.370606,19.702,31.482553,18.733671,31.375766,17.621177L31.37387,17.581701 29.230907,13.962816 22.261399,18.123934 26.40747,22.377669C27.150276,23.141019,27.230264,24.306093,26.654201,25.155003L26.643522,25.169146 26.636381,25.286112C26.628118,25.36014,26.616044,25.434453,26.600019,25.508835L24.851152,33.574084C24.592043,34.765377 23.418798,35.519273 22.228654,35.261475 21.03861,35.004976 20.280681,33.829283 20.53979,32.64039L22.288656,24.57524 22.309726,24.495231 17.488041,19.548167 17.480572,19.539678 17.253374,19.529043C16.366886,19.445599,15.589428,19.018761,15.078829,18.394262L15.074381,18.388281 12.282196,21.977999 12.216562,21.901865 12.1124,21.994324C11.720974,22.306216,11.1803,22.469,10.5833,22.469L2.1626606,22.469C0.96679688,22.469 0,21.817864 0,20.624998 0,19.428434 0.96679688,18.779999 2.1626606,18.779999L9.5252495,18.779999 9.3850002,18.617311 14.600033,11.548028C14.600033,11.548028,15.127697,11.125361,15.599133,10.798839L15.614553,10.78836 15.604,10.776026 24.149192,5.6036739 23.803184,4.9510002 14.7162,4.9510002C13.500099,4.9510002 12.514999,3.8623199 12.514999,2.6472778 12.514999,1.4298038 13.500099,0.3409996 14.7162,0.3409996z M34.6091,0C36.912666,0 38.780001,1.8671761 38.780001,4.1704998 38.780001,6.4739532 36.912666,8.3409996 34.6091,8.3409996 32.304335,8.3409996 30.437,6.4739532 30.437,4.1704998 30.437,1.8671761 32.304335,0 34.6091,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Reports">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M55.859353,59.282085C56.00929,59.285538,56.143475,59.392647,56.172002,59.547607L55.789193,65.810493C55.674588,66.466682,55.295579,65.802589,55.295579,65.802589L54.473962,64.431519C51.7422,68.327347 47.221295,70.881996 42.101273,70.881996 36.226228,70.881996 31.13625,67.53186 28.632329,62.638653 28.382323,62.158161 28.059378,61.686871 27.969502,61.146481 27.66084,59.337914 29.858891,59.01112 30.614098,59.864002 30.926646,60.216797 31.299044,60.827484 31.563321,61.306576 33.567227,65.081306 37.533479,67.649055 42.101273,67.649055 46.122369,67.649055 49.669251,65.651596 51.828099,62.602253L50.338567,62.323559C50.338567,62.323559,49.473847,62.210258,50.067658,61.849567L55.794392,59.287113C55.816193,59.283215,55.837933,59.28159,55.859353,59.282085z M40.764077,45.717999L43.468282,45.717999 43.468282,47.945969C44.940877,48.043633,45.939504,48.464172,46.57486,48.781933L46.850839,48.919876 45.9889,51.849625 45.591931,51.649216C44.965676,51.336708 43.994244,50.849598 42.497052,50.849598 41.307038,50.849598 40.589589,51.340611 40.589589,52.155632 40.589589,52.883549 41.269242,53.390064 43.278195,54.159683 46.150391,55.237812 47.377004,56.67535 47.377004,58.964413 47.377004,61.232674 45.806714,62.99192 43.348592,63.516731L43.348592,66.047997 40.616887,66.047997 40.616887,63.706738C39.216088,63.607735,37.791692,63.200325,36.902394,62.633808L36.672002,62.482704 37.5286,59.474827 37.945279,59.724831C38.568932,60.09864 39.856541,60.726257 41.489224,60.726257 42.825127,60.726257 43.684468,60.136341 43.684468,59.230118 43.684468,58.503498 43.274297,57.873283 41.294038,57.157166 39.122395,56.362843 36.898515,55.19091 36.898515,52.516441 36.898515,50.313221 38.372449,48.646427 40.764077,48.112602z M42.010037,40.691002C47.882275,40.691002 52.973134,44.039906 55.477063,48.93552 55.725755,49.413418 56.051247,49.888626 56.139745,50.42767 56.447038,52.237579 54.249299,52.563072 53.493916,51.708893 53.181527,51.354805 52.809136,50.742821 52.546143,50.264954 50.543599,46.492958 46.577512,43.922722 42.010037,43.922722 37.98795,43.922722 34.44249,45.919983 32.28362,48.96946L33.773167,49.248013C33.773167,49.248013,34.636472,49.363979,34.044091,49.72456L28.316394,52.28698C28.141854,52.318275,27.969985,52.199879,27.940001,52.026585L28.322789,45.767639C28.43744,45.104939,28.815036,45.774227,28.815036,45.774227L29.632752,47.140041C32.366937,43.245621,36.88775,40.691002,42.010037,40.691002z M21.804616,0L44.531026,0C48.257512,0,51.280999,3.0222199,51.280999,6.7460904L51.280999,38.274937 50.537671,37.898952C49.215222,37.269638,47.812577,36.778652,46.348977,36.444992L45.879922,36.344151 45.879922,6.7460904C45.879922,6.0039101,45.273122,5.3972201,44.531026,5.3972206L22.158713,5.3972206 21.794215,17.167999C21.794215,17.167999,21.325417,24.9519,12.747249,24.0117L5.3957184,23.8125 5.3957184,57.253899C5.3957189,57.998699,6.0024966,58.602901,6.7473038,58.602901L21.820422,58.602901 21.860354,58.884754C22.115357,60.533066,22.574946,62.114872,23.212727,63.604115L23.393945,64 6.7473038,64C3.0207885,64,2.9307267E-07,60.980499,0,57.253899L0,23.0051 2.6718498,20.1863 2.6743804,20.1094 16.677035,5.3972206 16.637936,5.3972206 12.89565,9.3464394 16.817534,5.1914101 16.872334,5.1914101 16.997233,5.0612788 17.007634,5.0612788z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Spreads">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="F1M70.546875,54.3758316040039L77.484375,54.3758316040039 77.484375,89.0633316040039 70.546875,89.0633316040039 70.546875,54.3758316040039z M48.5625,54.3758316040039L65.90625,71.7195816040039 48.5625,89.0633316040039 48.5625,75.1883316040039 8.109375,75.1883316040039 8.109375,68.2508316040039 48.5625,68.2508316040039 48.5625,54.3758316040039z M37.03125,19.6883316040039L37.03125,33.5633316040039 77.484375,33.5633316040039 77.484375,40.5008316040039 37.03125,40.5008316040039 37.03125,54.3758316040039 19.6875,37.0320816040039 37.03125,19.6883316040039z M8.109375,19.6883316040039L15.046875,19.6883316040039 15.046875,54.3758316040039 8.109375,54.3758316040039 8.109375,19.6883316040039z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Depth">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M0,27.006001L37.806999,27.006001 37.806999,31.806 0,31.806z M0,18.003L37.806999,18.003 37.806999,22.806 0,22.806z M0,8.9999999L37.806999,8.9999999 37.806999,13.803 0,13.803z M0,0L37.806999,0 37.806999,4.8030009 0,4.8030009z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Ladder" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M -2.7407407 21.999952 V 25 H 11.37037 v -3.000048 z m 0 -4.999952 v 2.999952 H 11.37037 V 17 Z m 0 -5 v 3 H 11.37037 v -3 z m 0 -5 v 3 H 11.37037 V 7 Z m -1 -7 c 0.552 0 1.0810413 0.45297098 1 1 V 5 H 11.37037 V 1 c 0 -0.5529995 0.448 -1 1 -1 0.552 0 1 0.4470005 1 1 0 11.544484 0 19.62158 0 30 0 0.553 -0.448 1 -1 1 -0.552 0 -0.918958 -0.45297 -1 -1 V 27 H -2.7407407 v 4 c 0 0.553 -0.448 1 -1 1 -0.552 0 -1 -0.447 -1 -1 0 -11.54448 0 -19.621581 0 -30 0 -0.5529995 0.448 -1 1 -1 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Trades">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M50.14375,33.389126C50.416863,33.394688,50.653496,33.587773,50.705998,33.864617L50.015995,45.114388C49.810295,46.291462,49.130394,45.097489,49.130394,45.097489L47.65659,42.640538C42.747776,49.635197 34.633152,54.221001 25.433924,54.221001 14.884193,54.221001 5.7437552,48.204125 1.2449617,39.419205 0.80087067,38.552021 0.21358696,37.705738 0.052086769,36.736958 -0.49735315,33.490925 3.4507786,32.901036 4.8049124,34.432404 5.3674143,35.067692 6.034036,36.16407 6.5079177,37.026051 10.106778,43.799416 17.2321,48.413819 25.433924,48.413819 32.656544,48.413819 39.026364,44.826695 42.903977,39.351506L40.229367,38.854115C40.229367,38.854115,38.677464,38.647118,39.742466,37.996033L50.024895,33.398526C50.064972,33.391365,50.104733,33.388333,50.14375,33.389126z M23.030291,9.0310004L27.889918,9.0310004 27.889918,13.028299C30.539786,13.205498,32.324932,13.958096,33.464161,14.528294L33.964176,14.775793 32.417435,20.038878 31.706417,19.68068C30.579987,19.11958 28.839241,18.244583 26.149073,18.244583 24.006916,18.244583 22.723183,19.122181 22.723183,20.590876 22.723183,21.894272 23.943314,22.804369 27.551308,24.187165 32.706444,26.124659 34.911,28.702853 34.911,32.817341 34.911,36.892929 32.090527,40.05172 27.673611,40.989117L27.673611,45.540001 22.767485,45.540001 22.767485,41.330414C20.252919,41.155815,17.695551,40.424118,16.101811,39.404721L15.683999,39.137619 17.221739,33.731438 17.969059,34.180634C19.088988,34.851235 21.402748,35.97873 24.340325,35.97873 26.734886,35.97873 28.276728,34.921635 28.276728,33.291336 28.276728,31.986641 27.547409,30.853846 23.986016,29.57255 20.083815,28.144253 16.095511,26.04406 16.095511,21.239174 16.095511,17.280985 18.737379,14.291395 23.030291,13.329098z M25.268765,0C35.819447,2.7347414E-07 44.961449,6.0155495 49.458798,14.804573 49.902695,15.669173 50.490094,16.516972 50.651287,17.48427 51.198281,20.734265 47.255726,21.318962 45.901341,19.789065 45.336346,19.153567 44.669552,18.051968 44.19566,17.19517 40.5957,10.421881 33.473275,5.8072398 25.268765,5.8072393 18.047545,5.8072398 11.678013,9.3918336 7.8003562,14.867073L10.474627,15.367072C10.474627,15.367072,12.026909,15.574172,10.962921,16.223872L0.67933281,20.826762C0.36037083,20.880062,0.057029126,20.669165,0.00099972012,20.354063L0.69093342,9.1118043C0.89552094,7.9296158,1.5738537,9.124924,1.5738539,9.124924L3.0452772,11.583379C7.9566038,4.584462,16.073666,2.7347414E-07,25.268765,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Sheets" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M22.1575,13.53399L21.794301,25.304994C21.794301,25.304994,21.3242,33.088695,12.747401,32.148692L5.3958107,31.949492 5.3958107,65.390895C5.3958107,66.135493,6.0026208,66.7391,6.7473808,66.7391L44.5313,66.7391C45.2734,66.7391,45.8802,66.135493,45.8802,65.390895L45.8802,14.883091C45.8802,14.140891,45.2734,13.53399,44.5313,13.53399z M21.804701,8.1369996L44.5313,8.1369996C48.257802,8.1370001,51.279999,11.15899,51.279999,14.883091L51.279999,65.390895C51.279999,69.117496,48.257802,72.136996,44.5313,72.136996L6.7473808,72.136996C3.0208105,72.136996,5.8073994E-07,69.117496,0,65.390895L0,31.142392 2.6718808,28.322993 2.6745006,28.246392 16.6771,13.53399 16.638001,13.53399 12.8945,17.483192 16.816401,13.328391 16.872401,13.328391 16.9961,13.19799 17.0078,13.19799z M30.352,0L55.255002,0 60.581002,0 60.581002,4.747 60.581002,55.207999 55.255002,55.207999 55.255002,4.747 30.352,4.747z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Surface">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="m 127.71875,0.03125 c 1.96953,0.68706766 3.77873,1.728511 5.53125,2.84375 5.68444,-0.1664634 11.35972,0.1351305 17.03125,0.46875 -1.73194,-1.1492389 -3.57847,-2.1023993 -5.53125,-2.8125 -5.6651,-0.45913017 -11.34995,-0.58354857 -17.03125,-0.5 z m -4.25,0.125 c -5.70361,0.2336956 -11.37548,0.81394241 -17.03125,1.5625 1.95847,0.6900238 3.78385,1.7005175 5.53125,2.8125 C 117.61899,3.7613446 123.30363,3.2513106 129,3 127.28567,1.8094865 125.39256,0.94326338 123.46875,0.15625 z M 149,0.90625 c 1.96418,0.6694319 3.78573,1.7017145 5.53125,2.8125 5.71276,0.5944911 11.3908,1.4529283 17.03125,2.53125 C 169.85207,5.0455955 167.95676,4.1939604 166.03125,3.40625 160.39919,2.2891664 154.71106,1.4856327 149,0.90625 z m -46.8125,1.4375 C 96.464888,3.3096165 90.767826,4.4520829 85.15625,5.9375 87.106815,6.6380546 88.941831,7.6391195 90.6875,8.75 96.310308,7.3225043 101.99157,6.1139557 107.71875,5.1875 106.00019,4.0048872 104.11138,3.1307925 102.1875,2.34375 z m 32.46875,1.5 c 2.00275,1.4247295 3.75993,3.1494432 5.53125,4.84375 5.68351,-0.080003 11.36274,0.089238 17.03125,0.5 -1.73044,-1.7529327 -3.58348,-3.3699033 -5.53125,-4.875 -5.66508,-0.4641114 -11.35053,-0.55229 -17.03125,-0.46875 z m -4.28125,0.125 C 124.103,4.2953783 119.00738,4.7504024 113.34375,5.5 c 1.99941,1.4415661 3.79164,3.1353901 5.53125,4.875 5.65135,-0.7706117 11.33386,-1.2798945 17.03125,-1.53125 -1.66132,-1.8295873 -3.58341,-3.3698478 -5.53125,-4.875 z m 39.9375,0.34375 c 1.96346,0.6759081 3.78484,1.7011488 5.53125,2.8125 5.74468,1.2638733 11.4064,2.8505892 17.03125,4.5625 -1.72987,-1.168721 -3.60534,-2.0558794 -5.53125,-2.84375 C 181.73627,7.0795573 176.0521,5.5785891 170.3125,4.3125 z m -14.375,0.375 c 1.9717,1.4743322 3.79243,3.136185 5.53125,4.875 5.71797,0.542825 11.39215,1.453188 17.03125,2.53125 -1.6913,-1.79287 -3.58414,-3.3704114 -5.53125,-4.875 C 167.33901,6.0657565 161.63964,5.35834 155.9375,4.6875 z m -46.84375,1.46875 c -5.72932,0.9221197 -11.402883,2.1554082 -17.03125,3.5625 1.99347,1.451281 3.791265,3.135015 5.53125,4.875 5.62016,-1.451631 11.30209,-2.635724 17.03125,-3.5625 -1.69439,-1.7852366 -3.54058,-3.4272419 -5.53125,-4.875 z M 80.90625,7.0625 c -5.768034,1.593637 -11.417957,3.561289 -17.03125,5.625 1.930762,0.74325 3.819326,1.676529 5.53125,2.84375 5.568779,-2.194858 11.293752,-3.937501 17.03125,-5.625 C 84.697913,8.7506893 82.833288,7.8508336 80.90625,7.0625 z m 96.3125,1.03125 c 2.01998,1.5283684 3.9853,3.332564 5.53125,4.875 5.75001,1.241656 11.41327,2.827536 17.03125,4.5625 -1.70386,-1.770251 -3.54256,-3.428678 -5.53125,-4.875 -5.59469,-1.822363 -11.3081,-3.215876 -17.03125,-4.5625 z M 141.5625,10.1875 c 1.98812,2.171216 3.79154,4.502672 5.53125,6.875 5.68335,-0.07635 11.3631,0.08322 17.03125,0.5 -1.70296,-2.41177 -3.58181,-4.690977 -5.53125,-6.90625 -5.82598,-0.440889 -11.98586,-0.537879 -17.03125,-0.46875 z m -4.25,0.125 c -5.69916,0.210199 -11.37949,0.783222 -17.03125,1.53125 1.96864,2.199545 3.78641,4.526916 5.53125,6.90625 5.65033,-0.779208 11.33395,-1.279899 17.03125,-1.53125 -1.7175,-2.400101 -3.58197,-4.691155 -5.53125,-6.90625 z m -49.5,0.5625 c -5.756209,1.627414 -11.443914,3.488666 -17.03125,5.625 1.986252,1.443163 3.797302,3.109802 5.53125,4.84375 C 81.914775,19.260145 87.586406,17.35867 93.34375,15.75 91.661607,13.944308 89.760517,12.380286 87.8125,10.875 z m 75.03125,0.15625 c 1.99219,2.183637 3.78522,4.525295 5.53125,6.90625 6.28774,0.687745 11.37979,1.450824 17.03125,2.53125 -1.68349,-2.427307 -3.58184,-4.691013 -5.53125,-6.90625 -5.63506,-1.107989 -11.31933,-1.943258 -17.03125,-2.53125 z M 116,12.5 c -5.73799,0.878008 -11.39825,2.174659 -17.03125,3.5625 2.03956,2.148921 3.76403,4.56042 5.5625,6.90625 5.61994,-1.453285 11.29946,-2.648737 17.03125,-3.5625 C 119.8176,17.015603 118.00451,14.67882 116,12.5 z m -56.40625,1.84375 c -5.792814,2.278458 -11.419014,4.940887 -17.03125,7.625 1.967004,0.694041 3.777949,1.728013 5.53125,2.84375 5.58415,-2.744879 11.247417,-5.328478 17.03125,-7.625 -1.725645,-1.141384 -3.572016,-2.162277 -5.53125,-2.84375 z M 184.125,14.4375 c 2.02152,2.155746 3.78605,4.526439 5.53125,6.90625 5.75343,1.228401 11.41327,2.827536 17.03125,4.5625 C 205.01516,23.467587 203.10649,21.216187 201.15625,19 195.55578,17.209943 189.86603,15.703904 184.125,14.4375 z m -89.40625,2.78125 c -5.757378,1.612569 -11.421181,3.531225 -17.03125,5.59375 2.013414,2.164294 3.785804,4.526096 5.53125,6.90625 C 88.826875,27.652066 94.492577,25.733692 100.25,24.125 98.572893,21.691803 96.66853,19.434409 94.71875,17.21875 z m -28.1875,0.9375 c -5.809395,2.239258 -11.434051,4.908712 -17.03125,7.625 1.996367,1.448111 3.791108,3.134858 5.53125,4.875 C 60.587618,27.843081 66.305928,25.370353 72.0625,23 70.325483,21.271546 68.515383,19.599256 66.53125,18.15625 z m 81.9375,0.90625 C 150.4643,21.946692 152.27759,24.946629 154,28 c 5.68473,-0.186058 11.35951,0.135118 17.03125,0.46875 -1.70966,-3.061344 -3.58704,-6.02118 -5.53125,-8.9375 -5.66815,-0.423667 -11.34913,-0.552311 -17.0Line truncated
<GeometryDrawing.Pen>
<Pen Brush="White" Thickness="2" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Analytics">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M17.9349,52.632801L13.5176,60.285198 22.3529,60.285198z M4.1452103,50.3647L4.1452103,52.622398 59.855499,52.622398 59.855499,50.3647z M17.062819,7.9790001L21.601147,36.012657 25.301687,19.424307 28.011845,37.14275 33.26696,12.41387 36.744106,37.14275 40.357449,27.929331 43.067604,37.14275 46.822746,19.489307 50.89698,37.14275 56.015999,23.676769 56.015999,42.608997 8.1710005,42.608997 8.1710005,23.135174 13.86557,31.999594z M4.1452103,3.8098803L4.1452103,45.6199 59.855499,45.6199 59.855499,3.8098803z M0,0L64,0 64,64 0,64z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Orders">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M50.14375,33.389126C50.416863,33.394688,50.653496,33.587773,50.705998,33.864617L50.015995,45.114388C49.810295,46.291462,49.130394,45.097489,49.130394,45.097489L47.65659,42.640538C42.747776,49.635197 34.633152,54.221001 25.433924,54.221001 14.884193,54.221001 5.7437552,48.204125 1.2449617,39.419205 0.80087067,38.552021 0.21358696,37.705738 0.052086769,36.736958 -0.49735315,33.490925 3.4507786,32.901036 4.8049124,34.432404 5.3674143,35.067692 6.034036,36.16407 6.5079177,37.026051 10.106778,43.799416 17.2321,48.413819 25.433924,48.413819 32.656544,48.413819 39.026364,44.826695 42.903977,39.351506L40.229367,38.854115C40.229367,38.854115,38.677464,38.647118,39.742466,37.996033L50.024895,33.398526C50.064972,33.391365,50.104733,33.388333,50.14375,33.389126z M23.030291,9.0310004L27.889918,9.0310004 27.889918,13.028299C30.539786,13.205498,32.324932,13.958096,33.464161,14.528294L33.964176,14.775793 32.417435,20.038878 31.706417,19.68068C30.579987,19.11958 28.839241,18.244583 26.149073,18.244583 24.006916,18.244583 22.723183,19.122181 22.723183,20.590876 22.723183,21.894272 23.943314,22.804369 27.551308,24.187165 32.706444,26.124659 34.911,28.702853 34.911,32.817341 34.911,36.892929 32.090527,40.05172 27.673611,40.989117L27.673611,45.540001 22.767485,45.540001 22.767485,41.330414C20.252919,41.155815,17.695551,40.424118,16.101811,39.404721L15.683999,39.137619 17.221739,33.731438 17.969059,34.180634C19.088988,34.851235 21.402748,35.97873 24.340325,35.97873 26.734886,35.97873 28.276728,34.921635 28.276728,33.291336 28.276728,31.986641 27.547409,30.853846 23.986016,29.57255 20.083815,28.144253 16.095511,26.04406 16.095511,21.239174 16.095511,17.280985 18.737379,14.291395 23.030291,13.329098z M25.268765,0C35.819447,2.7347414E-07 44.961449,6.0155495 49.458798,14.804573 49.902695,15.669173 50.490094,16.516972 50.651287,17.48427 51.198281,20.734265 47.255726,21.318962 45.901341,19.789065 45.336346,19.153567 44.669552,18.051968 44.19566,17.19517 40.5957,10.421881 33.473275,5.8072398 25.268765,5.8072393 18.047545,5.8072398 11.678013,9.3918336 7.8003562,14.867073L10.474627,15.367072C10.474627,15.367072,12.026909,15.574172,10.962921,16.223872L0.67933281,20.826762C0.36037083,20.880062,0.057029126,20.669165,0.00099972012,20.354063L0.69093342,9.1118043C0.89552094,7.9296158,1.5738537,9.124924,1.5738539,9.124924L3.0452772,11.583379C7.9566038,4.584462,16.073666,2.7347414E-07,25.268765,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Admin" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M18.660349,20.393C14.879011,20.393 11.806,23.468643 11.806,27.249899 11.806,31.026154 14.879011,34.103001 18.660349,34.103001 22.444386,34.103001 25.519998,31.026154 25.519998,27.249899 25.519998,23.468643 22.444386,20.393 18.660349,20.393z M50.07317,8.7561953C49.408178,8.7706149 48.735172,8.9156297 48.090648,9.2053407 45.51765,10.359123 44.36155,13.394207 45.51765,15.96858 46.671449,18.541552 49.709146,19.691384 52.283444,18.540251 54.856342,17.378819 56.012442,14.352736 54.856342,11.771862 53.990993,9.8450501 52.068145,8.7129386 50.07317,8.7561953z M15.597473,8.6000007L21.868224,8.6000007 22.20032,14.327933 22.20032,14.531032C23.236712,14.816134,24.218506,15.221134,25.133898,15.736836L25.253695,15.615635 29.675461,11.900828 34.111725,16.338337 30.296556,20.624846 30.165057,20.758946C30.683352,21.674349,31.08955,22.659951,31.378649,23.696451L31.544045,23.696451 37.293999,24.196451 37.293999,30.468565 31.566147,30.803267 31.378649,30.803267C31.08955,31.836972,30.683352,32.821373,30.165057,33.736874L30.280955,33.853974 33.993225,38.274582 29.558261,42.709496 25.271895,38.896988 25.133898,38.758988C24.218506,39.274586,23.236712,39.678185,22.20032,39.963387L22.20032,40.146988 21.868224,45.897 15.597473,45.897 15.093578,40.166485 15.093578,39.959488C14.064985,39.671688,13.084595,39.265385,12.174301,38.749787L12.040102,38.881485 7.7381763,42.709496 3.3033104,38.274582 6.9999428,33.869675 7.1522102,33.721176C6.6379356,32.807072,6.2343292,31.83057,5.9464817,30.803267L5.7499523,30.803267 0,30.468565 0,24.196451 5.7278118,23.696451 5.9464817,23.696451C6.2343292,22.665051,6.6379356,21.687248,7.1522102,20.775946L7.0128822,20.640444 3.1874237,16.338337 7.6209869,11.900828 12.027203,15.600036 12.174301,15.744536C13.084595,15.231535,14.064985,14.825334,15.093578,14.537533L15.093578,14.350033z M52.888157,0L57.259197,1.6601361 56.091211,5.7941664 56.035212,5.937414C56.665401,6.3971274,57.240894,6.9413698,57.753986,7.5533617L57.878984,7.4947021 61.949226,6.0845716 63.865797,10.35405 60.071657,12.331821 59.933659,12.393021C60.053354,13.18731,60.075457,13.977598,60.003952,14.758987L60.12245,14.803286 63.999998,16.682059 62.337223,21.053194 58.253977,19.771912 58.12108,19.721113C57.656389,20.352705,57.112095,20.928097,56.496105,21.441189L56.549604,21.556988 57.962284,25.627228 53.691446,27.541302 51.712375,23.744456 51.653774,23.615557C50.862186,23.736756,50.066597,23.760056,49.285309,23.687157L49.241009,23.800455 47.366036,27.678 42.991099,26.017823 44.277584,21.928082 44.325682,21.799183C43.696789,21.334391,43.121297,20.784899,42.607106,20.171606L42.487208,20.225006 38.469066,21.753483 36.553693,17.486847 40.297138,15.390477 40.441637,15.327978C40.321941,14.53499,40.299839,13.744601,40.372736,12.963413L40.24384,12.915114 36.321998,11.158738 37.984774,6.7851217 42.113513,7.9530752 42.263212,8.009104C42.728206,7.3840535,43.269797,6.8124616,43.879186,6.3033789L43.82189,6.1652506 42.29051,2.1496897 46.562749,0.22918414 48.656518,3.977782 48.722916,4.1289099C49.511906,4.0091622,50.299695,3.9843827,51.075585,4.0534113L51.127785,3.9218233z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Eye">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M33.597977,10.759002C37.946865,10.759002 41.485962,14.285001 41.485962,18.649 41.485962,23 37.946865,26.535 33.597977,26.535 29.23909,26.535 25.709992,23 25.709992,18.649 25.709992,17.784 25.849955,16.953001 26.109888,16.174002 26.779719,16.881001 27.70948,17.327002 28.759213,17.327002 30.778696,17.327002 32.418278,15.691001 32.418278,13.668001 32.418278,12.663001 32.008381,11.748001 31.348551,11.087002 32.058369,10.876001 32.818176,10.759002 33.597977,10.759002z M33.606682,4.3679962C25.92741,4.3679957 19.698065,10.594956 19.698065,18.27293 19.698065,25.953894 25.92741,32.177862 33.606682,32.177862 41.295838,32.177862 47.515175,25.953894 47.515175,18.27293 47.515175,10.594956 41.295838,4.3679957 33.606682,4.3679962z M34.867642,1.546141E-09C36.890393,2.6508449E-05 58.705193,0.41938579 68.893006,18.299923 68.893006,18.299923 57.1442,36.139837 34.44656,34.768854 34.44656,34.768854 14.428583,36.59984 0,18.299923 0,18.299923 9.0791523,0.4590019 34.716553,0.0010111886 34.716553,0.0010114873 34.768162,-1.4442128E-06 34.867642,1.546141E-09z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Coins">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M3.3390064,47.374004L26.00104,47.374004C26.17504,47.881321 26.361041,48.388939 26.575041,48.889757 27.610043,51.333344 29.086045,53.523722 30.968048,55.406689 31.135048,55.573593 31.309048,55.733997 31.476048,55.894005L3.3390064,55.894005C1.4960022,55.894005,0,54.398552,0,52.555387L0,50.712622C0,48.869556,1.4960022,47.374004,3.3390064,47.374004z M8.6740417,35.422004L25.713049,35.422004C25.220049,37.198282 24.972049,39.03446 24.972049,40.910738 24.972049,41.932125 25.046049,42.947113 25.193049,43.942001L8.6740417,43.942001C6.8310413,43.942001,5.3350391,42.44632,5.3350391,40.60354L5.3350391,38.760464C5.3350391,36.917886,6.8310413,35.422004,8.6740417,35.422004z M44.333998,28.91725L44.333998,31.014374C42.649975,31.25297 41.419993,31.901375 40.634958,32.963784 39.852975,34.026392 39.458993,35.225903 39.458993,36.554114 39.458993,37.565422 39.677987,38.455833 40.118966,39.221838 40.555979,39.98354 41.125986,40.573252 41.829967,40.99555 42.53297,41.425255 43.508984,41.850658 44.758986,42.28466 46.149979,42.776463 47.048965,43.183067 47.451004,43.502871 47.852982,43.819578 48.055986,44.291979 48.055986,44.913282 48.055986,45.51469 47.852982,46.022491 47.451004,46.448399 47.048965,46.874603 46.41597,47.0849 45.560011,47.0849 43.728954,47.0849 42.649975,46.093193 42.325999,44.11248L38.810005,45.030586C39.521005,48.178713,41.360971,49.909225,44.333998,50.214329L44.333998,52.91765 46.607986,52.91765 46.607986,50.202824C48.391985,50.015223 49.755999,49.390217 50.701008,48.33131 51.646992,47.273104 52.118979,45.952789 52.118979,44.36648 52.118979,43.331467 51.888998,42.429262 51.431965,41.65526 50.970966,40.886349 50.360981,40.276442 49.59096,39.839542 48.826006,39.401939 47.763016,38.933239 46.41597,38.440628 45.185011,37.991329 44.384962,37.612823 44.008986,37.307821 43.633984,36.999621 43.446972,36.561912 43.446972,35.991115 43.446972,35.429106 43.641979,34.952402 44.032972,34.558096 44.419996,34.163196 44.935011,33.967896 45.576002,33.967896 46.85701,33.967896 47.797989,34.850602 48.407976,36.612617L51.545002,35.327107C50.795002,32.756988,49.14699,31.319575,46.607986,31.015068L46.607986,28.91725z M3.3390026,23.690004L34.347016,23.690004C33.139015,24.471167 32.010015,25.379241 30.975014,26.414426 29.286014,28.103764 27.917013,30.053523 26.909013,32.203998L3.3390026,32.203998C1.4960022,32.203998,0,30.708376,0,28.865226L0,27.028776C0,25.185925,1.4960022,23.690004,3.3390026,23.690004z M45.470961,22.415C55.686974,22.415 63.96701,30.694868 63.959991,40.924053 63.959991,51.140034 55.680992,59.419998 45.464003,59.419998 41.41096,59.419998 37.659003,58.110893 34.613955,55.900974 31.696961,53.777658 29.412962,50.819633 28.130979,47.380901 27.716977,46.285692 27.408993,45.137482 27.215939,43.948774 27.055966,42.96047 26.96899,41.952459 26.968991,40.917248 26.96899,39.007633 27.255978,37.164823 27.796994,35.428709 28.150998,34.306995 28.597959,33.23199 29.145994,32.210482 31.195984,28.371248 34.553958,25.346428 38.626961,23.723612 40.743967,22.882503 43.053967,22.415 45.470961,22.415z M3.3390045,11.952L38.153052,11.952C39.996056,11.952,41.492057,13.448001,41.492057,15.290001L41.492057,17.133002C41.492057,18.976003,39.996056,20.472003,38.153052,20.472004L3.3390045,20.472004C1.4960022,20.472003,0,18.976003,0,17.133002L0,15.290001C0,13.448001,1.4960022,11.952,3.3390045,11.952z M8.6735134,0L43.487543,0C45.330534,0,46.826027,1.4958782,46.826027,3.3386841L46.826027,5.1814384C46.826027,7.0245428,45.330534,8.5200005,43.487543,8.5200005L8.6735134,8.5200005C6.8304424,8.5200005,5.3350277,7.0245428,5.3350277,5.1814384L5.3350277,3.3386841C5.3350277,1.4958782,6.8304424,0,8.6735134,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="BombIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
Geometry="M14.200889,0C15.299896,0 16.59991,0.50000046 17.998923,1.4989944 19.597936,2.5990016 20.397944,4.5970043 21.196948,6.4960083 22.495954,9.6950015 23.495961,11.693005 26.093989,11.594006 26.793992,11.594006 27.293996,12.093014 27.293996,12.693005 27.293996,13.393002 26.793992,13.892012 26.193997,13.892012 21.896949,14.092009 20.297938,10.394007 19.097932,7.3960032 18.398921,5.6969966 17.698918,4.0979957 16.699916,3.3979983 15.899907,2.8979978 14.600901,1.9989949 13.700884,2.4989952 12.701883,2.9980039 12.30187,5.0970048 12.20188,6.3960022L13.900898,6.2959961C14.600901,6.2959961,15.100904,6.6960057,15.199904,7.3960032L15.399903,9.6950015C16.799909,10.19401 18.098929,10.894008 19.197938,11.893001 23.995965,15.991012 24.494979,23.287025 20.397944,28.084026 16.099906,32.78203 8.8038569,33.381029 4.0068054,29.184019 -0.79122243,25.086023 -1.3902263,17.79001 2.8067985,12.993009 3.9068136,11.693005 5.405819,10.594005 7.0048309,9.9940128L6.9048391,7.9960098C6.9048391,7.3960032,7.3048363,6.7959966,8.0038471,6.6960057L9.9028645,6.5959992C9.9028645,5.3970083 10.302861,1.6989915 12.701883,0.50000046 13.10188,0.099990942 13.700884,0 14.200889,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CancelMail">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M10.659519,13.581999C10.787763,13.581999 10.916255,13.630751 11.01375,13.728755 11.207739,13.924762 11.207739,14.241775 11.01175,14.435782L8.5898266,16.850518 11.012901,19.265967C11.20889,19.460974 11.20889,19.776986 11.013901,19.972994 10.916906,20.070997 10.787913,20.119999 10.65992,20.119999 10.531927,20.119999 10.403934,20.070997 10.30694,19.973994L7.8819971,17.556247 5.4570541,19.973994C5.3600597,20.070997 5.2320671,20.119999 5.1040735,20.119999 4.9760809,20.119999 4.8470879,20.070997 4.7500935,19.972994 4.5551033,19.776986 4.5551033,19.460974 4.7510929,19.265967L7.1741672,16.850518 4.752244,14.435782C4.5562544,14.241775 4.5562544,13.924762 4.7502441,13.728755 4.9452333,13.532748 5.2642155,13.533748 5.4572048,13.727755L7.8819966,16.144916 10.306789,13.727755C10.403284,13.630751,10.531276,13.582,10.659519,13.581999z M7.7229891,10.151996C4.0159941,10.151996 0.99999809,13.156997 0.99999809,16.850998 0.99999809,20.544999 4.0159941,23.55 7.7229891,23.55 10.503235,23.55 12.895357,21.859687 13.917652,19.456124L14.034025,19.162648 14.034025,18.772999 14.164453,18.772999 14.191419,18.682897C14.357855,18.100457 14.44698,17.485905 14.44698,16.850998 14.44698,13.156997 11.429984,10.151996 7.7229891,10.151996z M28.477001,10.135L31.999016,13.663 28.424001,17.244999 27.716998,16.538999 29.693872,14.558 21.322995,14.558 21.322995,13.558 30.482195,13.558 27.769998,10.841z M7.4592972,5.1720018L15.45899,8.869 22.849004,5.1720018z M4.6849804,4.1720018L25.465012,4.1720018 25.465012,10.408002 24.465011,10.408002 24.465011,5.4821377 15.476991,9.9780006 5.6849813,5.4540205 5.6849813,9.4246554 5.7953281,9.3948154C6.4117265,9.2363219 7.0576777,9.1519957 7.7229891,9.1519957 11.981983,9.1519957 15.446978,12.605997 15.446978,16.850998 15.446978,17.514279 15.362384,18.158249 15.203383,18.772749L24.465023,18.772999 24.465023,16.665997 25.465026,16.665997 25.465026,19.772997 14.868521,19.772997 14.839026,19.844827C13.664856,22.607125 10.917235,24.550001 7.7229891,24.550001 3.4649954,24.550001 0,21.095999 0,16.850998 0,13.733575 1.8686953,11.042744 4.5478315,9.8331947L4.6849804,9.7732801z M7.8089724,0L29.631012,0 29.631012,7.2790012 28.63101,7.2790012 28.63101,1 8.8089738,1 8.8089738,3.1080008 7.8089724,3.1080008z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Display">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M2,2L2,25 30,25 30,2z M1,0L31,0C31.552002,0,32,0.44702148,32,1L32,26C32,26.552979,31.552002,27,31,27L17,27 17,30 25,30 25,32 7,32 7,30 15,30 15,27 1,27C0.44799805,27,0,26.552979,0,26L0,1C0,0.44702148,0.44799805,0,1,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Target">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M16.2,11.1C19,11.1 21.2,13.3 21.2,16.1 21.2,18.9 19,21.1 16.2,21.1 13.4,21.1 11.2,18.9 11.2,16.1 11.2,13.4 13.4,11.1 16.2,11.1z M16.2,6C10.6,6 6,10.6 6,16.1 6,21.7 10.5,26.2 16.1,26.2 21.7,26.2 26.2,21.7 26.2,16.1 26.3,10.6 21.7,6 16.2,6z M15.3,0L16.8,0 16.8,5.1999998C22.2,5.5,26.6,9.6999998,27.1,15L32,15 32,16.5 27.1,16.5 27.1,16.7C26.8,22.3,22.3,26.8,16.7,27.1L16.7,32 15.2,32 15.2,27.1 15.5,27.1 16,27.1C10.2,27,5.5,22.5,5.1999998,16.7L5.1999998,16.5 5.1999998,16.4 0,16.4 0,15 5.3000002,15C5.9000001,9.6999998,10.3,5.5,15.7,5.1999998L15.6,5.1999998 15.3,5.1999998z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Wrench">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M5.5803752,0C7.1813383,0 8.8833761,0.6000061 10.084373,1.8009948 11.785374,3.5029907 12.285377,5.8049927 11.685397,7.9060059L24.094478,20.31601C26.096505,19.714996 28.398524,20.216003 30.099524,21.916992 31.500535,23.317993 32.101552,25.320007 31.901538,27.121002L28.998504,24.118988C27.69753,22.817993 25.496465,22.817993 24.094478,24.118988 22.693467,25.519989 22.693467,27.622009 24.094478,29.02301L26.997514,31.924988C25.195498,32.225006 23.194447,31.625 21.793437,30.123993 20.191436,28.522003 19.591456,26.119995 20.191436,24.118988L7.7823553,11.709015C5.6803512,12.309998 3.3783338,11.80899 1.6773333,10.108002 0.37629925,8.7070007 -0.224718,6.8049927 0.076309212,5.0039978L2.978307,7.9060059C4.2793407,9.2070007 6.4813823,9.2070007 7.8823928,7.9060059 9.2834034,6.605011 9.2834034,4.4030151 7.8823928,3.0020142L4.9803342,0.10000607C5.1803479,0,5.3803615,0,5.5803752,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Clock" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M25.700012,16.000016L28.800019,16.000016 28.800019,17.099989 25.700012,17.099989z M23.200012,8.599998L17.200012,16.300004C17.200012,16.500016,17.100006,16.800002,17,17.000014L20.100006,22.50001 15.700012,17.699965C15,17.599989 14.5,17.000014 14.5,16.300004 14.5,15.599991 15,15.000017 15.700012,14.89998L15.800019,14.89998z M15.700012,2.9999971C8.7000124,3.2000091,3.0000002,9.0000224,3,16.000016L6.1000063,16.000016 6.1000063,17.099989 3.1000061,17.099989 3.1000061,17.300002C3.7000124,23.699959,9.1000063,28.79999,15.700012,29.000002L15.800019,29.000002 15.800019,26.000006 16.900025,26.000006 16.900025,29.000002 17.100006,29.000002C23.800019,28.500004 29.100006,22.899971 29.100006,16.099991 29.100006,9.3000092 23.800019,3.7000086 17.100006,3.2000089L16.900025,3.2000089 16.900025,6.2000065 15.800019,6.2000065 15.800019,2.9999971z M16,0C24.800019,0 32,7.2000055 32,16.000016 32,24.799994 24.800019,32 16,32 7.2000124,32 2.3106986E-07,24.799994 0,16.000016 2.3106986E-07,7.2000055 7.2000124,0 16,0z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Payment" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M28.000001,6.0000026L28.000001,15 6.0010006,15 6.0010006,17.000003 30.001,17.000003 30.001,6.0000026z M14.231,2.9540056L14.979999,2.9540056 14.979999,3.987005C15.704998,4.009005,16.200997,4.178005,16.550998,4.3600049L16.248998,5.0620046C15.994998,4.9340047 15.499998,4.7010047 14.725999,4.7010047 13.796,4.7010047 13.445001,5.1900046 13.445001,5.6160046 13.445001,6.1710043 13.893,6.4470041 14.943999,6.8310037 16.187998,7.2780037 16.816998,7.8320036 16.816998,8.7800031 16.816998,9.6210027 16.151998,10.409003 14.907999,10.591002L14.907999,11.698002 14.146,11.698002 14.146,10.622003C13.445001,10.611002,12.720001,10.420002,12.297002,10.154003L12.587001,9.4400029C13.022001,9.696003 13.651,9.8980026 14.328,9.8980026 15.185999,9.8980026 15.765998,9.4620028 15.765998,8.8540034 15.765998,8.2680035 15.293999,7.9060035 14.4,7.5870035 13.167001,7.1610038 12.406001,6.6710041 12.406001,5.7440041 12.406001,4.8600047 13.119,4.189005 14.231,4.0290052z M2,2.0000002L2,13 26.000001,13 26.000001,2.0000002z M0,0L28.000001,0 28.000001,4.0000031 32.001,4.0000031 32.001,19.000003 4.0010006,19.000003 4.0010006,15 0,15z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Accounting">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M7,26L19,26 19,28 7,28z M12.732999,14.533003L13.867999,14.533003 13.867999,15.486002C14.643999,15.519002,15.164999,15.671002,15.546999,15.844003L15.210999,17.068001C14.909999,16.949001 14.376999,16.700003 13.543999,16.700003 12.790999,16.700003 12.547999,17.003002 12.547999,17.307001 12.547999,17.664001 12.952999,17.892002 13.936999,18.238001 15.315999,18.693001 15.870998,19.289001 15.870998,20.264 15.870998,21.228001 15.141998,22.052 13.809999,22.268999L13.809999,23.372999 12.674999,23.372999 12.674999,22.344C11.898999,22.310999,11.146,22.116999,10.705999,21.878L11.052999,20.610001C11.539999,20.860001 12.223,21.087999 12.975999,21.087999 13.635999,21.087999 14.087999,20.85 14.087999,20.416 14.087999,20.004 13.716999,19.744001 12.859999,19.474001 11.620999,19.083 10.775999,18.542002 10.775999,17.490002 10.775999,16.537003 11.492999,15.790002 12.732999,15.562002z M2,12L2,30 24,30 24,12z M2,7L2,10 24,10 24,7z M2,2L2,5 24,5 24,2z M0,0L26,0 26,32 0,32z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Add">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M12.099998,0L19.799995,0 19.799995,12.1 32,12.1 32,19.799996 19.900002,19.799996 19.900002,31.999999 12.199997,31.999999 12.199997,19.900003 0,19.900003 0,12.199999 12.099998,12.199999z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="AddEncircled">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Transparent" Geometry="M14.100037,6L14.100037,14.099998 6,14.099998 6,18 14.100037,18 14.100037,26.099998 18,26.099998 18,18 26,18 26,14.099998 17.900024,14.099998 17.900024,6z M16,0C24.800049,0 32,7.1999969 32,16 32,24.800003 24.800049,32 16,32 7.2000122,32 0,24.800003 0,16 0,7.1999969 7.2000122,0 16,0z">
<GeometryDrawing.Pen>
<Pen Thickness="2" Brush="Black"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Beaker">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M454.352,398.431L331,190.879V87.42c17.459-6.192,30-22.865,30-42.42c0-24.813-20.187-45-45-45H196
c-24.813,0-45,20.187-45,45c0,19.555,12.541,36.228,30,42.42v103.459L57.659,398.413c-14.085,23.476-14.442,51.715-0.953,75.539
C70.196,497.776,94.594,512,121.972,512h268.055c27.378,0,51.776-14.224,65.266-38.048
C468.779,450.134,468.427,421.903,454.352,398.431z M196,30h120c8.271,0,15,6.729,15,15s-6.729,15-15,15H196
c-8.271,0-15-6.729-15-15S187.729,30,196,30z M208.895,202.664c1.378-2.319,2.105-4.966,2.105-7.664V90h90v30h-15
c-8.284,0-15,6.716-15,15s6.716,15,15,15h15v30h-15c-8.284,0-15,6.716-15,15s6.716,15,15,15h21.466l65.8,110.716
C362.112,326.413,347.079,332,331,332c-34.968,0-64.739-25.95-65.036-26.213c0,0-0.001-0.001-0.002-0.001
C264.139,304.162,227.422,272,181,272c-4.587,0-9.215,0.321-13.872,0.94L208.895,202.664z M429.187,459.171
C421.094,473.466,406.454,482,390.027,482H121.972c-16.427,0-31.066-8.534-39.16-22.829c-8.093-14.295-7.88-31.238,0.604-45.377
l61.501-103.482C157.353,304.799,169.477,302,181,302c34.968,0,64.74,25.951,65.006,26.186C247.551,329.566,284.39,362,331,362
c22.25,0,42.237-7.287,57.631-15.43l39.953,67.224c0.011,0.018,0.021,0.036,0.032,0.054
C437.067,427.933,437.281,444.876,429.187,459.171z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Book">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Transparent" Geometry="M16.378574,2.0941912E-05C17.053625,-0.0029775997,17.669592,0.31702943,17.669592,0.31702964L27.747614,10.181254C30.078613,11.977292,28.301632,12.163302,28.301632,12.163302L14.005584,15.500376C11.924586,18.496447,15.130586,19.519465,15.130586,19.519465L30.870606,16.081391C32.66065,16.035383,31.786623,17.428421,31.786623,17.428421L15.130586,21.214503C12.353603,22.20553,10.869592,20.092476,10.869592,20.092476L0.76355401,8.8182232C-1.4574583,4.6071207,1.8735417,3.616101,1.8735417,3.616101L16.08762,0.023016395C16.184605,0.0080166093,16.282566,2.082104E-05,16.378574,2.0941912E-05z">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="2"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Defrag">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M26.84801,26.411987L31.841998,26.411987 31.841998,31.915009 26.84801,31.915009z M10.497003,26.411987L18.709003,26.411987 18.709003,31.915009 10.497003,31.915009z M20.052005,18.708984L25.386005,18.708984 25.386005,31.915009 20.052005,31.915009z M10.497003,14.221985L18.709003,14.221985 18.709003,25.057983 10.497003,25.057983z M20.052005,9.5660095L25.386005,9.5660095 25.386005,17.18399 20.052005,17.18399z M26.84801,7.07901L31.841998,7.07901 31.841998,25.057983 26.84801,25.057983z M10.497003,1.9949951L18.709003,1.9949951 18.709003,12.686005 10.497003,12.686005z M0,0L9.2280055,0 9.2280055,32 0,32z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Knight">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M38.642,39.289c-3.895-3.373-2.645-7.564-0.338-13.896c1.898-5.21,4.051-11.118,1.445-16.945 c-1.789-4.001-6.2-8.319-13.215-8.442L25.963,0c-2.518,0-6.289,0.283-9.953,2.734c-0.286,0.191-0.462,0.51-0.472,0.855 c-0.01,0.345,0.148,0.672,0.424,0.879c0.583,0.438,0.94,1.313,1.138,2.049c-2.711,0.486-3.37,1.934-4.01,3.34 c-0.676,1.486-1.443,3.17-5.15,4.794c-1.008,0.442-1.693,1.499-1.789,2.757c-0.092,1.221,0.412,2.334,1.315,2.905 c0.385,0.244,0.778,0.269,1.094,0.289c0.382,0.025,0.657,0.043,1.07,0.409c0.327,0.292,0.593,0.621,0.827,0.912 c0.388,0.481,0.722,0.896,1.268,1.021c0.77,0.181,1.694-0.278,2.761-0.843c0.693-0.368,1.479-0.784,2.073-0.904 c0.754-0.15,1.721-0.323,2.52-0.323c0.684,0,0.909,0.134,0.928,0.114c0.18,1.047-1.972,2.48-3.87,3.745 c-3.333,2.224-7.481,4.988-6.394,9.455c0.17,0.699,0.523,2.123,3.82,3.819C6.66,39.331,1.21,41.742,1.21,43.609 c0,1.244,1.142,2.041,7.165,2.703C12.421,46.757,17.793,47,23.5,47s11.079-0.243,15.125-0.688 c6.022-0.662,7.165-1.459,7.165-2.703C45.79,42.247,42.89,40.596,38.642,39.289z">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="3"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Spawn">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M27,22.000013C25.346001,22.000013 24,23.345991 24,25.000013 24,26.654005 25.346001,28.000013 27,28.000013 28.653999,28.000013 30,26.654005 30,25.000013 30,23.345991 28.653999,22.000013 27,22.000013z M5,22C3.3460007,22 2,23.346 2,25 2,26.654 3.3460007,28 5,28 6.6540003,28 8,26.654 8,25 8,23.346 6.6540003,22 5,22z M16,2C14.346,2 13,3.3460007 13,5 13,6.6540003 14.346,8 16,8 17.654,8 19,6.6540003 19,5 19,3.3460007 17.654,2 16,2z M16,0C18.757,0 21,2.243 21,5 21,6.2061872 20.570676,7.3139925 19.856814,8.178627L19.749571,8.3023939 26.702677,20.009615 26.74309,20.006532C26.828189,20.002204 26.913844,20.000013 27,20.000013 29.757004,20.000013 32,22.242994 32,25.000013 32,27.757002 29.757004,30.000013 27,30.000013 24.242996,30.000013 22,27.757002 22,25.000013 22,23.104563 23.060166,21.452075 24.618662,20.604373L24.703606,20.560808 18.143555,9.5162544 17.944359,9.6064529C17.346375,9.8598127 16.68925,10 16,10 15.224594,10 14.489846,9.8225756 13.834221,9.5061913L13.749143,9.4625559 7.9581623,20.972196 7.9896793,20.994624C9.2092552,21.907268 10,23.363032 10,25 10,27.757 7.757,30 5,30 2.243,30 0,27.757 0,25 0,22.243 2.243,20 5,20 5.3446255,20 5.6812191,20.035047 6.0064049,20.101764L6.1420031,20.133139 12.151809,8.1885796 12.143186,8.178627C11.429324,7.3139925 11,6.2061872 11,5 11,2.243 13.243,0 16,0z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Tetris">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black" Geometry="M106.965,252.716H262.11c5.522,0,10-4.477,10-10v-77.572c0-5.523-4.478-10-10-10h-67.572V10c0-5.523-4.478-10-10-10 h-77.572c-5.522,0-10,4.477-10,10v232.716C96.965,248.239,101.443,252.716,106.965,252.716z M116.965,20h57.572v145.144 c0,5.523,4.478,10,10,10h67.572v57.572H116.965V20z"/>
<GeometryDrawing Brush="Black" Geometry="M417.253,193.93h-77.571c-5.522,0-10,4.477-10,10v67.572H262.11c-5.522,0-10,4.477-10,10v67.572H29.393 c-5.522,0-10,4.477-10,10v77.572c0,5.523,4.478,10,10,10h387.86c5.522,0,10-4.477,10-10V203.93 C427.253,198.407,422.776,193.93,417.253,193.93z M39.393,369.075h290.289v57.572H39.393V369.075z M407.253,426.646h-57.571 v-67.572c0-5.523-4.478-10-10-10H272.11v-57.572h67.572c5.522,0,10-4.477,10-10V213.93h57.571V426.646z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Filter">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="White" Geometry="M0,0L32,0 21.306,17.372993 21.272003,17.372993 21.272003,31.352 10.692001,31.352 10.692001,17.372993z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="FilterActive">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="PaleGreen" Geometry="M0,0L32,0 21.306,17.372993 21.272003,17.372993 21.272003,31.352 10.692001,31.352 10.692001,17.372993z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="FilterError">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Red" Geometry="M0,0L32,0 21.306,17.372993 21.272003,17.372993 21.272003,31.352 10.692001,31.352 10.692001,17.372993z"/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CancelIcon">
<DrawingImage.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="1" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry Center="3.5,3.5" RadiusX="7" RadiusY="7" />
<LineGeometry StartPoint="0.5,0.5" EndPoint="7,7" />
<LineGeometry StartPoint="0.5,7" EndPoint="7,0.5" />
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="PauseIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
Geometry="M18.51899,0L29.981999,0 29.981999,32 18.51899,32z M0,0L11.464992,0 11.464992,32 0,32z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="PlayIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
Geometry="M0,0L25.194,16 0,32z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<!-- help / support -->
<DrawingImage x:Key="SupportIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
Geometry="M23.679005,26.495C23.99901,26.495 24.265014,26.59 24.475017,26.78 24.685019,26.967 24.79102,27.204 24.79102,27.491 24.79102,27.783 24.68802,28.024 24.481016,28.214 24.271013,28.405 24.00301,28.5 23.679005,28.5 23.354001,28.5 23.085997,28.403 22.870994,28.208 22.655991,28.006 22.54899,27.766 22.54899,27.491 22.54899,27.207 22.655991,26.97 22.870994,26.78 23.085997,26.59 23.354001,26.495 23.679005,26.495z M23.734006,19.5C24.110011,19.5 24.460016,19.541 24.785021,19.625 25.110025,19.708 25.392029,19.839 25.632032,20.017 25.874036,20.195 26.062038,20.422 26.19904,20.7 26.333042,20.978 26.401043,21.311 26.401043,21.7 26.401043,21.947 26.373043,22.171 26.316042,22.371 26.259041,22.572 26.17704,22.762 26.067039,22.94 25.958037,23.118 25.822035,23.289 25.660033,23.453 25.498031,23.617 25.311028,23.786 25.101026,23.961 24.959023,24.078 24.835021,24.187 24.72802,24.289 24.620018,24.39 24.531017,24.49 24.460016,24.589 24.389015,24.689 24.335014,24.794 24.299014,24.905 24.262013,25.017 24.244013,25.144 24.244013,25.285 24.244013,25.383 24.257013,25.482 24.283013,25.583 24.310014,25.685 24.345015,25.77 24.390016,25.838L22.791993,25.838C22.751992,25.733 22.719992,25.615 22.697992,25.483 22.674991,25.351 22.663991,25.226 22.663991,25.109 22.663991,24.922 22.681992,24.752 22.718992,24.599 22.754992,24.445 22.809993,24.3 22.882994,24.164 22.955995,24.029 23.046997,23.898 23.155998,23.775 23.266,23.652 23.393002,23.529 23.539003,23.407 23.694005,23.278 23.828007,23.157 23.943009,23.046 24.059011,22.935 24.157012,22.823 24.238013,22.712 24.320014,22.6 24.380015,22.485 24.420015,22.365 24.460016,22.246 24.481016,22.113 24.481016,21.967 24.481016,21.841 24.459016,21.725 24.414016,21.618 24.369015,21.51 24.306014,21.419 24.222013,21.341 24.140012,21.264 24.03901,21.203 23.918009,21.159 23.799007,21.115 23.667005,21.092 23.521003,21.092 23.204998,21.092 22.876994,21.158 22.536989,21.29 22.195985,21.422 21.87398,21.621 21.569976,21.888L21.569976,20.059C21.88298,19.872 22.222985,19.733 22.59099,19.64 22.959995,19.547 23.341001,19.5 23.734006,19.5z M23.985949,18C20.670016,18 17.972007,20.69101 17.972007,24 17.972007,27.309021 20.670016,30 23.985949,30 27.302003,30 30.000989,27.309021 30.000989,24 30.000989,20.69101 27.302003,18 23.985949,18z M14,2C10.968,2 8.5,4.467 8.5,7.5 8.5,10.438219 10.81616,12.84526 13.717461,12.992831L13.973991,12.99934 13.99997,12.999012 14.027442,12.999304 14.28254,12.992831C17.18384,12.84526 19.5,10.438219 19.5,7.5 19.5,4.467 17.032,2 14,2z M14,0C18.136,0 21.5,3.3640003 21.5,7.5 21.5,9.95575 20.314059,12.13934 18.484733,13.508212L18.265061,13.664531 18.342722,13.68891C19.921902,14.202736,21.408062,14.995103,22.721599,16.037384L22.786062,16.089699 22.966662,16.064397C23.300515,16.021905 23.640717,16 23.985949,16 28.405035,16 32.000998,19.588989 32.000998,24 32.000998,28.411011 28.405035,32 23.985949,32 19.566984,32 15.971998,28.411011 15.971998,24 15.971998,20.96743 17.671191,18.323394 20.169134,16.967021L20.4065,16.845489 20.189965,16.712549C18.448412,15.669154,16.455822,15.076083,14.409823,15.006025L14.033219,14.999578 14,15 13.960834,14.999503 13.690718,15.00291C7.2160797,15.166433,1.9999962,20.449734,1.9999962,26.921989L0,26.928989 0,26.921989C0,20.80439,3.9878531,15.595488,9.51441,13.731782L9.7309766,13.661711 9.5152669,13.508212C7.6859417,12.13934 6.5,9.95575 6.5,7.5 6.5,3.3640003 9.8640003,0 14,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<!-- 'menu' three dots -->
<DrawingImage x:Key="MenuIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M23,14C24.10498,14 25,14.89502 25,16 25,17.10498 24.10498,18 23,18 21.89502,18 21,17.10498 21,16 21,14.89502 21.89502,14 23,14z M16,14C17.105,14 18,14.895 18,16 18,17.105 17.105,18 16,18 14.895,18 14,17.105 14,16 14,14.895 14.895,14 16,14z M9,14C10.105,14 11,14.895 11,16 11,17.105 10.105,18 9,18 7.8950005,18 7,17.105 7,16 7,14.895 7.8950005,14 9,14z M16,2C8.2799997,2 2,8.2800002 2,16 2,23.72 8.2799997,30 16,30 23.72,30 30,23.72 30,16 30,8.2800002 23.72,2 16,2z M16,0C24.822,0 32,7.178 32,16 32,24.822 24.822,32 16,32 7.1780005,32 0,24.822 0,16 0,7.178 7.1780005,0 16,0z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<!-- expander arrow -->
<DrawingImage x:Key="ArrowIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M299.152955025434,0L496.426178902388,0 268.890046089888,280.247772216797 198.190201729536,367.407897949219 199.87503144145,369.495361328125 271.502137154341,457.706451416016 498.999970406294,738 301.717621773481,738 101.234124153852,491.008697509766 99.5304498374462,488.936553955078 98.6409082114697,490.003173828125 0,368.488952636719 98.6409082114697,246.945526123047z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CancelBuys">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="{mbts:BTSColor MarketData.bid}"
Geometry="m 24.706673 31.196264 -3.086182 3.086182 5.965481 5.963348 -5.965481 5.96548 3.086182 3.084049 5.963348 -5.963348 5.96548 5.963348 3.084049 -3.084049 -5.963347 -5.96548 5.963347 -5.963348 -3.084049 -3.086182 -5.96548 5.965481 z M 5.3507926 32.045363 H 17.816449 v 2.401501 H 5.3507926 Z m 0 -4.937233 H 24.132994 v 2.401501 H 5.3507926 Z m 0 9.874466 h 5.5381524 v 2.401501 H 5.3507926 Z M 1.3730469 0 A 1.3741374 1.3741374 0 0 0 0 1.3730469 V 45.630859 a 1.3741374 1.3741374 0 0 0 1.3730469 1.373047 H 16.853516 a 17.906029 17.906029 0 0 1 -0.05859 -1.373047 17.906029 17.906029 0 0 1 0.06836 -1.375 H 2.7480469 V 2.7480469 H 33.326172 V 27.783203 a 17.906029 17.906029 0 0 1 1.375 -0.05859 17.906029 17.906029 0 0 1 1.373047 0.06836 V 1.3730469 A 1.3741374 1.3741374 0 0 0 34.701172 0 Z M 10.662215 24.759265 V 5.1202697 h 7.148923 q 3.286862 0 5.05355 1.2051818 1.766687 1.2051838 1.766687 3.3964241 0 1.5886494 -1.081924 2.7801354 -1.068231 1.191488 -2.739053 1.657126 v 0.05479 q 2.095375 0.26021 3.341644 1.547564 1.259962 1.287354 1.259962 3.136214 0 2.697964 -1.93103 4.286613 -1.931032 1.574956 -5.272673 1.574956 z M 15.085783 8.3797408 v 4.6563852 h 1.944726 q 1.369526 0 2.150155 -0.657372 0.794325 -0.671068 0.794325 -1.835164 0 -2.1638492 -3.23208 -2.1638492 z m 0 7.9432472 v 5.176805 h 2.39667 q 1.533868 0 2.39667 -0.712152 0.876495 -0.712155 0.876495 -1.944728 0 -1.17779 -0.862802 -1.848858 -0.849105 -0.671067 -2.382974 -0.671067 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CancelSells">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="{mbts:BTSColor MarketData.ask}"
Geometry="m 19.060265 26.797642 v -2.144583 q 0.583058 0.489233 1.266644 0.737201 0.683586 0.241265 1.380576 0.241265 0.408811 0 0.710393 -0.07372 0.308284 -0.07372 0.509339 -0.201055 0.207756 -0.134036 0.308284 -0.308283 0.100527 -0.18095 0.100527 -0.388706 0 -0.281477 -0.160844 -0.502637 -0.160844 -0.22116 -0.44232 -0.408811 -0.274775 -0.187651 -0.656779 -0.361898 -0.382004 -0.174248 -0.824324 -0.355197 -1.125906 -0.469128 -1.682158 -1.146012 -0.549549 -0.676884 -0.549549 -1.635245 0 -0.750604 0.301582 -1.28675 0.301582 -0.542847 0.817622 -0.891342 0.522743 -0.348495 1.206328 -0.509339 0.683586 -0.167545 1.447594 -0.167545 0.750604 0 1.326961 0.09383 0.583059 0.08712 1.072292 0.274775 v 2.003845 q -0.241266 -0.167545 -0.529444 -0.29488 -0.281477 -0.127335 -0.583059 -0.207757 -0.301582 -0.08712 -0.603164 -0.127334 -0.29488 -0.04021 -0.562953 -0.04021 -0.3686 0 -0.670182 0.07372 -0.301582 0.06702 -0.509339 0.194353 -0.207756 0.127334 -0.321687 0.308284 -0.113931 0.174247 -0.113931 0.395407 0 0.241266 0.127334 0.435619 0.127335 0.187651 0.361899 0.361898 0.234564 0.167546 0.569655 0.335091 0.335091 0.160844 0.757306 0.335091 0.576356 0.241266 1.03208 0.516041 0.462426 0.268073 0.790816 0.609866 0.328389 0.341793 0.502636 0.784113 0.174248 0.435618 0.174248 1.018677 0 0.804219 -0.308284 1.353768 -0.301582 0.542848 -0.824324 0.884641 -0.522743 0.335091 -1.219732 0.482531 -0.690288 0.14744 -1.460998 0.14744 -0.790815 0 -1.50791 -0.134036 -0.710393 -0.134037 -1.233135 -0.40211 z m 6.620223 3.788289 -1.556212 1.556212 3.008102 3.007026 -3.008102 3.008101 1.556212 1.555136 3.007026 -3.007026 3.008101 3.007026 1.555136 -1.555136 -3.007026 -3.008101 3.007026 -3.007026 -1.555136 -1.556212 -3.008101 3.008102 z m -9.76023 2.917766 h 2.792621 v 1.21096 h -2.792621 z m 0 -2.489606 h 6.285825 v 1.21096 h -6.285825 z m 0 -2.489607 h 9.470951 v 1.210961 H 15.920258 Z M 13.914475 14.855173 a 0.69291063 0.69291063 0 0 0 -0.692361 0.692361 v 22.317061 a 0.69291063 0.69291063 0 0 0 0.692361 0.692361 h 7.806047 a 9.0291392 9.0291392 0 0 1 -0.02954 -0.692361 9.0291392 9.0291392 0 0 1 0.03447 -0.693345 H 14.60782 V 16.24088 h 15.419061 v 12.624011 a 9.0291392 9.0291392 0 0 1 0.693346 -0.02954 9.0291392 9.0291392 0 0 1 0.692361 0.03447 V 15.547534 a 0.69291063 0.69291063 0 0 0 -0.692361 -0.692361 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="AddOrders" x:Shared="False">
<!-- Ticket icon -->
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M 5.3507926 32.045363 H 17.81645 v 2.401501 H 5.3507926 Z m 0 -4.937233 H 24.132995 v 2.401501 H 5.3507926 Z M 18.799228 22.222041 v 2.32929 h -1.567173 v -2.264886 q -2.179014 -0.01073 -4.057475 -0.987533 v -2.973336 q 0.622575 0.504501 1.856993 0.933864 1.234417 0.429362 2.200482 0.493766 v -3.907198 q -2.511771 -0.933863 -3.4349 -2.018003 -0.912395 -1.094874 -0.912395 -2.662047 0 -1.685248 1.191482 -2.8659947 1.19148 -1.1914807 3.155813 -1.3846939 V 4.918734 h 1.567173 v 1.9535992 q 2.264887 0.1073411 3.38123 0.7299162 V 10.500446 Q 20.677689 9.5880506 18.799228 9.3841034 v 4.0682086 q 2.35076 0.847992 3.370495 1.942866 1.019736 1.08414 1.019736 2.629845 0 1.781854 -1.137811 2.876728 -1.13781 1.08414 -3.25242 1.32029 z M 17.232055 12.829737 V 9.4270397 q -1.492034 0.2683516 -1.492034 1.5564393 0 1.105608 1.492034 1.846258 z m 1.567173 3.628113 v 3.25242 q 1.53497 -0.236149 1.53497 -1.53497 0 -1.051939 -1.53497 -1.71745 z m 13.258587 13.65074 h -3.954117 l 0.0014 7.641804 -7.643169 -10e-7 0.0014 3.952751 h 7.640439 l 0.0014 7.641803 h 3.951385 l 0.0014 -7.641802 7.640437 -10e-7 0.0014 -3.952751 -7.643169 10e-7 z M 5.3507926 36.982596 h 5.5381524 v 2.401501 H 5.3507926 Z M 1.3730469 0 A 1.3741374 1.3741374 0 0 0 0 1.3730469 V 45.630859 a 1.3741374 1.3741374 0 0 0 1.3730469 1.373047 H 16.853516 a 17.906029 17.906029 0 0 1 -0.05859 -1.373047 17.906029 17.906029 0 0 1 0.06836 -1.375 H 2.7480469 V 2.7480469 H 33.326172 V 27.783203 a 17.906029 17.906029 0 0 1 1.375 -0.05859 17.906029 17.906029 0 0 1 1.373047 0.06836 V 1.3730469 A 1.3741374 1.3741374 0 0 0 34.701172 0 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CancelOrders">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="m 26.463403 27.963318 h -2.359042 l -0.683586 -2.137882 h -3.417929 l -0.676884 2.137882 h -2.345638 l 3.498351 -9.610414 h 2.566798 z M 22.92484 24.163384 21.89276 20.933106 q -0.113931 -0.361899 -0.160844 -0.864535 h -0.05361 q -0.03351 0.422214 -0.167545 0.837727 l -1.045485 3.257086 z m 2.065112 7.055953 -1.51223 1.51223 2.923087 2.922042 -2.923087 2.923086 1.51223 1.511185 2.922042 -2.922042 2.923086 2.922042 1.511185 -1.511185 -2.922041 -2.923086 2.922041 -2.922042 -1.511185 -1.51223 -2.923086 2.923087 z m -9.484387 0.416058 h 6.108175 v 1.176737 h -6.108175 z m 0 -2.419244 h 9.203284 v 1.176735 h -9.203284 z m 0 4.83849 h 2.713696 v 1.176736 H 15.505565 Z M 13.556469 15.93316 a 0.67332766 0.67332766 0 0 0 -0.672794 0.672793 v 21.686339 a 0.67332766 0.67332766 0 0 0 0.672794 0.672793 h 7.585433 a 8.7739586 8.7739586 0 0 1 -0.02871 -0.672793 8.7739586 8.7739586 0 0 1 0.0335 -0.673751 H 14.230219 V 17.279703 h 14.983289 v 12.267233 a 8.7739586 8.7739586 0 0 1 0.67375 -0.02871 8.7739586 8.7739586 0 0 1 0.672794 0.0335 V 16.605953 A 0.67332766 0.67332766 0 0 0 29.887258 15.93316 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CancelSelected">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="m 24.706673 31.196264 -3.086181 3.086182 5.96548 5.963348 -5.96548 5.96548 3.086181 3.084049 5.963348 -5.963348 5.96548 5.963348 3.084049 -3.084049 -5.963347 -5.96548 5.963347 -5.963348 -3.084049 -3.086182 -5.96548 5.965481 z M 5.3507926 32.045363 H 17.81645 v 2.401501 H 5.3507926 Z m 0 -4.937233 H 24.132994 v 2.401501 H 5.3507926 Z M 26.434166 6.0031559 14.993666 17.443656 9.6399578 12.089946 6.0100982 15.719802 c 2.9622322 2.959826 6.0772448 6.092263 8.9969908 8.970151 L 30.064121 9.6329208 Z M 5.3507926 36.982596 h 5.5381524 v 2.401501 H 5.3507926 Z M 1.3730469 0 A 1.3741374 1.3741374 0 0 0 0 1.3730469 V 45.630859 a 1.3741374 1.3741374 0 0 0 1.3730469 1.373047 H 16.853516 a 17.906029 17.906029 0 0 1 -0.05859 -1.373047 17.906029 17.906029 0 0 1 0.06836 -1.375 H 2.7480469 V 2.7480469 H 33.326172 V 27.783203 a 17.906029 17.906029 0 0 1 1.375 -0.05859 17.906029 17.906029 0 0 1 1.373047 0.06836 V 1.3730469 A 1.3741374 1.3741374 0 0 0 34.701172 0 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ModifyOrder">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black"
Geometry="m 18.887708 18.355738 v 1.910329 h -1.285291 v -1.857509 q -1.787082 -0.0088 -3.327671 -0.809909 v -2.438532 q 0.510595 0.413758 1.522982 0.765893 1.012387 0.352134 1.804689 0.404954 V 13.12654 q -2.059987 -0.765892 -2.817076 -1.655032 -0.748286 -0.897943 -0.748286 -2.1832341 0 -1.382128 0.977174 -2.3504979 0.977173 -0.9771733 2.588188 -1.1356339 V 4.1647166 h 1.285291 v 1.6022121 q 1.85751 0.088034 2.77306 0.5986287 v 2.376908 Q 20.428297 7.9941795 18.887708 7.8269156 V 11.16339 q 1.927937 0.695466 2.764256 1.593409 0.83632 0.88914 0.83632 2.156824 0 1.461358 -0.933157 2.359301 -0.933156 0.88914 -2.667419 1.082814 z M 17.602417 10.652795 V 7.8621291 q -1.223667 0.2200841 -1.223667 1.2764876 0 0.9067463 1.223667 1.5141783 z m 1.285291 2.975537 v 2.667419 q 1.258881 -0.193674 1.258881 -1.258881 0 -0.86273 -1.258881 -1.408538 z M 7.8581956 26.412174 H 18.081699 v 1.969551 H 7.8581956 Z m 0 -4.04919 H 23.262109 v 1.969551 H 7.8581956 Z m 23.8237084 -0.610988 -12.064762 12.064763 4.39301 4.393009 12.064761 -12.064762 z m -0.0014 3.48158 0.91143 0.91143 -8.583182 8.583183 -0.91143 -0.91143 z m -12.817392 9.398532 -1.583992 5.915617 5.914283 -1.585326 z M 7.8581956 30.461364 H 12.40022 v 1.969551 H 7.8581956 Z M 4.5959132 0.13069836 A 1.1269761 1.1269761 0 0 0 3.4698314 1.2567801 V 37.554094 a 1.1269761 1.1269761 0 0 0 1.1260818 1.126082 H 15.310509 a 8.0150307 8.0150307 0 0 1 -0.01762 -0.337985 8.0150307 8.0150307 0 0 1 0.240273 -1.915781 H 5.7235967 V 2.3844637 H 30.801741 V 20.486667 a 8.0150307 8.0150307 0 0 1 0.863383 -0.04966 8.0150307 8.0150307 0 0 1 1.390383 0.12334 V 1.2567801 A 1.1269761 1.1269761 0 0 0 31.929425 0.13069836 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<!--DrawingImage x:Key="LadderCancelBuys">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="{mbts:BTSColor MarketData.bid}"
Geometry="M 9.9417804 -0.02293875 1.9154138 8.0034278 17.4301 23.512569 1.9154138 39.027256 9.9417804 47.048077 25.450922 31.538936 40.965607 47.048077 48.986428 39.027256 33.47729 23.512569 48.986428 8.0034278 40.965607 -0.02293875 25.450922 15.491746 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="LadderCancelSells">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="{mbts:BTSColor MarketData.ask}"
Geometry="M 9.9417804 -0.02293875 1.9154138 8.0034278 17.4301 23.512569 1.9154138 39.027256 9.9417804 47.048077 25.450922 31.538936 40.965607 47.048077 48.986428 39.027256 33.47729 23.512569 48.986428 8.0034278 40.965607 -0.02293875 25.450922 15.491746 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="LadderCancelOrders">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M 9.9417804 -0.02293875 1.9154138 8.0034278 17.4301 23.512569 1.9154138 39.027256 9.9417804 47.048077 25.450922 31.538936 40.965607 47.048077 48.986428 39.027256 33.47729 23.512569 48.986428 8.0034278 40.965607 -0.02293875 25.450922 15.491746 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage-->
<DrawingImage x:Key="Synthetics" x:Shared="False">
<!-- Spreads icon -->
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="m 69.641861 87.129943 a 36.813842 36.813842 0 0 0 -36.813776 36.813767 36.813842 36.813842 0 0 0 31.044618 36.31355 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.828154 39.50509 41.092964 41.092964 0 0 0 41.09258 41.0931 41.092964 41.092964 0 0 0 41.093104 -41.0931 41.092964 41.092964 0 0 0 -0.10284 -2.9068 41.092964 41.092964 0 0 0 -38.048841 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093347 -12.61939 l 33.150946 15.70705 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.12557 2.49907 27.542416 27.542416 0 0 0 27.54251 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.5425 27.542416 27.542416 0 0 0 -22.44618 11.61479 l -31.44563 -14.89935 a 36.813842 36.813842 0 0 0 1.55701 -10.53786 36.813842 36.813842 0 0 0 -36.813769 -36.813767 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="AddSynthetic" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M 36.50044 86.999995 A 36.813842 36.813842 0 0 0 -0.3133356 123.81377 36.813842 36.813842 0 0 0 30.731282 160.12732 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.8281546 39.50509 41.092964 41.092964 0 0 0 41.0925806 41.0931 41.092964 41.092964 0 0 0 41.093099 -41.0931 41.092964 41.092964 0 0 0 -0.102836 -2.9068 41.092964 41.092964 0 0 0 -38.04884 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093347 -12.61939 l 33.150948 15.70705 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.125574 2.49907 27.542416 27.542416 0 0 0 27.542513 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.5425 27.542416 27.542416 0 0 0 -22.44618 11.61479 L 71.757201 134.35163 A 36.813842 36.813842 0 0 0 73.314213 123.81377 36.813842 36.813842 0 0 0 36.50044 86.999995 Z m 116.60981 115.628085 0.007 37.48967 h -37.49716 l 0.007 19.39257 h 37.48344 L 153.11751 297 h 19.38493 l 0.007 -37.48968 h 37.48342 L 210 240.11775 h -37.49727 l 0.007 -37.48967 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="RemoveSynthetic" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M 37.03498 86.999995 A 36.813842 36.813842 0 0 0 0.22120379 123.81377 36.813842 36.813842 0 0 0 31.265822 160.12731 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.8281552 39.50509 41.092964 41.092964 0 0 0 41.0925812 41.0931 41.092964 41.092964 0 0 0 41.093099 -41.0931 41.092964 41.092964 0 0 0 -0.102836 -2.9068 41.092964 41.092964 0 0 0 -38.04884 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093346 -12.61938 l 33.150949 15.70704 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.125574 2.49907 27.542416 27.542416 0 0 0 27.542503 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.54249 27.542416 27.542416 0 0 0 -22.44618 11.61479 L 72.29174 134.35163 A 36.813842 36.813842 0 0 0 73.848752 123.81377 36.813842 36.813842 0 0 0 37.03498 86.999995 Z m 94.72671 153.117755 0.008 18.80608 c 0 0 -6.42588 -1.1e-4 78.75576 1.3e-4 l 0.009 -18.80621 c 0 0 4.48208 0 -78.77178 0 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ModifySynthetic" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M 37.03498 86.999995 A 36.813842 36.813842 0 0 0 0.2212037 123.81377 36.813842 36.813842 0 0 0 31.265822 160.12732 l 1.208194 21.35839 1.804543 31.90967 a 41.092964 41.092964 0 0 0 -29.8281553 39.50509 41.092964 41.092964 0 0 0 41.0925813 41.0931 41.092964 41.092964 0 0 0 41.093099 -41.0931 41.092964 41.092964 0 0 0 -0.102836 -2.9068 41.092964 41.092964 0 0 0 -38.04884 -38.03902 l -2.962092 -52.36321 a 36.813842 36.813842 0 0 0 20.093347 -12.61939 l 33.150948 15.70705 v 5.3e-4 a 27.542416 27.542416 0 0 0 -0.125574 2.49907 27.542416 27.542416 0 0 0 27.542503 27.54249 27.542416 27.542416 0 0 0 27.5425 -27.5425 27.542416 27.542416 0 0 0 -27.5425 -27.5425 27.542416 27.542416 0 0 0 -22.44618 11.61479 L 72.291741 134.35163 A 36.813842 36.813842 0 0 0 73.848753 123.81377 36.813842 36.813842 0 0 0 37.03498 86.999995 Z m 145.03189 90.486735 -76.71431 76.71435 27.93311 27.93293 L 210 205.41986 Z m -0.008 22.13769 5.79522 5.79544 -54.57645 54.57644 -5.7952 -5.79522 z m -81.50016 59.76108 -10.071854 37.61451 37.606034 -10.0803 z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CloneSynthetic" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="m 139.80129 180.78831 a 20.783495 20.783495 0 0 0 -20.78345 20.78346 20.783495 20.783495 0 0 0 17.52643 20.50105 l 0.68209 12.05803 1.01877 18.01482 a 23.1993 23.1993 0 0 0 -16.83968 22.30284 23.1993 23.1993 0 0 0 23.1991 23.19938 23.1993 23.1993 0 0 0 23.19935 -23.19938 23.1993 23.1993 0 0 0 -0.058 -1.64105 23.1993 23.1993 0 0 0 -21.4807 -21.47518 l -1.67225 -29.56198 a 20.783495 20.783495 0 0 0 11.34383 -7.12437 l 18.71558 8.86752 v 3.1e-4 a 15.549251 15.549251 0 0 0 -0.0708 1.41086 15.549251 15.549251 0 0 0 15.5493 15.54927 15.549251 15.549251 0 0 0 15.54931 -15.54927 15.549251 15.549251 0 0 0 -15.54931 -15.54932 15.549251 15.549251 0 0 0 -12.67213 6.5572 l -17.75282 -8.41152 a 20.783495 20.783495 0 0 0 0.87902 -5.94921 20.783495 20.783495 0 0 0 -20.78345 -20.78346 z M 31.983713 88.265691 A 30.676234 30.676234 0 0 0 1.3075339 118.94187 30.676234 30.676234 0 0 0 27.17639 149.20122 l 1.006764 17.79752 1.503689 26.58969 A 34.241941 34.241941 0 0 0 4.8316412 226.50722 34.241941 34.241941 0 0 0 39.073263 260.74928 34.241941 34.241941 0 0 0 73.315316 226.50722 34.241941 34.241941 0 0 0 73.229625 224.08505 34.241941 34.241941 0 0 0 41.524291 192.3879 L 39.05604 148.75469 A 30.676234 30.676234 0 0 0 55.799422 138.2392 l 27.624018 13.08837 v 4.4e-4 a 22.950541 22.950541 0 0 0 -0.104638 2.08242 22.950541 22.950541 0 0 0 22.950618 22.9506 22.950541 22.950541 0 0 0 22.95062 -22.9506 22.950541 22.950541 0 0 0 -22.95062 -22.95061 22.950541 22.950541 0 0 0 -18.703946 9.67837 L 61.362463 127.72286 A 30.676234 30.676234 0 0 0 62.65989 118.94187 30.676234 30.676234 0 0 0 31.983713 88.265691 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ViewSettings" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M22.889013,19.178117C23.365026,19.178117 23.75202,19.56508 23.75202,20.040055 23.75202,20.516007 23.365026,20.904069 22.889013,20.904069 22.413031,20.904069 22.02503,20.516007 22.02503,20.040055 22.02503,19.56508 22.413031,19.178117 22.889013,19.178117z M22.889013,15.528093C20.40003,15.528092 18.375006,17.552018 18.375006,20.040055 18.375006,22.529069 20.40003,24.554093 22.889013,24.554093 25.37702,24.554093 27.402014,22.529069 27.402014,20.040055 27.402014,17.552018 25.37702,15.528092 22.889013,15.528093z M22.167028,12.426042L23.834021,12.426042 23.834021,13.935075 23.981024,13.958024C24.912024,14.12404,25.772009,14.500016,26.509008,15.03505L26.62702,15.12404 27.757025,13.993058 28.935034,15.171037 27.806005,16.301042 27.940008,16.484025C28.422033,17.167008,28.769018,17.950089,28.943029,18.796037L28.996008,19.093034 30.500006,19.093034 30.500006,20.759049 29.02503,20.759049 28.997015,20.980119C28.848028,21.952043,28.472021,22.85109,27.924017,23.619035L27.805029,23.779069 28.935034,24.909074 27.757025,26.088029 26.62702,24.958024 26.61701,24.966081C25.866034,25.536027,24.981024,25.938004,24.019018,26.117082L23.834021,26.147111 23.834021,27.426042 22.167028,27.426042 22.167028,26.177018 21.949011,26.149064C20.942022,25.995011,20.014013,25.596086,19.228033,25.016007L19.151007,24.957047 18.019018,26.088029 16.841009,24.909074 17.972021,23.779069 17.863013,23.633073C17.294012,22.839005,16.908026,21.905046,16.767034,20.894059L16.75202,20.759049 15.500006,20.759049 15.500006,19.093034 16.783026,19.093034 16.812017,18.91005C16.991034,17.947038,17.393011,17.063004,17.963019,16.312028L17.972021,16.301042 16.841009,15.171037 18.019018,13.993058 19.15003,15.123063 19.310034,15.005021C20.078009,14.458024,20.977026,14.081071,21.949011,13.932023L22.167028,13.905046z M16.000014,6.0000114C14.346014,6.0000114 13.000014,7.3460112 13.000014,9.0000114 13.000014,10.654011 14.346014,12.000011 16.000014,12.000011 17.654014,12.000011 19.000014,10.654011 19.000014,9.0000114 19.000014,7.3460112 17.654014,6.0000114 16.000014,6.0000114z M16.000014,4.0000114C18.757014,4.0000114 21.000014,6.2430115 21.000014,9.0000114 21.000014,11.757011 18.757014,14.000011 16.000014,14.000011 13.243014,14.000011 11.000014,11.757011 11.000014,9.0000114 11.000014,6.2430115 13.243014,4.0000114 16.000014,4.0000114z M16.000123,0C24.651189,0 31.47924,8.0160384 31.765244,8.3580403 32.078245,8.7290418 32.078245,9.2720447 31.765244,9.6440461 31.700243,9.7220466 30.130231,11.580056 27.56321,13.533065L26.352201,11.941058C27.853213,10.798052 29.000222,9.6770465 29.645226,9.0010433 27.881213,7.1610341 22.366171,2.0000095 16.000123,2.0000095 9.6350741,2.0000095 4.1210318,7.1590343 2.3550186,9.0000434 4.013031,10.731052 8.9770689,15.388074 14.846114,15.946077L14.657112,17.936087C6.6410513,17.175083 0.49200439,9.9510479 0.23400211,9.6430461 -0.078000069,9.2720447 -0.078000069,8.7290418 0.23400211,8.3580403 0.52000427,8.0160384 7.3480568,0 16.000123,0z"
/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Export" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M23.471008,4.2230202L32,12.800012 23.471008,20.360005 23.471008,16.322012C23.471008,16.322012 8.7430115,12.294 5.0610046,20.360005 5.0610046,18.343985 6.3990173,8.2560073 23.471008,8.2560073z M0,0L21.334015,0 21.334015,2.1340014 21.334015,4.2690102 19.200012,4.2690102 19.200012,2.1340014 2.1340027,2.1340014 2.1340027,23.466997 19.200012,23.466997 19.200012,21.331989 21.334015,21.331989 21.334015,23.466997 21.334015,25.601 19.200012,25.601 0,25.601 0,23.466997 0,2.1340014z"
/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Import" x:Shared="False">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing
Brush="Black"
Geometry="M13.594002,4.2219891L13.594002,8.255989C30.661003,8.255989 32,18.345018 32,20.360004 28.319,12.293011 13.594002,16.32399 13.594002,16.32399L13.594002,20.360004 5.0610008,12.798993z M0,0L21.333,0 21.333,2.1329974 21.333,4.2670025 19.201,4.2670025 19.201,2.1329974 2.1330032,2.1329974 2.1330032,23.467003 19.201,23.467003 19.201,21.332998 21.333,21.332998 21.333,23.467003 21.333,25.6 19.201,25.6 0,25.6 0,23.467003 0,2.1329974z"
/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<!-- Pin
<Path Data="F1M3,11L3,7 0,7 0,6 1,6 1,1 1,0 6,0 6,1 6,6 7,6 7,7 4,7 4,11 3,11z M2,1L2,6 4,6 4,1 2,1z" />
Unpin
<Path Data="F1M0,3L4,3 4,0 5,0 5,1 10,1 11,1 11,6 10,6 5,6 5,7 4,7 4,4 0,4 0,3z M10,2L5,2 5,4 10,4 10,2z" />
-->
</ResourceDictionary>
@@ -1,56 +0,0 @@
using bts.api;
using bts.spark;
using mbts;
using mbts.co2;
using mbts.spark;
using mbts.ui;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media;
using static mbts.ui.shell.ProtoBufSerializationHelper;
namespace bts.shell
{
[Export(typeof(IShellModule))]
class MarketShellModule : IShellModule
{
[ImportingConstructor]
public MarketShellModule(IBus bus, MDConsumer consumer, OrdersModel orders_model, [Import("username")]string user_name) {
_tsf = new TimeAndSalesWindowFactory(this, bus, consumer);
_mvf = new MarketViewWindowFactory(this, bus, orders_model);
}
TimeAndSalesWindowFactory _tsf;
MarketViewWindowFactory _mvf;
#region IShellModule
public ImageSource icon => Icons.Date;
public string name => "Market";
public int priority => 10;
public IEnumerable<SparkCommand> actions => new [] {
SparkCommands.PickMarketView,
SparkCommands.PickTimeAndSales
};
public Task<IShellWindow> create(Stream load_stream) {
if (try_deserialize(load_stream, out ShellSerializationHeader header)) {
if (header.name == _tsf.name) return _tsf.load_window(load_stream, header.version);
if (header.name == _mvf.name) return _mvf.load_window(load_stream, header.version);
}
return null;
}
public void Dispose() {
Disposable.dispose(ref _tsf);
Disposable.dispose(ref _mvf);
}
#endregion
}
}
@@ -1,307 +0,0 @@
using bts.api;
using bts.api.orderman;
using mbts.co2;
using mbts.collections;
using mbts.spark.utilities;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.spark;
using mbts.ui.utility;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
namespace mbts.spark {
partial class MarketViewVM {
public class Row : SecurityMDRow, IDisposable, IEquatable<Row>, DIYGrid.IRowVM, DIYGrid.IActionableRowVM {
readonly IBus _bus;
readonly OrdersModel _orders_model;
readonly AnimationManager _animation = new AnimationManager();
readonly ObservableCollection<OrderRecordImmutable> _orders = new ObservableCollection<OrderRecordImmutable>();
readonly ObservableFilterCollection<OrderRecordImmutable> _working_orders, _working_bids, _working_asks;
readonly string _security_text, _security_key_text;
readonly Property<double> _bid_price, _ask_price, _last_price, _day_change, _settlement, _session_high, _session_low;
readonly Property<ushort> _bid_size, _ask_size;
readonly CellProperty<int> _position;
readonly CellProperty<ushort> _last_size;
readonly CellProperty<ulong> _volume;
readonly CellProperty<bool> _inside_bids, _inside_asks;
readonly CellProperty<int> _working_bid_volume, _working_ask_volume;
readonly CellProperty<double> _working_best_bid, _working_best_ask;
readonly CellProperty<string> _working_bids_text, _working_asks_text;
readonly MyOrderSummarizer _order_summarizer = new MyOrderSummarizer();
ulong _bbo_ref, _last_ref;
public Row(IBus bus, SecurityMD smd, OrdersModel orders_model) : base(smd) {
_bus = bus;
_orders_model = orders_model;
_security_text = smd.security.ToString();
_security_key_text = security_key.ToString();
string format_price(double price) => security.ContractSpec.format(price);
_position = new CellProperty<int>(0);
_bid_price = backing(nameof(bid_price), double.NaN);
_ask_price = backing(nameof(ask_price), double.NaN);
_bid_size = backing<ushort>(nameof(bid_size), 0);
_ask_size = backing<ushort>(nameof(ask_size), 0);
_last_price = backing(nameof(last_price), double.NaN);
_last_size = new CellProperty<ushort>(0);
_day_change = backing(nameof(day_change), double.NaN);
_session_low = backing(nameof(session_low), double.NaN);
_session_high = backing(nameof(session_high), double.NaN);
_settlement = backing(nameof(settlement), double.NaN);
_volume = new CellProperty<ulong>(0);
_inside_bids = new CellProperty<bool>();
_inside_asks = new CellProperty<bool>();
_working_bid_volume = new CellProperty<int>();
_working_ask_volume = new CellProperty<int>();
//
_working_orders = new ObservableFilterCollection<OrderRecordImmutable>(_orders, o => o.is_active());
_working_bids = new ObservableFilterCollection<OrderRecordImmutable>(_working_orders, o => o.Def.Side == Side.Buy);
_working_asks = new ObservableFilterCollection<OrderRecordImmutable>(_working_orders, o => o.Def.Side == Side.Sell);
_working_best_bid = new CellProperty<double>(format_price, double.NaN);
_working_best_ask = new CellProperty<double>(format_price, double.NaN);
_working_bids_text = new CellProperty<string>(string.Empty);
_working_asks_text = new CellProperty<string>(string.Empty);
//
default_command = new DelegateCommand(_show_ladder);
bid_price_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.Bid));
bid_size_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.BidSize));
working_bids_click = new DelegateCommand(() => _show_order_book(MarketViewView.Columns.WorkingBids));
ask_price_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.Ask));
ask_size_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.AskSize));
working_asks_click = new DelegateCommand(() => _show_order_book(MarketViewView.Columns.WorkingAsks));
_animation.AnimationsChanged += on_animations_changed;
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
_dispose = Disposable.Create(
_orders_model.on_security_orders(security.Id).ObserveOnDispatcher().Subscribe(_on_orders),
_position.ObserveOnDispatcher().Subscribe(v => _animation.animate_position(v.newval > v.oldval)),
_inside_bids.ObserveOnDispatcher().Subscribe(v => _animation.animate_working_bids_inside(v.newval)),
_inside_asks.ObserveOnDispatcher().Subscribe(v => _animation.animate_working_asks_inside(v.newval)),
_day_change.ObserveOnDispatcher().Subscribe(v => _animation.animate_day_change(v.newval > v.oldval)),
Disposable.Create(() => _animation.AnimationsChanged -= on_animations_changed)
);
}
public event Action invalidated;
#region Bound Properties
public bool inside_bids => _inside_bids.value;
public bool inside_asks => _inside_asks.value;
public int position => _position.value;
public double last_price => _last_price.Value;
public ushort last_size => _last_size.value;
public double bid_price => _bid_price.Value;
public ushort bid_size => _bid_size.Value;
public double ask_price => _ask_price.Value;
public ushort ask_size => _ask_size.Value;
public ulong volume => _volume.value;
public double settlement => _settlement.Value;
public double day_change => _day_change.Value;
public double session_low => _session_low.Value;
public double session_high => _session_high.Value;
public int working_bid_volume => _working_bid_volume.value;
public int working_ask_volume => _working_ask_volume.value;
public string working_bids_text => OrderUtils.order_collection_summary(_order_summarizer.best_working_bid, _order_summarizer.best_working_bid_qty, _order_summarizer.working_bid_qty, security.ContractSpec);
public string working_asks_text => OrderUtils.order_collection_summary(_order_summarizer.best_working_ask, _order_summarizer.best_working_ask_qty, _order_summarizer.working_ask_qty, security.ContractSpec);
public double working_best_bid => _working_best_bid.value;
public double working_best_ask => _working_best_ask.value;
public IList<CellAnimation> animations => _animation.get_animations().ToList();
public ICommand bid_price_click { get; }
public ICommand bid_size_click { get; }
public ICommand working_bids_click { get; }
public ICommand ask_price_click { get; }
public ICommand ask_size_click { get; }
public ICommand working_asks_click { get; }
public ICommand default_command { get; }
#endregion
public void refresh() {
bool dirty = false;
if (md.md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
_bid_price.set(b.price);
_bid_size.set(b.size);
_ask_price.set(a.price);
_ask_size.set(a.size);
_inside_bids.on_next_distinct(_bid_price.Value >= _working_best_bid.value, ref dirty);
_inside_asks.on_next_distinct(_ask_price.Value <= _working_best_ask.value, ref dirty);
}
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
_last_price.set(ps.price);
_last_size.on_next_distinct(ps.size, ref dirty);
_volume.on_next_distinct(v, ref dirty);
}
_settlement.set(md.md.settlement_price);
_session_low.set(md.md.session_low);
_session_high.set(md.md.session_high);
_day_change.set(last_price - settlement);
if (dirty)
invalidated?.Invoke();
}
public bool Equals(Row other) =>
other != null &&
other.security_key == security_key;
public override bool Equals(object obj) =>
Equals(obj as Row);
public override int GetHashCode() =>
security_key.GetHashCode();
#region Show Windows
void _show_ladder() => _bus.post(SparkTags.ShowLadderTag, md);
void _show_order_book(MarketViewView.Columns col) {
switch (col) {
case MarketViewView.Columns.WorkingBids: _show_order_book(Side.Buy); break;
case MarketViewView.Columns.WorkingAsks: _show_order_book(Side.Sell); break;
}
}
void _show_order_book(Side side) =>
_bus.post(SparkTags.ShowOrderBookTag, new bts.shell.OrderBookWindowFactory.OrderBookStartupData(
new List<SortingCriteria>(),
new bts.shell.OrderBookWindowFactory.FilterStates {
statuses = new[] { OrderStatus.Working },
sides = new[] { side },
security_criteria = new SecurityCriteria(security)
}));
void _show_order_ticket(MarketViewView.Columns col) {
var order = _orders_model.factory.order(security);
switch (col) {
case MarketViewView.Columns.Bid:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, bid_price, 0u));
break;
case MarketViewView.Columns.BidSize:
order.Side = Side.Sell;
_bus.post(SparkTags.ShowOrderTicketTag, (order, bid_price, bid_size));
break;
case MarketViewView.Columns.Ask:
order.Side = Side.Buy;
_bus.post(SparkTags.ShowOrderTicketTag, (order, ask_price, 0u));
break;
case MarketViewView.Columns.AskSize:
order.Side = Side.Buy;
_bus.post(SparkTags.ShowOrderTicketTag, (order, ask_price, ask_size));
break;
case MarketViewView.Columns.Last:
_bus.post(SparkTags.ShowOrderTicketTag, (order, last_price, 0u));
break;
case MarketViewView.Columns.LastSize:
_bus.post(SparkTags.ShowOrderTicketTag, (order, last_price, last_size));
break;
}
}
#endregion
#region Callbacks
void _on_orders(ITableUpdateTransform<OrderRecordImmutable, uint> orders) {
foreach (var o in orders.removed)
_order_summarizer.remove_order(o);
foreach (var o in orders.added)
_order_summarizer.add_order(o);
bool dirty = false;
_refresh_orders(ref dirty);
if (dirty)
invalidated?.Invoke();
}
void _refresh_orders(ref bool dirty) {
_position.on_next_distinct(_order_summarizer.position, ref dirty);
_working_bid_volume.on_next_distinct(_order_summarizer.working_bid_qty, ref dirty);
_working_ask_volume.on_next_distinct(_order_summarizer.working_ask_qty, ref dirty);
_working_best_bid.on_next_distinct(_order_summarizer.best_working_bid, ref dirty);
_working_best_ask.on_next_distinct(_order_summarizer.best_working_ask, ref dirty);
_inside_bids.on_next_distinct(_order_summarizer.best_working_bid >= bid_price, ref dirty);
_inside_asks.on_next_distinct(_order_summarizer.best_working_ask <= ask_price, ref dirty);
RaisePropertyChanged(nameof(working_bids_text), nameof(working_asks_text));
}
#endregion
class MyOrderSummarizer {
SortedSetMap<double, OrderRecordImmutable> _bids, _asks;
int _best_bid_working_qty, _best_ask_working_qty, _position, _working_bid_qty, _working_ask_qty;
public MyOrderSummarizer() {
_bids = new SortedSetMap<double, OrderRecordImmutable>(
OrderDataHelper.CompareUtils.bid_price_comparer,
OrderDataHelper.CompareUtils.order_record_id_eq_comparer);
_asks = new SortedSetMap<double, OrderRecordImmutable>(
OrderDataHelper.CompareUtils.ask_price_comparer,
OrderDataHelper.CompareUtils.order_record_id_eq_comparer);
}
// bid
public double best_working_bid => _bids.Count > 0 ? _bids.at_index(0).Key : double.NaN;
public int best_working_bid_qty => _best_bid_working_qty;
public int working_bid_qty => _working_bid_qty;
// ask
public double best_working_ask => _asks.Count > 0 ? _asks.at_index(0).Key : double.NaN;
public int best_working_ask_qty => _best_ask_working_qty;
public int working_ask_qty => _working_ask_qty;
// pos
public int position => _position;
public void add_order(OrderRecordImmutable o) {
// This is a market data form - not an orders form - so just show data for root/non-child orders.
if (o.has_parent())
return;
switch (o.side()) {
case Side.Buy:
_position += (int)o.filled();
if (o.is_active()) {
_working_bid_qty += o.working_quantity();
_bids.add(o.price(), o);
}
break;
case Side.Sell:
_position -= (int)o.filled();
if (o.is_active()) {
_working_ask_qty += o.working_quantity();
_asks.add(o.price(), o);
}
break;
default: return;
}
_refresh();
}
public void remove_order(OrderRecordImmutable o) {
// This is a market data form - not an orders form - so just show data for root/non-child orders.
if (o.has_parent())
return;
switch (o.side()) {
case Side.Buy:
_position -= (int)o.filled();
if (o.is_active()) {
_working_bid_qty -= o.working_quantity();
_bids.remove(o.price(), o);
}
break;
case Side.Sell:
_position += (int)o.filled();
if (o.is_active()) {
_working_ask_qty -= o.working_quantity();
_asks.remove(o.price(), o);
}
break;
default: return;
}
_refresh();
}
void _refresh() {
_best_bid_working_qty = _bids.Count > 0 ? _bids.at_index(0).Sum(o => o.working_quantity()) : 0;
_best_ask_working_qty = _asks.Count > 0 ? _asks.at_index(0).Sum(o => o.working_quantity()) : 0;
}
}
}
}
}
@@ -1,164 +0,0 @@
using bts.api;
using mbts.spark.filters;
using mbts.ui;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.Windows.Media;
using System.Reactive.Linq;
using static bts.shell.MarketViewWindowFactory;
using static mbts.ui.controls.DIYGrid;
using static mbts.ui.spark.MarketViewView;
namespace mbts.spark {
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
public MarketViewVM(IBus bus, OrdersModel orders_model, IObservable<StartupData> state)
: base(RXCollection.Create(state.SelectMany(s => s.security_criteria.subscribe_md(bus)), SecurityDataHelper.EqualityComparer.MDComparer), null) {
_bus = bus;
_orders_model = orders_model;
security_filter = new RegexFilterVM<Row>(r => r.security.ToString(), nameof(Row.security));
// Columns
const string size_col_header = "Qty", working_col_header = "Working";
const double working_orders_col_width = 105;
IMultiValueConverter price_converter = new ui.spark.converters.TickDisplayConverter();
add_col(Columns.Security, "Security", r => r.security.ToString(), nameof(Row.security), DefaultColumnWidths.Security, security_filter, DataGridFilterKnownTemplates.Regex);
add_col(Columns.Volume, "Volume", r => r.volume.ToString(), nameof(Row.volume), 64, volume_filter, DataGridFilterKnownTemplates.ULongMinMax);
add_col(Columns.Last, "Last", r => r.format_price(r.last_price), nameof(Row.last_price), DefaultColumnWidths.Price, last_price_filter, DataGridFilterKnownTemplates.DoubleMinMax);
add_col(Columns.LastSize, size_col_header, r => r.last_size.ToString(), nameof(Row.last_size), DefaultColumnWidths.Size, last_size_filter, DataGridFilterKnownTemplates.UShortMinMax);
add_col(Columns.Position, "Pos", r => r.position.ToString(), nameof(Row.position), DefaultColumnWidths.Size, position_filter, DataGridFilterKnownTemplates.IntMinMax, true);
add_hl_working_orders_col(Columns.WorkingBids, working_col_header, nameof(Row.working_bids_text), nameof(Row.working_best_bid), nameof(Row.working_bids_click), working_bid_volume_filter, BTSColors.MarketData.bid_brush);
add_hl_size_col(Columns.BidSize, size_col_header, nameof(Row.bid_size), nameof(Row.bid_size_click), bid_size_filter, BTSColors.MarketData.bid_brush);
add_hl_price_col(Columns.Bid, "Bid", nameof(Row.bid_price), nameof(Row.bid_price_click), bid_price_filter, BTSColors.header_text_brush, BTSColors.MarketData.bid_brush);
add_hl_price_col(Columns.Ask, "Ask", nameof(Row.ask_price), nameof(Row.ask_price_click), ask_price_filter, BTSColors.header_text_brush, BTSColors.MarketData.ask_brush);
add_hl_size_col(Columns.AskSize, size_col_header, nameof(Row.ask_size), nameof(Row.ask_size_click), ask_size_filter, BTSColors.MarketData.ask_brush);
add_hl_working_orders_col(Columns.WorkingAsks, working_col_header, nameof(Row.working_asks_text), nameof(Row.working_best_ask), nameof(Row.working_asks_click), working_ask_volume_filter, BTSColors.MarketData.ask_brush);
add_col(Columns.Settlement, "Settlement", r => r.format_price(r.settlement), nameof(Row.settlement), DefaultColumnWidths.Price, settlement_filter, DataGridFilterKnownTemplates.DoubleMinMax);
add_col(Columns.DayChange, "Change", r => r.format_price(r.day_change), nameof(Row.day_change), DefaultColumnWidths.Price, day_change_filter, DataGridFilterKnownTemplates.DoubleMinMax, true);
add_col(Columns.SessionLow, "Low", r => r.format_price(r.session_low), nameof(Row.session_low), DefaultColumnWidths.Price, session_low_filter, DataGridFilterKnownTemplates.DoubleMinMax);
add_col(Columns.SessionHigh, "High", r => r.format_price(r.session_high), nameof(Row.session_high), DefaultColumnWidths.Price, session_high_filter, DataGridFilterKnownTemplates.DoubleMinMax);
add_col(Columns.SecurityKey, "Security Key", r => r.security_key.ToString(), nameof(Row.security_key), DefaultColumnWidths.SecurityKey, security_key_filter, DataGridFilterKnownTemplates.Regex);
//
void add_col(Columns col_key, string header, Func<Row, string> get_text, string prop, double width, IDataGridColumnFilter filter, string filter_template, bool is_animatable = false) =>
columns.Add(new RenderTextColumn<Row, Columns>(col_key, get_text, filter, filter_template) {
Header = header,
sort_member_path = prop,
Width = width,
padding = is_animatable ? AnimatableCellPadding : DefaultCellPadding
});
void add_hl_price_col(Columns col_key, string header, string prop, string command_prop, IDataGridColumnFilter filter, Brush foreground, Brush background) =>
add_hl_col(col_key, header, price_binding(prop), prop, command_prop, filter, DataGridFilterKnownTemplates.DoubleMinMax, DefaultColumnWidths.Price, foreground, background, SelectionFill);
void add_hl_size_col(Columns col_key, string header, string prop, string command_prop, IDataGridColumnFilter filter, Brush foreground) =>
add_hl_col(col_key, header, new Binding(prop), prop, command_prop, filter, DataGridFilterKnownTemplates.UShortMinMax, DefaultColumnWidths.Size, foreground, null, null);
void add_hl_working_orders_col(Columns col_key, string header, string text_prop, string sort_prop, string command_prop, IDataGridColumnFilter filter, Brush foreground) =>
add_hl_col(col_key, header, new Binding(text_prop), sort_prop, command_prop, filter, DataGridFilterKnownTemplates.IntMinMax, working_orders_col_width, foreground, null, null);
void add_hl_col(
Columns col_key, string header, BindingBase binding, string prop, string command_prop,
IDataGridColumnFilter filter, string filter_template, double width, Brush foreground, Brush background, Brush background_overlay) =>
columns.Add(new HyperlinkElementColumn<Row, Columns>(
col_key, binding, new Binding(command_prop), filter, filter_template) {
Header = header,
sort_member_path = prop,
foreground = foreground,
background = background,
background_overlay = background_overlay,
Width = DefaultColumnWidths.Price
});
BindingBase price_binding(string prop) {
var mb = new MultiBinding { Converter = price_converter };
mb.Bindings.Add(new Binding(prop) { Mode = BindingMode.OneWay });
mb.Bindings.Add(new Binding($"{nameof(Row.security)}.{nameof(SecurityImmutable.ContractSpec)}") { Mode = BindingMode.OneWay });
return mb;
}
//
_resources.AddRange(
state.ObserveOnDispatcher().Subscribe(s => {
using (rows_view.DeferRefresh()) {
rows_view.SetSortingCriteria(s.sorting_criteria);
var filters = s.filters;
if (filters != null) {
security_filter.load_state(filters.security);
bid_price_filter.load_state(filters.bid_price);
bid_size_filter.load_state(filters.bid_size);
ask_price_filter.load_state(filters.ask_price);
ask_size_filter.load_state(filters.ask_size);
last_price_filter.load_state(filters.last_price);
last_size_filter.load_state(filters.last_size);
day_change_filter.load_state(filters.day_change);
settlement_filter.load_state(filters.settlement);
session_low_filter.load_state(filters.session_low);
session_high_filter.load_state(filters.session_high);
position_filter.load_state(filters.position);
working_bid_volume_filter.load_state(filters.working_bid_volume);
working_ask_volume_filter.load_state(filters.working_ask_volume);
volume_filter.load_state(filters.volume);
security_key_filter.load_state(filters.security_key);
}
}
}), DataGridFilterHelper.hook_filters(rows_view,
security_filter, bid_price_filter, bid_size_filter, ask_price_filter, ask_size_filter, last_price_filter, last_size_filter, day_change_filter, settlement_filter,
session_low_filter, session_high_filter, position_filter, working_bid_volume_filter, working_ask_volume_filter, volume_filter, security_key_filter),
WorkLoop.Start("MarketView", _refresh)
);
}
public ObservableCollection<ColumnBase> columns { get; } = new ObservableCollection<ColumnBase>();
#region Filters
public IDataGridColumnPersistentFilter<Row, string> security_filter { get; }
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> bid_price_filter { get; } = new DoubleMinMax<Row>(r => r.bid_price, nameof(Row.bid_price));
public IDataGridColumnPersistentFilter<Row, UShortMinMaxState> bid_size_filter { get; } = new UShortMinMax<Row>(r => r.bid_size, nameof(Row.bid_size));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> ask_price_filter { get; } = new DoubleMinMax<Row>(r => r.ask_price, nameof(Row.ask_price));
public IDataGridColumnPersistentFilter<Row, UShortMinMaxState> ask_size_filter { get; } = new UShortMinMax<Row>(r => r.ask_size, nameof(Row.ask_size));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> last_price_filter { get; } = new DoubleMinMax<Row>(r => r.last_price, nameof(Row.last_price));
public IDataGridColumnPersistentFilter<Row, UShortMinMaxState> last_size_filter { get; } = new UShortMinMax<Row>(r => r.last_size, nameof(Row.last_size));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> day_change_filter { get; } = new DoubleMinMax<Row>(r => r.day_change, nameof(Row.day_change));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> settlement_filter { get; } = new DoubleMinMax<Row>(r => r.settlement, nameof(Row.settlement));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> session_low_filter { get; } = new DoubleMinMax<Row>(r => r.session_low, nameof(Row.session_low));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> session_high_filter { get; } = new DoubleMinMax<Row>(r => r.session_high, nameof(Row.session_high));
public IDataGridColumnPersistentFilter<Row, IntMinMaxState> position_filter { get; } = new IntMinMax<Row>(r => r.position, nameof(Row.position));
public IDataGridColumnPersistentFilter<Row, IntMinMaxState> working_bid_volume_filter { get; } = new IntMinMax<Row>(r => r.working_bid_volume, nameof(Row.working_bid_volume));
public IDataGridColumnPersistentFilter<Row, IntMinMaxState> working_ask_volume_filter { get; } = new IntMinMax<Row>(r => r.working_ask_volume, nameof(Row.working_ask_volume));
public IDataGridColumnPersistentFilter<Row, ULongMinMaxState> volume_filter { get; } = new ULongMinMax<Row>(r => r.volume, nameof(Row.volume));
public IDataGridColumnPersistentFilter<Row, string> security_key_filter { get; } = new RegexFilterVM<Row>(r => r.security_key.ToString(), nameof(Row.security_key));
public FilterStates get_filter_states() {
return new FilterStates {
security = security_filter.get_state(),
bid_price = bid_price_filter.get_state(),
bid_size = bid_size_filter.get_state(),
ask_price = ask_price_filter.get_state(),
ask_size = ask_size_filter.get_state(),
last_price = last_price_filter.get_state(),
last_size = last_size_filter.get_state(),
day_change = day_change_filter.get_state(),
settlement = settlement_filter.get_state(),
session_low = session_low_filter.get_state(),
session_high = session_high_filter.get_state(),
position = position_filter.get_state(),
working_bid_volume = working_bid_volume_filter.get_state(),
working_ask_volume = working_ask_volume_filter.get_state(),
volume = volume_filter.get_state(),
security_key = security_key_filter.get_state()
};
}
#endregion
protected override Row row_factory(SecurityMD smd) => new Row(_bus, smd, _orders_model);
protected override void on_row_removed(Row row) => row.Dispose();
protected override IEnumerable<SortingCriteria> get_default_sorting() { yield return new SortingCriteria(nameof(Row.security), true); }
void _refresh() {
foreach (var r in _row_vms) r.refresh();
}
}
}
@@ -1,43 +0,0 @@
<UserControl
x:Class="mbts.ui.spark.MarketViewView"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:usp="clr-namespace:mbts.ui.spark"
FocusManager.IsFocusScope="True"
Background="{StaticResource CommonBackground}"
>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/view/Controls/DataGridEx/Filters/Views/FilterTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<AdornerDecorator>
<c:DIYGrid
x:Name="_grid"
Columns="{Binding columns}"
CurrentRow="{Binding current_row}"
Rows="{Binding rows_view}"
>
<c:DIYGrid.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/>
<KeyBinding Key="Return" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/>
</c:DIYGrid.InputBindings>
<c:DIYGrid.CommandBindings>
<CommandBinding
Command="{x:Static c:DIYGrid.DefaultRowCommand}"
Executed="{x:Static c:DIYGrid.DefaultRowActionExecuted}"
CanExecute="{x:Static c:DIYGrid.DefaultRowActionCanExecute}"
/>
</c:DIYGrid.CommandBindings>
<c:DIYGrid.RowTemplate>
<DataTemplate>
<usp:MarketViewRowView usp:GridAnimation.RowAnimation="{Binding animations}"/>
</DataTemplate>
</c:DIYGrid.RowTemplate>
</c:DIYGrid>
</AdornerDecorator>
</UserControl>
@@ -1,23 +0,0 @@
using mbts.spark;
using mbts.ui.controls;
using System.Linq;
using System.Windows.Controls;
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for MarketSheetsView.xaml
/// </summary>
partial class MarketViewView : UserControl {
public enum Columns { Security, Volume, Last, LastSize, Position, WorkingBids, Bid, BidSize, Ask, AskSize, WorkingAsks, Settlement, DayChange, SessionLow, SessionHigh, SecurityKey }
public MarketViewView() {
InitializeComponent();
AdornerHelper.attach_continuously_on_loaded(
() => new GridAnimation.DIYGridAnimationAdorner<Columns>(
_grid, _grid.descendants_of_type<DIYGridRowsPresenter>().First()),
_grid);
}
}
class MarketViewRowView : DIYGrid.HighPerformanceRow<MarketViewVM.Row, MarketViewView.Columns> { }
}
@@ -1,70 +0,0 @@
using bts.api;
using bts.shell;
using bts.spark;
using mbts.ui;
using mbts.ui.spark;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows;
namespace mbts.spark {
class MarketViewWindow : SparkWindow<MarketViewWindowFactory.StartupData>, ISharedWindow {
const string _window_type = "MarketView", _thread_id = "MarketView";
readonly OrdersModel _orders_model;
readonly AllowOnce _init_guard = new AllowOnce("MarketView");
MarketViewVM _vm;
MarketViewView _view;
MarketViewWindowFactory.StartupData _state;
IReadOnlyList<SparkCommand> _commands;
IDisposable _subscriptions;
public MarketViewWindow(MarketViewWindowFactory factory, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
: base("Market View", bus, factory, SparkCommands.ShowMarketView.icon) {
_orders_model = orders_model;
_state = state;
Icon.Freeze();
}
event Action<MarketViewWindowFactory.StartupData> _state_changed;
public override string window_type => _window_type;
public override UIElement Content => _view;
public override IEnumerable<SparkCommand> Commands => _commands;
public override MarketViewWindowFactory.StartupData SaveState => _state = new MarketViewWindowFactory.StartupData(_state.security_criteria, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states());
public override double MinWidth => 1035 + SPARK_MENU_COLLAPSED_WIDTH + LAUNCHER_BUTTON_BORDER_WIDTH;
public string thread_id => _thread_id;
public void thread_init() {
_init_guard.check_access();
Logger.notnull(_state);
var state_src = Observable.FromEvent<Action<MarketViewWindowFactory.StartupData>, MarketViewWindowFactory.StartupData>(cb => _state_changed += cb, cb => _state_changed -= cb).StartWith(_state);
_vm = new MarketViewVM(_bus, _orders_model, state_src);
_view = new MarketViewView { DataContext = _vm };
var update_securities_tag = new SparkTags.SparkTag<SecurityCriteria>("MarketView Callback");
var update_securities_cmd = SparkCommand.create("Update Market View", Icon, update_securities_tag);
_commands = new List<SparkCommand> {
SparkCommand.create("Change Securities", Icons.Admin, SparkTags.ShowAndEditPickMultiple, () => (update_securities_cmd, _state.security_criteria)),
SparkCommands.ShowLadders.complete(_vm.selected_security_mds_observable(), smds => smds.Count > 0),
SparkCommands.ShowOrderTicketFromSecurity.complete(_vm.current_security_md, md => md.HasValue, ObjectHelper.ValueOrDefault),
SparkCommands.ShowFills.complete(_vm.selected_securities_observable(), _ => true,
secs => new FillsWindowFactory.StartupData(new FillsWindowFactory.FilterStates {
security = secs.Count > 0 ? new SecurityCriteria(secs) : _state.security_criteria
})
),
SparkCommands.ShowTimeAndSales.complete(_vm.selected_securities_observable(), _ => true, secs => secs.Count > 0 ? new SecurityCriteria(secs) : _state.security_criteria),
SparkCommands.ShowSyntheticCreate.complete(_vm.selected_securities_observable(), secs => secs.Count > 0 && secs.Count < 3, secs => new SecurityCriteria(secs))
};
_subscriptions = _bus.subscribe(update_securities_tag).ObserveOnDispatcher().Subscribe(c =>
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states())));
}
public override void Dispose() {
Disposable.dispose(ref _subscriptions);
_vm.Dispose();
Commands.OfType<IDisposable>().DisposeAll();
}
}
}
@@ -1,89 +0,0 @@
using bts.api;
using mbts.spark;
using mbts.spark.filters;
using mbts.ui;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace bts.shell {
class MarketViewWindowFactory : ShellWindowFactory<MarketViewWindowFactory.StartupData> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
public MarketViewWindowFactory(MarketShellModule module, IBus bus, OrdersModel orders_model) : base(module, "MarketView") {
_bus = bus;
_orders_model = orders_model;
_dispose = bus.subscribe(SparkTags.ShowMarketViewTag).ObserveOnDispatcher().Subscribe(_show);
}
public override Task<IShellWindow> load(StartupData state) =>
Task.FromResult(_create(state));
void _show(SecurityCriteria criteria) =>
_bus.post(SparkTags.ShowWindow, _create(new StartupData(criteria, new List<SortingCriteria> { new SortingCriteria(nameof(MarketViewVM.Row.security), true) }, null)));
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _bus, _orders_model, state);
[ProtoContract]
public class StartupData {
public const int Version = 1;
[ProtoMember(1)]
public readonly SecurityCriteria security_criteria;
[ProtoMember(2)]
public readonly List<SortingCriteria> sorting_criteria;
[ProtoMember(3)]
public readonly FilterStates filters;
StartupData() { }
public StartupData(SecurityCriteria security_criteria)
: this (security_criteria, new List<SortingCriteria>(), null) { }
public StartupData(SecurityCriteria security_criteria, List<SortingCriteria> sorting_criteria, FilterStates filters) {
this.security_criteria = security_criteria;
this.sorting_criteria = sorting_criteria;
this.filters = filters;
}
}
[ProtoContract]
public class FilterStates {
[ProtoMember(1)]
public string security;
[ProtoMember(2)]
public DoubleMinMaxState bid_price;
[ProtoMember(3)]
public UShortMinMaxState bid_size;
[ProtoMember(4)]
public DoubleMinMaxState ask_price;
[ProtoMember(5)]
public UShortMinMaxState ask_size;
[ProtoMember(6)]
public DoubleMinMaxState last_price;
[ProtoMember(7)]
public UShortMinMaxState last_size;
[ProtoMember(8)]
public DoubleMinMaxState day_change;
[ProtoMember(9)]
public DoubleMinMaxState settlement;
[ProtoMember(10)]
public DoubleMinMaxState session_low;
[ProtoMember(11)]
public DoubleMinMaxState session_high;
[ProtoMember(12)]
public IntMinMaxState position;
[ProtoMember(13)]
public IntMinMaxState working_bid_volume;
[ProtoMember(14)]
public IntMinMaxState working_ask_volume;
[ProtoMember(15)]
public ULongMinMaxState volume;
[ProtoMember(16)]
public string security_key;
}
}
}
@@ -1,99 +0,0 @@
using bts.api;
using bts.co2;
using mbts.co2;
using mbts.collections.extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
namespace mbts.spark {
struct TradeInfo {
public readonly SecurityImmutable security;
public readonly TradeMessageImmutable trade;
public TradeInfo(SecurityImmutable security, TradeMessageImmutable trade) {
this.security = security;
this.trade = trade;
}
}
class TimeAndSalesModel {
static readonly TimeSpan _poll_interval = TimeSpan.FromSeconds(0.4);
public TimeAndSalesModel(IBus bus, MDConsumer consumer, SecurityCriteria security_criteria) {
trades = security_criteria.subscribe_md_map(bus)
.Scan(new Dictionary<ChannelKey, ChannelConsumer>(),
(cache, md_map) => {
var copy = new Dictionary<ChannelKey, ChannelConsumer>(cache);
copy.sync_with_demux(md_map, get_channel_key, get_channel_consumer, update_channel_consumer);
return copy;
}
).Select(cache =>
Observable.Interval(_poll_interval)
.Select(_ => new List<TradeInfo>(cache.Values.SelectMany(c => c.read_trades())))
).SelectMany(_ => _);
ChannelKey get_channel_key(KeyValuePair<uint, SecurityMD> md_kv) =>
new ChannelKey(md_kv.Value.security.Symbol, md_kv.Value.security.security_type(), md_kv.Value.security.Exchange);
ChannelConsumer get_channel_consumer(IGrouping<ChannelKey, KeyValuePair<uint, SecurityMD>> channel_sec_group) {
var key = channel_sec_group.Key;
var rv = new ChannelConsumer(consumer.get_channel(key.symbol, key.type, key.exchange));
rv.set_securities(channel_sec_group);
return rv;
}
void update_channel_consumer(KeyValuePair<ChannelKey, ChannelConsumer> channel_kv, IEnumerable<KeyValuePair<uint, SecurityMD>> security_kvs) =>
channel_kv.Value.set_securities(security_kvs);
}
public IObservable<IReadOnlyList<TradeInfo>> trades { get; }
private class ChannelKey : IEquatable<ChannelKey> {
public readonly string symbol;
public readonly SecurityType type;
public readonly Venue exchange;
public ChannelKey(string symbol, SecurityType type, Venue exchange) {
this.symbol = symbol;
this.type = type;
this.exchange = exchange;
}
public bool Equals(ChannelKey other) =>
other != null &&
other.symbol == symbol &&
other.type == type &&
other.exchange == exchange;
public override bool Equals(object obj) =>
Equals(obj as ChannelKey);
public override int GetHashCode() =>
symbol.GetHashCode() ^
type.GetHashCode() ^
exchange.GetHashCode();
}
private class ChannelConsumer {
readonly MDConsumerChannel _channel;
Dictionary<uint, SecurityImmutable> _securities = new Dictionary<uint, SecurityImmutable>();
long _cursor = 0;
public ChannelConsumer(MDConsumerChannel channel) =>
_channel = channel;
public void set_securities(IEnumerable<KeyValuePair<uint, SecurityMD>> securities) =>
_securities = securities.ToDictionary(kv => kv.Key, kv => kv.Value.security);
public IEnumerable<TradeInfo> read_trades() {
var copy = _securities;
foreach (var tm in _channel.read_trades(ref _cursor)) {
if (copy.TryGetValue(tm.Key, out SecurityImmutable sec))
yield return new TradeInfo(sec, tm);
}
}
}
}
}
@@ -1,136 +0,0 @@
using bts.api;
using bts.co2;
using mbts.spark.filters;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.spark;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;
using static bts.shell.TimeAndSalesWindowFactory;
namespace mbts.spark {
class TimeAndSalesVM : SecurityGrid<TimeAndSalesVM.Row, TradeInfo> {
readonly IBus _bus;
public TimeAndSalesVM(IBus bus, TimeAndSalesModel model, IReadOnlyCollection<SortingCriteria> sorting_criteria, FilterStates filters)
: base(RXCollection.CreateBuffer(model.trades, 1000), sorting_criteria) {
_bus = bus;
show_ladder = DelegateCommandParamObserver.Create(current_row_observable, r => _show_ladder_async(r).ignore(), r => r != null);
security_filter = new RegexFilterVM<Row>(r => r.security.ToString(), nameof(Row.security));
if (filters != null) {
time_filter.load_state(filters.time);
security_filter.load_state(filters.security);
price_filter.load_state(filters.price);
size_filter.load_state(filters.size);
trade_key_filter.load_state(filters.trade_key);
security_key_filter.load_state(filters.security_key);
}
// Columns
add_column(TimeAndSalesView.Columns.Security, "Security", DIYGrid.DefaultColumnWidths.Security, security_filter, DataGridFilterKnownTemplates.Regex);
add_column(TimeAndSalesView.Columns.Time, "Time", DIYGrid.DefaultColumnWidths.Time, time_filter, DataGridFilterKnownTemplates.TimeFilter);
add_column(TimeAndSalesView.Columns.Price, "Price", DIYGrid.DefaultColumnWidths.Price, price_filter, DataGridFilterKnownTemplates.DoubleMinMax);
add_column(TimeAndSalesView.Columns.Size, "Size", DIYGrid.DefaultColumnWidths.Size, size_filter, DataGridFilterKnownTemplates.UIntMinMax);
add_column(TimeAndSalesView.Columns.TradeKey, "Trade Key", DIYGrid.DefaultColumnWidths.TradeKey, trade_key_filter, DataGridFilterKnownTemplates.Regex);
add_column(TimeAndSalesView.Columns.SecurityKey, "Security Key", DIYGrid.DefaultColumnWidths.SecurityKey, security_key_filter, DataGridFilterKnownTemplates.Regex);
void add_column(TimeAndSalesView.Columns col_key, string header, double width, IDataGridColumnFilter filter, string filter_template) =>
columns.Add(new DIYGrid.RenderTextColumn<Row>(r => r[col_key], filter, filter_template) { Header = header, Width = width });
//
_resources.AddRange(
show_ladder,
DataGridFilterHelper.hook_filters(
rows_view, time_filter, security_filter, price_filter, size_filter, trade_key_filter, security_key_filter
)
);
}
public ObservableCollection<DIYGrid.ColumnBase> columns { get; } = new ObservableCollection<DIYGrid.ColumnBase>();
public DelegateCommandParamObserver<Row> show_ladder { get; }
#region Filters
public IDataGridColumnPersistentFilter<Row, TimeFilterTuple> time_filter { get; } = new TimeFilterVM<Row>(r => r.time, nameof(Row.time));
public IDataGridColumnPersistentFilter<Row, string> security_filter { get; }
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> price_filter { get; } = new DoubleMinMax<Row>(r => r.price, nameof(Row.price));
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> size_filter { get; } = new UIntMinMax<Row>(r => r.size, nameof(Row.size));
public IDataGridColumnPersistentFilter<Row, string> security_key_filter { get; } = new RegexFilterVM<Row>(r => r.security_key.ToString(), nameof(Row.security_key));
public IDataGridColumnPersistentFilter<Row, string> trade_key_filter { get; } = new RegexFilterVM<Row>(r => r.trade_key.ToString(), nameof(Row.trade_key));
public FilterStates get_filter_states() =>
new FilterStates {
time = time_filter.get_state(),
security = security_filter.get_state(),
price = price_filter.get_state(),
size = size_filter.get_state(),
trade_key = trade_key_filter.get_state(),
security_key = security_key_filter.get_state()
};
#endregion
protected override IEnumerable<SortingCriteria> get_default_sorting() {
yield return new SortingCriteria(nameof(Row.time), false);
}
protected override Row row_factory(TradeInfo row_model) =>
new Row(this, row_model.security, row_model.trade);
async Task _show_ladder_async(Row row) {
var smd_lookup = await SparkUtils.get_security_md_async(_bus, row.security.Id);
if (smd_lookup.success) _bus.post(SparkTags.ShowLadderTag, smd_lookup.result);
}
public class Row : SecurityRow, DIYGrid.IRowVM {
readonly uint _trade_key;
readonly string
_security_text,
_time_text,
_price_text,
_size_text,
_trade_key_text,
_security_key_text;
public Row(TimeAndSalesVM parent, SecurityImmutable security, TradeMessageImmutable trade) : base(security) {
_trade_key = trade.Key;
time = trade.Time.lldatetime();
price = trade.Mantissa * Math.Pow(10, trade.Exponent);
size = trade.Size;
show_ladder = new DelegateCommand(() => parent._show_ladder_async(this).ignore());
_security_text = security.ToString();
_time_text = time.ToString("M/d h:mm:ss tt");
_price_text = security.ContractSpec.format(price);
_size_text = size.ToString();
_trade_key_text = _trade_key.ToString();
_security_key_text = security_key.ToString();
}
public event Action invalidated;
public uint trade_key => _trade_key;
public DateTime time { get; }
public double price { get; }
public uint size { get; }
public ICommand show_ladder { get; }
public string this[TimeAndSalesView.Columns col] {
get {
switch (col) {
case TimeAndSalesView.Columns.Security: return _security_text;
case TimeAndSalesView.Columns.Time: return _time_text;
case TimeAndSalesView.Columns.Price: return _price_text;
case TimeAndSalesView.Columns.Size: return _size_text;
case TimeAndSalesView.Columns.TradeKey: return _trade_key_text;
case TimeAndSalesView.Columns.SecurityKey: return _security_key_text;
default: return null;
}
}
}
void _invalidate() =>
invalidated?.Invoke();
}
}
}
@@ -1,41 +0,0 @@
<UserControl
x:Class="mbts.ui.spark.TimeAndSalesView"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:usp="clr-namespace:mbts.ui.spark"
FocusManager.IsFocusScope="True"
Background="{StaticResource CommonBackground}"
>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/view/Resources/Converters.xaml"/>
<ResourceDictionary Source="/view/Controls/DataGridEx/Filters/Views/FilterTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<AdornerDecorator>
<Grid>
<c:DIYGrid Columns="{Binding columns}" Rows="{Binding rows_view}" CurrentRow="{Binding current_row}">
<c:DIYGrid.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/>
<KeyBinding Key="Return" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/>
</c:DIYGrid.InputBindings>
<c:DIYGrid.CommandBindings>
<CommandBinding
Command="{x:Static c:DIYGrid.DefaultRowCommand}"
Executed="{x:Static c:DIYGrid.DefaultRowActionExecuted}"
CanExecute="{x:Static c:DIYGrid.DefaultRowActionCanExecute}"
/>
</c:DIYGrid.CommandBindings>
<c:DIYGrid.RowTemplate>
<DataTemplate>
<usp:TimeAndSalesRowView/>
</DataTemplate>
</c:DIYGrid.RowTemplate>
</c:DIYGrid>
</Grid>
</AdornerDecorator>
</UserControl>
@@ -1,17 +0,0 @@
using mbts.spark;
using mbts.ui.controls;
using System.Windows.Controls;
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for TimeAndSalesView.xaml
/// </summary>
partial class TimeAndSalesView : UserControl {
public enum Columns { Time, Security, Price, Size, OrderType, TradeKey, SecurityKey }
public TimeAndSalesView() =>
InitializeComponent();
}
class TimeAndSalesRowView : DIYGrid.HighPerformanceRow<TimeAndSalesVM.Row, TimeAndSalesView.Columns> { }
}
@@ -1,90 +0,0 @@
using bts.api;
using bts.shell;
using bts.spark;
using mbts.co2;
using mbts.ui;
using mbts.ui.spark;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Media;
using static bts.shell.TimeAndSalesWindowFactory;
namespace mbts.spark {
class TimeAndSalesWindow : SparkWindow<StartupData>, ISlowWindow {
const string _window_type = "TimeAndSales";
readonly MDConsumer _consumer;
readonly TimeAndSalesWindowFactory _factory;
SingleValuePump<TimeAndSalesVM> _vm;
StartupData _state;
TimeAndSalesView _view;
SparkCommand[] _commands;
IDisposable _subscriptions;
public TimeAndSalesWindow(TimeAndSalesWindowFactory factory, IBus bus, MDConsumer consumer, StartupData state, ImageSource icon)
: base("Time And Sales", bus, factory, SparkCommands.ShowTimeAndSales.icon) {
Logger.assert(state != null);
_consumer = consumer;
_factory = factory;
_state = state;
Icon.Freeze();
}
public override string window_type => _window_type;
public override IEnumerable<SparkCommand> Commands => _commands;
public override UIElement Content => _view;
public override double MinWidth => 444 + SPARK_MENU_COLLAPSED_WIDTH + LAUNCHER_BUTTON_BORDER_WIDTH;
public override StartupData SaveState => _state = new StartupData(_state.security_criteria, _vm.value.rows_view.GetSortingCriteria(), _vm.value.get_filter_states());
public override void Dispose() =>
_dispose_resources();
public void thread_init() {
_dispose_resources();
_vm = new SingleValuePump<TimeAndSalesVM>();
var update_securities_tag = new SparkTags.SparkTag<SecurityCriteria>("TimeAndSales Callback");
var update_securities_cmd = SparkCommand.create("Update Time and Sales", Icon, update_securities_tag);
var current_smd_source = _vm.observable.SelectMany(vm => vm.current_security_md_observable(_bus)).ObserveOnDispatcher();
var selected_secs_source = _vm.observable.SelectMany(vm => vm.selected_securities_observable()).ObserveOnDispatcher();
_commands = new SparkCommand[] {
SparkCommand.create("Change Securities", Icons.Admin, SparkTags.ShowAndEditPickMultiple, () => (update_securities_cmd, _state.security_criteria)),
SparkCommands.ShowLadder.complete(current_smd_source, md => md.HasValue, ObjectHelper.ValueOrDefault),
SparkCommands.ShowOrderTicketFromSecurity.complete(current_smd_source, md => md.HasValue, ObjectHelper.ValueOrDefault),
SparkCommands.ShowFills.complete(selected_secs_source, always_true, get_fills_startup_data),
SparkCommands.ShowMarketView.complete(selected_secs_source, always_true, secs => secs.Count > 0 ? new SecurityCriteria(secs) : _state.security_criteria)
};
_subscriptions = _bus.subscribe(update_securities_tag).ObserveOnDispatcher().Subscribe(update_criteria);
_initialize();
bool always_true<T>(T _) => true;
FillsWindowFactory.StartupData get_fills_startup_data(IReadOnlyList<SecurityImmutable> secs) =>
new FillsWindowFactory.StartupData(new FillsWindowFactory.FilterStates {
security = secs.Count > 0 ? new SecurityCriteria(secs) : _state.security_criteria
});
void update_criteria(SecurityCriteria c) {
_state = new StartupData(c, _vm.value.rows_view.GetSortingCriteria(), _vm.value.get_filter_states());
_initialize();
}
}
void _dispose_resources() {
Disposable.dispose(ref _subscriptions);
Disposable.dispose(ref _vm);
if (_commands != null) {
_commands.OfType<IDisposable>().DisposeAll();
_commands = null;
}
}
void _initialize() {
var model = new TimeAndSalesModel(_bus, _consumer, _state.security_criteria);
_vm.value = new TimeAndSalesVM(_bus, model, _state.sorting_criteria, _state.filters);
if (_view == null)
_view = new TimeAndSalesView();
_view.DataContext = _vm.value;
}
}
}
@@ -1,75 +0,0 @@
using bts.api;
using bts.spark;
using mbts;
using mbts.co2;
using mbts.spark;
using mbts.spark.filters;
using mbts.ui;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace bts.shell {
class TimeAndSalesWindowFactory : ShellWindowFactory<TimeAndSalesWindowFactory.StartupData> {
readonly IBus _bus;
readonly MDConsumer _consumer;
IReadOnlyDictionary<uint, SecurityMD> _securities = new Dictionary<uint, SecurityMD>();
public TimeAndSalesWindowFactory(IShellModule module, IBus bus, MDConsumer consumer) : base(module, "TimeAndSales") {
_bus = bus;
_consumer = consumer;
_dispose = Disposable.Create(
bus.subscribe(SparkTags.SecuritiesTag).Subscribe(s => _securities = s),
bus.subscribe(SparkTags.ShowTimeAndSalesTag).ObserveOnDispatcher().Subscribe(show)
);
}
public override Task<IShellWindow> load(StartupData state) =>
Task.FromResult<IShellWindow>(new TimeAndSalesWindow(this, _bus, _consumer, state, SparkCommands.PickTimeAndSales.icon));
public async void show(SecurityCriteria criteria) {
var w = await load(new StartupData(criteria));
_bus.post(SparkTags.ShowWindow, w);
}
[ProtoContract]
public class StartupData {
[ProtoMember(1)]
public readonly SecurityCriteria security_criteria;
[ProtoMember(2)]
public readonly List<SortingCriteria> sorting_criteria;
[ProtoMember(3)]
public FilterStates filters;
StartupData() { }//for ptorobuf
public StartupData(SecurityCriteria security_criteria)
: this (security_criteria, new List<SortingCriteria>(), null) { }
public StartupData(SecurityCriteria security_criteria, List<SortingCriteria> sorting_criteria, FilterStates filters) {
this.security_criteria = security_criteria;
this.sorting_criteria = sorting_criteria;
this.filters = filters;
}
}
[ProtoContract]
public class FilterStates {
[ProtoMember(1)]
public TimeFilterTuple time;
[ProtoMember(2)]
public string security;
[ProtoMember(3)]
public DoubleMinMaxState price;
[ProtoMember(4)]
public UIntMinMaxState size;
[ProtoMember(5)]
public string trade_key;
[ProtoMember(6)]
public string security_key;
}
}
}
@@ -1,58 +0,0 @@
using mbts;
using mbts.ui;
using mbts.ui.shell;
using mbts.spark;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using bts.spark;
using System.IO;
using System.Windows.Media;
using bts.api;
using System.ComponentModel.Composition;
namespace bts.ui {
[Export(typeof(IShellModule))]
class SettingsShellModule : IShellModule {
readonly IBus _bus;
IDisposable _dispose;
WorkspacesModel ws_model;
[ImportingConstructor]
public SettingsShellModule(IBus bus, WorkspacesModel ws) {
// todo: settings dialog
ws_model = ws;
_dispose = bus.subscribe(SparkTags.ShowWorkspaces).Subscribe(_ => show_workspaces_dialog());
_bus = bus;
}
public ImageSource icon => Icons.Admin;
public string name => "Settings";
public int priority => 40;
public IEnumerable<SparkCommand> actions => new []{
SparkCommands.ShowWorkspaces
//SparkCommands.ShowSettings
};
public Task<IShellWindow> create(Stream load_stream) {
throw new NotImplementedException();
}
public void show_workspaces_dialog()
{
WorkspacesDialogView ws_dialog = new WorkspacesDialogView(ws_model);
ws_dialog.Show();
}
public void Dispose() {
Disposable.dispose(ref _dispose);
}
}
}
@@ -1,436 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sp="clr-namespace:bts.spark;assembly=spark_api"
xmlns:msp="clr-namespace:mbts.spark"
xmlns:u="clr-namespace:mbts.ui"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:cv="clr-namespace:mbts.ui.converters"
xmlns:usp="clr-namespace:mbts.ui.spark"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/view/Resources/Converters.xaml"/>
<ResourceDictionary Source="/view/Resources/ComboBoxes.xaml"/>
<ResourceDictionary Source="/view/Resources/DataGrid.xaml"/>
<ResourceDictionary Source="/view/Resources/DataTemplates.xaml"/>
<ResourceDictionary Source="/view/Controls/Popup/PopupControl.xaml"/>
<ResourceDictionary Source="/Modules/Spreader/ParameterSectionView.xaml"/>
</ResourceDictionary.MergedDictionaries>
<sys:Double x:Key="GroupLevelIndent">18</sys:Double>
<sys:Double x:Key="RowHeaderWidth">285</sys:Double>
<sys:Double x:Key="RowHeight">16</sys:Double>
<sys:Double x:Key="NegativeRowHeight">-16</sys:Double>
<sys:Double x:Key="ItemsHostCanBeDisabledCollapsedHeight">15</sys:Double>
<Thickness
x:Key="GroupLevelMargin"
Left="{StaticResource GroupLevelIndent}"
/>
<Thickness
x:Key="GroupContentAlignedWithHeaderMargin"
Left="{StaticResource GroupLevelIndent}"
Top="{StaticResource NegativeRowHeight}"
/>
<cv:SyntheticPriceCalcDisplayTextConverter x:Key="SyntheticPriceCalcDisplayConverter"/>
<cv:TickFactorsTextConverter x:Key="TickFactorsTextConverter"/>
<usp:RowHeaderGroupIndentConverter
x:Key="RowHeaderGroupIndentConverter"
Indent="{StaticResource GroupLevelIndent}"
/>
<usp:RowHeaderGroupIndentConverter
x:Key="ReverseRowHeaderGroupIndentConverter"
Indent="{StaticResource GroupLevelIndent}"
Reverse="True"
/>
<usp:RowGroupExpanderWidthConverter
x:Key="RowGroupExpanderWidthConverter"
Indent="{StaticResource GroupLevelIndent}"
Offset="{StaticResource RowHeight}"
RowHeaderWidth="{StaticResource RowHeaderWidth}"
/>
<usp:DataGridParameterCellTemplateConverter x:Key="ParameterCellTemplateConverter">
<usp:DataGridParameterCellTemplateConverter.BooleanTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Left" IsChecked="{Binding value}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.BooleanTemplate>
<usp:DataGridParameterCellTemplateConverter.DoubleTemplate>
<DataTemplate>
<TextBlock Text="{Binding value}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.DoubleTemplate>
<usp:DataGridParameterCellTemplateConverter.IntTemplate>
<DataTemplate>
<TextBlock Text="{Binding value}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.IntTemplate>
<usp:DataGridParameterCellTemplateConverter.UIntTemplate>
<DataTemplate>
<TextBlock Text="{Binding value}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.UIntTemplate>
<usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="AbsoluteLabel" Text="{x:Static cv:QuantityMeasureCaseDisplayTextConverter.ABSOLUTE_TEXT}" FontSize="10" FontStyle="Italic"/>
<TextBlock x:Name="RatioLabel" Text="{x:Static cv:QuantityMeasureCaseDisplayTextConverter.RATIO_TEXT}" FontSize="10" FontStyle="Italic"/>
<TextBlock x:Name="AbsoluteValue" Grid.Column="1" HorizontalAlignment="Left" Text="{Binding absolute}"/>
<TextBlock x:Name="RatioValue" Grid.Column="1" HorizontalAlignment="Left" Text="{Binding ratio}"/>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding quantity_case}" Value="{u:Enum absolute, Type={u:Nested sp:QuantityMeasure.QuantityOneofCase}}">
<Setter Property="Visibility" TargetName="AbsoluteLabel" Value="Visible"/>
<Setter Property="Visibility" TargetName="AbsoluteValue" Value="Visible"/>
<Setter Property="Visibility" TargetName="RatioLabel" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="RatioValue" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding quantity_case}" Value="{u:Enum Ratio, Type={u:Nested sp:QuantityMeasure.QuantityOneofCase}}">
<Setter Property="Visibility" TargetName="RatioLabel" Value="Visible"/>
<Setter Property="Visibility" TargetName="RatioValue" Value="Visible"/>
<Setter Property="Visibility" TargetName="AbsoluteLabel" Value="Collapsed"/>
<Setter Property="Visibility" TargetName="AbsoluteValue" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
</usp:DataGridParameterCellTemplateConverter>
<usp:DataGridParameterCellTemplateConverter x:Key="ParameterCellEditingTemplateConverter">
<usp:DataGridParameterCellTemplateConverter.BooleanTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Left" IsChecked="{Binding value}" IsEnabled="{Binding enabled}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.BooleanTemplate>
<usp:DataGridParameterCellTemplateConverter.DoubleTemplate>
<DataTemplate>
<c:TickUpDownDouble Value="{Binding value}" IsEnabled="{Binding enabled}" Increment="{Binding tick_increment, FallbackValue={u:Double 1}}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.DoubleTemplate>
<usp:DataGridParameterCellTemplateConverter.IntTemplate>
<DataTemplate>
<c:TickUpDownInt Value="{Binding value}" IsEnabled="{Binding enabled}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.IntTemplate>
<usp:DataGridParameterCellTemplateConverter.UIntTemplate>
<DataTemplate>
<c:TickUpDownUInt Value="{Binding value}" IsEnabled="{Binding enabled}"/>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.UIntTemplate>
<usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
<DataTemplate>
<Grid IsEnabled="{Binding enabled}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<ComboBox
VerticalAlignment="Center" Margin="-2,0,0,0" Padding="3,3,0,3"
ItemsSource="{u:EnumBindingSource {u:Nested sp:QuantityMeasure.QuantityOneofCase}, Except=None}"
SelectedItem="{Binding quantity_case}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource QuantityMeasureCaseDisplayConverter}}" FontSize="10" FontStyle="Italic"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<c:TickUpDownDouble x:Name="AbsoluteTickUpDown" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,0,-2,0" Value="{Binding absolute}"/>
<c:TickUpDownDouble x:Name="RatioTickUpDown" Grid.Column="1" HorizontalAlignment="Stretch" Value="{Binding ratio}"/>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding quantity_case}" Value="{u:Enum absolute, Type={u:Nested sp:QuantityMeasure.QuantityOneofCase}}">
<Setter Property="Visibility" TargetName="AbsoluteTickUpDown" Value="Visible"/>
<Setter Property="Visibility" TargetName="RatioTickUpDown" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding quantity_case}" Value="{u:Enum Ratio, Type={u:Nested sp:QuantityMeasure.QuantityOneofCase}}">
<Setter Property="Visibility" TargetName="RatioTickUpDown" Value="Visible"/>
<Setter Property="Visibility" TargetName="AbsoluteTickUpDown" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
</usp:DataGridParameterCellTemplateConverter>
<Style x:Key="ExpanderToggleButton" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="12" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Path
x:Name="arrow"
Data="M0,0L3.5,3.5 0,7"
HorizontalAlignment="Center"
Margin="0,5,0,0"
SnapsToDevicePixels="False"
Stroke="#77333333"
StrokeThickness="2"
VerticalAlignment="Top"
/>
<ContentPresenter
Grid.Column="1"
ContentSource="{TemplateBinding Content}"
Margin="3,0,0,0"
/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="arrow" Value="M0,0L3.5,3.5 7,0"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="GroupItemTemplate" TargetType="GroupItem">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton
x:Name="ExpanderToggle"
HorizontalAlignment="Left"
IsChecked="True"
Style="{StaticResource ExpanderToggleButton}"
Width="{Binding Name.level, Converter={StaticResource RowGroupExpanderWidthConverter}}"
Panel.ZIndex="1"
>
<usp:ParameterSectionView SectionTitle="{Binding Name.name}" Description="{Binding Name.description}"/>
</ToggleButton>
<ItemsPresenter x:Name="ItemsHost" Grid.Row="1" Margin="{StaticResource GroupLevelMargin}"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Name}" Value="{x:Null}">
<Setter Property="Visibility" TargetName="ExpanderToggle" Value="Collapsed"/>
<Setter Property="Margin" TargetName="ItemsHost" Value="0"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name.can_be_disabled}" Value="{u:True}">
<Setter Property="Margin" TargetName="ItemsHost" Value="{StaticResource GroupContentAlignedWithHeaderMargin}"/>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsChecked, ElementName=ExpanderToggle}" Value="False"/>
<Condition Binding="{Binding Name.can_be_disabled}" Value="{u:True}"/>
</MultiDataTrigger.Conditions>
<Setter Property="Height" TargetName="ItemsHost" Value="{StaticResource ItemsHostCanBeDisabledCollapsedHeight}"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsChecked, ElementName=ExpanderToggle}" Value="False"/>
<Condition Binding="{Binding Name.can_be_disabled}" Value="{u:False}"/>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="GroupItemStyle" TargetType="GroupItem">
<Setter Property="Template" Value="{StaticResource GroupItemTemplate}"/>
</Style>
<ControlTemplate x:Key="DataGridRowTemplate" TargetType="DataGridRow">
<Border
x:Name="DGR_Border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"
>
<SelectiveScrollingGrid Margin="{Binding section_count, Converter={StaticResource ReverseRowHeaderGroupIndentConverter}}">
<SelectiveScrollingGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</SelectiveScrollingGrid.ColumnDefinitions>
<DataGridRowHeader
Background="Transparent"
Padding="{Binding section_count, Converter={StaticResource RowHeaderGroupIndentConverter}}"
Content="{Binding display_name}"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
Visibility="{Binding
HeadersVisibility,
ConverterParameter={x:Static DataGridHeadersVisibility.Row},
Converter={x:Static DataGrid.HeadersVisibilityConverter},
RelativeSource={RelativeSource AncestorType=DataGrid}}"
/>
<DataGridCellsPresenter Grid.Column="1" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</SelectiveScrollingGrid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="usp:ExecutionStrategyEditor.RowHasErrors" Value="True">
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="DataGridRowStyle" TargetType="DataGridRow">
<Setter Property="BorderThickness" Value="1,0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template" Value="{StaticResource DataGridRowTemplate}"/>
<Setter Property="usp:ExecutionStrategyEditor.RowHasErrors" Value="{Binding has_errors}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding read_only}" Value="True">
<Setter Property="TextElement.Foreground" Value="{u:BTSColor UI.input_disabled_text_dark}"/>
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Foreground="Black" Text="{Binding display_name, StringFormat='{}Can\&apos;t change \&apos;{0}\&apos; after creation'}"/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding display_name}" Value="{x:Static sys:String.Empty}">
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
</Style.Triggers>
</Style>
<DataGridTextColumn x:Key="AddColumnPlaceholder" x:Shared="False" IsReadOnly="True">
<DataGridTextColumn.Header>
<c:PopupControl
ShowExpanderArrow="False" PopupPlacement="Right" Header="Add Leg" Padding="6,0"
Background="{StaticResource Button.Static.BackgroundBrush}"
IsOpen="{Binding IsNewLegPopupOpen, RelativeSource={RelativeSource AncestorType=usp:ExecutionStrategyEditor}, Mode=TwoWay}"
IsEnabled="{Binding CanUserAddNewLeg, RelativeSource={RelativeSource AncestorType=usp:ExecutionStrategyEditor}}"
>
<msp:ContractPickerView
CloseOnOK="False" CloseOnCancel="False"
DataContext="{Binding ContractPickerModel, RelativeSource={RelativeSource AncestorType=usp:ExecutionStrategyEditor}}"
/>
</c:PopupControl>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataTemplate x:Key="RemovableColumnHeaderTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button
Command="{Binding RemoveLegCommand, RelativeSource={RelativeSource AncestorType=usp:ExecutionStrategyEditor}}"
CommandParameter="{Binding}" Style="{StaticResource RoundCloseButton}"
/>
<TextBlock Grid.Column="1" Margin="4,0,0,0" Text="{Binding Converter={StaticResource SecurityTextConverter}}"/>
</Grid>
</DataTemplate>
<ControlTemplate x:Key="ExecutionStrategyEditorTemplate" TargetType="usp:ExecutionStrategyEditor">
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Padding="{TemplateBinding Padding}"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" IsEnabled="{TemplateBinding IsNew}">Name</TextBlock>
<TextBox
x:Name="PART_Name_TextBox" Grid.Column="1" Margin="6,0,0,0" HorizontalAlignment="Stretch" IsEnabled="{TemplateBinding IsNew}"
Text="{Binding SyntheticName, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, ValidatesOnDataErrors=True, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"
>
<u:Behavior.BindingUpdateGroups>
<u:BindingUpdateGroupCollection>
<u:BindingUpdateGroup Source="{Binding DataContext, Source={u:DirectReference PART_Name_TextBox}}" Target="{Binding Source={u:DirectReference PART_Name_TextBox}}">
<u:PropertyTuple PropertyName="Text" Type="{x:Type TextBox}"/>
</u:BindingUpdateGroup>
</u:BindingUpdateGroupCollection>
</u:Behavior.BindingUpdateGroups>
</TextBox>
<TextBlock
Grid.Column="2" VerticalAlignment="Center" Margin="6,0,0,0" Text="Ticks" IsEnabled="{TemplateBinding IsNew}"
Visibility="{Binding LegTuples.Count, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource IntNotZeroVisibilityConverter}}"
/>
<ComboBox
x:Name="PART_Tick_ComboBox" Grid.Column="3" Margin="6,0,0,0" IsEnabled="{TemplateBinding IsNew}" HorizontalAlignment="Stretch"
ItemsSource="{TemplateBinding AvailableTickFactors}" SelectedItem="{Binding TickFactors, RelativeSource={RelativeSource TemplatedParent}}"
Visibility="{Binding LegTuples.Count, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource IntNotZeroVisibilityConverter}}"
>
<ComboBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource ComboBox.DelineatedGroupContainerStyle}"/>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource TickFactorsTextConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Column="4" VerticalAlignment="Center" Margin="6,0,0,0">Pricing</TextBlock>
<ComboBox
Grid.Column="5" Margin="6,0,0,0" IsEnabled="False"
ItemsSource="{x:Static usp:ExecutionStrategyEditor.PriceCalcItems}" SelectedItem="{Binding PriceCalc, RelativeSource={RelativeSource TemplatedParent}}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource SyntheticPriceCalcDisplayConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<c:HelpButton Grid.Column="6" Margin="3,0,0,0"/>
</Grid>
<c:DataGridEx
x:Name="PART_DataGrid"
Grid.Row="1"
Margin="0,4,0,0"
BorderBrush="Transparent"
BorderThickness="0"
GridLinesVisibility="None"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
HeadersVisibility="All"
RowHeaderWidth="{StaticResource RowHeaderWidth}"
RowStyle="{StaticResource DataGridRowStyle}"
ItemsSource="{Binding ParameterRowsView, RelativeSource={RelativeSource TemplatedParent}}"
>
<DataGrid.Resources>
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}" TargetType="Button">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Rectangle Fill="{u:BTSColor header}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupItemStyle}"/>
</DataGrid.GroupStyle>
</c:DataGridEx>
</Grid>
</Border>
</ControlTemplate>
<Style TargetType="usp:ExecutionStrategyEditor">
<Setter Property="ParameterCellTemplateConverter" Value="{StaticResource ParameterCellTemplateConverter}"/>
<Setter Property="ParameterCellEditingTemplateConverter" Value="{StaticResource ParameterCellEditingTemplateConverter}"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template" Value="{StaticResource ExecutionStrategyEditorTemplate}"/>
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Style>
</ResourceDictionary>
@@ -1,319 +0,0 @@
using bts.api;
using bts.spark;
using mbts.spark;
using mbts.ui.adorners;
using mbts.ui.controls;
using mbts.ui.utility;
using mbts.user.settings;
using mbts.utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using static mbts.spark.SyntheticEditorVM;
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for ExecutionStrategyEditor.xaml
/// </summary>
partial class ExecutionStrategyEditor : Control {
static ExecutionStrategyEditor() =>
DefaultStyleKeyProperty.OverrideMetadata(typeof(ExecutionStrategyEditor), new FrameworkPropertyMetadata(typeof(ExecutionStrategyEditor)));
public ExecutionStrategyEditor() =>
AdornerHelper.attach_continuously_on_loaded(() => new ExecutionStrategyErrorAdorner(this), this);
#region SyntheticName
public static readonly DependencyProperty SyntheticNameProperty = DependencyProperty.Register("SyntheticName", typeof(string), typeof(ExecutionStrategyEditor),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string SyntheticName { get => GetValue(SyntheticNameProperty) as string; set => SetValue(SyntheticNameProperty, value); }
#endregion
#region TickFactors
public static readonly DependencyProperty TickFactorsProperty = DependencyProperty.Register("TickFactors", typeof(TickFactors), typeof(ExecutionStrategyEditor),
new FrameworkPropertyMetadata(new TickFactors(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public TickFactors TickFactors { get => GetValue(TickFactorsProperty) as TickFactors; set => SetValue(TickFactorsProperty, value); }
#endregion
#region AvailableTickFactors
public static readonly DependencyProperty AvailableTickFactorsProperty = DependencyProperty.Register(
nameof(AvailableTickFactors), typeof(IEnumerable), typeof(ExecutionStrategyEditor), new PropertyMetadata(new TickFactors[0]));
public IEnumerable AvailableTickFactors { get => GetValue(AvailableTickFactorsProperty) as IEnumerable; set => SetValue(AvailableTickFactorsProperty, value); }
#endregion
#region IsNew
public static readonly DependencyProperty IsNewProperty =
DependencyProperty.Register(
nameof(IsNew),
typeof(bool),
typeof(ExecutionStrategyEditor),
new PropertyMetadata(false, OnIsNewChanged));
static void OnIsNewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
d.CoerceValue(CanUserAddNewLegProperty);
public bool IsNew {
get => (bool)GetValue(IsNewProperty);
set => SetValue(IsNewProperty, value);
}
#endregion
#region CanUserAddNewLeg
public static readonly DependencyProperty CanUserAddNewLegProperty =
DependencyProperty.Register(
nameof(CanUserAddNewLeg),
typeof(bool),
typeof(ExecutionStrategyEditor),
new PropertyMetadata(false, null, CoerceCanUserAddNewLeg));
static object CoerceCanUserAddNewLeg(DependencyObject d, object baseValue) {
var value = (bool)baseValue;
if (value) {
if (!((ExecutionStrategyEditor)d).IsNew)
return false;
}
return value;
}
public bool CanUserAddNewLeg {
get => (bool)GetValue(CanUserAddNewLegProperty);
set => SetValue(CanUserAddNewLegProperty, value);
}
#endregion
#region IsNewLegPopupOpen
public static readonly DependencyProperty IsNewLegPopupOpenProperty = DependencyProperty.Register("IsNewLegPopupOpen", typeof(bool), typeof(ExecutionStrategyEditor),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public bool IsNewLegPopupOpen { get => (bool)GetValue(IsNewLegPopupOpenProperty); set => SetValue(IsNewLegPopupOpenProperty, value); }
#endregion
#region PriceCalc
public static readonly DependencyProperty PriceCalcProperty = DependencyProperty.Register("PriceCalc", typeof(SyntheticContract.Types.PriceCalc), typeof(ExecutionStrategyEditor),
new FrameworkPropertyMetadata(SyntheticContract.Types.PriceCalc.Diff, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public SyntheticContract.Types.PriceCalc PriceCalc { get => (SyntheticContract.Types.PriceCalc)GetValue(PriceCalcProperty); set => SetValue(PriceCalcProperty, value); }
public static readonly IEnumerable<SyntheticContract.Types.PriceCalc> PriceCalcItems = EnumHelper.get_values<SyntheticContract.Types.PriceCalc>();
#endregion
#region LegTuples
public static readonly DependencyProperty LegTuplesProperty = DependencyProperty.Register("LegTuples", typeof(IReadOnlyCollection<LegSpreaderParamsTuple>), typeof(ExecutionStrategyEditor),
new FrameworkPropertyMetadata(new LegSpreaderParamsTuple[0], FrameworkPropertyMetadataOptions.AffectsMeasure, ConnectLegTuples, CoerceLegTuples));
static object CoerceLegTuples(DependencyObject d, object baseValue) =>
baseValue as IReadOnlyCollection<LegSpreaderParamsTuple> ?? new LegSpreaderParamsTuple[0];
public IReadOnlyCollection<LegSpreaderParamsTuple> LegTuples { get => GetValue(LegTuplesProperty) as IReadOnlyCollection<LegSpreaderParamsTuple>; set => SetValue(LegTuplesProperty, value); }
#endregion
#region ParameterRows
public static readonly DependencyProperty ParameterRowsProperty = DependencyProperty.Register("ParameterRows", typeof(IEnumerable<IParameterRowVM>), typeof(ExecutionStrategyEditor),
new PropertyMetadata(Enumerable.Empty<IParameterRowVM>(), OnParameterRowsChanged));
static void OnParameterRowsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
ExceptionAssert.Argument.IsNot<INotifyCollectionChanged>(e.NewValue, nameof(ParameterRows));
((ExecutionStrategyEditor)d)._on_new_parameter_rows(e.NewValue as IEnumerable<IParameterRowVM>);
}
ObservableCollection<IParameterRowVM> _rows;
void _on_new_parameter_rows(IEnumerable<IParameterRowVM> new_rows) {
if (_rows == null) {
_rows = new ObservableCollection<IParameterRowVM>(new_rows);
var rows_view = ParameterRowsView = CollectionViewSource.GetDefaultView(_rows);
Action set_group_descriptions = () => {
int n_groups = _rows.Count == 0 ? 0 : _rows.Max(r => r.section_path.Length);
for (int i = 0; i < n_groups; i++)
rows_view.GroupDescriptions.Add(new PropertyGroupDescription($"[{i}]"));
};
set_group_descriptions();
_rows.CollectionChanged += (s, e) => {
rows_view.GroupDescriptions.Clear();
set_group_descriptions();
};
}
}
public IEnumerable<IParameterRowVM> ParameterRows { get => GetValue(ParameterRowsProperty) as IEnumerable<IParameterRowVM>; set => SetValue(ParameterRowsProperty, value); }
#endregion
#region ParameterRowsView (ReadOnly)
static readonly DependencyPropertyKey ParameterRowsViewPropertyKey = DependencyProperty.RegisterReadOnly("ParameterRowsView", typeof(ICollectionView), typeof(ExecutionStrategyEditor),
new PropertyMetadata());
public static readonly DependencyProperty ParameterRowsViewProperty = ParameterRowsViewPropertyKey.DependencyProperty;
public ICollectionView ParameterRowsView { get => GetValue(ParameterRowsViewProperty) as ICollectionView; set => SetValue(ParameterRowsViewPropertyKey, value); }
#endregion
#region ParameterCellTemplateConverter
public static readonly DependencyProperty ParameterCellTemplateConverterProperty = DependencyProperty.Register("ParameterCellTemplateConverter", typeof(IValueConverter), typeof(ExecutionStrategyEditor),
new PropertyMetadata(ConnectLegTuples));
public IValueConverter ParameterCellTemplateConverter { get => GetValue(ParameterCellTemplateConverterProperty) as IValueConverter; set => SetValue(ParameterCellTemplateConverterProperty, value); }
#endregion
#region ParameterCellEditingTemplateConverter
public static readonly DependencyProperty ParameterCellEditingTemplateConverterProperty = DependencyProperty.Register("ParameterCellEditingTemplateConverter", typeof(IValueConverter), typeof(ExecutionStrategyEditor),
new PropertyMetadata(ConnectLegTuples));
public IValueConverter ParameterCellEditingTemplateConverter { get => GetValue(ParameterCellEditingTemplateConverterProperty) as IValueConverter; set => SetValue(ParameterCellEditingTemplateConverterProperty, value); }
#endregion
#region RowHasError
public static readonly DependencyProperty RowHasErrorsProperty = DependencyProperty.RegisterAttached("RowHasErrors", typeof(bool), typeof(ExecutionStrategyEditor), new PropertyMetadata(false));
public static bool GetRowHasErrors(DependencyObject d) { return (bool)d.GetValue(RowHasErrorsProperty); }
public static void SetRowHasErrors(DependencyObject d, bool value) { d.SetValue(RowHasErrorsProperty, value); }
#endregion
#region CellDataType
public static readonly DependencyProperty CellDataTypeProperty = DependencyProperty.RegisterAttached("CellDataType", typeof(Type), typeof(ExecutionStrategyEditor), new PropertyMetadata(null));
public static Type GetCellDataType(DependencyObject d) { return d.GetValue(CellDataTypeProperty) as Type; }
public static void SetCellDataType(DependencyObject d, Type value) { d.SetValue(CellDataTypeProperty, value); }
#endregion
#region RemoveLegCommand
public static readonly DependencyProperty RemoveLegCommandProperty = DependencyProperty.Register("RemoveLegCommand", typeof(ICommand), typeof(ExecutionStrategyEditor));
public ICommand RemoveLegCommand { get => GetValue(RemoveLegCommandProperty) as ICommand; set => SetValue(RemoveLegCommandProperty, value); }
#endregion
#region ContractPickerModel
public static readonly DependencyProperty ContractPickerModelProperty = DependencyProperty.Register(nameof(ContractPickerModel), typeof(mbts.spark.ContractPickerModel), typeof(ExecutionStrategyEditor));
public mbts.spark.ContractPickerModel ContractPickerModel { get => GetValue(ContractPickerModelProperty) as mbts.spark.ContractPickerModel; set => SetValue(ContractPickerModelProperty, value); }
#endregion
public override void OnApplyTemplate() =>
_connect_leg_tuples();
static void ConnectLegTuples(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
((ExecutionStrategyEditor)d)._connect_leg_tuples();
void _connect_leg_tuples() {
Disposable.dispose(ref _dg_line_adorner);
Disposable.dispose(ref _legs_collection_changed_sub);
var dg = (DataGridEx)GetTemplateChild("PART_DataGrid");
if (dg != null) {
var legs = LegTuples;
dg.Columns.SetItems(legs.Select(_column_factory));
if (IsNew) dg.Columns.Add((DataGridColumn)FindResource("AddColumnPlaceholder"));
_dg_line_adorner = AdornerHelper.attach_continuously_on_loaded(() => new ExecutionStrategyGridLineAdorner(dg), dg);
_legs_collection_changed_sub = (legs as INotifyCollectionChanged)?.Subscribe((s, e) => dg.Columns.ReflectChange(legs, _column_factory, e));
}
}
DataGridColumn _column_factory(LegSpreaderParamsTuple l) {
var col = new DataGridColumnInternal(l.leg.Security, ParameterCellTemplateConverter, ParameterCellEditingTemplateConverter) { Width = 75, };
if (IsNew) col.HeaderTemplate = (DataTemplate)FindResource("RemovableColumnHeaderTemplate");
DataGridEx.SetRightBorder(col, new DataGridExVerticalLine(false, true, Colors.DarkGray, 1));
return col;
}
IDisposable _legs_collection_changed_sub, _dg_line_adorner;
private class DataGridColumnInternal : DataGridDynamicColumn {
readonly IValueConverter _cell_template_converter, _cell_editing_template_converter;
public DataGridColumnInternal(Security security, IValueConverter cell_template_converter, IValueConverter cell_editing_template_converter) {
Header = security;
SetValue(DataGridEx.CellKeyProperty, security);
_cell_template_converter = cell_template_converter;
_cell_editing_template_converter = cell_editing_template_converter;
}
// I decided this was an easy and simple enough solution to justify breaking the mvvm paradigm
// The alternative - within strict bounds of the paradigm - is to change the DataGridParameterCellTemplateConverter into an IMultiValueConverter, bound to data_type AND read_only
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) {
if (dataItem is SyntheticEditorVM.RowVM row_vm) {
if (row_vm.read_only || row_vm.get_cell(Header) is SyntheticEditorVM.ICell cell_vm && !cell_vm.enabled)
return base.GenerateElement(cell, dataItem);
}
return base.GenerateEditingElement(cell, dataItem);
}
protected override FrameworkElement generate_element_internal() =>
_generate_element(_cell_template_converter);
protected override FrameworkElement generate_editing_element_internal() =>
_generate_element(_cell_editing_template_converter);
FrameworkElement _generate_element(IValueConverter cell_template_converter) {
var rv = new ContentControl();
rv.SetBinding(ContentControl.ContentProperty, new Binding());
rv.SetBinding(ContentControl.ContentTemplateProperty, new Binding("data_type") { Converter = cell_template_converter });
return rv;
}
}
class ExecutionStrategyErrorAdorner : NotifyDataErrorAdorner<ExecutionStrategyEditor, SyntheticEditorVM>, IDisposable {
readonly ChildProperty<TextBox> _name_text_box;
readonly ChildProperty<ComboBox> _tick_combo_box;
public ExecutionStrategyErrorAdorner(ExecutionStrategyEditor editor) : base(editor) {
_name_text_box = child_property<TextBox>("PART_Name_TextBox");
_tick_combo_box = child_property<ComboBox>("PART_Tick_ComboBox");
}
protected override void OnRender(DrawingContext drawing_context) {
const double y_offset = 10;
string leg_count_msg = _vm.GetErrors(nameof(SyntheticEditorVM.leg_count)).Cast<string>().FirstOrDefault();
if (leg_count_msg != null) {
this.draw_relative_text(RelativePosition.Below, leg_count_msg, drawing_context, _name_text_box.value, new SolidColorBrush(BTSColors.MarketData.driver_background), 0, y_offset);
} else {
if (_vm != null && _vm.GetErrors(nameof(SyntheticEditorVM.name)).Cast<string>().Any())
this.draw_border(drawing_context, _name_text_box.value, null, new Pen(Brushes.Red, 1));
if (_vm != null && _vm.GetErrors(nameof(SyntheticEditorVM.tick_factors)).Cast<string>().Any())
this.draw_border(drawing_context, _tick_combo_box.value, null, new Pen(Brushes.Red, 1));
string error_text = string.Join(", ", _vm.AllErrors);
this.draw_relative_text(RelativePosition.Below, error_text, drawing_context, _name_text_box.value, BTSColors.header_error_text_brush, 0, y_offset);
}
}
}
}
[ValueConversion(typeof(int), typeof(Thickness))]
class RowHeaderGroupIndentConverter : IValueConverter {
public double Indent { get; set; }
public bool Reverse { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
new Thickness(((int)value + 1) * (Reverse ? -Indent : Indent), 0, 0, 0);
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotImplementedException();
}
[ValueConversion(typeof(int), typeof(double))]
class RowGroupExpanderWidthConverter : IValueConverter {
public double Indent { get; set; }
public double RowHeaderWidth { get; set; }
public double Offset { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
RowHeaderWidth - (int)value * Indent - Offset;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}
[ValueConversion(typeof(Type), typeof(DataTemplate))]
class DataGridParameterCellTemplateConverter : IValueConverter {
public DataTemplate DoubleTemplate { get; set; }
public DataTemplate BooleanTemplate { get; set; }
public DataTemplate IntTemplate { get; set; }
public DataTemplate UIntTemplate { get; set; }
public DataTemplate QuantityMeasureTemplate { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
Type t = (Type)value;
if (t == typeof(double)) return DoubleTemplate;
else if (t == typeof(bool)) return BooleanTemplate;
else if (t == typeof(int)) return IntTemplate;
else if (t == typeof(uint)) return UIntTemplate;
else if (t == typeof(QuantityMeasure)) return QuantityMeasureTemplate;
else return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotImplementedException();
}
}
@@ -1,21 +0,0 @@
using System.Threading.Tasks;
using bts.api;
using mbts.ui;
namespace bts.shell {
internal class LatencyReportWindowFactory : ShellWindowFactory<LatencyReportSaveState> {
IBus _bus;
public LatencyReportWindowFactory(IShellModule owner, IBus bus) : base(owner,"LatencyReport") {
_bus = bus;
}
public override Task<IShellWindow> load(LatencyReportSaveState state) {
throw new System.NotImplementedException();
}
}
[ProtoBuf.ProtoContract]
public class LatencyReportSaveState {
}
}
@@ -1,88 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="clr-namespace:mbts.ui"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:cv="clr-namespace:mbts.ui.converters"
xmlns:usp="clr-namespace:mbts.ui.spark"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<cv:ValueMap x:Key="EmptyStringVisibilityConverter" Default="{u:Visibility Visible}">
<cv:KeyValue Key="{x:Static sys:String.Empty}" Value="{u:Visibility Collapsed}"/>
<cv:KeyValue Key="{x:Null}" Value="{u:Visibility Collapsed}"/>
</cv:ValueMap>
<Style TargetType="usp:ParameterSectionView">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="usp:ParameterSectionView">
<FlowDocumentScrollViewer
IsSelectionEnabled="False"
Padding="0"
VerticalAlignment="Top"
VerticalScrollBarVisibility="Hidden"
>
<FlowDocument
FontFamily="Segoe UI"
FontSize="{x:Static u:FontSizes.Regular}"
IsOptimalParagraphEnabled="False"
PagePadding="0,0,3,3"
>
<Section
Margin="0"
Padding="0">
<Paragraph
Margin="0"
Padding="0"
>
<Floater
HorizontalAlignment="Left"
Margin="0"
Padding="0"
Width="{Binding ActualWidth, ElementName=panel}"
>
<BlockUIContainer Padding="0" Margin="0">
<StackPanel
x:Name="panel"
Orientation="Horizontal"
HorizontalAlignment="Left"
>
<TextBlock
FontFamily="Segoe UI"
FontSize="{x:Static u:FontSizes.Regular}"
FontWeight="Bold"
Text="{Binding SectionTitle, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
/>
<c:HelpButton
x:Name="PART_Description_HelpButton"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{Binding ToggleShowDescription, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Margin="3,0,0,0"
Opacity="0"
Visibility="{Binding Description, Converter={StaticResource EmptyStringVisibilityConverter}, RelativeSource={RelativeSource TemplatedParent}}"
/>
</StackPanel>
</BlockUIContainer>
</Floater>
<Run
x:Name="desc_text"
FontFamily="Segoe UI"
FontSize="{x:Static u:FontSizes.Regular}"
FontStyle="Italic"
Foreground="{u:BTSColor UI.input_disabled_text_dark}"
/>
</Paragraph>
</Section>
</FlowDocument>
</FlowDocumentScrollViewer>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" TargetName="PART_Description_HelpButton" Value="1"/>
</Trigger>
<Trigger Property="ShowDescription" Value="True">
<Setter Property="Text" TargetName="desc_text" Value="{Binding Description, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
@@ -1,42 +0,0 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace mbts.ui.spark {
class ParameterSectionView : Control {
static ParameterSectionView() =>
DefaultStyleKeyProperty.OverrideMetadata(typeof(ParameterSectionView), new FrameworkPropertyMetadata(typeof(ParameterSectionView)));
#region SectionTitle
public static readonly DependencyProperty SectionTitleProperty = DependencyProperty.Register(
nameof(SectionTitle), typeof(string), typeof(ParameterSectionView), new PropertyMetadata(string.Empty));
public string SectionTitle { get => GetValue(SectionTitleProperty) as string; set => SetValue(SectionTitleProperty, value); }
#endregion
#region Description
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
nameof(Description), typeof(string), typeof(ParameterSectionView), new PropertyMetadata(string.Empty));
public string Description { get => GetValue(DescriptionProperty) as string; set => SetValue(DescriptionProperty, value); }
#endregion
#region ShowDescription
public static readonly DependencyProperty ShowDescriptionProperty = DependencyProperty.Register(
nameof(ShowDescription), typeof(bool), typeof(ParameterSectionView), new PropertyMetadata(false));
public bool ShowDescription { get => (bool)GetValue(ShowDescriptionProperty); set => SetValue(ShowDescriptionProperty, value); }
#endregion
#region ToggleShowDescription (ReadOnly)
static readonly DependencyPropertyKey ToggleShowDescriptionPropertyKey = DependencyProperty.RegisterReadOnly(
nameof(ToggleShowDescription), typeof(ICommand), typeof(ParameterSectionView), new PropertyMetadata(null));
public static readonly DependencyProperty ToggleShowDescriptionProperty = ToggleShowDescriptionPropertyKey.DependencyProperty;
public ICommand ToggleShowDescription { get => GetValue(ToggleShowDescriptionPropertyKey.DependencyProperty) as ICommand; private set => SetValue(ToggleShowDescriptionPropertyKey, value); }
#endregion
public ParameterSectionView() =>
ToggleShowDescription = new DelegateCommand(() => ShowDescription = !ShowDescription);
}
}
@@ -1,111 +0,0 @@
using bts.api;
using bts.spark;
using mbts;
using mbts.spark;
using mbts.ui;
using mbts.ui.spark;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace bts.shell {
[Export(typeof(IInitializable))]
partial class ShowSyntheticEditorHandler : IInitializable, IDisposable {
readonly OrdersModel _model;
readonly IBus _bus;
IDisposable _dispose;
[ImportingConstructor]
public ShowSyntheticEditorHandler(IBus bus, OrdersModel model) {
_bus = bus;
_model = model;
}
static void _show_synthetic_editor(SyntheticEditorVM vm) {
var v = new SyntheticEditorView { DataContext = vm };
WindowUtilities.listen_for_close_requests(v);
v.Show(-250, -200, true);
}
static string _get_clone_name(string name) {
if (string.IsNullOrEmpty(name))
return string.Empty;
var regex = new Regex(@"(?<=\()\d+(?=\)$)");
var match = regex.Match(name);
return match.Success && int.TryParse(match.Value, out int i) && i < int.MaxValue ?
regex.Replace(name, (i + 1).ToString()) :
name + "(1)";
}
async void _show_synthetic_create(SecurityCriteria security_criteria) =>
_show_synthetic_create((await security_criteria.securities(_bus)).ToList());
void _show_synthetic_create(IReadOnlyCollection<SecurityImmutable> securities) {
if (securities.Count == 1) {
var sec = securities.First();
switch (sec.ContractCase) {
case Security.ContractOneofCase.Future: _show_synthetic_create(new ContractLeg[] { SyntheticDataHelper.Defaults.ContractLeg(sec) }); break;
case Security.ContractOneofCase.Spread: _show_synthetic_create(sec.Spread.Legs.Select(l => l.CloneToMutable())); break;
case Security.ContractOneofCase.Synthetic: _show_synthetic_create(sec.Synthetic.Legs.Select(l => l.CloneToMutable())); break;
default: Logger.warn(log.Subsystem.Ui, $"{GetType()} unable to process security: {sec}"); break;
}
} else
_show_synthetic_create(securities.Select(s => new ContractLeg(SyntheticDataHelper.Defaults.ContractLeg(s))));
}
void _show_synthetic_strategy(SecurityImmutable security) {
if (security.ContractCase != Security.ContractOneofCase.Synthetic)
Logger.warn(log.Subsystem.Ui, $"{GetType()} observed a non-synthetic-security posted on {nameof(SparkTags.ShowSyntheticStrategyTag)}: {security}");
else
_show_synthetic_strategy_async(security).ignore();
}
async Task _show_synthetic_strategy_async(SecurityImmutable verified_synthetic) {
var lookup = await _model.spreader.lookup_strategy_async(verified_synthetic);
if (lookup.success)
_show_synthetic_editor(new SyntheticEditorVM(_model.spreader, verified_synthetic, lookup.result, _model.security_has_working_orders(verified_synthetic.Id)));
}
void _show_synthetic_clone((SecurityImmutable security, ExecutionStrategyImmutable strategy) args) {
if (args.security.ContractCase == Security.ContractOneofCase.Synthetic) {
var mutable_sec = args.security.CloneToMutable();
mutable_sec.Id = 0;
mutable_sec.Synthetic.Name = _get_clone_name(mutable_sec.Synthetic.Name);
_show_synthetic_editor(new SyntheticEditorVM(_bus, _model.spreader, new SecurityImmutable(mutable_sec), args.strategy, true));
} else
_show_synthetic_strategy(args.security);
}
void _show_synthetic_create(IEnumerable<ContractLeg> legs) {
var syn = SyntheticDataHelper.Defaults.SyntheticContract("Synthetic", legs);
var sec = new SecurityImmutable(new Security {
Synthetic = syn,
Symbol = legs.FirstOrDefault()?.Security.Symbol ?? string.Empty,
ContractSpec = SecurityDataHelper.Defaults.ContractSpecification
});
_show_synthetic_editor(new SyntheticEditorVM(_bus, _model.spreader, sec, new ExecutionStrategyImmutable(SyntheticDataHelper.Defaults.ExecutionStrategy(sec))));
}
#region IInitializable
int IInitializable.priority => int.MaxValue;
void IInitializable.initialize() {
Disposable.dispose(ref _dispose);
_dispose = Disposable.Create(
_bus.subscribe(SparkTags.ShowSyntheticCreateTag).ObserveOnDispatcher().Subscribe(_show_synthetic_create),
_bus.subscribe(SparkTags.ShowSyntheticStrategyTag).ObserveOnDispatcher().Subscribe(_show_synthetic_strategy),
_bus.subscribe(SparkTags.ShowSyntheticCloneTag).ObserveOnDispatcher().Subscribe(_show_synthetic_clone)
);
}
void IDisposable.Dispose() =>
Disposable.dispose(ref _dispose);
#endregion
}
}
@@ -1,72 +0,0 @@
using bts.api;
using bts.api.synthetic;
using bts.spark;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace mbts.spark {
[Export]
class SpreaderModel {
readonly IBus _bus;
readonly SyntheticSecurityService _service;
readonly ErrorReporter _error;
[ImportingConstructor]
public SpreaderModel(IBus bus, SyntheticSecurityService service, ErrorReporter error) {
_bus = bus;
_service = service;
_error = error;
}
public IObservable<IReadOnlyDictionary<uint, ExecutionStrategyImmutable>> strategy => _bus.subscribe(SparkTags.SyntheticstrategiesTag);
public IObservable<IReadOnlyDictionary<uint, (ExecutionStrategyImmutable? strategy, SecurityMD md)>> strategy_tuple =>
_bus.subscribe(SparkTags.SecuritiesTag)
.Select(md_map => md_map.Values.Where(smd => smd.security.ContractCase == Security.ContractOneofCase.Synthetic).ToList())
// CombineLatest waits for both sources to fire once, sometimes strategy does not fire, so StartWith circumvents this issue
.CombineLatest(_bus.subscribe(SparkTags.SyntheticstrategiesTag).StartWith(new Dictionary<uint, ExecutionStrategyImmutable>()),
(synthetics, strategies) => synthetics
.ToDictionary(smd => smd.security.Id)
.LeftJoin(strategies, (security, strategy) => (new ExecutionStrategyImmutable?(strategy), security), security => (new ExecutionStrategyImmutable?(), security))
);
public IObservable<ExecutionStrategyImmutable> security_strategy(uint security_key) =>
strategy.TrySelect(s => {
bool success = s.TryGetValue(security_key, out ExecutionStrategyImmutable result);
return (result, success);
});
public async Task<(ExecutionStrategyImmutable result, bool success)> lookup_strategy_async(SecurityImmutable security) =>
await lookup_strategy_async(security.Id);
public async Task<(ExecutionStrategyImmutable result, bool success)> lookup_strategy_async(uint id) {
var result = await _service.query_security_metadata_async(new MetadataQuery { SecurityKey = { id } });
if (result.success) {
var v = result.value.Data.FirstOrDefault(i => i.SecurityKey == id);
if (v != null) {
return (v.Strategy, true);
}
}
return (null, false);
}
public async Task<uint?> create_synthetic(SecurityImmutable synthetic) {
var result = await _service.create_synthetic_async(synthetic);
return _error.handle_error(result, "Error creating synthetic: {0}", r => r.Error, e => e == CreateResult.Types.Error.Ok, r => new uint?(r.Key), () => null).result;
}
public async Task<bool> save_strategy(uint synthetic, ExecutionStrategyImmutable strategy) {
var result = await _service.update_security_metadata_async(new Metadata { SecurityKey = synthetic, Strategy = strategy.CloneToMutable() });
return _error.handle_error(result, "Error saving execution strategy: {0}", r => r.Error, e => e == UpdateResult.Types.Error.Ok);
}
public async Task<bool> verify_name_is_unique(string name) {
var (result, success) = await strategy_tuple.FirstAsyncTask(SparkUtils.DefaultTimeOut);
name = name.Trim().ToLower();
return success && !result.Values.Any(st => st.md.security.Synthetic.Name.Trim().ToLower() == name);
}
}
}
@@ -1,47 +0,0 @@
using bts.api;
using bts.spark;
using mbts;
using mbts.spark;
using mbts.ui;
using mbts.ui.shell;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media;
namespace bts.shell
{
[Export(typeof(IShellModule))]
class SpreaderShellModule : IShellModule {
SyntheticManagementWindowFactory _smwf;
LatencyReportWindowFactory _lrwf;
[ImportingConstructor]
public SpreaderShellModule(IBus bus, OrdersModel orders_model) {
_smwf = new SyntheticManagementWindowFactory(this, bus, orders_model);
_lrwf = new LatencyReportWindowFactory(this, bus);
}
public ImageSource icon => Icons.Cube3d;
public string name => "Spreader";
public int priority => 30;
public IEnumerable<SparkCommand> actions => new[] {
SparkCommands.ShowSyntheticManagement
};
public Task<IShellWindow> create(Stream load_stream) {
if (ProtoBufSerializationHelper.try_deserialize(load_stream, out ShellSerializationHeader header)) {
if (header.name == _smwf.name) return _smwf.load_window(load_stream, header.version);
if (header.name == _lrwf.name) return _lrwf.load_window(load_stream, header.version);
}
return null;
}
public void Dispose() {
Disposable.dispose(ref _smwf);
Disposable.dispose(ref _lrwf);
}
}
}
@@ -1,11 +0,0 @@
using System.Windows;
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for SyntheticEditorView.xaml
/// </summary>
partial class SyntheticEditorView : Window {
public SyntheticEditorView() =>
InitializeComponent();
}
}
@@ -1,80 +0,0 @@
<UserControl x:Class="mbts.ui.spark.SyntheticManagementView" x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="clr-namespace:mbts.ui"
xmlns:c="clr-namespace:mbts.ui.controls">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/view/Controls/DataGridEx/Filters/Views/FilterTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<c:DataGridEx
x:Name="grid" BorderThickness="0" IsReadOnly="True" CanUserSortColumns="True"
GridLinesVisibility="None" ItemsSource="{Binding rows_view}"
CurrentItem="{Binding current_row, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="u:AttachedCommands.DoubleClick" Value="{Binding show_ladder}"/>
<Setter Property="u:AttachedCommands.Enter" Value="{Binding show_ladder}"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<!--<DataGridTextColumn
Header="Create Time" Binding="{Binding create_time}"
c:DataGridFilterProperties.Filter="{Binding DataContext.create_time_filter, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.create_time_filter.active, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource TimeFilterTemplate}"
/>-->
<DataGridTextColumn
Header="Name" Binding="{Binding name}"
c:DataGridFilterProperties.Filter="{Binding DataContext.name_filter, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.name_filter.active, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.name_filter.open, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource RegexTemplate}"
/>
<DataGridTextColumn
Header="Description" Binding="{Binding description}"
c:DataGridFilterProperties.Filter="{Binding DataContext.description_filter, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.description_filter.active, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.description_filter.open, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource RegexTemplate}"
/>
<DataGridTextColumn
Header="# Legs" Binding="{Binding n_legs}"
c:DataGridFilterProperties.Filter="{Binding DataContext.n_legs_filter, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.n_legs_filter.active, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.n_legs_filter.open, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource IntMinMaxTemplate}"
/>
<DataGridTemplateColumn
Header="# Working Orders"
c:DataGridFilterProperties.Filter="{Binding DataContext.n_working_orders_filter, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.n_working_orders_filter.active, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.n_working_orders_filter.open, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource IntMinMaxTemplate}"
>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink Command="{Binding show_order_book}">
<TextBlock Text="{Binding n_working_orders}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn
Header="Security Key" Binding="{Binding security_key}" Width="*"
c:DataGridFilterProperties.Filter="{Binding DataContext.security_key_filter, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterActive="{Binding DataContext.security_key_filter.active, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.security_key_filter.open, Source={u:DirectReference grid}}"
c:DataGridFilterProperties.FilterTemplate="{StaticResource IntMinMaxTemplate}"
/>
</DataGrid.Columns>
</c:DataGridEx>
</Grid>
</UserControl>
@@ -1,12 +0,0 @@
using mbts.spark.filters;
using System.Windows.Controls;
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for SyntheticManagementView.xaml
/// </summary>
internal partial class SyntheticManagementView : UserControl {
public SyntheticManagementView() =>
InitializeComponent();
}
}
@@ -1,75 +0,0 @@
using bts.api;
using bts.shell;
using bts.spark;
using mbts.ui;
using mbts.ui.spark;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows;
using static bts.shell.SyntheticManagementWindowFactory;
namespace mbts.spark {
class SyntheticManagementWindow : SparkWindow<StartupData> {
const string _window_type = "SyntheticManagement";
SingleValuePump<SyntheticManagementDialogVM> _vm = new SingleValuePump<SyntheticManagementDialogVM>();
StartupData _state;
OrdersModel _orders_model;
SyntheticManagementView _view;
public static SyntheticManagementWindow create(SyntheticManagementWindowFactory factory, IBus bus, OrdersModel orders_model, StartupData state) {
var window = new SyntheticManagementWindow(factory, bus, orders_model);
window.initialize(state);
return window;
}
SyntheticManagementWindow(SyntheticManagementWindowFactory factory, IBus bus, OrdersModel orders_model)
: base("Synthetic Management", bus, factory, SparkCommands.ShowSyntheticManagement.icon) {
_orders_model = orders_model;
Commands = new SparkCommand[] {
SparkCommand.create("Add", Icons.AddSynthetic, SparkTags.ShowSyntheticCreateTag).complete(
() => new SecurityCriteria(), () => true
), SparkCommand.create("Remove", Icons.RemoveSynthetic, SparkTags.SyntheticDeleteTag).complete(
_vm.observable.SelectMany(vm => vm.current_row_observable),
can_row_change, r => r == null ? 0 : r.security_key
), SparkCommand.create("Change", Icons.ModifySynthetic, SparkTags.ShowSyntheticStrategyTag).complete(
_vm.observable.SelectMany(vm => vm.current_row_observable),
can_row_change, r => r == null ? SecurityDataHelper.Defaults.SecurityImmutable : r.security
), SparkCommand.create("Clone", Icons.CloneSynthetic, SparkTags.ShowSyntheticCloneTag).complete(
_vm.observable.SelectMany(vm => vm.current_row_observable),
r => r != null && r.strategy.HasValue, r => r == null ? default : (r.security, r.strategy.Value)
), SparkCommands.ShowLadder.complete(
_vm.observable.SelectMany(vm => vm.current_security_md), md => md.HasValue, ObjectHelper.ValueOrDefault
), SparkCommands.ShowOrders.complete(() => new OrderBookWindowFactory.OrderBookStartupData {
filters = new OrderBookWindowFactory.FilterStates {
security_criteria = new SecurityCriteria(_vm.value.row_vms.Select(r => r.security))
}
})
};
bool can_row_change(SyntheticManagementDialogVM.Row r) =>
r != null && r.n_working_orders == 0;
}
public void initialize(StartupData state) {
Logger.notnull(state);
_state = state;
_vm.value = new SyntheticManagementDialogVM(_bus, _orders_model, state.sorting_criteria, state.filters ?? new FilterStates());
if (_view == null) _view = new SyntheticManagementView { DataContext = _vm.value };
else _view.DataContext = _vm.value;
}
public override string window_type => _window_type;
public override UIElement Content => _view;
public override IEnumerable<SparkCommand> Commands { get; }
public override StartupData SaveState => _state = new StartupData(_vm.value.rows_view.GetSortingCriteria(), _vm.value.get_filter_states());
public override double MinWidth => 700;
public override void Dispose() {
Disposable.dispose(ref _vm);
Commands.OfType<IDisposable>().DisposeAll();
}
}
}
@@ -1,58 +0,0 @@
using bts.api;
using mbts.spark;
using mbts.spark.filters;
using mbts.ui;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace bts.shell {
class SyntheticManagementWindowFactory : ShellWindowFactory<SyntheticManagementWindowFactory.StartupData> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
public SyntheticManagementWindowFactory(SpreaderShellModule module, IBus bus, OrdersModel orders_model) : base(module, "SyntheticManagement") {
_bus = bus;
_orders_model = orders_model;
_dispose = bus.subscribe(SparkTags.ShowSyntheticManagementTag).ObserveOnDispatcher().Subscribe(show);
}
public override Task<IShellWindow> load(StartupData state) =>
Task.FromResult<IShellWindow>(SyntheticManagementWindow.create(this, _bus, _orders_model, state));
public async void show(SparkTags.Nothing nothing) =>
_bus.post(SparkTags.ShowWindow, await load(new StartupData()));
[ProtoContract]
public class StartupData {
public const int Version = 1;
[ProtoMember(1)]
public readonly List<SortingCriteria> sorting_criteria;
[ProtoMember(2)]
public readonly FilterStates filters;
public StartupData() : this(new List<SortingCriteria>(), null) { }
public StartupData(List<SortingCriteria> sorting_criteria, FilterStates filters) {
this.sorting_criteria = sorting_criteria;
this.filters = filters;
}
}
[ProtoContract]
public class FilterStates {
[ProtoMember(1)]
public string description;
[ProtoMember(2)]
public TimeFilterTuple create_time;
[ProtoMember(3)]
public string name;
[ProtoMember(4)]
public IntMinMaxState n_legs;
[ProtoMember(5)]
public UIntMinMaxState n_working_orders;
}
}
}
@@ -1,22 +0,0 @@
using System.Threading.Tasks;
using bts.api;
using mbts.ui;
using mbts.spark;
namespace bts.shell {
internal class SyntheticSpreadsShellWindowFactory : ShellWindowFactory<SyntheticSpreadsSaveState> {
readonly IBus _bus;
public SyntheticSpreadsShellWindowFactory(IShellModule owner, IBus bus) : base (owner, "SyntheticSpreads") {
_bus = bus;
}
public override Task<IShellWindow> load(SyntheticSpreadsSaveState state) {
throw new System.NotImplementedException();
}
}
[ProtoBuf.ProtoContract]
public class SyntheticSpreadsSaveState {
}
}
@@ -1,112 +0,0 @@
using bts.spark;
using mbts.ui.shell;
using mbts.ui.spark;
using System;
using System.Reactive.Linq;
namespace mbts.spark {
partial class SyntheticEditorVM {
class CellBase : DisposableViewModelBase {
readonly Property<bool> _enabled;
protected CellBase(IRowModel model, LegSpreaderParamsTuple leg_tup) =>
_enabled = backing(nameof(enabled), model.observe_enabled(leg_tup).ObserveOnDispatcher());
public bool enabled => _enabled.Value;
}
class Cell<T> : CellBase, ICell {
readonly RowModelBase<T> _model;
readonly LegSpreaderParamsTuple _leg_tup;
IDisposable _override_value_sub;
public Cell(RowModelBase<T> model, LegSpreaderParamsTuple leg_tup)
: base(model, leg_tup) {
_model = model;
_leg_tup = leg_tup;
_override_value_sub = model.observe_override_value(leg_tup).ObserveOnDispatcher().Subscribe(v => {
value = v;
RaisePropertyChanged(nameof(value));
});
}
public event Action value_changed;
public virtual Type data_type { get; } = typeof(T);
public T value {
get => _model.get_value(_leg_tup);
set {
_model.set_value(_leg_tup, value);
value_changed?.Invoke();
}
}
protected override void Dispose(bool disposing) {
Disposable.dispose(ref _override_value_sub);
base.Dispose(disposing);
}
}
class QuantityMeasureCell : CellBase, ICell {
readonly RowModelBase<QuantityMeasure> _model;
readonly LegSpreaderParamsTuple _leg_tup;
uint _absolute;
double _ratio;
public QuantityMeasureCell(RowModelBase<QuantityMeasure> model, LegSpreaderParamsTuple leg_tup)
: base(model, leg_tup) {
_model = model;
_leg_tup = leg_tup;
}
public event Action value_changed;
public Type data_type { get; } = typeof(QuantityMeasure);
public double ratio {
get => _get_qm().Ratio;
set {
_get_qm().Ratio = value;
_on_value_changed(nameof(ratio));
}
}
public uint absolute {
get => _get_qm().Absolute;
set {
_get_qm().Absolute = value;
_on_value_changed(nameof(absolute));
}
}
public QuantityMeasure.QuantityOneofCase quantity_case {
get => _get_qm().QuantityCase;
set {
var qm = _get_qm();
if (qm.QuantityCase != value) {
switch(value) {
case QuantityMeasure.QuantityOneofCase.Absolute:
_ratio = qm.Ratio;
qm.Absolute = _absolute;
_on_value_changed(nameof(absolute), nameof(quantity_case));
break;
case QuantityMeasure.QuantityOneofCase.Ratio:
_absolute = qm.Absolute;
qm.Ratio = _ratio;
_on_value_changed(nameof(ratio), nameof(quantity_case));
break;
}
}
}
}
QuantityMeasure _get_qm() => _model.get_value(_leg_tup);
void _on_value_changed(params string[] props) {
RaisePropertyChanged(props);
value_changed?.Invoke();
}
}
}
}
@@ -1,20 +0,0 @@
using mbts.ui.spark;
using System.Collections.Generic;
using System.Linq;
namespace mbts.spark {
partial class SyntheticEditorVM {
class IsQuoteModel : RowModelBase<bool> {
public override string display_name { get; } = "Enable Quoting";
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.IsActiveQuoting;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) =>
leg_tup.leg_params.IsActiveQuoting = value;
public override bool has_errors(IReadOnlyCollection<LegSpreaderParamsTuple> leg_tups) =>
!leg_tups.Any(lt => lt.leg_params.IsActiveQuoting);
}
}
}
@@ -1,24 +0,0 @@
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class HedgeRatioModel : RowModelBase<double> {
public override string display_name { get; } = "Hedge Ratio";
public override double get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.QuoteParams.LeanQuantityRatio;
public override void set_value(LegSpreaderParamsTuple leg_tup, double value) =>
leg_tup.leg_params.QuoteParams.LeanQuantityRatio = value;
public override ICell create_cell(LegSpreaderParamsTuple leg_tup) => new HedgeRatioCell(this, leg_tup);
class HedgeRatioCell : Cell<double> {
public HedgeRatioCell(RowModelBase<double> model, LegSpreaderParamsTuple leg_tup)
: base(model, leg_tup) { }
public double tick_increment => 0.1;
}
}
}
}
@@ -1,24 +0,0 @@
using mbts.ui.spark;
using System;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PriceMultiplierModel : RowModelBase<double> {
public PriceMultiplierModel(bool read_only) =>
this.read_only = read_only;
public event Action price_mult_changed;
public override bool read_only { get; }
public override string display_name { get; } = "Price Multiplier";
public override double get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg.PriceMultiplier;
public override void set_value(LegSpreaderParamsTuple leg_tup, double value) {
leg_tup.leg.PriceMultiplier = value;
price_mult_changed?.Invoke();
}
}
}
}
@@ -1,30 +0,0 @@
using bts.api;
using mbts.ui.spark;
using System;
namespace mbts.spark {
partial class SyntheticEditorVM {
class QuantityModel : RowModelBase<double> {
public QuantityModel(bool read_only) =>
this.read_only = read_only;
public event Action quantity_changed;
public override bool read_only { get; }
public override string display_name { get; } = "Quantity";
public override double get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg.Side == Side.Buy ? leg_tup.leg.Quantity : -leg_tup.leg.Quantity;
public override void set_value(LegSpreaderParamsTuple leg_tup, double value) {
if (value >= 0) {
leg_tup.leg.Side = Side.Buy;
leg_tup.leg.Quantity = value;
} else {
leg_tup.leg.Side = Side.Sell;
leg_tup.leg.Quantity = -value;
}
quantity_changed?.Invoke();
}
}
}
}
@@ -1,38 +0,0 @@
using mbts.ui.shell;
using System;
namespace mbts.spark {
class ParameterSection : ViewModelBase, IEquatable<ParameterSection> {
readonly string _description;
bool _show_description;
public ParameterSection(string name, bool can_be_disabled = false, string description=null) {
this.name = name;
this.can_be_disabled = can_be_disabled;
_description = description;
}
public string name { get; }
public bool can_be_disabled { get; }
public int level { get; set; }
public string description => _description;
public bool show_description {
get => _show_description;
set {
_show_description = value;
RaisePropertyChanged(nameof(description));
}
}
public bool Equals(ParameterSection other) =>
other != null && other.name == name;
public override bool Equals(object obj) =>
Equals(obj as ParameterSection);
public override int GetHashCode() =>
name.GetHashCode();
public override string ToString() => name;
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgeOppositeMarketVolumeBasedCrossCrossTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Cross Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.OppositeMarketVolumeBasedCross };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_omv_cross(leg_tup).CrossTicks = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_omv_cross(leg_tup) is PostHedgeOppositeMarketVolumeBasedForcedCross omv_cross ?
omv_cross.CrossTicks :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_omv_cross(leg_tup) is PostHedgeOppositeMarketVolumeBasedForcedCross omv_cross)
omv_cross.CrossTicks = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_omv_cross(leg_tup) != null;
PostHedgeOppositeMarketVolumeBasedForcedCross _get_omv_cross(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.OppositeMarketVolumeBasedForcedCross;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PostHedgeOppositeMarketVolumeBasedForcedCross.CrossTicks);
}
}
}
@@ -1,36 +0,0 @@
using bts.shell;
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgeOppositeMarketVolumeBasedCrossEnabledModel : RowModelBase<bool> {
readonly PostHedgeOppositeMarketVolumeBasedCrossThresholdModel _threshold;
readonly PostHedgeOppositeMarketVolumeBasedCrossCrossTicksModel _ticks;
public PostHedgeOppositeMarketVolumeBasedCrossEnabledModel(PostHedgeOppositeMarketVolumeBasedCrossThresholdModel threshold, PostHedgeOppositeMarketVolumeBasedCrossCrossTicksModel ticks) {
_threshold = threshold;
_ticks = ticks;
}
public override string display_name { get; } = string.Empty;
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.OppositeMarketVolumeBasedCross };
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.OppositeMarketVolumeBasedForcedCross != null;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
if (value) {
if (leg_tup.leg_params.PostHedgeParams.OppositeMarketVolumeBasedForcedCross == null) {
leg_tup.leg_params.PostHedgeParams.OppositeMarketVolumeBasedForcedCross = SyntheticDataHelper.Defaults.PostHedgeOppositeMarketVolumeBasedForcedCross;
_threshold.apply_value(leg_tup);
_ticks.apply_value(leg_tup);
}
} else {
leg_tup.leg_params.PostHedgeParams.OppositeMarketVolumeBasedForcedCross = null;
}
_threshold.set_enabled(leg_tup, value);
_ticks.set_enabled(leg_tup, value);
}
}
}
}
@@ -1,41 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgeOppositeMarketVolumeBasedCrossThresholdModel : RowModelBase<QuantityMeasure> {
IDictionary<uint, QuantityMeasure> _value_store = new Dictionary<uint, QuantityMeasure>();
public override string display_name { get; } = "Threshold";
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.OppositeMarketVolumeBasedCross };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_omv_cross(leg_tup).QuantityThreshold = _value_from_store(leg_tup);
public override QuantityMeasure get_value(LegSpreaderParamsTuple leg_tup) =>
_get_omv_cross(leg_tup) is PostHedgeOppositeMarketVolumeBasedForcedCross omv_cross ?
omv_cross.QuantityThreshold :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, QuantityMeasure value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_omv_cross(leg_tup) is PostHedgeOppositeMarketVolumeBasedForcedCross omv_cross)
omv_cross.QuantityThreshold = value;
}
public override ICell create_cell(LegSpreaderParamsTuple leg_tup) => new QuantityMeasureCell(this, leg_tup);
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_omv_cross(leg_tup) != null;
PostHedgeOppositeMarketVolumeBasedForcedCross _get_omv_cross(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.OppositeMarketVolumeBasedForcedCross;
QuantityMeasure _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PostHedgeOppositeMarketVolumeBasedForcedCross.QuantityThreshold);
}
}
}
@@ -1,36 +0,0 @@
using bts.shell;
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgePriceBasedCrossEnabledModel : RowModelBase<bool> {
readonly PostHedgePriceBasedCrossTicksModel _cross_ticks;
readonly PostHedgePriceBasedCrossMarketTicksModel _market_cross_ticks;
public PostHedgePriceBasedCrossEnabledModel(PostHedgePriceBasedCrossTicksModel cross_ticks, PostHedgePriceBasedCrossMarketTicksModel market_cross_ticks) {
_cross_ticks = cross_ticks;
_market_cross_ticks = market_cross_ticks;
}
public override string display_name { get; } = string.Empty;
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.TicksAwayCross };
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.PriceBasedCross != null;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
if (value) {
if (leg_tup.leg_params.PostHedgeParams.PriceBasedCross == null) {
leg_tup.leg_params.PostHedgeParams.PriceBasedCross = SyntheticDataHelper.Defaults.PostHedgePriceBasedForcedCross;
_cross_ticks.apply_value(leg_tup);
_market_cross_ticks.apply_value(leg_tup);
}
} else {
leg_tup.leg_params.PostHedgeParams.PriceBasedCross = null;
}
_cross_ticks.set_enabled(leg_tup, value);
_market_cross_ticks.set_enabled(leg_tup, value);
}
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgePriceBasedCrossMarketTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Cross Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.TicksAwayCross };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_price_based_cross(leg_tup).MarketCrossTicks = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_price_based_cross(leg_tup) is PostHedgePriceBasedForcedCross price_based_cross ?
price_based_cross.MarketCrossTicks :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_price_based_cross(leg_tup) is PostHedgePriceBasedForcedCross price_based_cross)
price_based_cross.MarketCrossTicks = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_price_based_cross(leg_tup) != null;
PostHedgePriceBasedForcedCross _get_price_based_cross(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.PriceBasedCross;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PostHedgePriceBasedForcedCross.MarketCrossTicks);
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgePriceBasedCrossTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.TicksAwayCross };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_price_based_cross(leg_tup).TicksThreshold = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_price_based_cross(leg_tup) is PostHedgePriceBasedForcedCross price_based_cross ?
price_based_cross.TicksThreshold :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_price_based_cross(leg_tup) is PostHedgePriceBasedForcedCross price_based_cross)
price_based_cross.TicksThreshold = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_price_based_cross(leg_tup) != null;
PostHedgePriceBasedForcedCross _get_price_based_cross(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.PriceBasedCross;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PostHedgePriceBasedForcedCross.TicksThreshold);
}
}
}
@@ -1,36 +0,0 @@
using bts.shell;
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgeTimeBasedCrossEnabledModel : RowModelBase<bool> {
readonly PostHedgeTimeBasedCrossTimeModel _time;
readonly PostHedgeTimeBasedCrossMarketTicksModel _market_cross_ticks;
public PostHedgeTimeBasedCrossEnabledModel(PostHedgeTimeBasedCrossTimeModel time, PostHedgeTimeBasedCrossMarketTicksModel market_cross_ticks) {
_time = time;
_market_cross_ticks = market_cross_ticks;
}
public override string display_name { get; } = string.Empty;
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.TimeBasedCross };
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.TimeBasedForcedCross != null;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
if (value) {
if (leg_tup.leg_params.PostHedgeParams.TimeBasedForcedCross == null) {
leg_tup.leg_params.PostHedgeParams.TimeBasedForcedCross = SyntheticDataHelper.Defaults.PostHedgeTimeBasedForcedCross;
_time.apply_value(leg_tup);
_market_cross_ticks.apply_value(leg_tup);
}
} else {
leg_tup.leg_params.PostHedgeParams.TimeBasedForcedCross = null;
}
_time.set_enabled(leg_tup, value);
_market_cross_ticks.set_enabled(leg_tup, value);
}
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgeTimeBasedCrossMarketTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Cross Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.TimeBasedCross };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_time_based_cross(leg_tup).MarketCrossTicks = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_time_based_cross(leg_tup) is PostHedgeTimeBasedForcedCross time_based_cross ?
time_based_cross.MarketCrossTicks :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_time_based_cross(leg_tup) is PostHedgeTimeBasedForcedCross time_based_cross)
time_based_cross.MarketCrossTicks = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_time_based_cross(leg_tup) != null;
PostHedgeTimeBasedForcedCross _get_time_based_cross(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.TimeBasedForcedCross;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PostHedgeTimeBasedForcedCross.MarketCrossTicks);
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PostHedgeTimeBasedCrossTimeModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Time(ms)";
public override ParameterSection[] section_path { get; } = new[] { Sections.PostHedge, Subsections.TimeBasedCross };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_time_based_cross(leg_tup).TimeInMsThreshold = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_time_based_cross(leg_tup) is PostHedgeTimeBasedForcedCross time_based_cross ?
time_based_cross.TimeInMsThreshold :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_time_based_cross(leg_tup) is PostHedgeTimeBasedForcedCross time_based_cross)
time_based_cross.TimeInMsThreshold = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_time_based_cross(leg_tup) != null;
PostHedgeTimeBasedForcedCross _get_time_based_cross(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PostHedgeParams.TimeBasedForcedCross;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PostHedgeTimeBasedForcedCross.TimeInMsThreshold);
}
}
}
@@ -1,16 +0,0 @@
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class MaxTicksInsideMarketModel : RowModelBase<uint> {
public override string display_name { get; } = "Max Inside Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.PreHedge };
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PreHedgeParams.MaxPriceFromInsideMarket.HedgeTickLimit;
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) =>
leg_tup.leg_params.PreHedgeParams.MaxPriceFromInsideMarket.HedgeTickLimit = value;
}
}
}
@@ -1,36 +0,0 @@
using bts.shell;
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PreHedgePaylessEnabledModel : RowModelBase<bool> {
readonly PreHedgePaylessThresholdModel _threshold;
readonly PreHedgePaylessTicksModel _ticks;
public PreHedgePaylessEnabledModel(PreHedgePaylessThresholdModel threshold, PreHedgePaylessTicksModel ticks) {
_threshold = threshold;
_ticks = ticks;
}
public override string display_name { get; } = string.Empty;
public override ParameterSection[] section_path { get; } = new[] { Sections.PreHedge, Subsections.Payless };
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PreHedgeParams.QuantityBasedPaylessTicks != null;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
if (value) {
if (leg_tup.leg_params.PreHedgeParams.QuantityBasedPaylessTicks == null) {
leg_tup.leg_params.PreHedgeParams.QuantityBasedPaylessTicks = SyntheticDataHelper.Defaults.PreHedgeQuantityBasedPayLessTicks;
_threshold.apply_value(leg_tup);
_ticks.apply_value(leg_tup);
}
} else {
leg_tup.leg_params.PreHedgeParams.QuantityBasedPaylessTicks = null;
}
_threshold.set_enabled(leg_tup, value);
_ticks.set_enabled(leg_tup, value);
}
}
}
}
@@ -1,41 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PreHedgePaylessThresholdModel : RowModelBase<QuantityMeasure> {
IDictionary<uint, QuantityMeasure> _value_store = new Dictionary<uint, QuantityMeasure>();
public override string display_name { get; } = "Threshold";
public override ParameterSection[] section_path { get; } = new[] { Sections.PreHedge, Subsections.Payless };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_payless_ticks(leg_tup).QuantityThreshold = _value_from_store(leg_tup);
public override QuantityMeasure get_value(LegSpreaderParamsTuple leg_tup) =>
_get_payless_ticks(leg_tup) is PreHedgeQuantityBasedPayLessTicks payless_ticks ?
payless_ticks.QuantityThreshold :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, QuantityMeasure value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_payless_ticks(leg_tup) is PreHedgeQuantityBasedPayLessTicks payless_ticks)
payless_ticks.QuantityThreshold = value;
}
public override ICell create_cell(LegSpreaderParamsTuple leg_tup) => new QuantityMeasureCell(this, leg_tup);
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_payless_ticks(leg_tup) != null;
PreHedgeQuantityBasedPayLessTicks _get_payless_ticks(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PreHedgeParams.QuantityBasedPaylessTicks;
QuantityMeasure _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PreHedgeQuantityBasedPayLessTicks.QuantityThreshold);
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PreHedgePaylessTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Payless Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.PreHedge, Subsections.Payless };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_payless_ticks(leg_tup).PaylessTicks = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_payless_ticks(leg_tup) is PreHedgeQuantityBasedPayLessTicks payless_ticks ?
payless_ticks.PaylessTicks :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_payless_ticks(leg_tup) is PreHedgeQuantityBasedPayLessTicks payless_ticks)
payless_ticks.PaylessTicks = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_payless_ticks(leg_tup) != null;
PreHedgeQuantityBasedPayLessTicks _get_payless_ticks(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PreHedgeParams.QuantityBasedPaylessTicks;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PreHedgeQuantityBasedPayLessTicks.PaylessTicks);
}
}
}
@@ -1,36 +0,0 @@
using bts.shell;
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PreHedgePayupEnabledModel : RowModelBase<bool> {
readonly PreHedgePayupThresholdModel _threshold;
readonly PreHedgePayupTicksModel _ticks;
public PreHedgePayupEnabledModel(PreHedgePayupThresholdModel threshold, PreHedgePayupTicksModel ticks) {
_threshold = threshold;
_ticks = ticks;
}
public override string display_name { get; } = string.Empty;
public override ParameterSection[] section_path { get; } = new[] { Sections.PreHedge, Subsections.Payup };
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PreHedgeParams.QuantityBasedPayupTicks != null;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
if (value) {
if (leg_tup.leg_params.PreHedgeParams.QuantityBasedPayupTicks == null) {
leg_tup.leg_params.PreHedgeParams.QuantityBasedPayupTicks = SyntheticDataHelper.Defaults.PreHedgeQuantityBasedPayUpTicks;
_threshold.apply_value(leg_tup);
_ticks.apply_value(leg_tup);
}
} else {
leg_tup.leg_params.PreHedgeParams.QuantityBasedPayupTicks = null;
}
_threshold.set_enabled(leg_tup, value);
_ticks.set_enabled(leg_tup, value);
}
}
}
}
@@ -1,41 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PreHedgePayupThresholdModel : RowModelBase<QuantityMeasure> {
IDictionary<uint, QuantityMeasure> _value_store = new Dictionary<uint, QuantityMeasure>();
public override string display_name { get; } = "Threshold";
public override ParameterSection[] section_path { get; } = new[] { Sections.PreHedge, Subsections.Payup };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_payup_ticks(leg_tup).QuantityThreshold = _value_from_store(leg_tup);
public override QuantityMeasure get_value(LegSpreaderParamsTuple leg_tup) =>
_get_payup_ticks(leg_tup) is PreHedgeQuantityBasedPayupTicks payup_ticks ?
payup_ticks.QuantityThreshold :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, QuantityMeasure value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_payup_ticks(leg_tup) is PreHedgeQuantityBasedPayupTicks payup_ticks)
payup_ticks.QuantityThreshold = value;
}
public override ICell create_cell(LegSpreaderParamsTuple leg_tup) => new QuantityMeasureCell(this, leg_tup);
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_payup_ticks(leg_tup) != null;
PreHedgeQuantityBasedPayupTicks _get_payup_ticks(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PreHedgeParams.QuantityBasedPayupTicks;
QuantityMeasure _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PreHedgeQuantityBasedPayUpTicks.QuantityThreshold);
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class PreHedgePayupTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Payup Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.PreHedge, Subsections.Payup };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_payup_ticks(leg_tup).PayupTicks = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_payup_ticks(leg_tup) is PreHedgeQuantityBasedPayupTicks payup_ticks ?
payup_ticks.PayupTicks :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_payup_ticks(leg_tup) is PreHedgeQuantityBasedPayupTicks payup_ticks)
payup_ticks.PayupTicks = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_payup_ticks(leg_tup) != null;
PreHedgeQuantityBasedPayupTicks _get_payup_ticks(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.PreHedgeParams.QuantityBasedPayupTicks;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.PreHedgeQuantityBasedPayUpTicks.PayupTicks);
}
}
}
@@ -1,36 +0,0 @@
using bts.shell;
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class QuoteInsideMarketThrottleEnabledModel : RowModelBase<bool> {
readonly QuoteInsideMarketThrottleTicksModel _ticks;
readonly QuoteInsideMarketThrottleMinMoveModel _min_move;
public QuoteInsideMarketThrottleEnabledModel(QuoteInsideMarketThrottleTicksModel ticks, QuoteInsideMarketThrottleMinMoveModel min_move) {
_ticks = ticks;
_min_move = min_move;
}
public override string display_name { get; } = string.Empty;
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.InsideMarketThrottleThresholds };
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.QuoteParams.QuoteInsideMarketDistanceWithTravel != null;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
if (value) {
if (leg_tup.leg_params.QuoteParams.QuoteInsideMarketDistanceWithTravel == null) {
leg_tup.leg_params.QuoteParams.QuoteInsideMarketDistanceWithTravel = SyntheticDataHelper.Defaults.QuoteInsideMarketDistanceWithTravel;
_ticks.apply_value(leg_tup);
_min_move.apply_value(leg_tup);
}
} else {
leg_tup.leg_params.QuoteParams.QuoteInsideMarketDistanceWithTravel = null;
}
_ticks.set_enabled(leg_tup, value);
_min_move.set_enabled(leg_tup, value);
}
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class QuoteInsideMarketThrottleMinMoveModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Min Move";
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.InsideMarketThrottleThresholds };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_inside_market_throttle(leg_tup).Limit = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_inside_market_throttle(leg_tup) is QuoteInsideMarketDistanceWithTravel inside_market_throttle ?
inside_market_throttle.Limit :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_inside_market_throttle(leg_tup) is QuoteInsideMarketDistanceWithTravel inside_market_throttle)
inside_market_throttle.Limit = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_inside_market_throttle(leg_tup) != null;
QuoteInsideMarketDistanceWithTravel _get_inside_market_throttle(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.QuoteParams.QuoteInsideMarketDistanceWithTravel;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.QuoteInsideMarketDistanceWithTravel.Limit);
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class QuoteInsideMarketThrottleTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.InsideMarketThrottleThresholds };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_inside_market_throttle(leg_tup).TicksFromInside = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_inside_market_throttle(leg_tup) is QuoteInsideMarketDistanceWithTravel inside_market_throttle ?
inside_market_throttle.TicksFromInside :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_inside_market_throttle(leg_tup) is QuoteInsideMarketDistanceWithTravel inside_market_throttle)
inside_market_throttle.TicksFromInside = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_inside_market_throttle(leg_tup) != null;
QuoteInsideMarketDistanceWithTravel _get_inside_market_throttle(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.QuoteParams.QuoteInsideMarketDistanceWithTravel;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.QuoteInsideMarketDistanceWithTravel.TicksFromInside);
}
}
}
@@ -1,36 +0,0 @@
using bts.shell;
using mbts.ui.spark;
namespace mbts.spark {
partial class SyntheticEditorVM {
class QuoteThrottleEnabledModel : RowModelBase<bool> {
readonly QuoteThrottleInsideTicksModel _inside_ticks;
readonly QuoteThrottleOutsideTicksModel _outside_ticks;
public QuoteThrottleEnabledModel(QuoteThrottleInsideTicksModel inside_ticks, QuoteThrottleOutsideTicksModel outside_ticks) {
_inside_ticks = inside_ticks;
_outside_ticks = outside_ticks;
}
public override string display_name { get; } = string.Empty;
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.Throttle };
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.QuoteParams.QuoteMuteZone != null;
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
if (value) {
if (leg_tup.leg_params.QuoteParams.QuoteMuteZone == null) {
leg_tup.leg_params.QuoteParams.QuoteMuteZone = SyntheticDataHelper.Defaults.QuoteMuteZone;
_inside_ticks.apply_value(leg_tup);
_outside_ticks.apply_value(leg_tup);
}
} else {
leg_tup.leg_params.QuoteParams.QuoteMuteZone = null;
}
_inside_ticks.set_enabled(leg_tup, value);
_outside_ticks.set_enabled(leg_tup, value);
}
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class QuoteThrottleInsideTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Inside Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.Throttle };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_throttle(leg_tup).InsideTicks = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_throttle(leg_tup) is QuoteMuteZone throttle ?
throttle.InsideTicks :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_throttle(leg_tup) is QuoteMuteZone throttle)
throttle.InsideTicks = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_throttle(leg_tup) != null;
QuoteMuteZone _get_throttle(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.QuoteParams.QuoteMuteZone;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.QuoteMuteZone.InsideTicks);
}
}
}
@@ -1,39 +0,0 @@
using bts.shell;
using bts.spark;
using mbts.collections.extensions;
using mbts.ui.spark;
using System.Collections.Generic;
namespace mbts.spark {
partial class SyntheticEditorVM {
class QuoteThrottleOutsideTicksModel : RowModelBase<uint> {
IDictionary<uint, uint> _value_store = new Dictionary<uint, uint>();
public override string display_name { get; } = "Outside Ticks";
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.Throttle };
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
_get_throttle(leg_tup).OutsideTicks = _value_from_store(leg_tup);
public override uint get_value(LegSpreaderParamsTuple leg_tup) =>
_get_throttle(leg_tup) is QuoteMuteZone throttle ?
throttle.OutsideTicks :
_value_from_store(leg_tup);
public override void set_value(LegSpreaderParamsTuple leg_tup, uint value) {
_value_store[leg_tup.SecurityKey] = value;
if (_get_throttle(leg_tup) is QuoteMuteZone throttle)
throttle.OutsideTicks = value;
}
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
_get_throttle(leg_tup) != null;
QuoteMuteZone _get_throttle(LegSpreaderParamsTuple leg_tup) =>
leg_tup.leg_params.QuoteParams.QuoteMuteZone;
uint _value_from_store(LegSpreaderParamsTuple leg_tup) =>
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.QuoteMuteZone.OutsideTicks);
}
}
}
@@ -1,134 +0,0 @@
using mbts.ui.shell;
using mbts.ui.spark;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Reactive.Subjects;
namespace mbts.spark {
partial class SyntheticEditorVM {
internal interface IRowModel {
string display_name { get; }
bool read_only { get; }
ParameterSection[] section_path { get; }
bool has_errors(IReadOnlyCollection<LegSpreaderParamsTuple> leg_tups);
object get_value(LegSpreaderParamsTuple leg_tup);
void set_value(LegSpreaderParamsTuple leg_tup, object value);
void override_value(LegSpreaderParamsTuple leg_tup, object value);
void set_enabled(LegSpreaderParamsTuple leg_tup, bool enabled);
ICell create_cell(LegSpreaderParamsTuple leg_tup);
IObservable<object> observe_override_value(LegSpreaderParamsTuple leg_tup);
IObservable<bool> observe_enabled(LegSpreaderParamsTuple leg_tup);
}
internal interface IRowModel<T> : IRowModel {
new T get_value(LegSpreaderParamsTuple leg_tup);
void set_value(LegSpreaderParamsTuple leg_tup, T value);
void override_value(LegSpreaderParamsTuple leg_tup, T value);
new IObservable<T> observe_override_value(LegSpreaderParamsTuple leg_tup);
}
internal interface ICell {
event Action value_changed;
Type data_type { get; }
bool enabled { get; }
}
abstract class RowModelBase<T> : ViewModelBase, IRowModel {
readonly Dictionary<uint, ReplaySubject<bool>> _enabled_store = new Dictionary<uint, ReplaySubject<bool>>();
readonly Dictionary<uint, Subject<T>> _override_value_store = new Dictionary<uint, Subject<T>>();
protected RowModelBase() { }
public abstract string display_name { get; }
public virtual bool read_only { get; } = false;
public virtual ParameterSection[] section_path { get; } = new ParameterSection[0];
public virtual bool has_errors(IReadOnlyCollection<LegSpreaderParamsTuple> leg_tups) => false;
public abstract T get_value(LegSpreaderParamsTuple leg_tup);
public abstract void set_value(LegSpreaderParamsTuple leg_tup, T value);
public virtual ICell create_cell(LegSpreaderParamsTuple leg_tup) => new Cell<T>(this, leg_tup);
public void set_enabled(LegSpreaderParamsTuple leg_tup, bool enabled) =>
_enabled_store.GetOrAdd(leg_tup.SecurityKey, sec => new ReplaySubject<bool>(1)).OnNext(enabled);
public void override_value(LegSpreaderParamsTuple leg_tup, T value) {
if (_override_value_store.TryGetValue(leg_tup.SecurityKey, out Subject<T> subject))
subject.OnNext(value);
}
public IObservable<bool> observe_enabled(LegSpreaderParamsTuple leg_tup) =>
_enabled_store.GetOrAdd(leg_tup.leg.Security.Id, sec => {
var rs = new ReplaySubject<bool>(1);
rs.OnNext(_get_enabled(leg_tup));
return rs;
});
public IObservable<T> observe_override_value(LegSpreaderParamsTuple leg_tup) =>
_override_value_store.GetOrAdd(leg_tup.leg.Security.Id, sec => new Subject<T>());
protected virtual bool _get_enabled(LegSpreaderParamsTuple leg_tup) => true;
#region IRowModel (explicit)
object IRowModel.get_value(LegSpreaderParamsTuple leg_tup) => get_value(leg_tup);
void IRowModel.set_value(LegSpreaderParamsTuple leg_tup, object value) {
T tval = ExceptionAssert.Argument.Is<T>(value, nameof(value));
set_value(leg_tup, tval);
}
void IRowModel.override_value(LegSpreaderParamsTuple leg_tup, object value) {
T tval = ExceptionAssert.Argument.Is<T>(value, nameof(value));
override_value(leg_tup, tval);
}
IObservable<object> IRowModel.observe_override_value(LegSpreaderParamsTuple leg_tup) =>
(IObservable<object>)observe_override_value(leg_tup);
#endregion
}
private static class Sections {
public static ParameterSection Quote => new ParameterSection("Quote");
public static ParameterSection PreHedge => new ParameterSection("Pre-Hedge");
public static ParameterSection PostHedge => new ParameterSection("Post-Hedge");
}
private static class Subsections {
public static ParameterSection Throttle =>
new ParameterSection("Throttle", true,
"reduces re-quoting updates by defining a region on either side " +
"of the working quoting order, inside which quote updates will not be sent.");
public static ParameterSection InsideMarketThrottleThresholds =>
new ParameterSection("Inside Market Throttle Thresholds", true,
"reduces re-quoting for quotes that are moving toward the inside market. " +
"Orders moving toward the inside market are not re-quoted if:\n\n" +
"i. New order is more than 'Ticks' away from the inside market or\n" +
"ii. New order has not moved 'Min Move' away from the current price");
public static ParameterSection Payless =>
new ParameterSection("Pay Less", true,
"when the quantity at the level of the calculated hedge price is more than " +
"'Threshold,' the hedge order is paid less by 'Payless Ticks.'");
public static ParameterSection Payup =>
new ParameterSection("Pay Up", true,
"when the quantity at the level of the calculated hedge price is less than " +
"'Threshold,' then the hedge order is paid up by 'Payup Ticks.'");
public static ParameterSection TicksAwayCross =>
new ParameterSection("Ticks Away Cross", true,
"forces legged hedging orders to automatically cross the market if they get too " +
"far away from the opposite inside market.If a legged hedge order's price gets 'Ticks' away " +
"from the opposite inside market, it is re-priced to cross the opposite inside market by 'Cross Ticks.'");
public static ParameterSection TimeBasedCross =>
new ParameterSection("Time Based Cross", true,
"forces legged hedge orders to automatically cross the market, if they are still " +
"working beyond a certain time period.If a hedge order is legged for 'Time(ms)', " +
"it is re-priced to cross the opposite inside market by 'Cross Ticks.'");
public static ParameterSection OppositeMarketVolumeBasedCross =>
new ParameterSection("Size Based Cross", true,
"forces legged hedging orders to automatically cross the market if the volume " +
"of the opposite inside market drops below the threhold. If opposite inside market volume drops below 'Threshold,' " +
"it is re-priced to cross the opposite inside market by 'Cross Ticks.'");
}
}
}
@@ -1,51 +0,0 @@
using bts.api;
using mbts.collections;
using mbts.ui.controls;
using mbts.ui.spark;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace mbts.spark {
partial class SyntheticEditorVM {
public interface IParameterRowVM {
string display_name { get; }
bool read_only { get; }
ParameterSection[] section_path { get; }
}
internal class RowVM : DataGridExRow<Security>, IParameterRowVM, IDisposable {
readonly ObservantDictionary<Security, ICell, LegSpreaderParamsTuple> _cells;
readonly Property<bool> _has_errors;
public RowVM(IRowModel model, ObservableCollection<LegSpreaderParamsTuple> legs) {
display_name = model.display_name;
section_path = model.section_path;
for (int i = 0; i < section_count; i++)
section_path[i].level = i;
read_only = model.read_only;
_has_errors = backing(nameof(has_errors), false);
_cells = ObservantDictionary.Create(legs, l => l.leg.Security, model.create_cell, EqualityComparer.Create<Security, uint>(s => s.Id));
_cells.ValueDestroyed += c => (c as IDisposable)?.Dispose();
foreach (var c in _cells.Values) c.value_changed += () => _has_errors.set(model.has_errors(legs));
}
public string display_name { get; }
public ParameterSection[] section_path { get; }
public int section_count => section_path.Length;
public bool read_only { get; }
public bool has_errors => _has_errors.Value;
public override object get_cell(Security col_key) =>
_cells.TryGetValue(col_key, out ICell value) ? value : null;
public ParameterSection this[string section_no] =>
int.TryParse(section_no, out int i) && i < section_path.Length ? section_path[i] : null;
public void Dispose() =>
_cells.Values.OfType<IDisposable>().DisposeAll();
}
}
}
@@ -1,340 +0,0 @@
using bts.api;
using bts.shell;
using bts.spark;
using mbts.ui;
using mbts.ui.shell;
using mbts.ui.spark;
using mbts.ui.utility;
using mbts.user.settings;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
namespace mbts.spark {
/// <summary>
/// The view model designed to serve as the DataContext for the SyntheticEditorView
/// </summary>
partial class SyntheticEditorVM : DisposableViewModelBase, IRequestViewClose, IRequestBindingSourceUpdate, IDisposable {
readonly ObservableCollection<TickFactors> _available_tick_factors = new ObservableCollection<TickFactors>(TickUtils.all_present_ticks());
readonly QuantityModel _quantity_model;
readonly PriceMultiplierModel _price_mult_model;
readonly List<IDisposable> _resources = new List<IDisposable>();
readonly Property<bool> _has_working_orders, _can_add_leg;
Security _synthetic;
bool _set_name_automatically, _set_ticks_automatically, _set_quantities_automatically, _set_price_mults_automatically, _is_setting_quantities, _is_setting_price_mults;
TickFactors _tick_factors;
ExecutionStrategyImmutable _strategy;
/// <summary>
/// Inititalizes a new instance of SyntheticEditorVM class. This constructor may only be used for already-existing synthetic securities (id must be non-zero).
/// </summary>
/// <param name="synthetic">The already-existing synthetic security who's strategy may be modified</param>
/// <param name="strategy">The already-existing strategy that may be modified</param>
public SyntheticEditorVM(SpreaderModel model, SecurityImmutable synthetic, ExecutionStrategyImmutable strategy, IObservable<bool> security_has_working_orders)
: this(synthetic, strategy, false) {
ExceptionAssert.InvalidOperation.That(synthetic.Id != 0, "This constructor may only be used for already-existing synthetic securities (id must be non-zero).");
_tick_factors = TickUtils.get_regional_ticks(synthetic.ContractSpec).low_tick;
title = $"Edit '{synthetic.Synthetic.Name}'";
icon = Icons.ModifySynthetic;
_has_working_orders = backing(nameof(has_working_orders), security_has_working_orders.ObserveOnDispatcher());
var commit = new ObservantAsyncCommand(commit_async);
_resources.Add(security_has_working_orders.Select(v => !v).ObserveOnDispatcher().Subscribe(commit));
_resources.Add(_has_working_orders.ObserveOnDispatcher().Subscribe(vals => {
if (vals.newval)
set_error(nameof(has_working_orders), "Security has working orders");
else clear_error(nameof(has_working_orders));
}));
this.commit = commit;
async Task commit_async() {
await model.save_strategy(_synthetic.Id, get_strategy());
RequestClose?.Invoke(this, new EventArgs());
}
}
/// <summary>
/// Initializes a new instance of SyntheticEditorVM class. This constructor may only be used for new synthetic securities (id must be zero).
/// </summary>
/// <param name="bus">The application bus</param>
/// <param name="synthetic">The new synthetic security to create, or existing synthetic security who's strategy to modify, on commit</param>
/// <param name="strategy">The new strategy to create, or existing strategy to modify, on commit</param>
public SyntheticEditorVM(IBus bus, SpreaderModel model, SecurityImmutable synthetic, ExecutionStrategyImmutable strategy, bool override_auto_set_behavior = false)
: this (synthetic, strategy, true) {
ExceptionAssert.InvalidOperation.That(synthetic.Id == 0, "This constructor may only be used for new synthetic securities (id must be zero).");
title = "Create Synthetic";
icon = Icons.Synthetics;
_has_working_orders = backing(nameof(has_working_orders), false);
contract_picker_model = new ContractPickerModel(bus, false, null, new SecurityCriteria(new[] {
new SecurityCriteriaClause() {
exchanges = EnumHelper.get_values_except(Venue.Bts).ToLArray()
}
}));
contract_picker_model.cancel_action = _close_new_leg_popup;
contract_picker_model.ok_action = () => {
if (!leg_tuples.Any(l => l.leg.Security.Id == contract_picker_model.result.security.Id)) {
leg_tuples.Add(new LegSpreaderParamsTuple(
SyntheticDataHelper.Defaults.ContractLeg(contract_picker_model.result.security),
SyntheticDataHelper.Defaults.LegSpreaderParams
));
_close_new_leg_popup();
}
};
remove_leg = new DelegateCommand<Security>(s => leg_tuples.removeFirst(l => l.leg.Security.Id == s.Id));
commit = new AsyncCommand(commit_async, () => leg_count >= 2);
if (override_auto_set_behavior) {
_set_name_automatically = false;
_set_ticks_automatically = false;
_set_quantities_automatically = false;
_set_price_mults_automatically = false;
_tick_factors = TickUtils.get_regional_ticks(_synthetic.ContractSpec).low_tick;
} else {
_deduce_name();
_deduce_ticks();
_deduce_quantities();
_deduce_price_mults();
}
_validate_leg_count();
leg_tuples.CollectionChanged += (s, e) => {
if (_set_name_automatically) _deduce_name();
if (_set_ticks_automatically) _deduce_ticks();
if (_set_quantities_automatically) _deduce_quantities();
if (_set_price_mults_automatically) _deduce_price_mults();
commit.RaiseCanExecuteChanged();
_validate_leg_count();
};
async Task commit_async(){
RequestUpdate?.Invoke();
bool valid = true;
if (string.IsNullOrWhiteSpace(name)) {
flash_error_msg("Please enter a name", SparkUtils.UI.MessageFlashDuration, nameof(name)).ignore();
valid = false;
} else if (!await model.verify_name_is_unique(name)) {
flash_error_msg("Name already taken", SparkUtils.UI.MessageFlashDuration, nameof(name)).ignore();
valid = false;
}
if (_tick_factors == null || !_tick_factors.is_valid() || !_available_tick_factors.Contains(_tick_factors)) {
flash_error_msg("Please select ticks", SparkUtils.UI.MessageFlashDuration, nameof(tick_factors)).ignore();
valid = false;
}
if (valid) {
_synthetic.Synthetic.Legs.Clear();
_synthetic.Synthetic.Legs.AddRange(leg_tuples.Select(l => l.leg).OrderBy(l => l.Security, SecurityHelper.Comparer.Instance));
_synthetic.Symbol = _deduce_symbol(_synthetic);
double tick_frac = _tick_factors.tick_unit / _tick_factors.tick_base;
_synthetic.ContractSpec.LowTick = tick_frac;
_synthetic.ContractSpec.HighTick = tick_frac;
_synthetic.ContractSpec.PriceBreak = double.MaxValue;
uint? id = await model.create_synthetic(_synthetic);
if (id.HasValue && id != 0) {
if (await model.save_strategy(id.Value, get_strategy())) {
var (smd, success) = await SparkUtils.get_security_md_async(bus, id.Value);
if (success)
bus.post(SparkTags.ShowLadderTag, smd);
}
RequestClose?.Invoke(this, new EventArgs());
}
}
}
}
SyntheticEditorVM(SecurityImmutable synthetic, ExecutionStrategyImmutable strategy, bool is_new) {
this.is_new = is_new;
_set_name_automatically = is_new;
_set_ticks_automatically = is_new;
_set_quantities_automatically = is_new;
_set_price_mults_automatically = is_new;
available_tick_factors_view = CollectionViewSource.GetDefaultView(_available_tick_factors);
available_tick_factors_view.GroupDescriptions.Add(new PropertyGroupDescription(nameof(TickFactors.tick_base)));
_quantity_model = new QuantityModel(!is_new);
_price_mult_model = new PriceMultiplierModel(!is_new);
if (is_new) {
_quantity_model.quantity_changed += () => {
if (_set_name_automatically) _deduce_name();
if (!_is_setting_quantities) {
_set_quantities_automatically = false;
_set_price_mults_automatically = false;
}
_is_setting_quantities = false;
};
_price_mult_model.price_mult_changed += () => {
if (!_is_setting_price_mults) {
_set_price_mults_automatically = false;
_set_quantities_automatically = false;
}
_is_setting_price_mults = false;
};
_can_add_leg = backing(nameof(can_add_leg), leg_tuples.ObserveSelf().Select(_ => leg_count < 2), leg_count < 2);
} else {
_can_add_leg = backing(nameof(can_add_leg), false);
}
var quote_throttle_outside_ticks = new QuoteThrottleOutsideTicksModel();
var quote_throttle_inside_ticks = new QuoteThrottleInsideTicksModel();
var quote_inside_market_throttle_ticks = new QuoteInsideMarketThrottleTicksModel();
var quote_inside_market_throttle_min_move = new QuoteInsideMarketThrottleMinMoveModel();
var pre_hedge_payless_threshold = new PreHedgePaylessThresholdModel();
var pre_hedge_payless_ticks = new PreHedgePaylessTicksModel();
var pre_hedge_payup_threshold = new PreHedgePayupThresholdModel();
var pre_hedge_payup_ticks = new PreHedgePayupTicksModel();
var post_hedge_price_based_cross_ticks = new PostHedgePriceBasedCrossTicksModel();
var post_hedge_price_based_cross_market_ticks = new PostHedgePriceBasedCrossMarketTicksModel();
var post_hedge_time_based_cross_ticks = new PostHedgeTimeBasedCrossMarketTicksModel();
var post_hedge_time_based_cross_time = new PostHedgeTimeBasedCrossTimeModel();
var post_hedge_opposite_market_based_cross_threshold = new PostHedgeOppositeMarketVolumeBasedCrossThresholdModel();
var post_hedge_opposite_market_based_cross_cross_ticks = new PostHedgeOppositeMarketVolumeBasedCrossCrossTicksModel();
rows = new IRowModel[] {
_quantity_model,
_price_mult_model,
new IsQuoteModel(),
new HedgeRatioModel(),
new QuoteThrottleEnabledModel(quote_throttle_inside_ticks, quote_throttle_outside_ticks),
quote_throttle_inside_ticks,
quote_throttle_outside_ticks,
//new QuoteInsideMarketThrottleEnabledModel(quote_inside_market_throttle_ticks, quote_inside_market_throttle_min_move),
//quote_inside_market_throttle_ticks,
//quote_inside_market_throttle_min_move,
//new MaxTicksInsideMarketModel(),
new PreHedgePaylessEnabledModel(pre_hedge_payless_threshold, pre_hedge_payless_ticks),
pre_hedge_payless_threshold,
pre_hedge_payless_ticks,
new PreHedgePayupEnabledModel(pre_hedge_payup_threshold, pre_hedge_payup_ticks),
pre_hedge_payup_threshold,
pre_hedge_payup_ticks,
new PostHedgePriceBasedCrossEnabledModel(post_hedge_price_based_cross_ticks, post_hedge_price_based_cross_market_ticks),
post_hedge_price_based_cross_ticks,
post_hedge_price_based_cross_market_ticks,
new PostHedgeTimeBasedCrossEnabledModel(post_hedge_time_based_cross_time, post_hedge_time_based_cross_ticks),
post_hedge_time_based_cross_time,
post_hedge_time_based_cross_ticks,
new PostHedgeOppositeMarketVolumeBasedCrossEnabledModel(post_hedge_opposite_market_based_cross_threshold, post_hedge_opposite_market_based_cross_cross_ticks),
post_hedge_opposite_market_based_cross_threshold,
post_hedge_opposite_market_based_cross_cross_ticks
}.Select(m => new RowVM(m, leg_tuples)).ToList();
set_synthetic(synthetic, strategy);
}
public event EventHandler RequestClose;
public event Action RequestUpdate;
public string title { get; }
public ImageSource icon { get; }
public string name {
get => _synthetic.Synthetic.Name;
set {
_synthetic.Synthetic.Name = value;
_set_name_automatically = false;
RaisePropertyChanged();
}
}
public TickFactors tick_factors {
get => _tick_factors;
set {
_tick_factors = value;
_set_ticks_automatically = false;
RaisePropertyChanged();
}
}
public bool has_working_orders => _has_working_orders.Value;
public bool is_new { get; }
public bool is_new_leg_popup_open { get; set; }
public bool can_add_leg => _can_add_leg.Value;
public SyntheticContract.Types.PriceCalc price_calc { get => _synthetic.Synthetic.PriceCalc; set => _synthetic.Synthetic.PriceCalc = value; }
public ObservableCollection<LegSpreaderParamsTuple> leg_tuples { get; } = new ObservableCollection<LegSpreaderParamsTuple>();
public int leg_count => leg_tuples.Count;
public IReadOnlyCollection<RowVM> rows { get; }
public IRaiseCanExecuteChangedCommand commit { get; }
public ICommand remove_leg { get; }
public ContractPickerModel contract_picker_model { get; }
public ICollectionView available_tick_factors_view { get; }
public ExecutionStrategyImmutable get_strategy() {
var mutable_strategy = _strategy.CloneToMutable();
mutable_strategy.LegParamsMap.Clear();
foreach (var lt in leg_tuples) mutable_strategy.LegParamsMap.Add(lt.leg.Security.Id, lt.leg_params);
return new ExecutionStrategyImmutable(mutable_strategy);
}
public void set_synthetic(SecurityImmutable synthetic, ExecutionStrategyImmutable strategy) {
_synthetic = synthetic.CloneToMutable();
_synthetic.Exchange = Venue.Bts;
_strategy = strategy;
leg_tuples.SetItems(_get_legs(_synthetic, strategy));
RaisePropertyChanged(nameof(name), nameof(tick_factors));
}
protected override void Dispose(bool disposing) {
foreach (var r in rows) r.Dispose();
contract_picker_model?.Dispose();
Disposable.dispose(_resources);
base.Dispose(disposing);
}
static string _deduce_symbol(SecurityImmutable security) {
if (!string.IsNullOrWhiteSpace(security.Symbol)) return security.Symbol;
if (security.Synthetic.Legs.Count() > 0) return security.Synthetic.Legs.First().Security.Symbol;
return string.Empty;
}
static IEnumerable<LegSpreaderParamsTuple> _get_legs(Security synthetic, ExecutionStrategyImmutable strategy) =>
synthetic.Synthetic.Legs
.OrderBy(l => l.Security, SecurityHelper.Comparer.Instance)
.Select(l => new LegSpreaderParamsTuple(l, strategy.LegParamsMap[l.Security.Id].Clone()));
void _close_new_leg_popup() {
is_new_leg_popup_open = false;
RaisePropertyChanged(nameof(is_new_leg_popup_open));
}
void _deduce_name() {
_synthetic.Synthetic.Name = SecurityFormatter.format_contract_legs(leg_tuples.Select(l => new ContractLegImmutable(l.leg)));
RaisePropertyChanged(nameof(name));
}
void _deduce_price_mults() {
if (leg_tuples.Count == 2) {
_is_setting_price_mults = true;
_price_mult_model.override_value(leg_tuples[1], -1);
} else if (leg_tuples.Count == 3) {
_is_setting_price_mults = true;
_price_mult_model.override_value(leg_tuples[1], -2);
}
}
void _deduce_quantities() {
if (leg_tuples.Count == 2) {
_is_setting_quantities = true;
_quantity_model.override_value(leg_tuples[1], -1);
} else if (leg_tuples.Count == 3) {
_is_setting_quantities = true;
_quantity_model.override_value(leg_tuples[1], -2);
}
}
void _deduce_ticks() {
_tick_factors = TickUtils.deduce_ticks(leg_tuples.Select(l => l.leg.Security.ContractSpec));
if (_tick_factors != null && !_available_tick_factors.Contains(tick_factors))
_available_tick_factors.Add(_tick_factors);
RaisePropertyChanged(nameof(tick_factors));
}
void _validate_leg_count() {
if (leg_count < 2) set_error(nameof(leg_count), "Please select 2 or more legs");
else clear_error(nameof(leg_count));
}
}
}
@@ -1,107 +0,0 @@
using bts.api;
using bts.shell;
using bts.spark;
using mbts.spark.filters;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
using static bts.shell.SyntheticManagementWindowFactory;
namespace mbts.spark {
class SyntheticManagementDialogVM : SecurityMDGrid<SyntheticManagementDialogVM.Row, (ExecutionStrategyImmutable? strategy, SecurityMD md)> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
public SyntheticManagementDialogVM(IBus bus, OrdersModel orders_model) : this(bus, orders_model, null, null) { }
public SyntheticManagementDialogVM(IBus bus, OrdersModel orders_model, IReadOnlyCollection<SortingCriteria> sorting, FilterStates filters)
: base(orders_model.spreader.strategy_tuple.Select(map => map.Values), sorting) {
_bus = bus;
_orders_model = orders_model;
if (filters != null) {
create_time_filter.load_state(filters.create_time);
name_filter.load_state(filters.name);
description_filter.load_state(filters.description);
n_legs_filter.load_state(filters.n_legs);
n_working_orders_filter.load_state(filters.n_working_orders);
}
_dispose = DataGridFilterHelper.hook_filters(rows_view, create_time_filter, name_filter, description_filter, n_legs_filter, n_working_orders_filter);
}
protected override Row row_factory((ExecutionStrategyImmutable? strategy, SecurityMD md) row_model) =>
new Row(_bus, row_model.md, row_model.strategy, _orders_model);
protected override void on_row_removed(Row row) => row.Dispose();
#region Filters
public IDataGridColumnPersistentFilter<Row, TimeFilterTuple> create_time_filter { get; } = new TimeFilterVM<Row>(r => r.create_time, nameof(Row.create_time));
public IDataGridColumnPersistentFilter<Row, string> name_filter { get; } = new RegexFilterVM<Row>(r => r.name, nameof(Row.name));
public IDataGridColumnPersistentFilter<Row, string> description_filter { get; } = new RegexFilterVM<Row>(r => r.description, nameof(Row.description));
public IDataGridColumnPersistentFilter<Row, IntMinMaxState> n_legs_filter { get; } = new IntMinMax<Row>(r => r.n_legs, nameof(Row.n_legs));
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> n_working_orders_filter { get; } = new UIntMinMax<Row>(r => r.n_working_orders, nameof(Row.n_legs));
public FilterStates get_filter_states() =>
new FilterStates {
description = description_filter.get_state(),
create_time = create_time_filter.get_state(),
name = name_filter.get_state(),
n_legs = n_legs_filter.get_state(),
n_working_orders = n_working_orders_filter.get_state()
};
#endregion
public class Row : SecurityMDRow, IEquatable<Row> {
public readonly ExecutionStrategyImmutable? strategy;
readonly IBus _bus;
readonly Property<uint> _n_working_orders;
public Row(IBus bus, SecurityMD security_md, ExecutionStrategyImmutable? strategy, OrdersModel orders_model) : base(security_md) {
_bus = bus;
this.strategy = strategy;
_n_working_orders = backing(nameof(n_working_orders),
orders_model.on_security_orders(security_key)
.Select(t => (uint)(t.state
.Where(kv => kv.Value.is_active())
.Count())
).ObserveOnDispatcher());
name = security.Synthetic.Name;
n_legs = security.Synthetic.Legs.Count();
description = SecurityFormatter.format_contract_legs(security.Synthetic.Legs);
show_ladder = new DelegateCommand(_show_ladder);
show_order_book = new DelegateCommand(_show_order_book);
}
public DateTime create_time => DateTime.MinValue; //TODO
public string name { get; }
public int n_legs { get; }
public string description { get; }
public bool strategy_present => strategy.HasValue;
public uint n_working_orders => _n_working_orders.Value;
public ICommand show_ladder { get; }
public ICommand show_order_book { get; }
public bool Equals(Row other) =>
other != null &&
other.security_key == security_key;
public override bool Equals(object obj) =>
Equals(obj as Row);
public override int GetHashCode() =>
security_key.GetHashCode();
void _show_ladder() =>
_bus.post(SparkTags.ShowLadderTag, md);
void _show_order_book() =>
_bus.post(SparkTags.ShowOrderBookTag, new OrderBookWindowFactory.OrderBookStartupData {
filters = new OrderBookWindowFactory.FilterStates {
security_criteria = new SecurityCriteria(security)
}
});
}
}
}
@@ -1,24 +0,0 @@
using mbts.ui;
using mbts.ui.controls;
using System.Collections.Generic;
using System.Windows.Media;
namespace bts.shell {
public static class ActivityLogCategory {
public static ILogViewerCategory order = new LogViewerCategory("Order", BTSColors.Orders.sent_brush);
public static ILogViewerCategory fill = new LogViewerCategory("Fill", BTSColors.Orders.filled_dark_brush);
public static ILogViewerCategory cancel = new LogViewerCategory("Cancel", BTSColors.Orders.working_cancel_brush);
public static ILogViewerCategory modify = new LogViewerCategory("Modify", BTSColors.Orders.modified_brush);
public static ILogViewerCategory warn = new LogViewerCategory("Warn", Brushes.Gold);
public static IEnumerable<ILogViewerCategory> all_categories {
get {
yield return order;
yield return fill;
yield return cancel;
yield return modify;
yield return warn;
}
}
}
}
@@ -1,49 +0,0 @@
using bts.api;
using bts.spark;
using mbts;
using mbts.ui;
using mbts.ui.controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
namespace bts.shell
{
class ActivityLogWindow : SparkWindow<ActivityWindowState>, ISharedWindow {
const string _window_type = "ActivityLog";
readonly IObservable<LogViewerMessage> _message_src;
readonly LogViewerMessageCollection _messages = new LogViewerMessageCollection();
IDisposable _dispose;
LogViewer _content;
public ActivityLogWindow(IObservable<LogViewerMessage> messages, IBus bus, ActivityWindowFactory isw)
: base("Activity Log", bus, isw, SparkCommands.ShowActivityLog.icon) {
_message_src = messages;
}
public override string window_type => _window_type;
public override ActivityWindowState SaveState => new ActivityWindowState();
public override UIElement Content => _content;
public string thread_id => nameof(ActivityLogWindow);
public override void Dispose() {
Disposable.dispose(ref _dispose);
}
public void thread_init() {
_dispose = _message_src.ObserveOnDispatcher().Subscribe(_messages.AddLog);
_content =
new LogViewer {
ItemsSource = _messages,
Categories = ActivityLogCategory.all_categories
};
}
}
}
@@ -1,48 +0,0 @@
using System;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using bts.api;
using bts.shell;
using mbts;
using mbts.spark;
using mbts.ui;
using mbts.ui.controls;
namespace bts.shell {
internal class ActivityWindowFactory : ShellWindowFactory<ActivityWindowState> {
readonly IBus _bus;
readonly IConnectableObservable<LogViewerMessage> messages;
public ActivityWindowFactory(IShellModule owner, IBus bus) : base(owner, "Activity Window") {
_bus = bus;
messages = bus.subscribe(SparkTags.LogActivity)
.Select(a => new LogViewerMessage(a.category, $"{a.security}: {a.message}"))
.Replay(512);
_dispose = Disposable.Create(
bus.subscribe(SparkTags.ShowActivityLog).Subscribe(show_log),
messages.Connect(),
messages.Subscribe(msg => Logger.info(log.Subsystem.Ui, msg.message))
);
}
public void show_log(SparkTags.Nothing _) {
_bus.post(SparkTags.ShowWindow, create_window());
}
private IShellWindow create_window() {
return new ActivityLogWindow(messages, _bus, this);
}
public override Task<IShellWindow> load(ActivityWindowState state) {
return Task.FromResult(create_window());
}
}
[ProtoBuf.ProtoContract]
class ActivityWindowState {
// nothing yet
}
}
@@ -1,54 +0,0 @@
using mbts.ui;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bts.spark;
using System.IO;
using System.Windows.Media;
using bts.api;
using mbts;
using mbts.spark;
using System.Reactive.Linq;
using static mbts.ui.shell.ProtoBufSerializationHelper;
namespace bts.shell {
[Export(typeof(IShellModule))]
class HelpShellModule : IShellModule {
IDisposable _dispose;
[ImportingConstructor]
public HelpShellModule(IBus bus, IBrowserWindowManager browser) {
_awf = new ActivityWindowFactory(this, bus);
_dispose = Disposable.Create(
bus.subscribe(SparkTags.ShowUri).ObserveOnDispatcher().Subscribe(u => browser.Pages.Add(u))
);
}
ActivityWindowFactory _awf;
public ImageSource icon => Icons.Support;
public string name => "Help";
public int priority => 50;
public IEnumerable<SparkCommand> actions => new[] {
//SparkCommands.ShowManual,
//SparkCommands.ShowAuditLogs,
//SparkCommands.ShowDiagnostics,
SparkCommands.ShowReportIssue.complete("Created from launcher"),
SparkCommands.ShowAboutSpark,
SparkCommands.ShowActivityLog
};
public Task<IShellWindow> create(Stream load_stream) {
return dispatch_to_factory(load_stream, _awf);
}
public void Dispose() {
}
}
}
@@ -1,168 +0,0 @@
using bts.api;
using bts.api.orderman;
using bts.spark;
using mbts.spark.filters;
using mbts.spark.utilities;
using mbts.ui;
using mbts.ui.utility;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Data;
using static bts.shell.FillsWindowFactory;
using static mbts.ui.controls.DIYGrid;
using static mbts.ui.spark.FillsView;
using OrderType = bts.api.orderman.CustomOrderDefinition.CustomOneofCase;
namespace mbts.spark {
class FillsVM : SecurityGrid<FillsVM.Row, FillTuple> {
readonly OrdersModel _model;
public FillsVM(IBus bus, OrdersModel model, StartupData state)
: this(bus, model, _get_observable(bus, model, state), state.sorting_criteria, state.filters) { }
FillsVM(IBus bus, OrdersModel model, IObservable<ITableUpdateTransform<FillTuple, string>> fills_source, IReadOnlyCollection<SortingCriteria> sorting_criteria, FilterStates filters)
: base(RXCollection.CreateTableUpdate(fills_source), sorting_criteria) {
_model = model;
account_filter = DiscreteValuesFilterVM.Create<Row, string>(_model.factory.subscribe_accounts(), r => r.account, nameof(Row.account));
user_filter = DiscreteValuesFilterVM.Create<Row, string>(_model.factory.subscribe_users(), r => r.user, nameof(Row.user));
security_filter = DiscreteValuesFilterVM.Create<Row, SecurityImmutable, SecurityCriteria>(
fills_source.with_respect_to(ft => ft.security ?? SecurityDataHelper.Defaults.SecurityImmutable, s => s.Id, ft => ft.key).Select(t => (t.added, t.removed)),
r => r.security,
SecurityCriteria.from_securities,
SecurityCriteria.get_to_securities(bus),
nameof(Row.security),
SecurityDataHelper.EqualityComparer.IDComparer,
Comparer<SecurityImmutable>.Default
);
if (filters != null) {
fill_time_filter.load_state(filters.fill_time);
time_in_force_filter.load_state(filters.time_in_force);
order_type_filter.load_state(filters.order_type);
account_filter.load_state(filters.account);
user_filter.load_state(filters.user);
exchange_filter.load_state(filters.exchange);
security_filter.load_state(filters.security);
side_filter.load_state(filters.side);
price_filter.load_state(filters.price);
size_filter.load_state(filters.size);
fill_key_filter.load_state(filters.fill_key);
order_key_filter.load_state(filters.order_key);
security_key_filter.load_state(filters.security_key);
} else {
fill_time_filter.load_state(
new TimeFilterTuple(ui.controls.TimeFilterMode.CMEOpen,
TimeTextTuple.FromDateTime(DateTime.Today),
TimeTextTuple.FromDateTime(DateTime.Today.AddDays(1))
)
);
}
// columns
add_col(Columns.Security, DefaultColumnHeaders.Security, r => r.security.ToString(), nameof(Row.security), security_filter, DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.Security);
add_col(Columns.FillTime, DefaultColumnHeaders.FillTime, r => r.fill_time.ToString("M/d h:mm:ss tt"), nameof(Row.fill_time), fill_time_filter, DataGridFilterKnownTemplates.TimeFilter, DefaultColumnWidths.Time);
add_col(Columns.User, DefaultColumnHeaders.User, r => r.user, nameof(Row.user), user_filter, DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.User);
add_col(Columns.Account, DefaultColumnHeaders.Account, r => r.account, nameof(Row.account), account_filter, DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.Account);
add_col(Columns.Exchange, DefaultColumnHeaders.Exchange, r => r.exchange.ToString(), nameof(Row.exchange), exchange_filter, DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.Exchange);
add_col(Columns.TimeInForce, DefaultColumnHeaders.TimeInForce, r => r.time_in_force.ToString(), nameof(Row.time_in_force), time_in_force_filter, DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.TimeInForce);
columns.Add(new OrderTypeColumn<Columns>(Columns.OrderType, new Binding(nameof(Row.order_type)), new Binding(nameof(Row.order_metadata)), order_type_filter) { sort_member_path = nameof(Row.order_type) });
columns.Add(new SideColumn<Row, Columns>(Columns.Side, r => r.side, side_filter) { sort_member_path = nameof(Row.side) });
add_col(Columns.Size, DefaultColumnHeaders.Size, r => r.size.ToString(), nameof(Row.size), size_filter, DataGridFilterKnownTemplates.UIntMinMax, DefaultColumnWidths.Size);
add_col(Columns.Price, DefaultColumnHeaders.Price, r => r.format_price(r.price), nameof(Row.price), price_filter, DataGridFilterKnownTemplates.DoubleMinMax, DefaultColumnWidths.Price);
add_col(Columns.FillKey, DefaultColumnHeaders.FillKey, r => r.fill_key.ToString(), nameof(Row.fill_key), fill_key_filter, DataGridFilterKnownTemplates.Regex, DefaultColumnWidths.FillKey);
add_col(Columns.OrderKey, DefaultColumnHeaders.OrderKey, r => r.order_key.ToString(), nameof(Row.order_key), order_key_filter, DataGridFilterKnownTemplates.Regex, DefaultColumnWidths.OrderKey);
add_col(Columns.SecurityKey, DefaultColumnHeaders.SecurityKey, r => r.security_key.ToString(), nameof(Row.security_key), security_key_filter, DataGridFilterKnownTemplates.Regex, DefaultColumnWidths.SecurityKey);
//
void add_col(Columns col_key, string header, Func<Row, string> get_text, string prop, IDataGridColumnFilter filter, string filter_template, double width) =>
columns.Add(new RenderTextColumn<Row, Columns>(col_key, get_text, filter, filter_template) {
Header = header,
sort_member_path = prop,
Width = width
});
//
_resources.Add(DataGridFilterHelper.hook_filters(rows_view,
fill_time_filter, time_in_force_filter, order_type_filter, account_filter, user_filter, exchange_filter,
security_filter, side_filter, price_filter, size_filter, fill_key_filter, order_key_filter, security_key_filter
));
}
public ObservableCollection<ColumnBase> columns { get; } = new ObservableCollection<ColumnBase>();
#region Filters
public IDataGridColumnPersistentFilter<Row, TimeFilterTuple> fill_time_filter { get; } = new TimeFilterVM<Row>(r => r.fill_time, nameof(Row.fill_time));
public IDataGridColumnPersistentFilter<Row, TimeInForce[]> time_in_force_filter { get; } = DiscreteValuesFilterVM.Create<Row, TimeInForce>(EnumHelper.get_values<TimeInForce>().ToLArray(), r => r.time_in_force, nameof(Row.time_in_force));
public IDataGridColumnPersistentFilter<Row, OrderType[]> order_type_filter { get; } = DiscreteValuesFilterVM.Create<Row, OrderType>(EnumHelper.get_values<OrderType>().ToLArray(), r => r.order_type, nameof(Row.order_type));
public IDataGridColumnPersistentFilter<Row, string[]> account_filter { get; }
public IDataGridColumnPersistentFilter<Row, string[]> user_filter { get; }
public IDataGridColumnPersistentFilter<Row, Venue[]> exchange_filter { get; } = DiscreteValuesFilterVM.Create<Row, Venue>(EnumHelper.get_values<Venue>().ToLArray(), r => r.exchange, nameof(Row.exchange));
public IDataGridColumnPersistentFilter<Row, SecurityCriteria> security_filter { get; }
public IDataGridColumnPersistentFilter<Row, Side[]> side_filter { get; } = DiscreteValuesFilterVM.Create<Row, Side>(new[] { Side.Buy, Side.Sell }, r => r.side, nameof(Row.side));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> price_filter { get; } = new DoubleMinMax<Row>(r => r.price, nameof(Row.price));
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> size_filter { get; } = new DoubleMinMax<Row>(r => r.size, nameof(Row.size));
public IDataGridColumnPersistentFilter<Row, string> fill_key_filter { get; } = new RegexFilterVM<Row>(r => r.fill_key, nameof(Row.fill_key));
public IDataGridColumnPersistentFilter<Row, string> order_key_filter { get; } = new RegexFilterVM<Row>(r => r.order_key.ToString(), nameof(Row.order_key));
public IDataGridColumnPersistentFilter<Row, string> security_key_filter { get; } = new RegexFilterVM<Row>(r => r.security_key.ToString(), nameof(Row.security_key));
public FilterStates get_filters() =>
new FilterStates {
fill_time = fill_time_filter.get_state(),
time_in_force = time_in_force_filter.get_state(),
order_type = order_type_filter.get_state(),
account = account_filter.get_state(),
user = user_filter.get_state(),
exchange = exchange_filter.get_state(),
security = security_filter.get_state(),
side = side_filter.get_state(),
price = price_filter.get_state(),
size = size_filter.get_state(),
fill_key = fill_key_filter.get_state(),
order_key = order_key_filter.get_state(),
security_key = security_key_filter.get_state()
};
#endregion
protected override Row row_factory(FillTuple row_model) => new Row(row_model, _model);
protected override IEnumerable<SortingCriteria> get_default_sorting() { yield return new SortingCriteria(nameof(Row.fill_time), false); }
static IObservable<ITableUpdateTransform<FillTuple, string>> _get_observable(IBus bus, OrdersModel model, StartupData state) {
if (state.orders != null && state.orders.Length == 0) {
var orders_hash = new HashSet<uint>(state.orders);
return model.on_fill_tuples.filter(f => orders_hash.Contains(f.fill.OrderKey));
} else return model.on_fill_tuples;
}
public class Row : SecurityRow, IEquatable<Row>, IRowVM {
readonly OrdersModel _model;
readonly FillImmutable _fill;
readonly OrderRecordImmutable _order;
public Row(FillTuple fill_tuple, OrdersModel model) : base(fill_tuple.security ?? SecurityDataHelper.Defaults.Security) {
_fill = fill_tuple.fill;
_order = fill_tuple.order ?? OrderDataHelper.Defaults.OrderRecordImmutable;
_model = model;
}
public DateTime fill_time => _fill.Timestamp.ToDateTimeOffset().LocalDateTime;
public TimeInForce time_in_force => _order.Def.TimeInForce;
public OrderType order_type => _order.Def.CustomDef.CustomCase;
public OrderMetadata order_metadata => _model.factory.get_metadata(_order.Def.CustomDef.CustomCase);
public string account => _order.Def.Account;
public string user => _order.Def.User;
public Venue exchange => security.Exchange;
public Side side => _fill.Side;
public double price => _fill.LastPrice;
public double size => _fill.LastShares;
public string fill_key => _fill.FillKey;
public string order_key => _order.Key.ToString();
public bool Equals(Row other) => other != null && other._fill.Equals(_fill) && other._order.Equals(_order);
public override bool Equals(object obj) => Equals(obj as Row);
public override int GetHashCode() => _fill.FillKey.GetHashCode() ^ _order.Key.GetHashCode();
public event Action invalidated;
void _raise_invalidated() => invalidated?.Invoke();
}
}
}
@@ -1,47 +0,0 @@
<UserControl
x:Class="mbts.ui.spark.FillsView"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:usp="clr-namespace:mbts.ui.spark"
xmlns:uspcv="clr-namespace:mbts.ui.spark.converters"
FocusManager.IsFocusScope="True"
Background="{StaticResource CommonBackground}"
>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/view/Controls/DataGridEx/Filters/Views/FilterTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
<uspcv:TickDisplayConverter x:Key="TickDisplayConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<AdornerDecorator>
<Grid>
<c:DIYGrid
x:Name="_grid"
Columns="{Binding columns}"
CurrentRow="{Binding current_row}"
Rows="{Binding rows_view}"
>
<c:DIYGrid.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/>
<KeyBinding Key="Return" Command="{x:Static c:DIYGrid.DefaultRowCommand}"/>
</c:DIYGrid.InputBindings>
<c:DIYGrid.CommandBindings>
<CommandBinding
Command="{x:Static c:DIYGrid.DefaultRowCommand}"
Executed="{x:Static c:DIYGrid.DefaultRowActionExecuted}"
CanExecute="{x:Static c:DIYGrid.DefaultRowActionCanExecute}"
/>
</c:DIYGrid.CommandBindings>
<c:DIYGrid.RowTemplate>
<DataTemplate>
<usp:FillsRowView/>
</DataTemplate>
</c:DIYGrid.RowTemplate>
</c:DIYGrid>
</Grid>
</AdornerDecorator>
</UserControl>
@@ -1,17 +0,0 @@
using mbts.spark;
using mbts.ui.controls;
using System.Windows.Controls;
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for FillsView.xaml
/// </summary>
partial class FillsView : UserControl {
public enum Columns { FillTime, User, Account, Exchange, Security, TimeInForce, OrderType, Side, Price, Size, FillKey, OrderKey, SecurityKey, ExchangeOrderID }
public FillsView() =>
InitializeComponent();
}
class FillsRowView : DIYGrid.HighPerformanceRow<FillsVM.Row, FillsView.Columns> { }
}
@@ -1,40 +0,0 @@
using bts.api;
using bts.shell;
using bts.spark;
using mbts.ui;
using mbts.ui.spark;
using mbts.utils;
using System.Windows;
using StartupData = bts.shell.FillsWindowFactory.StartupData;
namespace mbts.spark {
class FillsWindow : SparkWindow<StartupData>, ISharedWindow {
const string _window_type = "Fills", _thread_id = "Fills";
readonly AllowOnce _init_guard = new AllowOnce("Fills");
readonly OrdersModel _orders_model;
FillsVM _vm;
FillsView _view;
StartupData _state;
public FillsWindow(FillsWindowFactory factory, IBus bus, OrdersModel orders_model, StartupData state)
: base("Fills", bus, factory, SparkCommands.ShowFills.icon) {
_orders_model = orders_model;
_state = state;
}
public override string window_type => _window_type;
public override UIElement Content => _view;
public override StartupData SaveState => _state = new StartupData(_state.orders, _vm.rows_view.GetSortingCriteria(), _vm.get_filters());
public override double MinWidth => 1050 + SPARK_MENU_COLLAPSED_WIDTH + LAUNCHER_BUTTON_BORDER_WIDTH;
public string thread_id => _thread_id;
public void thread_init() {
_init_guard.check_access();
Logger.notnull(_state);
_vm = new FillsVM(_bus, _orders_model, _state);
_view = new FillsView { DataContext = _vm };
}
public override void Dispose() => Disposable.dispose(ref _vm);
}
}
@@ -1,79 +0,0 @@
using bts.api;
using bts.api.orderman;
using mbts.spark;
using mbts.spark.filters;
using mbts.ui;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace bts.shell {
class FillsWindowFactory : ShellWindowFactory<FillsWindowFactory.StartupData> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
public FillsWindowFactory(TradingShellModule module, IBus bus, OrdersModel orders_model)
: base(module, "Fills") {
_bus = bus;
_orders_model = orders_model;
_dispose = bus.subscribe(SparkTags.ShowFillsTag).ObserveOnDispatcher().Subscribe(show);
}
public override Task<IShellWindow> load(StartupData state) =>
Task.FromResult<IShellWindow>(new FillsWindow(this, _bus, _orders_model, state));
public async void show(StartupData state) =>
_bus.post(SparkTags.ShowWindow, await load(state));
[ProtoContract]
public class StartupData {
public const int Version = 1;
public StartupData() { }
public StartupData(uint[] orders) : this(orders, null, null) { }
public StartupData(FilterStates filters) : this(null, null, filters) { }
public StartupData(uint[] orders, List<SortingCriteria> sorting_criteria, FilterStates filters) {
this.orders = orders;
this.sorting_criteria = sorting_criteria;
this.filters = filters;
}
[ProtoMember(1)]
public uint[] orders;
[ProtoMember(2)]
public List<SortingCriteria> sorting_criteria;
[ProtoMember(3)]
public FilterStates filters;
}
[ProtoContract]
public class FilterStates {
[ProtoMember(1)]
public TimeFilterTuple fill_time;
[ProtoMember(2)]
public TimeInForce[] time_in_force;
[ProtoMember(3)]
public CustomOrderDefinition.CustomOneofCase[] order_type;
[ProtoMember(4)]
public string[] account;
[ProtoMember(5)]
public string[] user;
[ProtoMember(6)]
public Venue[] exchange;
[ProtoMember(7)]
public SecurityCriteria security;
[ProtoMember(8)]
public Side[] side;
[ProtoMember(9)]
public DoubleMinMaxState price;
[ProtoMember(10)]
public DoubleMinMaxState size;
[ProtoMember(11)]
public string fill_key;
[ProtoMember(12)]
public string order_key;
[ProtoMember(13)]
public string security_key;
}
}
}
@@ -1,127 +0,0 @@
using bts.api;
using mbts;
using mbts.config;
using mbts.persist;
using mbts.spark;
using mbts.ui;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using LadderSettings = mbts.spark.LadderSettings;
namespace bts.shell {
class LadderWindowFactory : ShellWindowFactory<LadderSaveState> {
const string _window_type = "ladder";
readonly IBus _bus;
readonly IWindowManager _wm;
readonly UserSettingsHub _settings_hub;
readonly OrdersModel _orders_model;
readonly int _max_ladders_open;
IReadOnlyDictionary<uint, SecurityMD> _securities = new Dictionary<uint, SecurityMD>();
public LadderWindowFactory(IShellModule owner, IBus bus, IWindowManager wm, UserSettingsHub settings_hub, OrdersModel orders_model)
: base(owner, "SparkLadder") {
_bus = bus;
_wm = wm;
_settings_hub = settings_hub;
_orders_model = orders_model;
var window_props = Configuration.get<bts.config.IShellWindowProps>();
_max_ladders_open = (int)(window_props?.ladder?.max_total_open ?? 75);
_dispose = Disposable.Create(
bus.subscribe(SparkTags.SecuritiesTag).Subscribe(s => _securities = s),
bus.subscribe(SparkTags.ShowLadderTag).ObserveOnDispatcher().Subscribe(s => show_windows(new[] { s })),
bus.subscribe(SparkTags.ShowLaddersTag).ObserveOnDispatcher().Subscribe(show_windows)
);
}
public async override Task<IShellWindow> load(LadderSaveState state) {
await Wait.until_true(() => _securities.ContainsKey(state.security_key), TimeSpan.FromSeconds(15));
if (_securities.TryGetValue(state.security_key, out SecurityMD security)) {
return create_ladder_window(security, state.settings);
}
return null;
}
static LadderSaveState _get_state(LadderVM vm) =>
new LadderSaveState { security_key = vm.security.Id, settings = vm.get_save_state() };
int _ladder_count = 0;
IShellWindow create_ladder_window(SecurityMD md, LadderSettings state_settings) {
var id = Interlocked.Increment(ref _ladder_count) % Environment.ProcessorCount;
var view = new Lazy<UIElement>(() => {
var model = new LadderModel(md, _orders_model);
var settings_manager = new WindowSettingsManager<LadderSettings>(
_settings_hub, state_settings,
us => sanitize_ladder_settings(us.ladder),
(us, v) => us.with(sanitize_ladder_settings(v)));
var vm = new LadderVM(_bus, model, settings_manager);
return new LadderView(vm);
});
string thread = Configuration.get<bts.config.toggles.LaddersOnThreads>().enabled ? $"Ladder{id:00}" : "";
return ShellWindow.create(
module, md.security.ToString(), _window_type, view,
(v,s) => save(_get_state(((LadderView)v).vm), s),
icon: Icons.Ladder,
thread_id: thread);
// if there are new props, make sure they are not null, invalid, etc.
LadderSettings sanitize_ladder_settings(LadderSettings s) {
// these MarketBreakLines are new settings props, ensure they are not null
if (s.bid_break_line == null)
s.bid_break_line = LadderSettings.Default.bid_break_line;
if (s.ask_break_line == null)
s.ask_break_line = LadderSettings.Default.ask_break_line;
if (s.mid_break_line == null)
s.mid_break_line = LadderSettings.Default.mid_break_line;
return s;
}
}
void show_windows(IReadOnlyCollection<SecurityMD> securities) {
int n_allowed = _max_ladders_open - _wm.list_windows().Where(w => w.window_type == _window_type).Count();
int n_opened = 0;
foreach (var s in securities) {
if (++n_opened > n_allowed) {
BTSMessageBox.Show($"The maximum number of ladders are already opened ({_max_ladders_open}).", "Ladders",
BTSMessageBoxButtons.OK, MessageBoxImage.Exclamation, true, false, true);
break;
} else {
_bus.post(SparkTags.ShowWindow, create_ladder_window(s, null));
}
}
}
// TODO: whenever we re-implement the linked ladder, need to add some field to the LadderSaveState to indicate the owning window
//void show_linked(IObservable<SecurityMD> keystream) {
// var view = new LadderView();
// IDisposable sub = null;
// var window =
// ShellWindow.create(module, "loading", view,
// Disposable.Create(() => {
// (view.DataContext as LadderVM)?.Dispose();
// sub?.Dispose();
// }), s => {
// var vm = view.DataContext as LadderVM;
// if (vm != null) save(_get_state(vm), s);
// }, Icons.Ladder);
// sub =
// keystream
// .Select(smd => new LadderVM(_bus, new LadderModel(smd, _orders_model),
// Observable.Return(_orders_model.factory.default_ladder_settings(smd.security)))
// ).Aggregate((old, vm) => { old.Dispose(); return vm; })
// .Subscribe(vm => { view.DataContext = vm; window.Title = vm.security.ToString(); });
//}
}
[ProtoContract]
class LadderSaveState {
[ProtoMember(1)]
public UInt32 security_key;
[ProtoMember(2)]
public mbts.spark.LadderSettings settings;
}
}
@@ -1,90 +0,0 @@
using bts.api;
using bts.spark;
using mbts.spark;
using mbts.spark.filters;
using mbts.ui;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace bts.shell {
internal class OrderBookWindowFactory : ShellWindowFactory<OrderBookWindowFactory.OrderBookStartupData> {
readonly IBus _bus;
readonly OrdersModel _model;
public OrderBookWindowFactory(IShellModule owner, IBus bus, OrdersModel model) : base(owner, "SparkOrderBookWindow") {
_bus = bus;
_model = model;
_dispose = bus.subscribe(SparkTags.ShowOrderBookTag).ObserveOnDispatcher().Subscribe(show);
}
public override Task<IShellWindow> load(OrderBookStartupData state) {
var w = new OrderBookWindow(_model, this, _bus, state, SparkCommands.ShowOrders.icon) as IShellWindow;
return Task.FromResult(w);
}
async void show(OrderBookStartupData startup_data) {
var w = await load(startup_data);
_bus.post(SparkTags.ShowWindow, w);
}
[ProtoContract]
public class OrderBookStartupData {
[ProtoMember(5)]
public readonly List<SortingCriteria> sort_criteria;
[ProtoMember(10)]
public FilterStates filters;
public OrderBookStartupData() {
this.sort_criteria = new List<SortingCriteria>();
}
public OrderBookStartupData(List<SortingCriteria> sorting_criteria, FilterStates filters) {
this.sort_criteria = sorting_criteria;
this.filters = filters;
}
}
[ProtoContract]
public class FilterStates {
[ProtoMember(1)]
public SecurityCriteria security_criteria;
[ProtoMember(2)]
public string order_key_regex;
[ProtoMember(3)]
public TimeFilterTuple time_created;
[ProtoMember(4)]
public string[] users;
[ProtoMember(5)]
public string[] accounts;
[ProtoMember(6)]
public Venue[] exchanges;
[ProtoMember(7)]
public api.orderman.TimeInForce[] tifs;
[ProtoMember(8)]
public api.orderman.CustomOrderDefinition.CustomOneofCase[] order_types;
[ProtoMember(9)]
public Side[] sides;
[ProtoMember(10)]
public UIntMinMaxState qty;
[ProtoMember(11)]
public DoubleMinMaxState price;
[ProtoMember(12)]
public UIntMinMaxState qty_filled;
[ProtoMember(13)]
public DoubleMinMaxState avg_price;
[ProtoMember(14)]
public DoubleMinMaxState last_price;
[ProtoMember(15)]
public api.orderman.OrderStatus[] statuses;
[ProtoMember(16)]
public string exchange_message_regex;
[ProtoMember(17)]
public TimeFilterTuple last_change;
[ProtoMember(18)]
public string security_regex;
}
}
}
@@ -1,41 +0,0 @@
using bts.api;
using bts.spark;
using mbts.spark;
using mbts.ui;
using mbts.ui.spark;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace bts.shell {
internal class PAndLWindowFactory : ShellWindowFactory<PAndLWindowFactory.PAndLStartupData> {
readonly IBus _bus;
readonly PAndLModel _model;
public PAndLWindowFactory(IShellModule owner, IBus bus, PAndLModel model) : base(owner, "SparkPAndL") {
_bus = bus;
_model = model;
_dispose = bus.subscribe(SparkTags.ShowPAndLTag).ObserveOnDispatcher().Subscribe(show);
}
public override Task<IShellWindow> load(PAndLStartupData state) {
var w = new PAndLWindow(_model, this, _bus, state, SparkCommands.ShowPAndL.icon) as IShellWindow;
return Task.FromResult(w);
}
async void show(PAndLStartupData startup_data) {
var w = await load(startup_data);
_bus.post(SparkTags.ShowWindow, w);
}
[ProtoContract]
public class PAndLStartupData {
}
}
}
@@ -1,59 +0,0 @@
using bts.api;
using bts.spark;
using mbts.persist;
using mbts.spark;
using mbts.ui;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media;
using static mbts.ui.shell.ProtoBufSerializationHelper;
namespace bts.shell {
[Export(typeof(IShellModule))]
class TradingShellModule : IShellModule {
LadderWindowFactory _lwf;
OrderBookWindowFactory _obwf;
FillsWindowFactory _fwf;
PAndLWindowFactory _plwf;
[ImportingConstructor]
public TradingShellModule(IBus bus, IWindowManager wm, UserSettingsHub settings_hub, OrdersModel orders_model, PAndLModel pandl_model) {
_lwf = new LadderWindowFactory(this, bus, wm, settings_hub, orders_model);
_obwf = new OrderBookWindowFactory(this, bus, orders_model);
_fwf = new FillsWindowFactory(this, bus, orders_model);
_plwf = new PAndLWindowFactory(this, bus, pandl_model);
}
public ImageSource icon => Icons.Trades;
public string name => "Trading";
public int priority => 20;
public IEnumerable<SparkCommand> actions => new [] {
SparkCommands.ShowOrders.complete(() => OrderBookWindow.default_startup_data),
SparkCommands.ShowFills.complete(() => new FillsWindowFactory.StartupData()),
SparkCommands.ShowPAndL.complete(() => new PAndLWindowFactory.PAndLStartupData()),
SparkCommands.PickLadder,
SparkCommands.PickOrderTicket
};
IEnumerable<IShellWindowFactory> window_factories() {
yield return _lwf;
yield return _obwf;
yield return _fwf;
yield return _plwf;
}
public Task<IShellWindow> create(Stream load_stream) {
return dispatch_to_factory(load_stream, window_factories().ToLArray());
}
public void Dispose() {
foreach (var i in window_factories())
if (i != null) i.Dispose();
}
}
}
@@ -1,138 +0,0 @@
using bts.api;
using bts.api.orderman;
using mbts.ui;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
namespace mbts.spark {
class ExistingOrderTicketVM : DisposableViewModelBase, IRequestViewClose {
readonly Property<SecurityImmutable> _security;
readonly Property<double> _price, _current_price;
readonly Property<uint> _current_size;
readonly Property<string> _current_account;
readonly Property<TimeInForce> _current_time_in_force;
readonly Property<CustomOrderDefinition.CustomOneofCase> _current_order_type;
readonly Property<bool> _price_dirty, _size_dirty, _account_dirty, _time_in_force_dirty, _order_type_dirty;
public ExistingOrderTicketVM(OrdersModel model, IObservable<OrderRecordTuple> order_source, IObservable<int[]> calculator_buttons) {
uint? key = null;
var security_md_source = order_source.Where(ot => ot.security_md.HasValue).Select(ot => ot.security_md.Value);
var security_source = security_md_source.Select(smd => smd.security);
//
_security = backing(nameof(security), security_source, SecurityDataHelper.Defaults.SecurityImmutable);
properties_vm = new OrderPropertiesEditorVM(model, security_source.ObserveOnDispatcher(), order_source.Select(ot => new InlineOrderProperties(model, ot.order.Def)));
_price = backing(nameof(price), double.NaN);
size_calculator = new CalculatorLogic(null, calculator_buttons);
_current_price = backing(nameof(current_price), order_source.Select(ort => ort.order.State.Price));
_current_size = backing(nameof(current_size), order_source.Select(ort => ort.order.State.Quantity));
_current_account = backing(nameof(current_account), order_source.Select(ort => ort.order.Def.Account));
_current_time_in_force = backing(nameof(current_time_in_force), order_source.Select(ort => ort.order.Def.TimeInForce));
_current_order_type = backing(nameof(current_order_type), order_source.Select(ort => ort.order.Def.CustomDef.CustomCase));
//
_price_dirty = backing(
nameof(price_dirty),
_price.observe_current(true).CombineLatest(
_current_price.observe_current(true),
(val, curr) => !double.IsNaN(val) && val != curr));
_size_dirty = backing(
nameof(size_dirty),
size_calculator.observe_current(true)
.CombineLatest(_current_size.observe_current(true),
(val, curr) => val.HasValue && val.Value != curr));
_account_dirty = backing(
nameof(account_dirty),
properties_vm.observe_account(true)
.CombineLatest(_current_account.observe_current(true),
(val, curr) => val != curr));
_time_in_force_dirty = backing(
nameof(time_in_force_dirty),
properties_vm.observe_time_in_force(true)
.CombineLatest(_current_time_in_force.observe_current(true),
(val, curr) => val != curr));
_order_type_dirty = backing(
nameof(order_type_dirty),
properties_vm.observe_order_type(true)
.CombineLatest(_current_order_type.observe_current(true),
(val, curr) => val != null && val.order_type != curr));
//
var price_dirty_source = _price_dirty.Select(vals => vals.newval).StartWith(false);
var size_dirty_source = _size_dirty.Select(vals => vals.newval).StartWith(false);
var modify_order = new ObservantCommand(() => {
if (key.HasValue) {
if (_price_dirty.Value) {
if (_size_dirty.Value) {
model.update_order(key.Value, price, size_calculator.value.Value).ignore();
} else {
model.update_order_price(key.Value, price).ignore();
}
} else if (_size_dirty.Value) {
model.update_order_size(key.Value, size_calculator.value.Value).ignore();
} else {
size_calculator.flash_error();
flash_error(nameof(price)).ignore();
return;
}
RequestClose?.Invoke(this, new EventArgs());
}
});
_dispose = Disposable.Create(
size_calculator,
properties_vm,
bbo = new BBOVM(security_md_source),
order_source.ObserveOnDispatcher().Subscribe(ort => {
key = ort.order.Key;
if (DoubleHelper.IsNaNOrInfinity(price))
price = ort.order.State.Price;
if (!size_calculator.value.HasValue || !size_calculator.value_setter_called)
size_calculator.bypass_value_setter(ort.order.State.Quantity);
}),
Observable.Merge(_price_dirty, _size_dirty, _account_dirty, _time_in_force_dirty, _order_type_dirty).ObserveOnDispatcher().Subscribe(_ => RaisePropertyChanged(nameof(dirty_items_text))),
_price_dirty.observe_current(true).CombineLatest(_size_dirty.observe_current(true), (pd, sd) => pd || sd).DistinctUntilChanged().ObserveOnDispatcher().Subscribe(modify_order));
this.modify_order = modify_order;
set_price_command = new DelegateCommand<double>(_price.set);
}
public event EventHandler RequestClose;
public SecurityImmutable security => _security.Value;
public OrderPropertiesEditorVM properties_vm { get; }
public double price { get => _price.Value; set => _price.Value = value; }
public CalculatorLogic size_calculator { get; }
public double current_price => _current_price.Value;
public uint current_size => _current_size.Value;
public string current_account => _current_account.Value;
public TimeInForce current_time_in_force => _current_time_in_force.Value;
public CustomOrderDefinition.CustomOneofCase current_order_type => _current_order_type.Value;
public bool price_dirty => _price_dirty.Value;
public bool size_dirty => _size_dirty.Value;
public bool account_dirty => _account_dirty.Value;
public bool time_in_force_dirty => _time_in_force_dirty.Value;
public bool order_type_dirty => _order_type_dirty.Value;
public bool can_change_account { get; } = false;
public bool can_change_time_in_force { get; } = false;
public bool can_change_order_type { get; } = false;
public string dirty_items_text {
get {
var dirty_items = _dirty_items().ToList();
if (dirty_items.Count == 0)
return "(no changes)";
else return "change " + string.Join(", ", dirty_items);
}
}
public BBOVM bbo { get; }
public ICommand modify_order { get; }
public ICommand set_price_command { get; }
IEnumerable<string> _dirty_items() {
if (_price_dirty.Value) yield return "price";
if (_size_dirty.Value) yield return "size";
if (_account_dirty.Value) yield return "account";
if (_time_in_force_dirty.Value) yield return "tif";
if (_order_type_dirty.Value) yield return "type";
}
}
}
-32
View File
@@ -1,32 +0,0 @@
using bts.api;
using bts.api.orderman;
using System;
namespace mbts.spark
{
class FillTuple : IEquatable<FillTuple> {
public readonly FillImmutable fill;
public readonly OrderRecordImmutable? order;
public readonly SecurityImmutable? security;
public readonly string key;
public FillTuple(FillImmutable fill, OrderRecordImmutable? order, SecurityImmutable? security) {
this.fill = fill;
this.order = order;
this.security = security;
// a FillTuple that DOES NOT HAVE associated order/security needs to be distinguishable
// from a FillTuple (of the same underlying FillImmutable) that DOES HAVE associated order/security
key = fill.FillKey;
if (!order.HasValue) key += "!o";
if (!security.HasValue) key += "!s";
}
public bool Equals(FillTuple other) => other != null
&& other.order.HasValue == order.HasValue
&& other.security.HasValue == security.HasValue
&& other.fill.Equals(fill);
public override bool Equals(object obj) => Equals(obj as FillTuple);
public override int GetHashCode() => key.GetHashCode();
}
}
-185
View File
@@ -1,185 +0,0 @@
using bts.api;
using bts.api.core;
using bts.api.orderman;
using mbts.collections;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
namespace mbts.spark {
class FillTupleSource : IDisposable {
public static IObservable<ITableUpdateTransform<FillTuple, string>> create_observable(
IObservable<IReadOnlyDictionary<uint, SecurityMD>> securities,
IObservable<TableUpdate<OrderRecordImmutable, uint>> orders,
IObservable<TableUpdate<FillImmutable, string>> fills
) {
FillTupleSource source = null;
int ref_count = 0;
return Observable.Create<TableUpdateTransform<FillTuple, string>>(observer => {
if (Interlocked.Increment(ref ref_count) == 1) {
SparkUtils.lazy_assert(source == null, () => fmt_assert_msg("source should be null, there must be a leak."));
source = new FillTupleSource(securities, orders, fills);
}
IDisposable sub = source.fill_tuples.Subscribe(observer);
return Disposable.Create(() => {
Disposable.dispose_once(ref sub);
if (Interlocked.Decrement(ref ref_count) == 0)
Disposable.dispose_once(ref source);
});
});
string fmt_assert_msg(string msg) => $"{nameof(FillTupleSource)}.{nameof(create_observable)}: {msg}";
}
IDisposable _dispose;
FillTupleSource(
IObservable<IReadOnlyDictionary<uint, SecurityMD>> securities,
IObservable<TableUpdate<OrderRecordImmutable, uint>> orders,
IObservable<TableUpdate<FillImmutable, string>> fills) {
State state = new State();
var src = Observable.FromEvent<Action<TableUpdateTransform<FillTuple, string>>, TableUpdateTransform<FillTuple, string>>(cb => _updated += cb, cb => _updated -= cb);
fill_tuples = Observable.Create<TableUpdateTransform<FillTuple, string>>(observer => {
var init_state = state.fill_tuples.state.ToDictionary();
observer.OnNext(new TableUpdateTransform<FillTuple, string>(init_state, init_state.Values.ToList(), new List<FillTuple>(0)));
return src.Subscribe(observer);
});
_dispose = Disposable.Create(
securities.ObserveOnDispatcher().Subscribe(s => update(state.update_securities(s))),
orders.ObserveOnDispatcher().Subscribe(o => update(state.update_orders(o))),
fills.ObserveOnDispatcher().Subscribe(f => update(state.update_fills(f)))
);
void update(State new_state) {
state = new_state;
_updated?.Invoke(state.fill_tuples);
}
}
event Action<TableUpdateTransform<FillTuple, string>> _updated;
IObservable<TableUpdateTransform<FillTuple, string>> fill_tuples { get; }
public void Dispose() =>
Disposable.dispose(ref _dispose);
class State {
readonly IReadOnlyDictionary<string, FillImmutable> _fills;
readonly IReadOnlyDictionary<uint, OrderRecordImmutable> _orders;
readonly IReadOnlyDictionary<uint, SecurityMD> _securities;
readonly TableUpdateTransform<FillTuple, string> _fill_tuples;
readonly SetMap<uint, string> _order_fills;
readonly SetMap<uint, string> _security_fills;
public State() : this(
new Dictionary<string, FillImmutable>(),
new Dictionary<uint, OrderRecordImmutable>(),
new Dictionary<uint, SecurityMD>(),
new TableUpdateTransform<FillTuple, string>(new Dictionary<string, FillTuple>(), new List<FillTuple>(), new List<FillTuple>()),
new SetMap<uint, string>(),
new SetMap<uint, string>()
) { }
State(
IReadOnlyDictionary<string, FillImmutable> fills,
IReadOnlyDictionary<uint, OrderRecordImmutable> orders,
IReadOnlyDictionary<uint, SecurityMD> securities,
TableUpdateTransform<FillTuple, string> fill_tuples,
SetMap<uint, string> order_fill_tuples,
SetMap<uint, string> security_fill_tuples
) {
_fills = fills;
_orders = orders;
_securities = securities;
_fill_tuples = fill_tuples;
_order_fills = order_fill_tuples;
_security_fills = security_fill_tuples;
}
public TableUpdateTransform<FillTuple, string> fill_tuples => _fill_tuples;
public State update_fills(TableUpdate<FillImmutable, string> fills) {
var removed = fills.removed.Select(get_fill_tuple).ToList();
var added = fills.added.Select(get_fill_tuple).ToList();
var order_fills = _order_fills.clone();
var security_fills = _security_fills.clone();
HashSet<string> added_keys = new HashSet<string>(fills.added.Select(f => f.FillKey)),
removed_keys = new HashSet<string>(fills.removed.Select(f => f.FillKey));
foreach (var ft in removed) {
string k = ft.fill.FillKey;
if (!added_keys.Contains(k)) {
order_fills.remove(ft.fill.OrderKey, k);
security_fills.remove(ft.fill.SecurityKey, k);
}
}
foreach (var ft in added) {
string k = ft.fill.FillKey;
if (!removed_keys.Contains(k)) {
order_fills.add(ft.fill.OrderKey, k);
security_fills.add(ft.fill.SecurityKey, k);
}
}
return new State(fills.state, _orders, _securities, _fill_tuples.update(removed, added, f => f.key), order_fills, security_fills);
//
FillTuple get_fill_tuple(FillImmutable fill) =>
new FillTuple(fill, _orders.TryGetValue(fill.OrderKey, out OrderRecordImmutable o) ? o : new OrderRecordImmutable?(),
_securities.TryGetValue(fill.SecurityKey, out SecurityMD s) ? s.security : new SecurityImmutable?());
}
public State update_orders(TableUpdate<OrderRecordImmutable, uint> orders) {
List<FillTuple> added = new List<FillTuple>(), removed = new List<FillTuple>();
orders.detect_changed_keys(o => o.Key, out HashSet<uint> removed_keys, out HashSet<uint> added_keys, out HashSet<uint> changed_keys);
foreach (var k in removed_keys) {
if (_order_fills.try_lookup(k, out ISet<string> fill_keys)) {
removed.AddRange(get_fill_tuples(_orders[k], fill_keys));
added.AddRange(get_fill_tuples(null, fill_keys));
}
}
foreach (var k in added_keys) {
if (_order_fills.try_lookup(k, out ISet<string> fill_keys)) {
removed.AddRange(get_fill_tuples(null, fill_keys));
added.AddRange(get_fill_tuples(orders.get(k), fill_keys));
}
}
foreach (var k in changed_keys) {
if (_order_fills.try_lookup(k, out ISet<string> fill_keys)) {
removed.AddRange(get_fill_tuples(_orders[k], fill_keys));
added.AddRange(get_fill_tuples(orders.get(k), fill_keys));
}
}
return new State(_fills, orders.state, _securities, _fill_tuples.update(removed, added, ft => ft.key), _order_fills, _security_fills);
//
IEnumerable<FillTuple> get_fill_tuples(OrderRecordImmutable? o, ISet<string> fill_keys) =>
fill_keys.Select(k => {
var fill = _fills[k];
return new FillTuple(fill, o, _securities.TryGetValue(fill.SecurityKey, out SecurityMD s) ? s.security : new SecurityImmutable?());
});
}
public State update_securities(IReadOnlyDictionary<uint, SecurityMD> securities) {
List<FillTuple> added = new List<FillTuple>(), removed = new List<FillTuple>();
_securities.Keys.difference(securities.Keys, out IEnumerable<uint> added_keys, out IEnumerable<uint> removed_keys);
foreach (var k in removed_keys) {
if (_security_fills.try_lookup(k, out ISet<string> fill_keys)) {
removed.AddRange(get_fill_tuples(_securities[k].security, fill_keys));
added.AddRange(get_fill_tuples(null, fill_keys));
}
}
foreach (var k in added_keys) {
if (_security_fills.try_lookup(k, out ISet<string> fill_keys)) {
removed.AddRange(get_fill_tuples(null, fill_keys));
added.AddRange(get_fill_tuples(securities[k].security, fill_keys));
}
}
return new State(_fills, _orders, securities, _fill_tuples.update(removed, added, f => f.key), _order_fills, _security_fills);
//
IEnumerable<FillTuple> get_fill_tuples(SecurityImmutable? s, ISet<string> fill_keys) =>
fill_keys.Select(k => {
var fill = _fills[k];
return new FillTuple(fill, _orders.TryGetValue(fill.OrderKey, out OrderRecordImmutable o) ? o : new OrderRecordImmutable?(), s);
});
}
}
}
}
@@ -1,96 +0,0 @@
using bts.api;
using bts.api.orderman;
using mbts.ui;
using mbts.ui.shell;
using System;
using System.Reactive.Linq;
using System.Windows.Input;
namespace mbts.spark {
class InlineOrderTicketProperties {
public readonly InlineUserProperty<double> price;
public readonly InlineUserProperty<uint> size;
public readonly InlineOrderProperties order_props;
public InlineOrderTicketProperties(OrdersModel model, LadderSettings settings)
: this(new InlineOrderProperties(model, settings), size: new InlineUserProperty<uint>(settings.size, true)) { }
public InlineOrderTicketProperties(OrdersModel model, OrderDefinitionImmutable def, double price = double.NaN, uint size = 0)
: this(new InlineOrderProperties(model, def), new InlineUserProperty<double>(price, true), new InlineUserProperty<uint>(size, true)) { }
public InlineOrderTicketProperties(
InlineOrderProperties order_props,
InlineUserProperty<double> price = null,
InlineUserProperty<uint> size = null
) {
this.order_props = order_props;
this.price = price ?? new InlineUserProperty<double>();
this.size = size ?? new InlineUserProperty<uint>();
}
}
class NewOrderTicketVM : DisposableViewModelBase, IRequestViewClose {
readonly Property<SecurityImmutable> _security;
public NewOrderTicketVM(OrdersModel model, SecurityMD security_md, OrderDefinitionImmutable def, double price, uint size, IObservable<int[]> calculator_buttons)
: this(model, Observable.Return(security_md), Observable.Return(new InlineOrderTicketProperties(model, def, price, size)), calculator_buttons) { }
public NewOrderTicketVM(
OrdersModel model,
SecurityMD security_md,
IObservable<LadderSettings> settings)
: this(model, Observable.Return(security_md), settings.Select(s => new InlineOrderTicketProperties(model, s)), settings.Select(s => s.calculator_buttons)) { }
public NewOrderTicketVM(
OrdersModel model,
IObservable<SecurityMD> security_md_source,
IObservable<InlineOrderTicketProperties> props_source,
IObservable<int[]> calculator_buttons
) {
var security_source = security_md_source.Select(smd => smd.security);
_security = backing(nameof(security), security_source, SecurityDataHelper.Defaults.SecurityImmutable);
properties_vm = new OrderPropertiesEditorVM(model, security_source, props_source.Select(p => p.order_props));
bbo = new BBOVM(security_md_source);
send_order = new DelegateCommand<Side>(side => {
bool price_valid = _validate_price(), size_valid = size_calculator.validate();
if (price_valid && size_valid && !HasErrors && !properties_vm.HasErrors) {
model.send_order(properties_vm.create(side), price, size_calculator.value.Value).ignore();
RequestClose?.Invoke(this, new EventArgs());
}
});
set_price_command = new DelegateCommand<double>(set_price);
_dispose = Disposable.Create(
size_calculator = new CalculatorLogic(0, calculator_buttons),
props_source.ObserveOnDispatcher().Subscribe(p => on_props(p.price, p.size))
);
void on_props(InlineUserProperty<double> price_prop, InlineUserProperty<uint> size_prop) {
if (price_prop.has_value && (price_prop.force_override || DoubleHelper.IsNaNOrInfinity(price)))
set_price(price_prop.value);
if (size_prop.has_value && (size_prop.force_override || size_calculator.value == 0))
size_calculator.value = size_prop.value;
}
void set_price(double price) {
this.price = price;
RaisePropertyChanged(nameof(price));
}
}
public event EventHandler RequestClose;
public SecurityImmutable security => _security.Value;
public double price { get; set; }
public CalculatorLogic size_calculator { get; }
public OrderPropertiesEditorVM properties_vm { get; }
public BBOVM bbo { get; }
public ICommand send_order { get; }
public ICommand set_price_command { get; }
bool _validate_price() {
if (DoubleHelper.IsNaNOrInfinity(price)) {
flash_error(nameof(price)).ignore();
return false;
} else return true;
}
}
}
@@ -1,176 +0,0 @@
using bts.api;
using bts.api.core;
using bts.api.orderman;
using bts.shell;
using mbts;
using mbts.spark;
using mbts.ui.controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bts.spark {
internal class Activity {
public SecurityImmutable? security;
public string message;
public ILogViewerCategory category;
}
class OrderActivitySummarizer : IDisposable {
readonly IBus _bus;
IReadOnlyDictionary<uint, SecurityMD> _security = new Dictionary<uint, SecurityMD>();
IDisposable _dispose;
static readonly IEqualityComparer<OrderRecordImmutable> _id_comparer =
mbts.utils.EqualityComparer.Create<OrderRecordImmutable, uint>(a => a.Key);
public OrderActivitySummarizer(IBus bus, IObservable<TableUpdate<OrderRecordImmutable, uint>> orders) {
_bus = bus;
_dispose = Disposable.Create(
bus.subscribe(SparkTags.SecuritiesTag).Subscribe(sec => _security = sec),
orders.Subscribe(orders_updated)
);
}
public void Dispose() => Disposable.dispose(ref _dispose);
#region formatting
(SecurityImmutable?, ContractSpecificationImmutable?) get_security(uint security_key) {
if (_security.TryGetValue(security_key, out SecurityMD md)) {
return (md.security, md.security.ContractSpec);
}
return (null, null);
}
string format_order_success(uint key, double price, uint size, Side side, ContractSpecificationImmutable? spec) {
return $"({key}) {side.ToString().ToLower()} {size} @ {spec.format(price)}";
}
string format_order_fail(double price, uint size, Side side, ContractSpecificationImmutable? spec, string error) {
return $"Failed to {side.ToString().ToLower()} {size} @ {spec.format(price)}. {error}";
}
string format_cancel_success(OrderRecordImmutable order, ContractSpecificationImmutable? spec) {
return $"({order.Key}) Canceled {order.short_description(spec)}, was working {order.working_quantity()}";
}
string format_cancel_error(OrderRecordImmutable order, ContractSpecificationImmutable? spec, string error) {
return $"({order.Key}) Failed to cancel {order.short_description(spec)}: {error}";
}
string format_fill_summary(OrderRecordImmutable before, OrderRecordImmutable after) {
int fb = (int)before.State.FilledQuantity;
int fa = (int)after.State.FilledQuantity;
return $"({after.Key}) {after.Def.Side.past_tense()} {(fa - fb)} ({fa} total), still working {after.working_quantity()}";
}
public static string format_status_change(uint key, OrderStatus old_status, OrderStatus new_status) {
return $"({key}) Status changed from {old_status} to {new_status}";
}
public static string modified_description(OrderRecordImmutable old_order, OrderRecordImmutable new_order, ContractSpecificationImmutable? spec) {
double old_price = old_order.State.Price, new_price = new_order.State.Price;
uint old_size = old_order.State.Quantity, new_size = new_order.State.Quantity;
string modified_size_partial_description(int working_size) {
return $"size from {old_size} to {new_size}, working {working_size}";
}
string modified_price_partial_description() {
return $"price from {spec.format(old_price)} to {spec.format(new_price)}";
}
if (old_price != new_price || old_size != new_size) {
StringBuilder sb = new StringBuilder($"({old_order.Key}) Changed ");
if (old_price != new_price) {
sb.Append(modified_price_partial_description());
if (old_size != new_size)
sb.Append($", {modified_size_partial_description(new_order.working_quantity())}");
}
else
sb.Append(modified_size_partial_description(new_order.working_quantity()));
return sb.ToString();
}
else
return string.Empty;
}
#endregion
void orders_updated(TableUpdate<OrderRecordImmutable, uint> update) {
// Go though added and changed orders
var added = new HashSet<OrderRecordImmutable>(update.added, _id_comparer);
var changed = new HashSet<OrderRecordImmutable>(update.added, _id_comparer);
var removed = update.removed.ToDictionary(o => o.Key);
added.ExceptWith(update.removed);
changed.ExceptWith(added);
foreach (var order in added) {
if (!string.IsNullOrEmpty(order.State.LastMsg) && order.State.Created.ToDateTime().Date == DateTime.Today) {
(var security, var spec) = get_security(order.Def.SecurityKey);
if (security.HasValue) {
log_status(ActivityLogCategory.warn, security, order.State.LastMsg);
}
}
}
foreach (var neworder in changed) {
var oldorder = removed[neworder.Key];
(var security, var spec) = get_security(neworder.Def.SecurityKey);
//
// description
var mod_desc = modified_description(oldorder, neworder, spec.Value);
if (!string.IsNullOrEmpty(mod_desc)) {
log_status(ActivityLogCategory.modify, security, mod_desc);
}
//
// filled quantity
if (oldorder.State.FilledQuantity != neworder.State.FilledQuantity && !neworder.has_parent()) {
log_status(ActivityLogCategory.fill, security, format_fill_summary(oldorder, neworder));
}
//
// status
if (oldorder.State.Status != neworder.State.Status && !neworder.has_parent()) {
log_status(ActivityLogCategory.modify, security,
format_status_change(neworder.Key, oldorder.State.Status, neworder.State.Status));
}
// last msg
if (oldorder.State.LastMsg != neworder.State.LastMsg) {
if (security.HasValue) {
log_status(ActivityLogCategory.warn, security, neworder.State.LastMsg);
}
}
}
}
public void log_status(ILogViewerCategory category, SecurityImmutable? security, string msg) {
_bus.post(SparkTags.LogActivity, new Activity { security = security, message = msg, category = category });
}
internal void on_send_order(OrderDefinitionImmutable order, double price, uint size, uint? key, string error) {
(var security, var spec) = get_security(order.SecurityKey);
log_status(ActivityLogCategory.order, security, key.HasValue ?
format_order_success(key.Value, price, size, order.Side, spec) :
format_order_fail(price, size, order.Side, spec, error));
}
internal void on_cancel_order(OrderRecordImmutable order, bool success, string error) {
(var security, var spec) = get_security(order.Def.SecurityKey);
log_status(ActivityLogCategory.cancel, security, success ?
format_cancel_success(order, spec):
format_cancel_error(order, spec, error));
}
internal void update_order(OrderRecordImmutable order, double price, uint size) {
(var security, var spec) = get_security(order.Def.SecurityKey);
log_status(ActivityLogCategory.modify,
security,
$"({order.Key}) change from {order.State.Quantity}@{spec.format(order.State.Price)} to {size}@{spec.format(price)}");
}
internal void update_order_failed(OrderRecordImmutable order, double price, uint size) {
(var security, var spec) = get_security(order.Def.SecurityKey);
log_status(ActivityLogCategory.modify,
security,
$"({order.Key}) failed to change from {order.State.Quantity}@{spec.format(order.State.Price)} to {size}@{spec.format(price)}");
}
}
}
Loaded 100 of 1629 files, more files were not shown because too many files have changed in this diff. Show more