Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd5c680155 |
No files matched your search
@@ -1,36 +1,34 @@
|
||||
nohup.out
|
||||
build/
|
||||
cmake-build-debug/
|
||||
.idea/
|
||||
.dir-locals.el
|
||||
*.pyc
|
||||
.vscode/*
|
||||
!.vscode/*.json
|
||||
.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
|
||||
src/server/sparkd/orderman/perf_analysis/data
|
||||
src/server/sparkd/orderman/perf_analysis/logs/
|
||||
src/server/sparkd/orderman/perf_analysis/trace_data/
|
||||
.fake
|
||||
*.fsx.lock
|
||||
*.code-workspace
|
||||
src/lib/orderman/perf_analysis/logs/latency_data/
|
||||
trace_data/
|
||||
/src/lib/orderman/perf_analysis/last_pretty_log.csv
|
||||
/src/lib/orderman/perf_analysis/log.csv
|
||||
/doc/user/public/*
|
||||
.ionide/*
|
||||
/.ignore
|
||||
nohup.out
|
||||
build/
|
||||
cmake-build-debug/
|
||||
.idea/
|
||||
.dir-locals.el
|
||||
*.pyc
|
||||
.vscode/*
|
||||
!.vscode/*.json
|
||||
.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
|
||||
src/server/sparkd/orderman/perf_analysis/data
|
||||
src/server/sparkd/orderman/perf_analysis/logs/
|
||||
src/server/sparkd/orderman/perf_analysis/trace_data/
|
||||
.fake
|
||||
*.fsx.lock
|
||||
*.code-workspace
|
||||
src/lib/orderman/perf_analysis/logs/latency_data/
|
||||
trace_data/
|
||||
/src/lib/orderman/perf_analysis/last_pretty_log.csv
|
||||
/src/lib/orderman/perf_analysis/log.csv
|
||||
/doc/user/public/*
|
||||
@@ -1,14 +1,83 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/ninja_debug/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","CL", "CLZ9", "--user=bts", "--pass="],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Excel Launch",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "C:/Program Files/Microsoft Office/Office14/EXCEL.EXE",
|
||||
"args": ["${workspaceRoot}/build/Debug/bin/net471/spark_excel-addin64-packed.xll"],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Client Tests",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/Debug/bin/net471/sparkcmd.exe",
|
||||
"args": ["test","test_filter"],
|
||||
"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/server/sparkd",
|
||||
"args": [
|
||||
"run"
|
||||
],
|
||||
"args": ["run"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server/",
|
||||
"environment": [],
|
||||
@@ -33,115 +102,26 @@
|
||||
"description": "LD LIBRARY",
|
||||
"text": "set env LD_LIBRARY_PATH=.",
|
||||
"ignoreFailures": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"pipeArgs": ["bts@sparkvm"],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/ninja_debug/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",
|
||||
"CL",
|
||||
"CLZ9",
|
||||
"--user=bts",
|
||||
"--pass="
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Excel Launch",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "C:/Program Files/Microsoft Office/Office14/EXCEL.EXE",
|
||||
"args": [
|
||||
"${workspaceRoot}/build/Debug/bin/net471/spark_excel-addin64-packed.xll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Client Tests",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/Debug/bin/net471/sparkcmd.exe",
|
||||
"args": [
|
||||
"test",
|
||||
"ApiUpdateTests"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Client Attach",
|
||||
"type": "clr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
},
|
||||
{
|
||||
"name": "Spreader Tests",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[spreader]"
|
||||
],
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"args": ["test", "[spreader]"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server/",
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
@@ -159,9 +139,7 @@
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"pipeArgs": ["bts@sparkvm"],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
@@ -173,10 +151,7 @@
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[admin_service]"
|
||||
],
|
||||
"args": ["test", "[admin_service]"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
|
||||
"environment": [],
|
||||
@@ -196,9 +171,7 @@
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"pipeArgs": ["bts@sparkvm"],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
@@ -210,10 +183,7 @@
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[limiter]"
|
||||
],
|
||||
"args": ["test", "[limiter]"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
|
||||
"environment": [],
|
||||
@@ -233,9 +203,7 @@
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"pipeArgs": ["bts@sparkvm"],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
@@ -247,10 +215,7 @@
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[algo]"
|
||||
],
|
||||
"args": ["test", "[mbo]"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server/",
|
||||
"environment": [],
|
||||
@@ -275,16 +240,14 @@
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"pipeArgs": ["bts@sparkvm"],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "SparkVM attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
@@ -292,18 +255,16 @@
|
||||
"processId": "${command:pickRemoteProcess}",
|
||||
"MIMode": "gdb",
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": ["bts@sparkvm"],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
"name": "Python",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
@@ -313,59 +274,12 @@
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {},
|
||||
"envFile": "${workspaceRoot}/.env",
|
||||
"args": [
|
||||
"DEBUG"
|
||||
],
|
||||
"args": [ "DEBUG" ],
|
||||
"debugOptions": [
|
||||
"WaitOnAbnormalExit",
|
||||
"WaitOnNormalExit",
|
||||
"RedirectOutput"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Remote Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickRemoteProcess}",
|
||||
"pipeTransport": {
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/home/bts/vsdbg/vsdbg",
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"quoteArgs": true
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
},
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Remote Launch",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "/usr/bin/dotnet",
|
||||
"args": [
|
||||
"sparkcmd.dll",
|
||||
"test",
|
||||
"test_join_create_and_takeout_market"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server",
|
||||
"pipeTransport": {
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/home/bts/vsdbg/vsdbg",
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"quoteArgs": true
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
},
|
||||
"justMyCode": false
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -58,6 +58,7 @@ else ()
|
||||
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.13.0.0 ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libACE-5.7.5.so ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
|
||||
COMMENT "Creating server runtime layout"
|
||||
DEPENDS sparkd data_files_dir)
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
public
|
||||
@@ -1,15 +0,0 @@
|
||||
# The URL the site will be built for
|
||||
base_url = "https://api.bluetradesys.com"
|
||||
|
||||
title = "BTS Spark API"
|
||||
description = "Documentation for the BTS Spark API"
|
||||
|
||||
compile_sass = true
|
||||
|
||||
highlight_code = true
|
||||
highlight_theme = "kronuz"
|
||||
insert_anchor_links = true
|
||||
build_search_index = true
|
||||
|
||||
[extra]
|
||||
author = "Blue Trading Systems"
|
||||
@@ -1,5 +0,0 @@
|
||||
+++
|
||||
title = "BTS Spark API"
|
||||
+++
|
||||
|
||||
This is index
|
||||
@@ -1,7 +0,0 @@
|
||||
+++
|
||||
title="Client API"
|
||||
template="client.html"
|
||||
sort_by="weight"
|
||||
+++
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
+++
|
||||
title="Getting Started"
|
||||
template="client.html"
|
||||
sort_by="weight"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
+++
|
||||
title = "Install Prerequisites"
|
||||
template="client.html"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
## Coming Soon
|
||||
|
||||
* Install .net core
|
||||
@@ -1,25 +0,0 @@
|
||||
+++
|
||||
title="Algo API"
|
||||
template="documentation.html"
|
||||
redirect_to = "server/getting-started/overview/"
|
||||
sort_by="weight"
|
||||
+++
|
||||
|
||||
Getting Started
|
||||
- Install (docker, editor)
|
||||
- Downloading
|
||||
- Write your first algo
|
||||
- Testing
|
||||
|
||||
Reference
|
||||
- Subscriptions
|
||||
- Child Orders
|
||||
- Detaching
|
||||
- Attaching
|
||||
- ...
|
||||
|
||||
Samples
|
||||
- Iceberg
|
||||
- Pro-rata
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
+++
|
||||
title="Getting Started"
|
||||
template="documentation.html"
|
||||
sort_by="weight"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 54 KiB |
@@ -1,138 +0,0 @@
|
||||
+++
|
||||
title = "Development"
|
||||
weight = 3
|
||||
+++
|
||||
|
||||
# Visual Studio Code
|
||||
|
||||
In this section we're going to use the Remote - Containers feature of <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code<i class="fa fa-fw fa-window-restore" aria-hidden="true"></i></a> to simplify the development experience. If you are using a different editor skip to the <a href="#other-editors">other editor</a> section below.
|
||||
|
||||
## Remote - Containers
|
||||
|
||||
The Visual Studio Code Remote containers extension allows it to run a complete development environment inside the Spark SDK Docker container. The editor UI runs as a thin client on your desktop and connects to a headless instance running inside the Spark SDK Docker environment. This configuration allows us to ship a pre-configured set of [Tasks](https://code.visualstudio.com/Docs/editor/tasks) for building and testing your code.
|
||||
|
||||
Start Visual Studio Code and click on the puzzle piece icon on the left-hand side to open the extensions panel. Use the search box at the top to find the "Remote - Containers" extension and install it.
|
||||
|
||||
<img src="../vscode_remote_containers.png" width="640" />
|
||||
|
||||
## Into the Code
|
||||
|
||||
Open the examples/algo_template directory using the File->Open Folder menu option. If you opted to add it to your path during install, you could run `code .` from your command prompt.
|
||||
|
||||
When the workspace opens, you should see a notification offering to let you re-open the workspace inside the container.
|
||||
|
||||
<img src="../vscode_notification.png" width="480" />
|
||||
|
||||
The first time you open the workspace inside the container it will take a few seconds to configure the spark_sdk docker container. While the workspace is open in Visual Studio Code the docker image will also be running in the background. The container will stop automatically when you close the editor.
|
||||
|
||||
Open algo_template.cpp from the file browser on the left or by pressing ctrl-p and typing the name. Each Algo is a standard C++ class which implements **IAlgoOrder**. Placing your cursor on IAlgoOrder and pressing F12 will take you to the IAlgoOrder.h header file where you can browse the API. To learn more about how an Algo is instantiated see the [Algo Initialization](/server/ref/initialization).
|
||||
|
||||
## Compiling
|
||||
|
||||
To build press "Ctrl+Shift+B". You should see the build output at the bottom of your screen. If the build was successful the resulting algo_template.so will be automatically copied to the plugins directory where it will be loaded by the Spark server process on start.
|
||||
|
||||
<img src="../compiled.png" width="640" />
|
||||
|
||||
## Debugging
|
||||
|
||||
To debug your Algo set a breakpoint (F9) and open the Debug panel (Ctrl+Shift+D) and choose "(gdb) Launch". This will launch the Spark Server inside the container with the debugger attached.
|
||||
|
||||
<img src="../gdb_launch.png" width="380" />
|
||||
|
||||
With sparkd running you can launch the Spark Client (spark_client.cmd) and it will connect to the running server. Log in with the user "bts" and no password and open a ladder. You can now select your Algo on the order type dropdown and activate it by clicking on a price on the ladder.
|
||||
|
||||
<img src="../myalgo.png" width="150" />
|
||||
|
||||
While sparkd is running you can also access the Spark Server Admin interface on [http://localhost:9000](http://localhost:9000). Use the same "bts" login to access the admin interface. Here you can manage user and account permissions and risk limits.
|
||||
|
||||
## Starting Spark Server
|
||||
|
||||
To start the Spark Server without attaching a debugger press "Ctrl+Shift+P" and select "Tasks: Run Task" and then "Start Sparkd" and "Never scan task output" This will open a new terminal where you can see any messages logged with the **Sdk** subsystem as well as any warnings or errors. To stop the Spark server simply kill the terminal (trash can icon) or run the "Stop Sparkd" task.
|
||||
|
||||
## Next Steps
|
||||
|
||||
If you would like to understand more about how Docker is working behind the scenes continue to the [next section](#other-editors). Otherwise, continue to [Algo Registration](/server/ref/registration) to learn how Algos are registered with the Spark.
|
||||
|
||||
<hr>
|
||||
|
||||
# Other Editors
|
||||
|
||||
In this section you will be more exposed to the details of how Docker works and how to compile and test your Algo using the command line.
|
||||
|
||||
## Docker
|
||||
|
||||
Spark Server is built and runs only on Linux so you need a Linux development environment to effectively develop plug-ins for it. Docker lets you take the spark_sdk.img disk image and run it inside a virtual Linux machine running on your Windows desktop.
|
||||
|
||||
First, some terminology. A Docker "image" is a disk image containing a complete filesystem. The spark_sdk.img file you imported earlier is an image. A Docker "container" is what you get when you get when you attach this image to a running Linux system. You can connect to a running container and use it to run commands like the C++ compiler or the Spark server. Directories from your local filesystem can be mapped into the Docker container when it starts so you can easily share files.
|
||||
|
||||
### Start
|
||||
|
||||
The first step is to start the spark_sdk Docker container with the examples directory mapped so we can compile the examples inside the container. In your command prompt cd to the *examples* directory that you unzipped from the spark_sdk.zip file. Then run the following command to start the container.
|
||||
|
||||
Windows Command Prompt:
|
||||
{% clipable() %}
|
||||
docker run --rm -it -v %CD%:/examples -u bts -w /examples --shm-size 1024m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
|
||||
{% end %}
|
||||
|
||||
**Powershell** / Linux / Mac:
|
||||
{% clipable() %}
|
||||
docker run --rm -it -v ${PWD}:/examples -u bts -w /examples --shm-size 1024m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
|
||||
{% end %}
|
||||
|
||||
### Attach
|
||||
|
||||
The container will remain as long as this prompt is open. You can attach an additional to the running container with the following command:
|
||||
{% clipable() %}
|
||||
docker exec -it spark_sdk bash
|
||||
{% end %}
|
||||
|
||||
## Compiling
|
||||
|
||||
Let's look at the algo_template sample first. All of the samples are laid out similarly with a `build.sh` script for compiling. As long as you are running build.sh inside the spark Docker container, it automatically copies the build output to /sparkbin/plugins/ where it needs to be to get loaded by the Spark server.
|
||||
|
||||
```
|
||||
bts@spark_sdk:/examples$ cd algo_template/
|
||||
bts@spark_sdk:/examples/algo_template$ ./build.sh
|
||||
algo_template.so copied to /sparkbin/plugins/
|
||||
Restart sparkd to see changes.
|
||||
```
|
||||
|
||||
## Starting Spark Server
|
||||
|
||||
To start the Spark server `cd /sparkbin/` and run `./sparkd run`. Press Ctrl+C to stop it.
|
||||
```
|
||||
bts@spark_sdk:/sparkbin$ ./sparkd run
|
||||
2019-10-25 16:21:09.383626|262552152803600|Gen|Warn |1 |main|132 |Run.cpp:53 |dev|
|
||||
------------------------------------ Sparkd launched --------------------------------
|
||||
```
|
||||
|
||||
You will see any Sdk log messages as well as any log messages at or above Warning level from other parts of the system. If you need additional diagnostic information more details logs are stored in /sparkdata/data/logging/log. These logs will be automatically deleted when you stop the Docker container.
|
||||
|
||||
With sparkd running you can launch the Spark Client (spark_client.cmd) and it will connect to the running server. Log in with the user "bts" and no password and open a ladder. You can now select your Algo on the order type dropdown and activate it by clicking on a price on the ladder.
|
||||
|
||||
<img src="../myalgo.png" width="150" />
|
||||
|
||||
While sparkd is running you can also access the Spark Server Admin interface on [http://localhost:9000](http://localhost:9000). Use the same "bts" login to access the admin interface. Here you can manage user and account permissions and risk limits.
|
||||
|
||||
## Debugging
|
||||
|
||||
You can debug your algo using gdb from the bash command prompt.
|
||||
|
||||
```bts@spark_sdk:/sparkbin$ gdb --args ./sparkd run
|
||||
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
|
||||
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
...
|
||||
Reading symbols from ./sparkd...done.
|
||||
(gdb) break algo_template.cpp:45
|
||||
No source file named algo_template.cpp.
|
||||
Make breakpoint pending on future shared library load? (y or [n]) y
|
||||
Breakpoint 1 (algo_template.cpp:45) pending.
|
||||
(gdb) run
|
||||
Starting program: /sparkbin/sparkd run
|
||||
```
|
||||
|
||||
If your editor supports debugging over the ssh protocol you can start sshd from inside the container.
|
||||
|
||||
## Next
|
||||
|
||||
Continue to [Algo Registration](/server/ref/registration) to learn how Algos are registered with the Spark.
|
||||
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
@@ -1,79 +0,0 @@
|
||||
+++
|
||||
title = "Download SDK"
|
||||
weight = 2
|
||||
+++
|
||||
|
||||
## Request Access 🔑
|
||||
|
||||
To start using the Server SDK you will need to request access though our sales department. Please email <a href="mailto:info@bluetradesys.com">info@bluetradesys.com</a> or call <a href="tel:919-913-0850">(919) 913-0850</a> and we will provide download credentials.
|
||||
|
||||
## Download
|
||||
|
||||
Download the latest SDK image here: [spark_sdk.zip](https://api.bluetradesys.com/download/spark_sdk.zip)
|
||||
|
||||
Unzip that folder into a working directory. Inside you should see something like this:
|
||||
|
||||
```
|
||||
spark_sdk.img
|
||||
client/
|
||||
spark_client.cmd
|
||||
examples/
|
||||
```
|
||||
|
||||
## Import
|
||||
|
||||
Import the spark_sdk image into docker using the `docker load` command.
|
||||
{% clipable() %}
|
||||
docker load < spark_sdk.img
|
||||
{% end %}
|
||||
|
||||
<div class="info">
|
||||
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
|
||||
<strong>If you see this error it means Docker Desktop is not running:</strong>
|
||||
|
||||
|
||||
error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.40/images/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.
|
||||
</div>
|
||||
|
||||
Confirm that the import worked by running `docker images` which should list the new image.
|
||||
```
|
||||
c:\bts> docker images
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
bluetradingsystems/spark_sdk latest e2be89436e73 4 hours ago 3.89GB
|
||||
```
|
||||
|
||||
<!--
|
||||
## Run
|
||||
|
||||
Start the docker container by running
|
||||
```
|
||||
docker run -d -v %CD%:/work --name spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8000:8000 -p 8001:8001 -p 8008:8008 bluetradingsytems/spark_sdk
|
||||
```
|
||||
<div class="linux">
|
||||
<i class="fa fa-linux fa-fw" aria-hidden="true"></i>
|
||||
If you are using Linux or Mac replace <strong>%CD%</strong> with <strong>$PWD</strong>.
|
||||
</div>
|
||||
|
||||
The first time you invoke `docker run` you may be prompted to "share" your filesystem with Docker. This usually works fine but if you run into trouble, see <a href="">Docker Desktop for Windows tips</a> on avoiding common problems.
|
||||
|
||||
## Success 🎉
|
||||
Docker is now running the spark SDK image. If you are on Windows or Mac it is running inside a virtual Linux machine. You can see that is is running by typing `docker ps` to list running docker containers. If you restart the Docker Desktop application you will need to start the spark_sdk image again using `docker start spark_sdk`.
|
||||
|
||||
You should now be able to access an admin interface at http://localhost:8008/ which will let you stop and start the spark server process.
|
||||
-->
|
||||
|
||||
## Update
|
||||
|
||||
To update your Spark SDK simply download an unzip a new [spark_sdk.zip](https://api.bluetradesys.com/download/spark_sdk.zip) and use `docker load < spark_sdk.img` to overwrite the old image with the new one.
|
||||
|
||||
To preserve the old image so you can go back to it later run `docker tag spark_sdk spark_sdk:your_custom_tag` before loading the new SDK image.
|
||||
|
||||
<!--
|
||||
Then stop, remove and restart spark_sdk.
|
||||
```
|
||||
c:\bts> docker stop spark_sdk
|
||||
c:\bts> docker rm spark_sdk
|
||||
c:\bts> docker run -d -v %cd%:/sdk --name spark_sdk bluetradingsytems/spark_sdk
|
||||
|
||||
``` -->
|
||||
|
||||
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
@@ -1,57 +0,0 @@
|
||||
+++
|
||||
title = "Install Prerequisites"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
These instructions assume you are using Microsoft Windows but you should be able to follow them on a Linux or Mac with minor modifications.
|
||||
|
||||
{% linux() %}
|
||||
When there is a significant difference on non-Windows platforms it will be called out in a box like this one.
|
||||
{% end %}
|
||||
{% info() %}
|
||||
Tips or solutions to common problems will be highlighted in a box like this.
|
||||
{% end %}
|
||||
|
||||
The minimum hardware requirements for using the SDK are:
|
||||
- **12 GB** RAM (preferably 16 GB or more)
|
||||
- 4 CPU cores
|
||||
- 20 GB free hard disk space
|
||||
|
||||
The Spark SDK uses a tool called Docker to distribute all of the tools you need to build and test your trading algorithm ("Algo"). Once you have Docker installed you can download and import the Spark SDK image and be ready to start developing your Algo in a few minutes.
|
||||
|
||||
## Docker
|
||||
|
||||
Download and install <a href="https://www.docker.com/products/docker-desktop" target="_blank">Docker Desktop for Windows/Mac. <i class="fa fa-fw fa-window-restore" aria-hidden="true"></i></a>
|
||||
|
||||
<div class="linux">
|
||||
<i class="fa fa-linux fa-fw" aria-hidden="true"></i>
|
||||
If you are using Linux follow the <a href="https://docs.docker.com/install/#supported-platforms">official install instructions for Docker for your distribution.</a>
|
||||
</div>
|
||||
|
||||
During the install Docker may ask you to enable virtualization support and reboot.
|
||||
|
||||
Once Docker Desktop is installed and running it will create an icon in your system tray area that looks like the Docker logo.
|
||||

|
||||
|
||||
Right click on the tray icon and choose 'Settings' and choose the 'Advanced' tab.
|
||||
|
||||
Ensure that the docker image has 8192 MB of memory and at least 2 cores. Memory that you assign to the docker image will not be available to Windows/Mac while Docker is running. CPU cores are shared with the host OS. Since you are going to use this image to compile your Algo it makes sense to allow Docker to use all available cores.
|
||||
|
||||
<img src="../docker_config.png" width="640" >
|
||||
|
||||
## Sharing
|
||||
|
||||
You need to give Docker access to the Windows drive where your source code is kept.
|
||||
|
||||
Open Settings -> Shared Drives and check the drive where you intend to keep your Algo source code.
|
||||
|
||||
<div class="info">
|
||||
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
|
||||
If you run into trouble with drive sharing, see <a href="https://code.visualstudio.com/docs/remote/troubleshooting#_docker-desktop-for-windows-tips">Docker Desktop for Windows tips</a> on avoiding common problems.
|
||||
</div>
|
||||
|
||||
## Editor
|
||||
|
||||
The Server SDK includes a complete configuration for C++ development with the <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code <i class="fa fa-fw fa-window-restore" aria-hidden="true"></i></a> editor. If you are a new to C++ development on a Linux system we recommend you give this a try as it's the easiest way to get up and running quickly. Of course, If you have a different editor that you prefer we fully support that as well.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 46 KiB |
@@ -1,44 +0,0 @@
|
||||
+++
|
||||
title = "Overview"
|
||||
weight = 0
|
||||
+++
|
||||
|
||||
Using the **Spark Server SDK**, users can create new order types ("Algos"). In this case, users implement the new functionality in C++, producing a shared library that is loaded at run time by our Spark Server.
|
||||
|
||||
If you are interested in accessing Spark server remotely, please see the [Spark Client SDK](/client/).
|
||||
|
||||
## Speed
|
||||
|
||||
The Spark platform offers a sub-10 microsecond socket to socket response times for algorithmic trading. With the **Spark Server SDK**, you can create your order types in high-performance C++ and load them into the Spark server.
|
||||
|
||||
Since your order is running inside the Spark Server, there is virtually no overhead allowing your algorithm to take full advantage of the speed Spark offers. Hosting a high-performance language like C++ directly in the Spark server process allows it to respond to the market thousands of times faster than an Algo built using a proprietary drag and drop tool.
|
||||
|
||||
|
||||
## Easy to Get Started
|
||||
|
||||
If you are not actively developing with C++, it can be time-consuming to set up a complete development environment from scratch. That is why we provide a full development environment out of the box with [Docker](https://docker.io) so you can download and try the Server SDK quickly and easily.
|
||||
|
||||
Docker works across Windows, macOS, and Linux, so you don't need to change your development environment to try the Spark API. Docker also ensures that all of the dependencies you need are packaged together in one image, so you know it will work out of the box, no matter the platform.
|
||||
|
||||
## Implementation
|
||||
|
||||
Creating a new Algo begins with implementing a standard C++ class derived from IAlgoOrder. Start from the [algo_template](/server/samples/template) example to get going quickly.
|
||||
|
||||
The first call your new Algo receives is [do_before_launch](/server/ref/initialization#before-launch), which is an opportunity to validate parameters and allocate any long-lived resources needed during execution. Next, it receives either [do_launch](/server/ref/initialization#launch-launch-attached) in the case of a new order or [do_launch_attached](/server/ref/initialization#launch-launch-attached) if the order is attaching to an existing order.
|
||||
|
||||
The Algo receives a reference to [IAlgoServices](/server/ref/subscriptions/), which is how it calls out to the Spark system. It will use [IAlgoServices](/server/ref/subscriptions/) to subscribe to market events, launch and control child orders, and communicate its state to the larger Spark system.
|
||||
|
||||
## Fully Integrated
|
||||
|
||||
When a Spark Server plugin is loaded, it registers its exposed Algos with the Spark Server though the [init_spark_plugin](/server/ref/registration) callback. This callback allows the Algo to describe the parameters it expects so they can be automatically entered in the [Spark Client](https://www.bluetradingsystems.com/bts-spark/).
|
||||
|
||||
<img src="../myalgo.png" width="150" />
|
||||
<img src="../paramsui.png" width="460" />
|
||||
|
||||
Compose your Algo with out of the box Algos in the [Spark Algo Studio](https://www.bluetradingsystems.com/news/155-bts-algo-studio-provides-algo-library-with-customization-functionality) to create new functionality on the fly.
|
||||
|
||||
<img src="../algostudio.png" width="548" /><br />
|
||||
<img src="../iced_algo.png" width="460" />
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 93 KiB |
@@ -1,7 +0,0 @@
|
||||
+++
|
||||
title="Reference"
|
||||
template="documentation.html"
|
||||
sort_by="weight"
|
||||
weight = 2
|
||||
+++
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
+++
|
||||
title = "Questions"
|
||||
weight = 40
|
||||
+++
|
||||
|
||||
## I need to make a call that might take a few seconds. What is the best way to do this?
|
||||
|
||||
Create a background thread in [do_before_launch](/server/ref/initialization#before-launch) or [do_launch](/server/ref/initialization#launch-launch-attached) to do the work. Use [on_timer](/server/ref/subscriptions#timer) to poll until the result is available.
|
||||
@@ -1,97 +0,0 @@
|
||||
+++
|
||||
title = "Initialization"
|
||||
weight = 10
|
||||
+++
|
||||
|
||||
Each Algo derives from IAlgoOrder and overrides virtual methods to receive callbacks from the Spark system.
|
||||
|
||||
|
||||
## Before Launch
|
||||
|
||||
When an order is activated by a user or by another Algo, the first call it receives is do_before_launch. This call happens outside of the latency-sensitive path, so it's the place to validate parameters and set up data structures that the Algo might need.
|
||||
|
||||
This call returns an OrderOpResult, which allows it to fail and return an error message to its creator. If a user created this order, this message is displayed in the [Activity Log](https://www.bluetradingsystems.com/docs/bts_spark/Help/#activity-log) and across the bottom of the ladder.
|
||||
|
||||
Every SDK Algo is a "Dynamic" Algo since it's parameters are defined during [registration](/server/ref/registration/). Use the `get_if<T>` helper to retrieve a named parameter from the `order_params` collection as a `std::option<T>`. If a parameter has a valid default value you can use `std::option::value_or(...)` to set default values for missing parameters. If a parameter *must* exist or must be within a certain valid range, return an error to the caller.
|
||||
|
||||
```cpp
|
||||
OrderOpResult MyAlgo::do_before_launch(IBeforeLaunchAlgoServices& serv) {
|
||||
auto& def = serv.definition();
|
||||
auto& params = def.custom_def().dynamic().order_params();
|
||||
auto mqi = get_if<uint32_t>(params, "Min Quantity");
|
||||
if (!mqi || mqi.value() == 0)
|
||||
return OrderOpResult{
|
||||
ORDER_ERROR_INVALID_ORDER_DEFINITON,
|
||||
"Min Quantity parameter must be defined and non zero"};
|
||||
}
|
||||
```
|
||||
|
||||
<div class="info">
|
||||
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
|
||||
The parameters are defined during <a href="/server/ref/registration/">registration</a> by the <a href="/server/ref/registration/#dynamicorderdescriptor">DynamicOrderDescriptor</a>.
|
||||
</div>
|
||||
|
||||
### IBeforeLaunchAlgoServices
|
||||
|
||||
IBeforeLaunchAlgoServices is passed to `do_before_launch` and allows the Algo to query its environment.
|
||||
|
||||
```cpp
|
||||
class IBeforeLaunchAlgoServices {
|
||||
public:
|
||||
// The OrderDefinition for this algo
|
||||
virtual api::orderman::OrderDefinition const &definition() const = 0;
|
||||
|
||||
// The security this algo is paramterized with (also available from
|
||||
// definition())
|
||||
virtual api::Security const &security() const = 0;
|
||||
|
||||
// The unique order key for this algo
|
||||
virtual OrderKey order_key() const = 0;
|
||||
|
||||
// The parent key for this algo's parent or null_order_key() if the
|
||||
// algo does not have a parent
|
||||
virtual OrderKey parent_order_key() const = 0;
|
||||
|
||||
// The security identified by k or nullptr if no such security exists
|
||||
virtual api::Security const *lookup_security(SecurityKey k) const = 0;
|
||||
|
||||
// Wheter this algo is being attached to an existing order.
|
||||
// If an algo does not support attaching it can return an error
|
||||
// if is_attaching() == true from do_before_launch.
|
||||
virtual bool is_attaching() const = 0;
|
||||
|
||||
// Build a child template that can later can be used to quickly
|
||||
// launch child orders. The reserve parameter indicates how many
|
||||
// orders should be created ahead of time, before they are
|
||||
// launched. This is usefull to remove the relatively expensive
|
||||
// order creation operation to a background thread.
|
||||
virtual ChildTemplate &
|
||||
make_child_template(api::orderman::OrderDefinition const &child_def,
|
||||
size_t reserve = 1) = 0;
|
||||
|
||||
// Get the current time
|
||||
virtual TimeStamp get_time() const;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Launch / Launch Attached
|
||||
|
||||
Depending on the state of `is_attaching()` the next call will either be `do_launch` or `do_launch_attached`. The only difference is that in `do_launch_attached` the existing OrderKey and ChildState are provided.
|
||||
|
||||
`do_launch` and `do_launch_attached` are in the latency-sensitive path and should not do more work than needed. These functions get a reference to `IAlgoServices`, which is a superset of the functionality available on `IBeforeLaunchAlgoServices`. Most Algos should store a pointer or reference to this object for managing child orders (it has a stable address).
|
||||
|
||||
Now is the time to use `IAlgoServices` to subscribe to market events that are relevant to your Algo and create any child orders that need to exist at the start of your Algo. You can safely call IAlgoServices from any `IAlgoOrder` callback.
|
||||
|
||||
To learn more about subscribing to events see [subscriptions](/server/ref/subscriptions).
|
||||
|
||||
### Things to do in the launch callback
|
||||
☑ Store a reference to IAlgoServices
|
||||
☑ Subscribe to relevant market events
|
||||
☑ Launch a child order?
|
||||
|
||||
|
||||
## Update
|
||||
|
||||
If the user or parent Algo changes the order parameters (price, size, or the custom parameters defined during registration), Spark calls the `do_update` callback with the new parameters. It is up to the Algo to decide how to apply the new parameters to update the running state. It can do this by canceling, changing, or adding new child orders.
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
+++
|
||||
title = "Child Orders"
|
||||
weight = 30
|
||||
+++
|
||||
|
||||
Every Algo must, at some point, launch a child order to be useful. Each child order can be another Algo or regular exchange order. When the child order is updated or filled, those changes are also sent to the parent.
|
||||
|
||||
|
||||
# Templates
|
||||
|
||||
Since launching a child order is one of the most latency-sensitive things an Algo can do, the Server SDK enables you to create a child template. An order template prepares an order based on a known OrderDefinition and gets it ready to send on a background thread. When the Algo determines it is time to send the order, it only needs to provide the price and quantity to complete and send the order. If an Algo expects to send multiple child orders, it can reserve more than one. Preparing a child template is typically done in [do_before_launch](http://127.0.0.1:1111/server/ref/initialization/#before-launch) callback.
|
||||
|
||||
```cpp
|
||||
virtual ChildTemplate&
|
||||
IBeforeLaunchAlgoServices::make_child_template(
|
||||
api::orderman::OrderDefinition const &child_def,
|
||||
size_t reserve = 1);
|
||||
```
|
||||
|
||||
# Launch
|
||||
|
||||
IAlgoServices provides two overloads for launching child orders. By default, launching a child order automatically subscribes the Algo to its state changes.
|
||||
|
||||
Launch a child order from a template if you have one prepared. This is the fastest option.
|
||||
```cpp
|
||||
OrderKey IAlgoServices::launch_child(ChildTemplate&, Price, Quantity, bool subscribe = true);
|
||||
```
|
||||
Launch a child order by constructing an OrderDefinition as needed.
|
||||
```cpp
|
||||
OrderKey launch_child(OrderDefinition const &, Price, Quantity, bool subscribe = true);
|
||||
```
|
||||
|
||||
When a child is launched its `OrderKey` is returned to the caller. This ID can be used to update, cancel, or detach the child order.
|
||||
|
||||
## Update
|
||||
|
||||
To update an existing child order, call update_child and pass an Update. The Update type lets you change the price, size or the entire OrderDefinition. You only need to specify the fields that you intend to update so only set the price() field if that is what you are changing.
|
||||
|
||||
```cpp
|
||||
void IAlgoServices::update_child(OrderKey child, api::orderman::Update const &);
|
||||
```
|
||||
|
||||
## Cancel
|
||||
|
||||
To cancel an existing child order call `cancel_child`. When the order is canceled you will receive an update though the `on_child_change` callback.
|
||||
|
||||
```cpp
|
||||
void IAlgoServices::cancel_child(OrderKey child);
|
||||
```
|
||||
|
||||
## Detach
|
||||
|
||||
The lifetime of a child order is tied to its parent. If a parent is canceled or completed child orders are automatically stopped as well. If the Algo needs to launch an order that will continue after the Algo ends use `detach_child` to sever the connection. This order hierarchy can be viewed in the Spark [Order Book](https://www.bluetradingsystems.com/docs/bts_spark/Trading/#order-book).
|
||||
|
||||
```cpp
|
||||
void IAlgoServices::detach_child(OrderKey child);
|
||||
```
|
||||
To detach all children at once use `detach_all_children`.
|
||||
|
||||
```cpp
|
||||
void IAlgoServices::detach_all_children();
|
||||
```
|
||||
|
||||
# Child Updated
|
||||
|
||||
When a child order is updated the parent receives the `on_child_change` callback with an updated ChildState object.
|
||||
|
||||
```cpp
|
||||
void on_child_change(OrderKey, ChildState const &) override;
|
||||
|
||||
struct ChildState {
|
||||
Price price;
|
||||
Quantity quantity;
|
||||
Quantity total_fills;
|
||||
Price avg_price;
|
||||
Quantity last_fills;
|
||||
Price last_price;
|
||||
ChildStatus status;
|
||||
Quantity fills_at_attach_time;
|
||||
};
|
||||
```
|
||||
|
||||
<!--
|
||||
To talk about:
|
||||
- updating fills (update_fill_state)
|
||||
- handling child finished (unexpected cancel)
|
||||
-->
|
||||
|
||||
|
Before Width: | Height: | Size: 7.2 KiB |
@@ -1,92 +0,0 @@
|
||||
+++
|
||||
title = "Registration"
|
||||
weight = 1
|
||||
+++
|
||||
|
||||
When Spark Server starts, it loads all plugins listed in the /sparkbin/plugins directory and calls an exported function named `init_spark_plugin` which must have the following signature.
|
||||
|
||||
```cpp
|
||||
extern "C" void init_spark_plugin(bts::SparkServices &serv) { }
|
||||
```
|
||||
|
||||
The `init_spark_plugin` function registers the Algo with a DynamicOrderDescriptor. Once registered, the Algo appears in the [Spark ladder](https://www.bluetradingsystems.com/docs/bts_spark/Trading/#ladder) and the [Algo Studio](https://www.bluetradingsystems.com/docs/bts_spark/Trading/#algo-studio).
|
||||
|
||||
To register an Algo call `register_dynamic_algo_order` on the provided bts::SparkServices instance. This function takes the DynamicOrderDescriptor and a function that is called to construct the IAlgoOrder. A single init_spark_plugin can call register_dynamic_algo_order multiple times to register multiple Algos.
|
||||
|
||||
The DynamicOrderDescriptor must have a dynamic_order_type (name), or the registration will fail.
|
||||
|
||||
```cpp
|
||||
DynamicOrderDescriptor desc;
|
||||
desc.set_dynamic_order_type("My Algo");
|
||||
auto result =
|
||||
serv.register_dynamic_algo_order(
|
||||
desc, []() { return std::make_unique<MyAlgo>(); });
|
||||
if (result != bts::AlgoRegistrationResult::SUCCESS) {
|
||||
// Algo failed to register
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## DynamicOrderDescriptor
|
||||
|
||||
The DynamicOrderDescriptor describes the type of parameters that the Algo accepts. These inputs can come either from the user manually entering them or from a parent Algo. Spark Algos are composable, so one Algo can activate another. See [Child Orders](/server/ref/orders) for more on how to activate custom order types as child orders.
|
||||
|
||||
Add parameters to the DynamicOrderDescriptor by calling `add_param_desc()` and setting the name and parameter type.
|
||||
|
||||
```cpp
|
||||
*desc.add_param_desc() = param_bool("Enable Feature");
|
||||
*desc.add_param_desc() = param_uint32("Feature Quantity");
|
||||
```
|
||||
|
||||
The above parameters look like this when rendered in the Spark ladder.
|
||||
|
||||
<img src="../paramsui.png" width="460" />
|
||||
|
||||
And like this when viewed in the Spark order book.
|
||||
|
||||
<img src="../orderbook_truncated.png" width="988" />
|
||||
|
||||
Each descriptor can be one of the following types:
|
||||
```
|
||||
// Primitive
|
||||
int32
|
||||
uint32
|
||||
double
|
||||
string
|
||||
bool
|
||||
// Complex
|
||||
Order
|
||||
Array
|
||||
Struct
|
||||
```
|
||||
|
||||
**Currently the Spark UI only renders parameters with primitive types.** The complex types can only be provided by a parent order.
|
||||
|
||||
### Order
|
||||
|
||||
This parameter type indicates that another order type parameterizes this Algo. When the Algo needs to create a child order, it can use this parameter type to create a custom order type instead of defaulting to a limit order.
|
||||
|
||||
For example, an Algo might be designed to wait for a specific market condition before putting in an order. Instead of placing a limit order when the condition is met, the user can specify that it should an IceBerg order. The Algo doesn't need special logic to handle different child order types.
|
||||
|
||||
### Array
|
||||
|
||||
An array parameter is a collection of the same type of parameter. If your Algo needed to behave differently depending on a table of prices, you could send that list in though an array parameter.
|
||||
```cpp
|
||||
*desc.add_param_desc() =
|
||||
param_array("Price Points",
|
||||
param_double("unused").param_type());
|
||||
```
|
||||
|
||||
### Struct
|
||||
|
||||
A struct parameter is a set of named parameter types similar to the entire DynamicOrderDescriptor. The struct parameter type can be combined with the array type to handle tabular data.
|
||||
|
||||
```cpp
|
||||
*desc.add_param_desc() =
|
||||
param_array("Step Table",
|
||||
param_struct("", {
|
||||
param_uint32("Market Quantity"),
|
||||
param_uint32("Order Quantity")
|
||||
}).param_type());
|
||||
```
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
+++
|
||||
title = "Subscriptions"
|
||||
weight = 20
|
||||
+++
|
||||
|
||||
An Algo exists to observe changes in the market and respond to them. When the Algo is [launched](1/server/ref/initialization/#launch-launch-attached) it uses IAlgoServices to subscribe to the events it needs to operate. Each subscribe call is paired with a matching unsubscribe call, which takes the same argument to unsubscribe.
|
||||
|
||||
# Book
|
||||
|
||||
Subscribe to book updates for the specified security call use subscribe_book and unsubscribe book.
|
||||
```cpp
|
||||
// Subscribe to book updates for the specified security
|
||||
void IAlgoServices::subscribe_book(SecurityKey);
|
||||
void IAlgoServices::unsubscribe_book(SecurityKey);
|
||||
|
||||
// You implement
|
||||
virtual void on_book(SecurityKey, Book const &) override;
|
||||
```
|
||||
Get the `SecurityKey` of the current security using:
|
||||
```cpp
|
||||
services.subscribe_book(SecurityKey(algo_services().security().id()));
|
||||
```
|
||||
If your Algo needs to subscribe to other securities, their keys must be passed in as parameters.
|
||||
|
||||
|
||||
To get the details of a security use
|
||||
```cpp
|
||||
api::Security const* IBeforeLaunchAlgoServices::lookup_security(SecurityKey k) const = 0;
|
||||
```
|
||||
|
||||
# Timer
|
||||
To handle time-based logic, an Algo can subscribe to a common timer event that is invoked once every 10 milliseconds. Use the TimeStamp class from `bts_chrono.h` to efficiently handle time calculations.
|
||||
```cpp
|
||||
// Subscribe to a periodic 10ms timer
|
||||
void IAlgoServices::subscribe_timer();
|
||||
// You implement
|
||||
virtual void on_timer() override;
|
||||
```
|
||||
|
||||
# Ticker
|
||||
The status callback is called when the market for this security opens, closes, or has some other state transition.
|
||||
```cpp
|
||||
// Subscribe to trade ticker
|
||||
void IAlgoServices::subscribe_ticker(SecurityKey);
|
||||
// You implement
|
||||
void on_ticker(SecurityKey, TradeVector const&) override;
|
||||
```
|
||||
|
||||
# Trading Status
|
||||
|
||||
The status callback is called when the market for this security opens, closes, or has some other state transition.
|
||||
```cpp
|
||||
// Subscribe to security trading status
|
||||
void IAlgoServices::subscribe_status(SecurityKey);
|
||||
// You implement
|
||||
virtual void on_status(SecurityKey, co2::TradingStatus) override;
|
||||
```
|
||||
|
||||
# Child Orders
|
||||
|
||||
When an Algo launches a child order, it is subscribed to the changes on that child automatically. If the Algo unsubscribes from those changes, it can re-subscribe using this method.
|
||||
|
||||
```cpp
|
||||
// Subscribe to child order updates for the specified child order.
|
||||
void IAlgoServices::subscribe_child_change(OrderKey);
|
||||
// You implement
|
||||
virtual void on_child_change(OrderKey, ChildState const &) override;
|
||||
```
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
+++
|
||||
title="Samples"
|
||||
template="documentation.html"
|
||||
sort_by="weight"
|
||||
weight = 3
|
||||
+++
|
||||
|
||||
@@ -1,354 +0,0 @@
|
||||
+++
|
||||
title = "Join"
|
||||
weight = 10
|
||||
+++
|
||||
|
||||
|
||||
Join starts working N ticks away from the market (usually) and then watches for the opposite inside to become same side inside market; if there is then enough size on that market, it will join.
|
||||
|
||||
<div class="info">
|
||||
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
|
||||
This sample is part of the Server SDK examples included in the <a href="/server/getting-started/download/">spark_sdk.zip download</a>.
|
||||
</div>
|
||||
|
||||
```cpp
|
||||
#include "spark/lib/config/config.h"
|
||||
#include "spark/lib/config/protos/system.pb.h"
|
||||
#include "spark/lib/domain_model/Security.h"
|
||||
#include "spark/lib/orderman/orders/server/IAlgoOrder.h"
|
||||
#include "spark/lib/orderman/orders/server/IAlgoServices.h"
|
||||
#include "spark/lib/plugin/SparkServices.h"
|
||||
|
||||
#include "spark/lib/orderman/order_factory/IOrderFactory.h"
|
||||
#include "spark/lib/orderman/orderman_utils/Book.h"
|
||||
#include "spark/lib/orderman/orderman_utils/orderman_utils.h"
|
||||
#include "spark/lib/utils/PBUtils.h"
|
||||
|
||||
using namespace bts::api::orderman;
|
||||
using namespace bts::orderman;
|
||||
|
||||
namespace bts {
|
||||
namespace order_example {
|
||||
|
||||
// Join starts working N ticks away from the market (usually) and then
|
||||
// watches for the opposite inside to become same side inside market;
|
||||
// if there is then enough size on that market, it will join.
|
||||
class DynamicJoin : public IAlgoOrder {
|
||||
public:
|
||||
DynamicJoin();
|
||||
~DynamicJoin();
|
||||
|
||||
OrderOpResult do_before_launch(IBeforeLaunchAlgoServices &) override;
|
||||
void do_launch(IAlgoServices &) override;
|
||||
void do_launch_attached(IAlgoServices &, OrderKey, ChildState) override;
|
||||
void do_update(api::orderman::Update const &) override;
|
||||
void on_book(SecurityKey, Book const &) override;
|
||||
void on_child_change(OrderKey, ChildState const &) override;
|
||||
|
||||
private:
|
||||
enum class Status;
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
|
||||
IAlgoServices &algo_services() const;
|
||||
void try_to_join();
|
||||
};
|
||||
|
||||
// The three stages our algo goes through. We start by waiting to
|
||||
// observe the book for our security (WAITING_FOR_MD). Once we have a
|
||||
// book we use it to derive our target price and we continue to
|
||||
// monitor the book to see if we should join the market
|
||||
// (WAITING_TO_JOIN). Once the size and price constraints are met we
|
||||
// jump to the target price (JOINED). We remain in the JOINED state
|
||||
// until our order is filled or canceled.
|
||||
enum class DynamicJoin::Status { WAITING_FOR_MD, WAITING_TO_JOIN, JOINED };
|
||||
|
||||
// All state information needed for this algo
|
||||
struct DynamicJoin::PImpl {
|
||||
IAlgoServices *algo_services;
|
||||
Quantity min_quantity_to_join;
|
||||
Status status = Status::WAITING_FOR_MD;
|
||||
OrderKey child_key = null_order_key();
|
||||
ChildTemplate *child_template = nullptr;
|
||||
Book book_at_inception;
|
||||
Book last_book;
|
||||
};
|
||||
|
||||
DynamicJoin::DynamicJoin() : me(new PImpl()) {}
|
||||
DynamicJoin::~DynamicJoin() {}
|
||||
IAlgoServices &DynamicJoin::algo_services() const { return *me->algo_services; }
|
||||
|
||||
// This is called outside of the latency sensitive path
|
||||
// once. Expensive initialization should be done here, rather than
|
||||
// in do_launch()
|
||||
OrderOpResult DynamicJoin::do_before_launch(IBeforeLaunchAlgoServices &serv) {
|
||||
auto &def = serv.definition();
|
||||
bts_assert(def.has_custom_def());
|
||||
bts_assert(def.custom_def().has_dynamic());
|
||||
|
||||
// Validate our parameters, returning an error if we find a
|
||||
// problem. If an error is returned here the order will be
|
||||
// abandoned.
|
||||
auto ¶ms = def.custom_def().dynamic().order_params();
|
||||
auto mqi = get_if<uint32_t>(params, "Min Quantity");
|
||||
if (!mqi || mqi.value() == 0) {
|
||||
return OrderOpResult{
|
||||
ORDER_ERROR_INVALID_ORDER_DEFINITON,
|
||||
"Min Quantity parameter must be defined and non zero"};
|
||||
}
|
||||
|
||||
me->min_quantity_to_join = Quantity(mqi.value());
|
||||
|
||||
if (!serv.is_attaching()) {
|
||||
// If we are not attaching, create a child template so we can
|
||||
// quickly launch our child when the time comes.
|
||||
|
||||
// We will be sending a limit order with the same side,
|
||||
// security, trader, account, etc, as this algo order, so just
|
||||
// copy our definition to the child definition to start with.
|
||||
auto child_def = def;
|
||||
// Now add a limit order component to mark our child as a limit
|
||||
// order. Limit orders do not require any extra parameters
|
||||
// beyond those already inherited from this algo order
|
||||
// (i.e. beyond what we obtained through serv.definition()) so
|
||||
// we can just use a default constructed LimitOrderDefinition.
|
||||
*child_def.mutable_custom_def()->mutable_limit() = LimitOrderDefinition{};
|
||||
// Now just build the child template and cache it for future use
|
||||
me->child_template = &(serv.make_child_template(child_def));
|
||||
} else {
|
||||
// If we are attaching to an existing order then we do not need
|
||||
// to spawn a new child, so there is no need to setup a child
|
||||
// template
|
||||
}
|
||||
|
||||
// All is good, return a default constructed OrderOpResult which
|
||||
// indicates success.
|
||||
return {};
|
||||
}
|
||||
|
||||
// Called in the latency sensitive path, once, when the algo is first
|
||||
// launched.
|
||||
void DynamicJoin::do_launch(IAlgoServices &services) {
|
||||
// Cache our algo services
|
||||
me->algo_services = &services;
|
||||
|
||||
LOG(OrderMan, Diag, "Lauching DynamicJoin k: {} ",
|
||||
algo_services().order_key().value());
|
||||
|
||||
// Launch our child order
|
||||
me->child_key =
|
||||
services.launch_child(*me->child_template, algo_services().price(),
|
||||
algo_services().quantity());
|
||||
|
||||
// Subscribe to market data
|
||||
services.subscribe_book(SecurityKey(algo_services().security().id()));
|
||||
}
|
||||
|
||||
// Called in the latency sensitive path, once, when the algo is first
|
||||
// launched. In this case the algo is provided with an existing order
|
||||
// it is now responsible for managing.
|
||||
void DynamicJoin::do_launch_attached(IAlgoServices &services,
|
||||
OrderKey attached_order, ChildState st) {
|
||||
// The order was launched and attached to an existing order, with
|
||||
// key 'attached_order' and current state 'st'
|
||||
|
||||
// Cache our algo services
|
||||
me->algo_services = &services;
|
||||
|
||||
LOG(OrderMan, Diag,
|
||||
"Lauching DynamicJoin k: {} Attached to existing order: {}",
|
||||
algo_services().order_key().value(), attached_order.value());
|
||||
|
||||
// Cache the key of the attached order we will be managing
|
||||
me->child_key = attached_order;
|
||||
|
||||
// Subscribe to market data
|
||||
services.subscribe_book(SecurityKey(services.security().id()));
|
||||
|
||||
// Simulate a child change so we can update our own state to
|
||||
// reflect that of the child order we attached to. From this point
|
||||
// forward there is no distinction between an algo instance that
|
||||
// spawned a new child order and one that attached to an existing
|
||||
// order.
|
||||
on_child_change(attached_order, st);
|
||||
}
|
||||
|
||||
// Called when a human (or a supervising algo) updates a parameter for
|
||||
// this algo. The implementation validates the update and depending on
|
||||
// the validation outcome either applies the update or terminates the
|
||||
// algo.
|
||||
void DynamicJoin::do_update(api::orderman::Update const &update) {
|
||||
LOG(OrderMan, Diag, "DynamicJoin k: {} receiving update: {}",
|
||||
algo_services().order_key().value(), utils::pb::to_string(update));
|
||||
|
||||
// Validate update
|
||||
if (update.quantity() == 0) {
|
||||
// An invalid update has been detected so we terminate the
|
||||
// algo, signaling an error. Any child orders launched by
|
||||
// this algo will also be terminated.
|
||||
algo_services().terminate_error("Invalid update");
|
||||
return;
|
||||
}
|
||||
|
||||
// Updates have two parts, a standard part consisting of price and
|
||||
// size and present in all updates, and an optional part that is
|
||||
// specific to the algo in question. Below we check for the
|
||||
// existance of this optional part and validate if present.
|
||||
bool has_new_min_qty = false;
|
||||
if (update.has_custom()) {
|
||||
auto ¶ms = update.custom().dynamic().order_params();
|
||||
auto mqi = params.find("Min Quantity");
|
||||
|
||||
if (mqi == params.end() || mqi->second.as_uint32() == 0) {
|
||||
algo_services().terminate_error(
|
||||
"Minimum quantity to join must be greater than 0");
|
||||
return;
|
||||
}
|
||||
has_new_min_qty = true;
|
||||
me->min_quantity_to_join = Quantity(mqi->second.as_uint32());
|
||||
}
|
||||
|
||||
// Update is good, forward it to our child
|
||||
Update child_update;
|
||||
child_update.set_price(update.price());
|
||||
child_update.set_quantity(update.quantity());
|
||||
algo_services().update_child(me->child_key, child_update);
|
||||
|
||||
// Try to join again if conditions changed
|
||||
if (me->status == Status::WAITING_TO_JOIN && has_new_min_qty)
|
||||
try_to_join();
|
||||
}
|
||||
|
||||
// Called when the book for the specified security has changed
|
||||
void DynamicJoin::on_book(SecurityKey, Book const &b) {
|
||||
|
||||
// Cache the book, so we can reffer to it in the event of a
|
||||
// parameter change that might allow us to join
|
||||
me->last_book = b;
|
||||
|
||||
LOG(OrderMan, Diag, "DynamicJoin order {} on book. BID: {}@{} ASK: {}@{}",
|
||||
algo_services().order_key().value(), b.side(api::SIDE_BUY)[0].size(),
|
||||
b.side(api::SIDE_BUY)[0].price(), b.side(api::SIDE_SELL)[0].size(),
|
||||
b.side(api::SIDE_SELL)[0].price());
|
||||
|
||||
switch (me->status) {
|
||||
case Status::WAITING_FOR_MD: {
|
||||
|
||||
auto other_side =
|
||||
securities::other_side(algo_services().definition().side());
|
||||
auto &other_side_top = me->last_book.side(other_side)[0];
|
||||
|
||||
if (other_side_top.size() > 0) {
|
||||
// First time we get the opposite side market, we will use
|
||||
// this price as the target price for the join
|
||||
me->status = Status::WAITING_TO_JOIN;
|
||||
me->book_at_inception = b;
|
||||
LOG(OrderMan, Diag,
|
||||
"JoinOrder order {} receiving first book: {} Target: {}",
|
||||
algo_services().order_key().value(),
|
||||
me->min_quantity_to_join.value(), other_side_top.price());
|
||||
try_to_join();
|
||||
}
|
||||
} break;
|
||||
case Status::JOINED:
|
||||
// Nothing to do at this point
|
||||
break;
|
||||
case Status::WAITING_TO_JOIN:
|
||||
// Check if we reached the target and join if so
|
||||
try_to_join();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Given the current book, our target price and our min quantity
|
||||
// parameter, join if appropriate
|
||||
void DynamicJoin::try_to_join() {
|
||||
bts_assert(me->status == Status::WAITING_TO_JOIN);
|
||||
|
||||
auto my_side = algo_services().definition().side();
|
||||
auto other_side = securities::other_side(my_side);
|
||||
auto &my_side_psz = me->last_book.side(my_side)[0];
|
||||
auto &opposite_at_inception_psz = me->book_at_inception.side(other_side)[0];
|
||||
|
||||
if (my_side_psz.size() &&
|
||||
my_side_psz.size() >= me->min_quantity_to_join.value() &&
|
||||
securities::is_equal_or_better(
|
||||
my_side, Price(my_side_psz.price()),
|
||||
Price(opposite_at_inception_psz.price()))) {
|
||||
|
||||
// Time to update our child to join the market
|
||||
Update child_update;
|
||||
child_update.set_price(my_side_psz.price());
|
||||
child_update.set_quantity(algo_services().quantity().value());
|
||||
algo_services().update_child(me->child_key, child_update);
|
||||
me->status = Status::JOINED;
|
||||
|
||||
LOG(OrderMan, Diag, "DynamicJoin order {} joined: {}@{}",
|
||||
algo_services().order_key().value(),
|
||||
algo_services().quantity().value(), my_side_psz.price());
|
||||
|
||||
} else {
|
||||
LOG(OrderMan, Diag,
|
||||
"JoinOrder order {} still waiting to join. Order: {}@{} Top of "
|
||||
"the book: {}@{} Target: {}@{}",
|
||||
algo_services().order_key().value(),
|
||||
algo_services().quantity().value(), algo_services().price().value(),
|
||||
my_side_psz.size(), my_side_psz.price(),
|
||||
me->min_quantity_to_join.value(), opposite_at_inception_psz.price());
|
||||
}
|
||||
}
|
||||
|
||||
// Our child reported a change:
|
||||
void DynamicJoin::on_child_change(OrderKey, ChildState const &st) {
|
||||
// Our fill quantity and price is always a reflection of our
|
||||
// child's state
|
||||
algo_services().update_fill_state(st.total_fills, st.last_price);
|
||||
|
||||
switch (st.status) {
|
||||
case ChildStatus::WORKING:
|
||||
// Child order is still working, nothing to do
|
||||
return;
|
||||
case ChildStatus::COMPLETED:
|
||||
// Child order completed, we should also complete
|
||||
algo_services().complete();
|
||||
return;
|
||||
case ChildStatus::CANCELED:
|
||||
// Child order unexpectedly canceled, signal an error and
|
||||
// terminate
|
||||
algo_services().terminate_error("Unexpected child cancel");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This is called by the spark daemon at startup. In this call we
|
||||
// describe our algo's parameters and register a factory function to
|
||||
// create an instance of the algo.
|
||||
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
|
||||
using namespace bts;
|
||||
|
||||
DynamicOrderDescriptor join_desc;
|
||||
|
||||
// Start by naming our order type
|
||||
join_desc.set_dynamic_order_type("dyn join");
|
||||
|
||||
// Now add a single unsigned int parameter, Min Quantity, that will
|
||||
// determine the minimum quantity that must exist in the book in
|
||||
// order for us to join the market.
|
||||
*join_desc.add_param_desc() = param_uint32("Min Quantity");
|
||||
|
||||
// Associate the descriptor with a builder function and register
|
||||
// that with the Spark server.
|
||||
auto result =
|
||||
serv.register_dynamic_algo_order(
|
||||
join_desc, []() { return std::make_unique<DynamicJoin>(); });
|
||||
|
||||
if (result != bts::AlgoRegistrationResult::SUCCESS) {
|
||||
// The join_desc has errors
|
||||
// Check the error log for more details
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace order_example
|
||||
} // namespace bts
|
||||
|
||||
```
|
||||
@@ -1,146 +0,0 @@
|
||||
+++
|
||||
title = "Template"
|
||||
weight = 5
|
||||
+++
|
||||
|
||||
A mostly blank Algo template that can be used as a jump-start for developing a new Algo.
|
||||
|
||||
<div class="info">
|
||||
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
|
||||
This sample is part of the Server SDK examples included in the <a href="/server/getting-started/download/">spark_sdk.zip download</a>.
|
||||
</div>
|
||||
|
||||
```cpp
|
||||
#include "spark/lib/config/config.h"
|
||||
#include "spark/lib/config/protos/system.pb.h"
|
||||
#include "spark/lib/domain_model/Security.h"
|
||||
#include "spark/lib/orderman/orders/algo/IAlgoOrder.h"
|
||||
#include "spark/lib/orderman/orders/algo/IAlgoServices.h"
|
||||
#include "spark/lib/plugin/SparkServices.h"
|
||||
|
||||
#include "spark/lib/orderman/order_factory/IOrderFactory.h"
|
||||
#include "spark/lib/orderman/orderman_utils/Book.h"
|
||||
#include "spark/lib/orderman/orderman_utils/orderman_utils.h"
|
||||
#include "spark/lib/utils/PBUtils.h"
|
||||
|
||||
using namespace bts::api::orderman;
|
||||
using namespace bts::orderman;
|
||||
|
||||
namespace bts {
|
||||
namespace order_example {
|
||||
|
||||
// MyAlgo is a blank IAlgoOrder which you can copy when starting a new Algo
|
||||
class MyAlgo : public IAlgoOrder {
|
||||
public:
|
||||
MyAlgo();
|
||||
~MyAlgo();
|
||||
|
||||
OrderOpResult do_before_launch(IBeforeLaunchAlgoServices &) override;
|
||||
void do_launch(IAlgoServices &) override;
|
||||
void do_launch_attached(IAlgoServices &, OrderKey, ChildState) override;
|
||||
void do_update(api::orderman::Update const &) override;
|
||||
void on_book(SecurityKey, Book const &) override;
|
||||
void on_child_change(OrderKey, ChildState const &) override;
|
||||
|
||||
private:
|
||||
IAlgoServices* algo_services;
|
||||
ChildTemplate *child_template = nullptr;
|
||||
OrderKey child_key = null_order_key();
|
||||
};
|
||||
|
||||
|
||||
MyAlgo::MyAlgo() : algo_services(nullptr) {}
|
||||
MyAlgo::~MyAlgo() {}
|
||||
|
||||
// This is called outside of the latency sensitive path.
|
||||
// Expensive initialization should be done here, rather than in do_launch()
|
||||
OrderOpResult MyAlgo::do_before_launch(IBeforeLaunchAlgoServices &serv) {
|
||||
LOG(Sdk,Info, "MyAlgo: do_before_launch");
|
||||
// If we are not attaching, create a child template so we can
|
||||
// quickly launch our child when the time comes.
|
||||
if (!serv.is_attaching()) {
|
||||
// We will be sending a limit order with the same side,
|
||||
// security, trader, account, etc, as this algo order, so just
|
||||
// copy our definition to the child definition to start with.
|
||||
auto child_def = serv.definition();
|
||||
// Now add a limit order component to mark our child as a limit
|
||||
// order. Limit orders do not require any extra parameters
|
||||
// beyond those already inherited from this algo order
|
||||
// (i.e. beyond what we obtained through serv.definition()) so
|
||||
// we can just use a default constructed LimitOrderDefinition.
|
||||
*child_def.mutable_custom_def()->mutable_limit() = LimitOrderDefinition{};
|
||||
// Now just build the child template and cache it for future use
|
||||
child_template = &(serv.make_child_template(child_def));
|
||||
}
|
||||
// Default constructed result is successful
|
||||
return {};
|
||||
}
|
||||
|
||||
// Called in the latency sensitive path, once, when the algo is first launched.
|
||||
// If the Algo is attaching to an existing order do_launch_attached is called instead.
|
||||
void MyAlgo::do_launch(IAlgoServices &services) {
|
||||
algo_services = &services;
|
||||
// Subscribe to book updates for this security
|
||||
services.subscribe_book(SecurityKey(services.security().id()));
|
||||
// Launch a child limit order
|
||||
child_key =
|
||||
services.launch_child(*child_template, services.price(), services.quantity());
|
||||
LOG(Sdk,Info, "MyAlgo: do_launch");
|
||||
}
|
||||
|
||||
// Called in the latency sensitive path, once, when the algo is first
|
||||
// launched. In this case the algo is provided with an existing order
|
||||
// it is now responsible for managing.
|
||||
void MyAlgo::do_launch_attached(IAlgoServices &services,
|
||||
OrderKey attached_order, ChildState st) {
|
||||
algo_services = &services;
|
||||
// Subscribe to book updates for this security
|
||||
services.subscribe_book(SecurityKey(services.security().id()));
|
||||
// Keep track of the child key
|
||||
child_key = attached_order;
|
||||
LOG(Sdk,Info, "MyAlgo: do_launch_attached");
|
||||
}
|
||||
|
||||
// Called when a human (or a supervising algo) updates a parameter for
|
||||
// this algo. The implementation validates the update and depending on
|
||||
// the validation outcome either applies the update or terminates the algo.
|
||||
void MyAlgo::do_update(api::orderman::Update const &update) {
|
||||
}
|
||||
|
||||
// Called when the book for the specified security has changed
|
||||
void MyAlgo::on_book(SecurityKey, Book const &b) {
|
||||
}
|
||||
|
||||
// Our child reported a change
|
||||
void MyAlgo::on_child_change(OrderKey, ChildState const &st) {
|
||||
}
|
||||
|
||||
// This is called by the spark daemon at startup. In this call we
|
||||
// describe our algo's parameters and register a factory function to
|
||||
// create an instance of the algo.
|
||||
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
|
||||
using namespace bts;
|
||||
|
||||
DynamicOrderDescriptor desc;
|
||||
|
||||
// Start by naming our order type
|
||||
desc.set_dynamic_order_type("My Algo");
|
||||
|
||||
*desc.add_param_desc() = param_bool("Enable Feature");
|
||||
*desc.add_param_desc() = param_uint32("Feature Quantity");
|
||||
|
||||
// Associate the descriptor with a builder function and register
|
||||
// that with the Spark server.
|
||||
auto result =
|
||||
serv.register_dynamic_algo_order(
|
||||
desc, []() { return std::make_unique<MyAlgo>(); });
|
||||
|
||||
if (result != bts::AlgoRegistrationResult::SUCCESS) {
|
||||
// The desc has errors
|
||||
// Check the error log (/sparkdata/data/logging/log) for more details
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace order_example
|
||||
} // namespace bts
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
#/bin/bash
|
||||
|
||||
# ../../externals/linux/bin/zola/zola build
|
||||
zola.exe build
|
||||
|
||||
rsync -avzL public/ bts@api.bluetradesys.com:/data/sdk/public/
|
||||
|
||||
rm -rf ./public/
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
html, body {
|
||||
font-size: 16px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Source Sans Pro", "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
line-height: 1.6;
|
||||
// from http://www.heropatterns.com
|
||||
background-color: #0072a2;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%234b4b4b' fill-opacity='0.4'%3E%3Cpath opacity='.5' d='M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z'/%3E%3Cpath d='M6 5V0H5v5H0v1h5v94h1V6h94V5H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
|
||||
color: $foreground;
|
||||
|
||||
// for sticky footer
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $link-color;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(0, 124, 188, 0.25);
|
||||
|
||||
&:hover {
|
||||
border-bottom: 1px solid $link-color;
|
||||
}
|
||||
|
||||
&:visited {
|
||||
color: $link-color;
|
||||
}
|
||||
|
||||
// totally taken from stripe
|
||||
&.button {
|
||||
outline: none;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding: 0 14px;
|
||||
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .025em;
|
||||
color: #191919;
|
||||
text-decoration: none;
|
||||
transition: all .15s ease;
|
||||
border-bottom: none;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
text-decoration: none;
|
||||
box-shadow: 0 7px 14px rgba(50, 50, 93, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #f6f9fc;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
&.white {
|
||||
color: white;
|
||||
border-bottom-color: rgba(255, 255, 255, 0.25);
|
||||
|
||||
&:hover {
|
||||
border-bottom-color: white;
|
||||
}
|
||||
|
||||
&:visited {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 1rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
p code, li code {
|
||||
// color: #e6e1dc;
|
||||
// background-color: #383838;
|
||||
color: #191919;
|
||||
background-color: #f5f5f5;
|
||||
white-space: pre-wrap;
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.85rem;
|
||||
font-family: monospace;
|
||||
// box-shadow: 0 1px 3px rgba(0,0,0,.1), 0 1px 1px rgba(0,0,0,.1), 0 2px 1px -1px rgba(0,0,0,.12);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
.documentation {
|
||||
padding: 3rem;
|
||||
display: flex;
|
||||
|
||||
&__sidebar {
|
||||
margin-right: 2rem;
|
||||
|
||||
ul {
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
> ul {
|
||||
> li {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.documentation__sidebar__title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: 0.25rem;
|
||||
|
||||
li {
|
||||
border-left: 1px solid $background;
|
||||
padding-left: 0.75rem;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
li.active a {
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid $link-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&__content {
|
||||
width: 60%;
|
||||
// Same as the anchor absolute left to not overlap
|
||||
margin-left: 2rem;
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
.zola-anchor {
|
||||
font-size: 1.25rem;
|
||||
visibility: hidden;
|
||||
margin-left: -2rem;
|
||||
text-decoration: none;
|
||||
border-bottom-color: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.zola-anchor {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 10px solid black;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin-left: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 1000px) {
|
||||
.documentation {
|
||||
flex-direction: column;
|
||||
padding: 2rem;
|
||||
|
||||
&__content {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
border-top: 1px solid $background;
|
||||
order: 1;
|
||||
margin-right: 0;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
header {
|
||||
.header__logo {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
nav a {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.header__logo {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1000px) {
|
||||
header {
|
||||
padding: 1rem 0;
|
||||
|
||||
nav {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header__logo {
|
||||
// to force menu links to be on a line below
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
.inverted-colours {
|
||||
background: $foreground;
|
||||
color: $background;
|
||||
}
|
||||
|
||||
.hero {
|
||||
width: 60%;
|
||||
margin: 0 auto;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 4rem;
|
||||
text-align: center;
|
||||
|
||||
&__tagline {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.selling-points {
|
||||
padding: 3rem;
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.selling-point {
|
||||
// 2 selling points per row on desktop
|
||||
width: 50%;
|
||||
padding: 2rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.selling-header {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
padding-top: 0rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
img {
|
||||
align-self: center;
|
||||
max-width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
// and 1 on mobile
|
||||
@media only screen and (max-width: 1000px) {
|
||||
.hero {
|
||||
width: 90%;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.selling-points {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.selling-point {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
header {
|
||||
padding: 2rem 3rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1000px) {
|
||||
.container {
|
||||
max-width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
|
||||
&--reversed {
|
||||
background: $foreground;
|
||||
color: $background;
|
||||
}
|
||||
}
|
||||
|
||||
.linux {
|
||||
padding: 25px 15px;
|
||||
background: #eff0f1;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #0072a2;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 25px 15px;
|
||||
background: #ffffe0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #383838;
|
||||
}
|
||||
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 2rem 3rem;
|
||||
}
|
||||
@@ -1,447 +0,0 @@
|
||||
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in
|
||||
* IE on Windows Phone and in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers (opinionated).
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
footer,
|
||||
header,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in IE.
|
||||
*/
|
||||
|
||||
figcaption,
|
||||
figure,
|
||||
main { /* 1 */
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct margin in IE 8.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Remove the gray background on active links in IE 10.
|
||||
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent; /* 1 */
|
||||
-webkit-text-decoration-skip: objects; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font style in Android 4.3-.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct background and color in IE 9-.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
audio,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in iOS 4-7.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10-.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the overflow in IE.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers (opinionated).
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: sans-serif; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||
* controls in Android 4.
|
||||
* 2. Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
html [type="button"], /* 1 */
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct display in IE 9-.
|
||||
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10-.
|
||||
* 2. Remove the padding in IE 10-.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in Edge, IE, and Firefox.
|
||||
*/
|
||||
|
||||
details, /* 1 */
|
||||
menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Scripting
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
canvas {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hidden
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10-.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
.search-container {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 300px;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.search-results {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background: white;
|
||||
color: black;
|
||||
padding: 1rem;
|
||||
box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.5);
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
width: 150%;
|
||||
right: 0;
|
||||
|
||||
&__items {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 1rem;
|
||||
border-bottom: 1px solid #ccc;
|
||||
font-size: 0.9rem;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__item {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
a {
|
||||
font-size: 1.2rem;
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
.themes-container {
|
||||
padding: 3rem;
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1000px) {
|
||||
.themes-container {
|
||||
width: 100%;
|
||||
margin: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.themes {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.theme {
|
||||
width: 45%;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: none;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
|
||||
padding: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-info {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.thumb {
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07);
|
||||
width: 400px;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
h1, p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 1000px) {
|
||||
.themes .theme {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1000px) {
|
||||
.theme-info {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
@charset "utf-8";
|
||||
|
||||
@import "normalize";
|
||||
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
$background: #191919;
|
||||
$foreground: white;
|
||||
$link-color: #007CBC;
|
||||
|
||||
@import "base";
|
||||
@import "layout";
|
||||
@import "header";
|
||||
@import "index";
|
||||
@import "docs";
|
||||
@import "themes";
|
||||
@import "search";
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 55 KiB |
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg enable-background="new 0 0 523.438 166.055" version="1.1" viewBox="0 0 523.44 166.06" xmlns="http://www.w3.org/2000/svg"><path d="m297.43 153.29c-18.051-6.698-91.506-40.523-160.87-72.832-69.291-32.28-134.17-62.929-134.17-62.929-2.082-0.983-2.971-3.466-1.987-5.549 0.981-2.079 3.466-2.97 5.548-1.988 0.037 0.02 16.216 7.661 41.09 19.354 24.874 11.695 58.412 27.425 93.046 43.557 69.192 32.242 143.09 66.232 160.25 72.574 20.188 7.443 37.922 12.204 80.113 12.239 30.434 0 73.407-2.559 138.44-8.568 2.288-0.211 4.319 1.474 4.531 3.765 0.208 2.29-1.478 4.324-3.771 4.536-65.152 6.014-108.31 8.602-139.2 8.605h-0.423c-42.393-1e-3 -61.964-5.092-82.59-12.764z" fill="#B3B3B3"/><path d="m45.824 145.9v-138.39h101.28c27.03 0 44.924 12.184 44.924 35.789 0 17.513-8.947 26.27-19.226 29.506 12.564 3.996 21.702 15.039 21.702 31.22 0 25.319-17.516 41.88-44.545 41.88h-104.13zm41.692-60.155v-20.37h59.774c13.707 0 20.179-4.758 20.179-16.751 0-14.658-11.613-16.943-29.507-16.943h-67.96v90.234h70.052c17.325 0 29.889-4.759 29.889-18.276 0-11.423-7.423-17.894-20.939-17.894h-61.488z" fill="#0086BF"/><path d="m149.96 153.4h-104.13v-7.502h7.501-7.501v7.502h-7.504v-153.4h108.78c14.604 0.018 27.473 3.236 37.154 10.583 9.724 7.301 15.384 19.035 15.273 32.71 0.018 10.01-2.623 18.337-7.222 24.554-1.308 1.779-2.755 3.368-4.306 4.774 2.395 1.964 4.557 4.235 6.422 6.792 4.847 6.626 7.594 15.107 7.58 24.606 0.044 14.363-5.105 27.096-14.494 35.896-9.347 8.809-22.486 13.486-37.463 13.486-0.028 1e-3 -0.058 1e-3 -0.088 1e-3zm0-15.007c12.016-0.018 21.114-3.62 27.266-9.402 6.125-5.814 9.736-14.02 9.777-24.973-0.015-6.687-1.835-11.817-4.698-15.757-2.875-3.934-6.891-6.753-11.775-8.315l-22.267-7.085c-0.322 7e-3 -0.645 0.011-0.97 0.012h-52.271v5.367h53.988c7.892 0 15.036 1.876 20.422 6.475 5.429 4.589 8.092 11.651 8.015 18.922 0.016 4.524-1.103 8.88-3.35 12.497-2.236 3.632-5.46 6.38-9.02 8.3-7.172 3.825-15.677 4.938-25.019 4.979h-77.553v-105.24h75.46c6.958 0.014 13.253 0.288 19.035 1.724 5.677 1.383 11.425 4.37 14.807 10.025 2.23 3.702 3.174 8.068 3.171 12.698-5e-3 3.663-0.489 7.129-1.729 10.368-1.045 2.753-2.714 5.301-4.853 7.329l2.154-0.677c3.906-1.243 7.213-3.358 9.68-6.692 2.445-3.351 4.276-8.156 4.297-15.657-0.111-9.936-3.399-16.094-9.377-20.786-6.028-4.645-15.62-7.52-28.046-7.501l-93.773-3e-3v123.39h96.629v-1e-3zm-72.453-23.984h62.551c5.981 0.011 11.112-0.651 14.744-1.85 3.688-1.218 5.575-2.753 6.528-4.306 0.647-1.077 1.099-2.388 1.113-4.618-0.073-4.151-1.124-6.039-2.785-7.541-1.701-1.492-5.034-2.853-10.648-2.853h-61.49v-7.501h7.501-7.501v7.501h-7.504v-35.372h67.277c4.502 0.018 7.602-0.643 9.234-1.431 1.634-0.854 2.056-1.329 2.718-2.838 0.402-1.025 0.728-2.648 0.728-4.979-0.01-2.704-0.518-4.121-1.023-4.967-0.526-0.837-1.154-1.457-2.696-2.209-3.023-1.521-9.667-2.335-18.288-2.268h-60.459v75.232z" fill="#fff"/><path d="M251.22,145.899V31.68h-52.54V7.505h129.256V31.68h-52.539v114.22H251.22z" fill="#0086BF"/><path d="m251.22 153.4v-7.499h7.501-7.501v7.499h-7.504l-2e-3 -114.22h-52.538v-39.175h144.26v39.175h-52.541v114.22h-31.678zm16.673-15.001v-114.22h52.538v-9.171h-114.25v9.171h52.542v114.22h9.171v-1e-3z" fill="#fff"/><path d="m340.11 145.9v-24.176h103.74c12.942 0 20.177-7.233 20.177-18.083 0-11.802-7.234-17.893-20.177-17.893h-63.58c-26.075 0-42.257-16.562-42.257-39.404 0-22.271 15.038-38.831 42.639-38.831h99.365v24.174h-99.365c-11.042 0-17.514 6.473-17.514 16.94 0 10.469 6.661 16.751 17.324 16.751h63.388c27.98 0 43.02 13.134 43.02 39.974 0 23.226-14.089 40.546-43.02 40.546h-103.74z" fill="#383431"/><path d="m443.85 153.4h-103.74v-7.499h7.498-7.498v7.499h-7.505v-39.176h111.25c5.118-0.02 8.116-1.385 9.849-2.984 1.71-1.622 2.774-3.8 2.823-7.597-0.071-4.45-1.162-6.342-2.67-7.727-1.55-1.385-4.646-2.668-10.002-2.668h-63.58c-14.603 0.028-27.235-4.711-36.097-13.218-8.89-8.476-13.698-20.511-13.666-33.685-0.032-12.792 4.428-24.712 13.274-33.177 8.826-8.496 21.605-13.184 36.87-13.155h106.86v39.176h-106.86c-4.11 0.028-6.327 1.125-7.658 2.411-1.313 1.309-2.315 3.29-2.354 7.027 0.043 3.691 1.042 5.592 2.354 6.89 1.338 1.278 3.562 2.338 7.469 2.36h63.388c15.081-7e-3 27.896 3.536 37.065 11.888 9.185 8.367 13.511 20.865 13.455 35.59 0.022 13.078-4.037 25.357-12.824 34.248-8.729 8.882-21.678 13.796-37.497 13.796-0.066 1e-3 -0.135 1e-3 -0.2 1e-3zm-96.246-14.999 96.246-4e-3c13.017-0.037 21.505-3.779 27.018-9.329 5.488-5.576 8.475-13.569 8.494-23.712-0.052-12.118-3.246-19.606-8.572-24.519-5.35-4.923-14.046-7.951-26.939-7.956h-63.388c-6.76 0.022-13.199-2.056-17.858-6.541-4.686-4.459-7.014-10.932-6.972-17.712-0.038-6.729 2.191-13.218 6.88-17.764 4.659-4.564 11.2-6.707 18.14-6.678h91.856v-9.174l-91.856 4e-3c-12.341 0.026-20.88 3.617-26.474 8.971-5.574 5.382-8.632 12.875-8.667 22.358 0.035 9.665 3.317 17.334 9.038 22.85 5.746 5.486 14.244 9.029 25.721 9.049h63.58c7.58 0 14.573 1.767 19.88 6.38 5.34 4.606 7.87 11.665 7.799 19.018 0.048 7.05-2.504 13.916-7.652 18.62-5.117 4.73-12.205 6.982-20.026 6.965l-96.246-6e-3v9.18h-2e-3z" fill="#fff"/><path d="m45.824 145.9v-138.39h101.27c6Line truncated
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -1,180 +0,0 @@
|
||||
function debounce(func, wait) {
|
||||
var timeout;
|
||||
|
||||
return function () {
|
||||
var context = this;
|
||||
var args = arguments;
|
||||
clearTimeout(timeout);
|
||||
|
||||
timeout = setTimeout(function () {
|
||||
timeout = null;
|
||||
func.apply(context, args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// Taken from mdbook
|
||||
// The strategy is as follows:
|
||||
// First, assign a value to each word in the document:
|
||||
// Words that correspond to search terms (stemmer aware): 40
|
||||
// Normal words: 2
|
||||
// First word in a sentence: 8
|
||||
// Then use a sliding window with a constant number of words and count the
|
||||
// sum of the values of the words within the window. Then use the window that got the
|
||||
// maximum sum. If there are multiple maximas, then get the last one.
|
||||
// Enclose the terms in <b>.
|
||||
function makeTeaser(body, terms) {
|
||||
var TERM_WEIGHT = 40;
|
||||
var NORMAL_WORD_WEIGHT = 2;
|
||||
var FIRST_WORD_WEIGHT = 8;
|
||||
var TEASER_MAX_WORDS = 30;
|
||||
|
||||
var stemmedTerms = terms.map(function (w) {
|
||||
return elasticlunr.stemmer(w.toLowerCase());
|
||||
});
|
||||
var termFound = false;
|
||||
var index = 0;
|
||||
var weighted = []; // contains elements of ["word", weight, index_in_document]
|
||||
|
||||
// split in sentences, then words
|
||||
var sentences = body.toLowerCase().split(". ");
|
||||
|
||||
for (var i in sentences) {
|
||||
var words = sentences[i].split(" ");
|
||||
var value = FIRST_WORD_WEIGHT;
|
||||
|
||||
for (var j in words) {
|
||||
var word = words[j];
|
||||
|
||||
if (word.length > 0) {
|
||||
for (var k in stemmedTerms) {
|
||||
if (elasticlunr.stemmer(word).startsWith(stemmedTerms[k])) {
|
||||
value = TERM_WEIGHT;
|
||||
termFound = true;
|
||||
}
|
||||
}
|
||||
weighted.push([word, value, index]);
|
||||
value = NORMAL_WORD_WEIGHT;
|
||||
}
|
||||
|
||||
index += word.length;
|
||||
index += 1; // ' ' or '.' if last word in sentence
|
||||
}
|
||||
|
||||
index += 1; // because we split at a two-char boundary '. '
|
||||
}
|
||||
|
||||
if (weighted.length === 0) {
|
||||
return body;
|
||||
}
|
||||
|
||||
var windowWeights = [];
|
||||
var windowSize = Math.min(weighted.length, TEASER_MAX_WORDS);
|
||||
// We add a window with all the weights first
|
||||
var curSum = 0;
|
||||
for (var i = 0; i < windowSize; i++) {
|
||||
curSum += weighted[i][1];
|
||||
}
|
||||
windowWeights.push(curSum);
|
||||
|
||||
for (var i = 0; i < weighted.length - windowSize; i++) {
|
||||
curSum -= weighted[i][1];
|
||||
curSum += weighted[i + windowSize][1];
|
||||
windowWeights.push(curSum);
|
||||
}
|
||||
|
||||
// If we didn't find the term, just pick the first window
|
||||
var maxSumIndex = 0;
|
||||
if (termFound) {
|
||||
var maxFound = 0;
|
||||
// backwards
|
||||
for (var i = windowWeights.length - 1; i >= 0; i--) {
|
||||
if (windowWeights[i] > maxFound) {
|
||||
maxFound = windowWeights[i];
|
||||
maxSumIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var teaser = [];
|
||||
var startIndex = weighted[maxSumIndex][2];
|
||||
for (var i = maxSumIndex; i < maxSumIndex + windowSize; i++) {
|
||||
var word = weighted[i];
|
||||
if (startIndex < word[2]) {
|
||||
// missing text from index to start of `word`
|
||||
teaser.push(body.substring(startIndex, word[2]));
|
||||
startIndex = word[2];
|
||||
}
|
||||
|
||||
// add <em/> around search terms
|
||||
if (word[1] === TERM_WEIGHT) {
|
||||
teaser.push("<b>");
|
||||
}
|
||||
startIndex = word[2] + word[0].length;
|
||||
teaser.push(body.substring(word[2], startIndex));
|
||||
|
||||
if (word[1] === TERM_WEIGHT) {
|
||||
teaser.push("</b>");
|
||||
}
|
||||
}
|
||||
teaser.push("…");
|
||||
return teaser.join("");
|
||||
}
|
||||
|
||||
function formatSearchResultItem(item, terms) {
|
||||
return '<div class="search-results__item">'
|
||||
+ `<a href="${item.ref}">${item.doc.title}</a>`
|
||||
+ `<div>${makeTeaser(item.doc.body, terms)}</div>`
|
||||
+ '</div>';
|
||||
}
|
||||
|
||||
function initSearch() {
|
||||
var $searchInput = document.getElementById("search");
|
||||
var $searchResults = document.querySelector(".search-results");
|
||||
var $searchResultsItems = document.querySelector(".search-results__items");
|
||||
var MAX_ITEMS = 10;
|
||||
|
||||
var options = {
|
||||
bool: "AND",
|
||||
fields: {
|
||||
title: {boost: 2},
|
||||
body: {boost: 1},
|
||||
}
|
||||
};
|
||||
var currentTerm = "";
|
||||
var index = elasticlunr.Index.load(window.searchIndex);
|
||||
|
||||
$searchInput.addEventListener("keyup", debounce(function() {
|
||||
var term = $searchInput.value.trim();
|
||||
if (term === currentTerm || !index) {
|
||||
return;
|
||||
}
|
||||
$searchResults.style.display = term === "" ? "none" : "block";
|
||||
$searchResultsItems.innerHTML = "";
|
||||
if (term === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
var results = index.search(term, options);
|
||||
if (results.length === 0) {
|
||||
$searchResults.style.display = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
currentTerm = term;
|
||||
for (var i = 0; i < Math.min(results.length, MAX_ITEMS); i++) {
|
||||
var item = document.createElement("li");
|
||||
item.innerHTML = formatSearchResultItem(results[i], term.split(" "));
|
||||
$searchResultsItems.appendChild(item);
|
||||
}
|
||||
}, 150));
|
||||
}
|
||||
|
||||
|
||||
if (document.readyState === "complete" ||
|
||||
(document.readyState !== "loading" && !document.documentElement.doScroll)
|
||||
) {
|
||||
initSearch();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", initSearch);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{% extends "index.html" %}
|
||||
|
||||
{% block extra_nav_class %}{% endblock extra_nav_class %}
|
||||
{% block extra_content_class %}content--reversed{% endblock extra_content_class %}
|
||||
|
||||
{% block content %}
|
||||
{% set section = get_section(path="client/_index.md") %}
|
||||
<div class="documentation">
|
||||
<aside class="documentation__sidebar">
|
||||
<ul>
|
||||
{% for p in section.subsections %}
|
||||
{% set subsection = get_section(path=p) %}
|
||||
<li>
|
||||
<span class="documentation__sidebar__title">{{ subsection.title }}</span>
|
||||
<ul>
|
||||
{% for page in subsection.pages %}
|
||||
<li class="{% if current_path == page.path %}active{% endif %}">
|
||||
<a href="{{page.permalink}}">{{page.title}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</aside>
|
||||
<div class="documentation__content">
|
||||
{% block doc_content %}
|
||||
{% endblock doc_content %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
@@ -1,36 +0,0 @@
|
||||
{% extends "index.html" %}
|
||||
|
||||
{% block extra_nav_class %}{% endblock extra_nav_class %}
|
||||
{% block extra_content_class %}content--reversed{% endblock extra_content_class %}
|
||||
|
||||
{% block content %}
|
||||
{%if page.extra.section %}
|
||||
{% set section = get_section(path="{{page.extra.section}}/_index.md") %}
|
||||
{% else %}
|
||||
{% set section = get_section(path="server/_index.md") %}
|
||||
{% endif %}
|
||||
<div class="documentation">
|
||||
<aside class="documentation__sidebar">
|
||||
<ul>
|
||||
{% for p in section.subsections %}
|
||||
{% set subsection = get_section(path=p) %}
|
||||
<li>
|
||||
<span class="documentation__sidebar__title">{{ subsection.title }}</span>
|
||||
<ul>
|
||||
{% for page in subsection.pages %}
|
||||
<li class="{% if current_path == page.path %}active{% endif %}">
|
||||
<a href="{{page.permalink}}">{{page.title}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</aside>
|
||||
<div class="documentation__content">
|
||||
{% block doc_content %}
|
||||
{% endblock doc_content %}
|
||||
{% block next_link %} {% endblock next_link %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
@@ -1,101 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-gb">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600" rel="stylesheet" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="{% block description %}{{ config.description }}{% endblock description %}">
|
||||
<meta name="keywords" content="Futures, Options, Derivatives, Trade, Trading, Professional, options trading, futures trading, Software, API, SDK" />
|
||||
<meta name="rights" content="© Blue Trading Systems" />
|
||||
<meta name="author" content="{{ config.extra.author }}">
|
||||
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
|
||||
<link rel="stylesheet" href="{{ get_url(path="site.css") }}"/>
|
||||
<link rel="icon" href="{{ get_url(path="favicon.ico") }}">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<nav class="{% block extra_nav_class %}container{% endblock extra_nav_class %}">
|
||||
<a class="header__logo white" href="{{ config.base_url }}">
|
||||
<img width="100" src="/images/logo.svg">
|
||||
</a>
|
||||
<a class="white" href="{{ get_url(path="@/server/_index.md") }}" class="nav-link">Server SDK</a>
|
||||
<a class="white" href="{{ get_url(path="@/client/_index.md") }}" class="nav-link">Client SDK</a>
|
||||
<a class="white" href="https://www.bluetradingsystems.com/bts-spark" class="nav-link">About Spark</a>
|
||||
|
||||
<div class="search-container">
|
||||
<input id="search" type="search" placeholder="🔎 Search">
|
||||
|
||||
<div class="search-results">
|
||||
<div class="search-results__items"></div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div class="content {% block extra_content_class %}{% endblock extra_content_class %}">
|
||||
{% block content %}
|
||||
<div class="hero">
|
||||
<h1>Spark SDK</h1>
|
||||
<p class="hero__tagline">
|
||||
Spark consists of a client UI
|
||||
(<a class="white" href="https://www.bluetradingsystems.com/bts-spark#ladder-algo-screen">Spark Client</a>),
|
||||
a high-performance professional futures front end, connected via our proprietary protocol over TCP to our Spark Server, which in turn connects to execution venues via their native protocols.
|
||||
Use the Spark SDK to extend Spark Server with your custom Algos, then use the Client SDK to launch and control them.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="inverted-colours selling-points">
|
||||
<div class="selling-points__content container">
|
||||
<div class="selling-header">
|
||||
<img src="/images/API.png" width="100%" />
|
||||
</div>
|
||||
<div class="selling-point">
|
||||
<h2>
|
||||
Server SDK
|
||||
<i class="fa fa-tachometer" aria-hidden="true"></i>
|
||||
</h2>
|
||||
<p>
|
||||
Leverage the ultra-low latency Spark C++ API to develop and run your custom Algo. Have your first sub-10 microsecond trading algorithm running in under an hour.
|
||||
</p>
|
||||
<a href="{{ get_url(path="@/server/_index.md") }}" class="button">Get started</a>
|
||||
</div>
|
||||
|
||||
<div class="selling-point disabled">
|
||||
<h2>
|
||||
Client SDK
|
||||
<i class="fa fa-gamepad" aria-hidden="true"></i>
|
||||
</h2>
|
||||
<p>
|
||||
The Spark client SDK allows you to integrate spark with your existing ecosystem. The Spark Client is built entirely on this simple, powerful API.
|
||||
</p>
|
||||
<a href="" class="button" disabled>Get started</a>
|
||||
</div>
|
||||
|
||||
<!-- <div class="selling-point disabled">
|
||||
<h2>
|
||||
Microsoft Excel
|
||||
<i class="fa fa-table" aria-hidden="true"></i>
|
||||
</h2>
|
||||
<p>
|
||||
More of your business is built on excel than probably should be. Continue this worrying trend with the Spark Excel API.
|
||||
</p>
|
||||
<a href="" class="button" disabled>Get started</a>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
</div>
|
||||
<footer>
|
||||
© Blue Trading Systems
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") }}"></script>
|
||||
<script type="text/javascript" src="{{ get_url(path="search_index.en.js") }}"></script>
|
||||
<script type="text/javascript" src="{{ get_url(path="search.js") }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,25 +0,0 @@
|
||||
{% extends "documentation.html" %}
|
||||
|
||||
{% block title %}{{ page.title }} | {{ super() }} {% endblock title %}
|
||||
{% block doc_content %}
|
||||
<h1>{{page.title}}</h1>
|
||||
{{page.content | safe}}
|
||||
{% endblock doc_content %}
|
||||
|
||||
{% block next_link %}
|
||||
<p>
|
||||
{% if page.lighter %}
|
||||
<a href="{{ page.lighter.permalink }}">
|
||||
<i class="fa fa-chevron-left fa-fw" aria-hidden="true"></i>
|
||||
Previous
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if page.heavier %}
|
||||
<a href="{{ page.heavier.permalink }}">
|
||||
Next
|
||||
<i class="fa fa-chevron-right fa-fw" aria-hidden="true"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endblock next_link %}
|
||||
@@ -1,15 +0,0 @@
|
||||
<pre
|
||||
{% if background %}
|
||||
style="background-color:{{background}};"
|
||||
{% else %}
|
||||
style="background-color:#383838;"
|
||||
{% endif %}
|
||||
>
|
||||
<span
|
||||
{% if color %}
|
||||
style="color:{{color}};"
|
||||
{% else %}
|
||||
style="color:#e6e1dc;"
|
||||
{% endif %}
|
||||
><a onclick="navigator.clipboard.writeText('{{body}}')"><i class="fa fa-clipboard fa-underline" style="color: white; text-decoration: none;"></i></a> {{body}}</span>
|
||||
</pre>
|
||||
@@ -1,7 +0,0 @@
|
||||
{% for asset in page.assets -%}
|
||||
{%- if asset is matching("[.](jpg|png)$") -%}
|
||||
<a href="{{ get_url(path=asset) | safe }}" target="_blank">
|
||||
<img src="{{ resize_image(path=asset, width=240, height=180, op="fill", format="auto") | safe }}" />
|
||||
</a>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
@@ -1,4 +0,0 @@
|
||||
<div class="info">
|
||||
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
|
||||
{{body}}
|
||||
</div>
|
||||
@@ -1,4 +0,0 @@
|
||||
<div class="linux">
|
||||
<i class="fa fa-linux fa-fw" aria-hidden="true"></i>
|
||||
{{body}}
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
<img src="{{ resize_image(path=path, width=width, height=height, op=op) }}" />
|
||||
@@ -1 +1 @@
|
||||
set(sources /home/ppinto/Dropbox/bts/spark/doc/user/build.sh;content/_index.md;content/bts_spark/Glossary/_index.md;content/bts_spark/Help/_index.md;content/bts_spark/Help/about_spark.png;content/bts_spark/Help/image39.png;content/bts_spark/Help/image58.png;content/bts_spark/Launcher/_index.md;content/bts_spark/Launcher/image38.png;content/bts_spark/Launcher/image68.png;content/bts_spark/Logging-In-to-the-System/_index.md;content/bts_spark/Logging-In-to-the-System/image3.png;content/bts_spark/Logging-In-to-the-System/image64.png;content/bts_spark/Market/_index.md;content/bts_spark/Market/change_securities.png;content/bts_spark/Market/image11.png;content/bts_spark/Market/image14.png;content/bts_spark/Market/image20.png;content/bts_spark/Market/image21.png;content/bts_spark/Market/image23.png;content/bts_spark/Market/image24.png;content/bts_spark/Market/image34.png;content/bts_spark/Market/image49.png;content/bts_spark/Market/image53.png;content/bts_spark/Market/image66.png;content/bts_spark/Market/image69.png;content/bts_spark/Market/market_view.png;content/bts_spark/Market/settings_icon.png;content/bts_spark/Market/time_and_sales.png;content/bts_spark/My-Windows/_index.md;content/bts_spark/My-Windows/image15.png;content/bts_spark/My-Windows/image16.png;content/bts_spark/My-Windows/image37.png;content/bts_spark/Settings/_index.md;content/bts_spark/Settings/image51.png;content/bts_spark/Settings/image9.png;content/bts_spark/Spreader/_index.md;content/bts_spark/Spreader/image10.png;content/bts_spark/Spreader/image13.png;content/bts_spark/Spreader/image18.png;content/bts_spark/Spreader/image19.png;content/bts_spark/Spreader/image28.png;content/bts_spark/Spreader/image29.png;content/bts_spark/Spreader/image31.png;content/bts_spark/Spreader/image35.png;content/bts_spark/Spreader/image40.png;content/bts_spark/Spreader/image43.png;content/bts_spark/Spreader/image54.png;content/bts_spark/Spreader/image55.png;content/bts_spark/Spreader/image56.png;content/bts_spark/Spreader/image6.png;content/bts_spark/Spreader/image7.png;content/bts_spark/Spreader/image70.png;content/bts_spark/Spreader/image72.png;content/bts_spark/Spreader/image8.png;content/bts_spark/Trading/OrderTypes/index.md;content/bts_spark/Trading/_index.md;content/bts_spark/Trading/algo_studio.png;content/bts_spark/Trading/collapse_all_icon.png;content/bts_spark/Trading/cover_algo_control.png;content/bts_spark/Trading/expand_all_icon.png;content/bts_spark/Trading/image1.png;content/bts_spark/Trading/image17.png;content/bts_spark/Trading/image2.png;content/bts_spark/Trading/image25.png;content/bts_spark/Trading/image27.png;content/bts_spark/Trading/image33.png;content/bts_spark/Trading/image42.png;content/bts_spark/Trading/image44.png;content/bts_spark/Trading/image47.png;content/bts_spark/Trading/image48.png;content/bts_spark/Trading/image5.png;content/bts_spark/Trading/image50.png;content/bts_spark/Trading/image52.png;content/bts_spark/Trading/image57.png;content/bts_spark/Trading/image59.png;content/bts_spark/Trading/image60.png;content/bts_spark/Trading/image61.png;content/bts_spark/Trading/image62.png;content/bts_spark/Trading/image73.png;content/bts_spark/Trading/image74.png;content/bts_spark/Trading/join_algo_control.png;content/bts_spark/Trading/ladder.png;content/bts_spark/Trading/ladder_badges.png;content/bts_spark/Trading/ladder_main_part.png;content/bts_spark/Trading/lean_algo_control.png;content/bts_spark/Trading/mini_orderbook.png;content/bts_spark/Trading/oco_algo_control.png;content/bts_spark/Trading/offset_algo_control.png;content/bts_spark/Trading/pnl_calculation.png;content/bts_spark/Trading/pnl_window.png;content/bts_spark/Trading/recreate_icon.png;content/bts_spark/Trading/settings_icon.png;content/bts_spark/Trading/spark_menu_order_book.png;content/bts_spark/Trading/top_algo_control.png;content/bts_spark/Trading/trigger_algo_control.png;content/bts_spark/_index.md;content/release_notes/_index.md;content/system_requirements/_index.md;static/book.js;static/favicon.ico;static/image.js;templates/index.html;templates/page.html;templates/section.html;templates/shortcodes/back_button.html)
|
||||
set(sources /home/ppinto/Dropbox/bts/spark/doc/user/build.sh;content/_index.md;content/bts_spark/Glossary/index.md;content/bts_spark/Help/about_spark.png;content/bts_spark/Help/image39.png;content/bts_spark/Help/image58.png;content/bts_spark/Help/index.md;content/bts_spark/Launcher/image38.png;content/bts_spark/Launcher/image68.png;content/bts_spark/Launcher/index.md;content/bts_spark/Logging-In-to-the-System/image3.png;content/bts_spark/Logging-In-to-the-System/image64.png;content/bts_spark/Logging-In-to-the-System/index.md;content/bts_spark/Market/change_securities.png;content/bts_spark/Market/image11.png;content/bts_spark/Market/image14.png;content/bts_spark/Market/image20.png;content/bts_spark/Market/image21.png;content/bts_spark/Market/image23.png;content/bts_spark/Market/image24.png;content/bts_spark/Market/image34.png;content/bts_spark/Market/image49.png;content/bts_spark/Market/image53.png;content/bts_spark/Market/image66.png;content/bts_spark/Market/image69.png;content/bts_spark/Market/index.md;content/bts_spark/Market/market_view.png;content/bts_spark/Market/settings_icon.png;content/bts_spark/Market/time_and_sales.png;content/bts_spark/My-Windows/image15.png;content/bts_spark/My-Windows/image16.png;content/bts_spark/My-Windows/image37.png;content/bts_spark/My-Windows/index.md;content/bts_spark/Settings/image51.png;content/bts_spark/Settings/image9.png;content/bts_spark/Settings/index.md;content/bts_spark/Spreader/image10.png;content/bts_spark/Spreader/image13.png;content/bts_spark/Spreader/image18.png;content/bts_spark/Spreader/image19.png;content/bts_spark/Spreader/image28.png;content/bts_spark/Spreader/image29.png;content/bts_spark/Spreader/image31.png;content/bts_spark/Spreader/image35.png;content/bts_spark/Spreader/image40.png;content/bts_spark/Spreader/image43.png;content/bts_spark/Spreader/image54.png;content/bts_spark/Spreader/image55.png;content/bts_spark/Spreader/image56.png;content/bts_spark/Spreader/image6.png;content/bts_spark/Spreader/image7.png;content/bts_spark/Spreader/image70.png;content/bts_spark/Spreader/image72.png;content/bts_spark/Spreader/image8.png;content/bts_spark/Spreader/index.md;content/bts_spark/Trading/algo_studio.png;content/bts_spark/Trading/collapse_all_icon.png;content/bts_spark/Trading/cover_algo_control.png;content/bts_spark/Trading/expand_all_icon.png;content/bts_spark/Trading/image1.png;content/bts_spark/Trading/image17.png;content/bts_spark/Trading/image2.png;content/bts_spark/Trading/image25.png;content/bts_spark/Trading/image27.png;content/bts_spark/Trading/image33.png;content/bts_spark/Trading/image42.png;content/bts_spark/Trading/image44.png;content/bts_spark/Trading/image47.png;content/bts_spark/Trading/image48.png;content/bts_spark/Trading/image5.png;content/bts_spark/Trading/image50.png;content/bts_spark/Trading/image52.png;content/bts_spark/Trading/image57.png;content/bts_spark/Trading/image59.png;content/bts_spark/Trading/image60.png;content/bts_spark/Trading/image61.png;content/bts_spark/Trading/image62.png;content/bts_spark/Trading/image73.png;content/bts_spark/Trading/image74.png;content/bts_spark/Trading/index.md;content/bts_spark/Trading/join_algo_control.png;content/bts_spark/Trading/ladder.png;content/bts_spark/Trading/ladder_badges.png;content/bts_spark/Trading/ladder_main_part.png;content/bts_spark/Trading/lean_algo_control.png;content/bts_spark/Trading/mini_orderbook.png;content/bts_spark/Trading/oco_algo_control.png;content/bts_spark/Trading/offset_algo_control.png;content/bts_spark/Trading/pnl_calculation.png;content/bts_spark/Trading/pnl_window.png;content/bts_spark/Trading/recreate_icon.png;content/bts_spark/Trading/settings_icon.png;content/bts_spark/Trading/spark_menu_order_book.png;content/bts_spark/Trading/top_algo_control.png;content/bts_spark/Trading/trigger_algo_control.png;content/bts_spark/_index.md;content/bts_spark_sdk/Client/Overview.md;content/bts_spark_sdk/Client/Threading.md;content/bts_spark_sdk/Client/_index.md;content/bts_spark_sdk/Server/_index.md;content/bts_spark_sdk/_index.md;content/release_notes/_index.md;static/book.js;static/favicon.ico;static/image.js;templates/index.html;templates/page.html;templates/section.html;templates/shortcodes/back_button.html)
|
||||
@@ -7,6 +7,7 @@ zola_path=$(readlink -f "../../externals/linux/bin/zola/zola")
|
||||
|
||||
mkdir -p $temp_path
|
||||
cp -r ./* $temp_path
|
||||
cp -r ../../src/sdk/doc/* $temp_path/content/bts_spark_sdk/Server/
|
||||
|
||||
cd $temp_path
|
||||
$zola_path build -u '/docs/' -o $1 >$tmpfile 2>&1
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
+++
|
||||
title = "BTS Basic Algos"
|
||||
weight = 10
|
||||
sort_by = "weight"
|
||||
insert_anchor_links = "right"
|
||||
+++
|
||||
|
||||
|
||||
## Lean
|
||||
|
||||
The goal of the lean order is to watch the opposite-inside market size and cross when that size goes below the threshold (this also implies a cross if that size goes to zero and the market trades away from you) If the market trades toward you, you can opt into several different behaviors
|
||||
|
||||
##### Parameters
|
||||
* Cross Thresh - size thresh in absolute or ratio terms
|
||||
* Max Chase Ticks - max levels to pay up, in ticks
|
||||
|
||||
|
||||
## Join
|
||||
The goal of the join order is to watch the opposite-inside market and join when the market flips (that is, when the best offer becomes the best bid) and has at least threshold size.
|
||||
|
||||
##### Parameters
|
||||
* Join Thresh - size thresh in absolute or ratio terms
|
||||
|
||||
|
||||
## Top
|
||||
|
||||
The goal of the top order is to not trade by yourself, but the intent at the time of order entry is to get filled.If the order is on the market (say current bid price) AND the quantity on that bid price is below top thresh then cancel the order else remain working.
|
||||
|
||||
##### Parameters
|
||||
* Top Thresh - size thresh in absolute or ratio terms
|
||||
|
||||
|
||||
## Cover
|
||||
A Cover order’s purpose is to fire a hedge order (of any type) in response to fills from it’s child order on the opposite side of the market N ticks away
|
||||
|
||||
##### Parameters
|
||||
* Profit Ticks - ticks above or below fill price to place profit / cover order
|
||||
|
||||
|
||||
## OCO
|
||||
An OCO order creates a relationship between a child order and a 'stop' or 'other' order such that when one of these is cancelled, both cancel, or when one is filled, the other order's size is debited in the amount of the fill.
|
||||
|
||||
Composing this order with Cover simulates scalping functionality
|
||||
|
||||
##### Parameters
|
||||
* Stop Ticks - ticks below or above main order to place stop / other order
|
||||
@@ -154,7 +154,7 @@ insert_anchor_links = "right"
|
||||
|
||||
- Pay Less - If enabled by checking the checkbox, the spreader will
|
||||
attempt to pay less when the quantity at the level of the calculated
|
||||
hedge price is less than the threshold defined. The hedge order is
|
||||
hedge price is more than the threshold defined. The hedge order is
|
||||
paid less by the “Payless Ticks” as defined per leg.
|
||||
- Pay Up - If enabled by checking the checkbox, the spreader will pay
|
||||
up when the quantity at the level of the calculated hedge price is
|
||||
@@ -1,77 +0,0 @@
|
||||
+++
|
||||
title = "Basic Algos"
|
||||
weight = 1
|
||||
sort_by = "weight"
|
||||
insert_anchor_links = "right"
|
||||
aliases = ["./bts_spark/Algos/"]
|
||||
+++
|
||||
|
||||
## Lean
|
||||
|
||||
The goal of the lean order is to watch the opposite-inside market size and cross when that size goes below the threshold (this also implies a cross if that size goes to zero and the market trades away from you) If the market trades toward you, you can opt into several different behaviors
|
||||
|
||||
##### Parameters
|
||||
* Cross Thresh - size thresh in absolute or ratio terms
|
||||
* Max Chase Ticks - max levels to pay up, in ticks
|
||||
|
||||
|
||||
## Join
|
||||
The goal of the join order is to watch the opposite-inside market and join when the market flips (that is, when the best offer becomes the best bid) and has at least threshold size.
|
||||
|
||||
##### Parameters
|
||||
* Join Thresh - size thresh in absolute or ratio terms
|
||||
|
||||
|
||||
## Top
|
||||
|
||||
The goal of the top order is to not trade by yourself, but the intent at the time of order entry is to get filled.If the order is on the market (say current bid price) AND the quantity on that bid price is below top thresh then cancel the order else remain working.
|
||||
|
||||
##### Parameters
|
||||
* Top Thresh - size thresh in absolute or ratio terms
|
||||
|
||||
|
||||
## Cover
|
||||
A Cover order’s purpose is to fire a hedge order (of any type) in response to fills from it’s child order on the opposite side of the market N ticks away
|
||||
|
||||
##### Parameters
|
||||
* Profit Ticks - ticks above or below fill price to place profit / cover order
|
||||
|
||||
|
||||
## OCO
|
||||
An OCO order creates a relationship between a child order and a 'stop' or 'other' order such that when one of these is cancelled, both cancel, or when one is filled, the other order's size is debited in the amount of the fill.
|
||||
|
||||
Composing this order with Cover simulates scalping functionality
|
||||
|
||||
##### Parameters
|
||||
* Stop Ticks - ticks below or above main order to place stop / other order
|
||||
|
||||
## Splitter
|
||||
The splitter is useful for pro-rata markets where you want to vary your exposure independent of the order quantity that you want to fill. The splitter will complete when the number of fills reaches or exceeds the order quantity but it will put exposed_qty total size on the market. Splitter favors order size over queue position.
|
||||
|
||||
If exposed_qty is set to 0 the splitter will continue to exist in the Order Book but will cancel all of its child orders. This makes it a useful building block for custom algos that need to implement a 'paused' state.
|
||||
|
||||
##### Parameters
|
||||
* exposed_qty - The total quantity to expose on the market.
|
||||
* max_order_qty - The maximum size of a single order.
|
||||
|
||||
|
||||
## Scratch
|
||||
The scratch algo is similar to Lean, but instead of watching the opposite inside market, it watches the same side market and pays up when this quantity recedes below the scratch_threshold
|
||||
|
||||
##### Parameters
|
||||
* scratch_threshold - The quantity on the same side market below which to scratch
|
||||
* chase_ticks - The number of ticks through the opposite market to pay up
|
||||
|
||||
|
||||
## ProRata
|
||||
The prorata algo is a special case hedging algo for pro-rata markets. Users can specify two hedge types-- normal hedge and overfill hedge, the latter is spawned when you receive more fills than your fill_limit. Further, the algo attempts to scratch when in an overfilled state AND optionally the same side size falls below stay_in_threshold
|
||||
|
||||
##### Parameters
|
||||
* hedge_ticks - The amount of ticks better hedges are placed on the opposite side market as the fill
|
||||
* chase_ticks - How many ticks through the opposite market on a scratch
|
||||
* fill_limit - The limit after which the algo considers further fills to be 'overfills'
|
||||
* stay_in_threshold - A same side size threshold that enables the algo to 'stay in' even if overfilled
|
||||
* enable_scratch_on_overfill - When true, overfills are immediately scratched upon the algo exiting
|
||||
* enable_stay_in - When true, the algo will 'stay in' so long as the same side size is above stay_in_threshold, when false the algo attempts to 'get out' (and potentially scratch overfills) as soon as it reaches overfill status
|
||||
* hedge - Child order type to send for normal hedges
|
||||
* overfill_hedge - Child order type to send for overfill hedges
|
||||
@@ -4,346 +4,6 @@ weight = 3
|
||||
sort_by = "weight"
|
||||
insert_anchor_links = "right"
|
||||
+++
|
||||
## 2.15.0
|
||||
### User Visible Changes
|
||||
- Added ability to hide Ladder status messages via Ladder Settings -> Left Panel tab -> Show/Hide groupbox -> Status Message
|
||||
- Synthetic cloning now allows for any parameter to be changed, including tick size and leg contracts
|
||||
- Added ability to import synthetics from a CSV file; see our manual for further details on this process
|
||||
- Reduced Iceberg reloading latency
|
||||
### Bug Fixes
|
||||
- Fixed a bug where highlighted fills could lose their highlight status
|
||||
- Fixed a bug where the (Mini) OrderBook PIQ could be displaying an old value
|
||||
|
||||
## 2.14.3
|
||||
### Bug Fixes
|
||||
- Fixed a bug regarding ICE logon messaging
|
||||
|
||||
## 2.14.2
|
||||
### Bug Fixes
|
||||
- Fixed a bug regarding ICE messaging
|
||||
|
||||
## 2.14.1
|
||||
### Bug Fixes
|
||||
- Fixed a bug regarding ICE logon authentication
|
||||
|
||||
## 2.14.0
|
||||
### User Visible Changes
|
||||
- All ladders can now be recentered by (shift or alt) + double clicking over the Price column in a ladder
|
||||
- Added a Max Order Quantity setting to the Safety Checks tab on the Ladder settings. This setting allows for a user-defined maximum order quantity.
|
||||
- Added a Price Display Format setting to the Market Price and Size Display tab on the Ladder settings. This setting allows for price levels in the ladder to be displayed without a decimal separator.
|
||||
- Synthetic instrument creation with 3 legs no longer defaults to butterfly quantites
|
||||
### Bug Fixes
|
||||
- Fixed an issue where market transition were not observed by IAlgoOrder
|
||||
- Fixed a bug in error reporting
|
||||
- Fixed a bug in the PnL window where specifying a certain grouping order would lead to a UI failure
|
||||
|
||||
## 2.13.0
|
||||
### User Visible Changes
|
||||
- Added the name of the spreader to the parent algo badge (for spreader child orders), in the fills, orderbook and floating orderbook windows
|
||||
- Added support for sounds for new orders
|
||||
- Added a new quoting throttle parameter for the spreader, that throttles quotes that are moving toward the inside market but are still a configurable number of ticks away
|
||||
- Enabled the ladder to remember the left panel scroll position across front end restarts
|
||||
### Bug Fixes
|
||||
- Fixed the local fills window so that it does not show the admin fills
|
||||
- Removed the deleted accounts from the ladder accounts dropdown
|
||||
- Fixed the orderbook price for iceberg of spreaders
|
||||
|
||||
## 2.12.0
|
||||
### User Visible Changes
|
||||
- Added support for ICE market data and order execution
|
||||
### Internal Changes
|
||||
- Lots of permission / admin changes to facilitate ICE
|
||||
|
||||
## 2.11.0
|
||||
### User Visible Changes
|
||||
- Fixed fills form time filter to also apply to SOD fills
|
||||
- Addressed an issue that could prevent the web Admin UI from displaying over slow HTTP connections
|
||||
- Removed the option to enter manual spread fills
|
||||
- Fixed an issue that could cause erroneous fill account attribution in the event of a crash
|
||||
### Internal Changes
|
||||
- Added support for tag 1031. Currently defaults to Y, can it be override through config.
|
||||
- To facilitate support, allowed the bts user to view and edit algos from all other users
|
||||
- Improved system tests
|
||||
- Improved log messages in UI to include dispatcher thread name
|
||||
- Added support for Windows core dumps in the UI
|
||||
|
||||
## 2.10.0
|
||||
### User Visible Changes
|
||||
- Fills now include information about the algo that originated the fill
|
||||
- A new, more powerful PnL form is now available
|
||||
### API Changes
|
||||
- Added security state information (pre open, halted, normal, closed, etc)
|
||||
### Bug Fixes
|
||||
- Brought back the "select all" check box in the mini order book
|
||||
- Fixed an issue in the market data subsystem that on rare occasions could result in a startup crash
|
||||
### Internal Changes
|
||||
- Fixed an issue that was stopping us from interpreting SOD times as local rather than GMT
|
||||
## 2.9.3
|
||||
### Internal Changes
|
||||
- Fixed system test scripts
|
||||
## 2.9.2
|
||||
### Bug Fixes
|
||||
- Fixed an issue with the exchange simulator that could lead to crossed markets
|
||||
## 2.9.1
|
||||
### Bug Fixes
|
||||
- Fixed an issue with trade sound alerts, where in some cases the use of a "In Between" condition could lead to a UI failure.
|
||||
- Fixed an issue with the display of the new raw position column in the market view window.
|
||||
- Fixed the popup label that describes the raw position information in the ladder
|
||||
### Internal Changes
|
||||
- Avoided shipping production configuration defaults that lead to trying to download a position file for the development sftp server.
|
||||
### Api
|
||||
- C# API sample now uses synchronous calls.
|
||||
|
||||
## 2.9.0
|
||||
### User Visible Changes
|
||||
- Improved Workspace management User Interface
|
||||
- Added the ability to change grid background colors
|
||||
- The Spark UI Window group now has a title in the Windows task bar
|
||||
- Added sound alerts for trade events, see Launcher -> Settings -> Alerts
|
||||
- Allowed composite algos that are attached to existing orders to identify fills that were already present prior to attachment
|
||||
- Added import facilities for GMI position files
|
||||
- Added the ability for risk managers to enter manual fills
|
||||
- Added "raw" P&L columns, that is columns that *do not* include spread legs in their accounting
|
||||
### Bug Fixes
|
||||
- Fixed the settings action menu (Load/Save/Reset to Factory)
|
||||
- Fixed the method used to determine if a security is expired to take into account the start of day time
|
||||
### API Changes
|
||||
- Fixed an issue in the Client SDK that could lead to occasional failures to connect to the spark server as well as excessive memory usage.
|
||||
- Added the ability for algo orders to distinguish fills existing prior to launch
|
||||
### Internal Changes
|
||||
- Changed how we packaged certain third-party components
|
||||
- Added logging of entitlement status
|
||||
- Tagged outgoing orders with sequence number of marketdata or FIX event that triggered them
|
||||
## 2.8.3
|
||||
### Bug Fixes
|
||||
- Fixed a bug that could cause an OrderBook's Security column filter to be blank
|
||||
- Fixed a bug that could cause a UI failure when clearing a filter selection on a filtering widget
|
||||
## 2.8.2
|
||||
### Bug Fixes
|
||||
- Added proper display factors for SOM spreads
|
||||
- Fixed a bug that could cause a UI failure when trying to change settings in a synthetic ladder
|
||||
## 2.8.1
|
||||
### Bug fixes
|
||||
- Fixed an error in the UI grids filtering widget
|
||||
## 2.8.0
|
||||
### User Visible Changes
|
||||
- Added ProRata and Scratch algos
|
||||
- Ladder badge now grows/shrinks to fill the containing cell
|
||||
- Attached algo parameters are now displayed in the update panel
|
||||
- Fixed a bug where the update panel would show '-' values when only
|
||||
1 order was selected
|
||||
- Fixed a bug that cause cause a failure on startup if the user
|
||||
loaded a workspace with a Ladder that had a dynamic order type
|
||||
selected by default
|
||||
- Increased width of login panel to better show login error messages
|
||||
- Added optional 'Maker/Taker' pricing to Spreader algo
|
||||
- Algo buttons in ladder can now be made to deactivate after launching an algo or remain 'sticky'
|
||||
### Internal changes
|
||||
- Made it easier to generate simple UI's for new order types
|
||||
### API Changes
|
||||
- Dynamic orders can now use QuantityMeasure parameter types
|
||||
|
||||
## 2.7.2
|
||||
### User Visible Changes
|
||||
- Changed the login dialog to avoid leaking workspace names from other users.
|
||||
- Added new Splitter algo. From the manual: The splitter is useful
|
||||
for pro-rata markets where you want to vary your exposure
|
||||
independent of the order quantity that you want to fill. The
|
||||
splitter will complete when the number of fills reaches or exceeds
|
||||
the order quantity but it will put exposed_qty total size on the
|
||||
market. Splitter favors order size over queue position.
|
||||
### Internal Changes
|
||||
- Made spark more resilient to lack of connectivity to the CME web site for downloading of templates.
|
||||
|
||||
## 2.7.1
|
||||
### User Visible Changes
|
||||
- Fixed some issues with the Cover algo, where in some circumstances
|
||||
it would erroneously cancel launched hedges on completion.
|
||||
|
||||
## 2.7.0
|
||||
### User Visible Changes
|
||||
- Allowed algos to process "in-flight" fills while shutting down
|
||||
- Changed the cover algo to continue to hedge while shutting down
|
||||
### API Changes
|
||||
- Changed the API so that algos do not fully terminate until all
|
||||
their children are terminated. Algos that are in the process of
|
||||
shutting down in response to a complete or cancel call will still
|
||||
receive child updates, which they can use to calculate and report
|
||||
an accurate fill count (during this shutdown stage algos cannot
|
||||
create, cancel or update children). A new IAlgoServices method,
|
||||
is_shutting_down(), can be used to determine if an algo is
|
||||
shutting down.
|
||||
|
||||
## 2.6.2
|
||||
### User Visible Changes
|
||||
- Fixed an issue in the ladder where in some cases the mini order book could not be brought up from a badge
|
||||
- Fixed a rare race condition that could lead to erroneous limit enforcement
|
||||
- Fixed an issue with the margin limits where an error could occur if an account name with more than 12 chars was used
|
||||
|
||||
## 2.6.1
|
||||
### User Visible Changes
|
||||
- Fixed an issue in the ladder where an error could occur when trying to change ladder settings for the first time
|
||||
|
||||
## 2.6.0
|
||||
### User Visible Changes
|
||||
- In the ladder made last trade more distinctive when overlayed on the volumn column
|
||||
- In the ladder, corrected display of volume tool tip
|
||||
- In the ladder, changed the consolidation of last trade to consider only the price ignoring aggressor changes
|
||||
- Added an option for the Top Algo to delete itself if within N ticks from top of book
|
||||
- Address a rare issue that could lead to an error report on UI exit
|
||||
- Added margin risk limits
|
||||
- Added the "Offset" algo. Offset prices a child algo at a parameterizable distance from the top of the book
|
||||
- Avoided switching the current account and order type on open ladders when limits are changed
|
||||
### Internal Changes
|
||||
- Ensure that admin logins are always allowed to login, regardless of keycode status.
|
||||
|
||||
## 2.5.0
|
||||
### User Visible Changes
|
||||
- Added loss limit risk check
|
||||
- Made algos, synthetics and user names private so that multiple users can share a single system privately.
|
||||
- Allowed the mini order book defaults for column widths to be changed from the mini order book
|
||||
- Allowed the mini order book to shrink to the minimum size that will be needed to display the selected columns
|
||||
- Improved accuracy of the directional arrow when displaying last trades in the volumn column
|
||||
## 2.4.0
|
||||
### User Visible Settings
|
||||
- In the ladder, changed the last trade column to accumulate successive trades at the same price
|
||||
- Fixed a bug in the order book where the right side ladder would display the top leve order's security rather then current row's
|
||||
- Added OK, Cancel buttons to the security picker for ladder profiles or sounds
|
||||
- Added ladder settings for the mini order book
|
||||
- Added a safety check to guard against unintentional market crosses
|
||||
- Improved the Queue Holder mode in the spreader:
|
||||
- Added a Show Quantity, allowing the spreader to keep queue position of the trailing orders as Fills (of size Show Qty) happen
|
||||
- Improved spreader performance when in Queue Holder mode
|
||||
### Internal changes
|
||||
- Suppressed order callbacks for completed/canceled orders. This should eliminate some bogus error logs by spreader orders.
|
||||
- Addressed a potential concurrency issues with service initialization.
|
||||
|
||||
|
||||
## 2.3.0
|
||||
### User Visible Changes
|
||||
- Introduced multiple settings profiles for the ladder
|
||||
- This allows multiple standard configuration for the ladder, optionally with security specific variations
|
||||
- Made Cover order more independent from its hedging chidren:
|
||||
- Cover continues to operate even if an hedging child is canceled
|
||||
- When a cover is canceled it will detach from any running hedging children, instead of canceling them
|
||||
- Changed Lean, Join and Cover algos to hide themselves in the ladder once they have completed their work
|
||||
- Changed manual fills to appear in day PnL rather than in the SOD records
|
||||
- Add buy/sell coloring to fill rows in fills window
|
||||
- Streamlined the mini order book:
|
||||
- Display of the mini order book popup is quicker
|
||||
- Only exchange orders are displayed
|
||||
- Update buttons are only displayed for orders that are under control of an algo with the update applying to the entire algo, not just the exchange order
|
||||
- We can now select multiple rows to attach, detach, update or cancel multiple orders in a batch
|
||||
- A checkbox column has been added to make clearer which rows are selected
|
||||
### API Changes
|
||||
- Enhanced the API to allow algos to implement custom cancel handling
|
||||
- Allowed algos to control their visibility in the ladder through the API
|
||||
### Internal Changes
|
||||
- Added system requirements to Spark documentation
|
||||
- Implemented keycodes
|
||||
- Temporarily rejected stop and stop limit orders, pending bug fixes
|
||||
|
||||
## 2.2.0
|
||||
### User Visible Changes
|
||||
- Made our orders easier to spot in MBO display
|
||||
- Changed middle-click on center column to recenter ladder and introduced Alt middle-click on center to bring up the MBO popup
|
||||
- Fixed Net/Absolute radio button in risk admin UI
|
||||
- Fixed double counting of spread legs in limits
|
||||
- Removed expired fills from the system
|
||||
- Improved handling of orders with undiscovered securities
|
||||
- Added feedback to the ladder when the user attempts to middle click on bid/ask columns using an order that does not have parameters
|
||||
- Fixed display of algo studio algo types in order book
|
||||
- Hid net change setting in synthetic ladders
|
||||
- Fixed a number of problems with filtering on the Fills form
|
||||
- On the Lean algo, OnToward and Away are now calculated with respect to the opposite inside market at time of the order launch
|
||||
- Iceberg Spreaders with queue holders are not erroneously cancelled after the first fill
|
||||
- Added security symbol column to fills window
|
||||
- Re-organized ladder settings dialog to make it clearer and easier to use
|
||||
|
||||
## 2.1.4
|
||||
### User Visible Changes
|
||||
- Fixed handling of cancel button in security picker
|
||||
|
||||
## 2.1.3
|
||||
### User Visible Changes
|
||||
- Fixed a simulator bug in the handling of 0 sized orders
|
||||
|
||||
## 2.2.1
|
||||
### User Visible Changes
|
||||
- Fixed order book form exception when display a spreader order for whichs the legs were not present yet
|
||||
|
||||
## 2.1.1
|
||||
### User Visible Changes
|
||||
- Added PIQ to GLBX Iceberg orders
|
||||
- Corrected handling of stop limit orders
|
||||
|
||||
## 2.1.0
|
||||
### User Visible Changes
|
||||
- Added support for the GLBX Iceberg order type
|
||||
- Allowed quick algo param edits by middle-clicking on either the bid/ask columns or a "favorite" button
|
||||
- Added support for manual fills, either entered manually or imported from file. Manual fills are used only for P&L purposes, they have no impact on limits
|
||||
- Allowed the LTQ and VAP values to be overlayed on the same ladder column
|
||||
- Added day position information to the ladder
|
||||
- Added PIQ to the mini order book
|
||||
- Fixed a rare bug that could lead to server failure when requesting market data
|
||||
- Fixed a bug that could cause incorrect price displays for certain types of synthetic securities
|
||||
|
||||
## 2.0.5
|
||||
### User Visible Changes
|
||||
- Fixed a bug in the handling of rejected QHO orders
|
||||
- Implemented stricter position limit enforcement
|
||||
- Fixed a bug that could cause server failure when trying to attach to already attached orders
|
||||
|
||||
## 2.0.4
|
||||
### User Visible Changes
|
||||
- Fixed performance regression in order manager
|
||||
|
||||
### Internal changes
|
||||
- Improved market data diagnostics for bad configurations
|
||||
- Changed market data default buffer size
|
||||
|
||||
## 2.0.3
|
||||
### Internal changes
|
||||
- Improved backwards compatibility in UI settings
|
||||
|
||||
|
||||
## 2.0.2
|
||||
### User Visible Changes
|
||||
- Middle click the ladder price column to show the orders for that price level
|
||||
- Middle click the bid or ask column in the ladder no longer sends an order
|
||||
|
||||
### Internal changes
|
||||
- Improved market by order performance under heavy load
|
||||
- Fixed a concurrency bug in SIM
|
||||
|
||||
## 2.0.0
|
||||
### User Visible Changes
|
||||
- Support for attaching and detaching algos to existing orders
|
||||
- Support for display and update of all parameters in running algos
|
||||
- Streamlining of order badge decorations in ladder
|
||||
- New order search/filtering algorithm for order book
|
||||
- Simpler representation of complex algo chains in order book and mini order book
|
||||
- Visual and usability improvements to mini order book
|
||||
- Streamlining of algo parameter dialog in ladder
|
||||
- New spreader queue holder behavior
|
||||
- Visual improvements to the order book
|
||||
- New server side API
|
||||
- Improved admin UI performance
|
||||
- Optimized PIQ rendering
|
||||
### Internal changes
|
||||
- Exchange simulator no longer requires daily sequence number reset
|
||||
- Improved MD resilience to corrupted shared memory
|
||||
- Native orders can now buffer updates/cancels when disconnected or pending first acknowledgment
|
||||
- Improved settings manager tool output
|
||||
- Added diagnostics in the event MD memory corruption is detected
|
||||
- Added systems tests for join,lean, iceberg and spreader orders
|
||||
- Made exchange order recovery more resilient in the presence of database loss
|
||||
|
||||
## 1.6.2
|
||||
### User Visible Changes
|
||||
### Exchange simulator
|
||||
- Exchange simulator now now produce position in queue data
|
||||
|
||||
## 1.6.0
|
||||
### User Visible Changes
|
||||
#### New Features
|
||||
@@ -363,7 +23,7 @@ insert_anchor_links = "right"
|
||||
- Integrated stunnel into UI to make VPN setup unnecessary in unsecured environments.
|
||||
## 1.5.7
|
||||
### User Visible Changes
|
||||
- New videos have been added to the manual describing the [Algo Studio](./bts_spark/Trading/_index.md#algo-studio) and [Spreader](./bts_spark/Spreader/_index.md)
|
||||
- New videos have been added to the manual describing the [Algo Studio](./bts_spark/Trading/index.md#algo-studio) and [Spreader](./bts_spark/Spreader/index.md)
|
||||
- Fixed a bug that occasionally would cause windows to be position outside the visible screen on startup
|
||||
- Fixed a bug in the order book form that would occasionally cause the Recreate Order option to be unavailable
|
||||
- Added a confirmation step to Cancel All, Cancel Buys and Cancel Sells commands
|
||||
@@ -377,21 +37,21 @@ insert_anchor_links = "right"
|
||||
- These columns can be restored by toggling their visibility within the PnL's Settings form
|
||||
- A new Traded Today column has been added to the PnL
|
||||
- Filtering on this column will allow a user to restrict the report to only show today's position
|
||||
### Internal changes
|
||||
- Improved organization of the shell notification architecture
|
||||
### Internal changes
|
||||
- Improved organization of the shell notification architecture
|
||||
- Added logging to help troubleshoot shell exit hang
|
||||
|
||||
## 1.5.6
|
||||
### User Visible Changes
|
||||
- Fixed a bug that could cause limits to be erroneously enforced
|
||||
- Fixed a bug that could cause limits to be erroneously enforced
|
||||
- Improved algo documentation
|
||||
- Changed how the spreader uses net change
|
||||
- Simplified trigger algo user interface
|
||||
### Internal changes
|
||||
### Internal changes
|
||||
- Defaulted to not recording sim market data
|
||||
- Improved documentation build
|
||||
- Improved documentation build
|
||||
- Added additional performance tracing
|
||||
|
||||
|
||||
## 1.5.5
|
||||
- Fixed Market View 'stale working orders' bug
|
||||
|
||||
@@ -399,11 +59,11 @@ insert_anchor_links = "right"
|
||||
- Avoided logging when warming up cache
|
||||
|
||||
## 1.5.3
|
||||
- Fixed sounds startup issue
|
||||
- Fixed sounds startup issue
|
||||
|
||||
## 1.5.2
|
||||
- Added better logging to AlgoDefinitionService
|
||||
|
||||
|
||||
## 1.5.1
|
||||
- Fixed missing securities in the Fills and P&L windows.
|
||||
|
||||
@@ -424,7 +84,7 @@ insert_anchor_links = "right"
|
||||
#### Bug Fixes
|
||||
- Fixed the "Since Open" time filter to use the exchange open time rather than 8:30 AM
|
||||
- Fixed a bug in the order book where sometimes parent orders would not update their last message column.
|
||||
|
||||
|
||||
#### Algos
|
||||
- Added OCO Algo
|
||||
- An OCO order creates a relationship between a child order and a 'stop' or 'other' order such that when one of these is cancelled, both cancel, or when one is filled, the other order's size is debited in the amount of the fill. Composing this order with Cover simulates scalping functionality
|
||||
@@ -432,7 +92,7 @@ insert_anchor_links = "right"
|
||||
- Improved SDK documentation and usability
|
||||
- Dynamic orders are now properly identified in the order book
|
||||
#### Documentation
|
||||
- Information on the Spark API has been added to the Spark manual
|
||||
- Information on the Spark API has been added to the Spark manual
|
||||
- The documentation has been updated and reorganized to make information easier to find
|
||||
### Internal Changes
|
||||
- Improved robustness of limit system test
|
||||
@@ -487,7 +147,6 @@ insert_anchor_links = "right"
|
||||
- The zoom functionality can also be performed via hotkey and mouse wheel combinations
|
||||
- Zoom In = CTRL + Mouse wheel up
|
||||
- Zoom Out = CTRL + Mouse wheel down
|
||||
|
||||
- Reset zoom = CTRL + Mouse wheel click or double click on the zoom slider
|
||||
### Exchange simulator
|
||||
- Improved the exchange simulator to track real market data more closely
|
||||
@@ -594,7 +253,6 @@ insert_anchor_links = "right"
|
||||
- All windows now contain a settings page where grid settings (font color, size, etc) are applied
|
||||
- These settings can be saved on a per-window basis or as a Default for newly-launched windows
|
||||
|
||||
|
||||
## 1.3.1 Through 1.3.4
|
||||
|
||||
### Speed Enhancements
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
+++
|
||||
title = "System Requirements"
|
||||
weight = 4
|
||||
sort_by = "weight"
|
||||
insert_anchor_links = "right"
|
||||
+++
|
||||
|
||||
|
||||
### Minimum Workstation
|
||||
* New XPS Tower
|
||||
* 8th Generation Intel® Core™ i7-8700 6-Core Processor (12M Cache, up to 4.6 GHz)
|
||||
* 16GB, 2666MHz, DDR4 up to 64GB
|
||||
* Windows 10 Professional 64-bit
|
||||
* NVIDIA® GeForce® GTX 1070 with 8GB GDDR5 Graphics Memory
|
||||
* 1 x 2.5" 256GB SATA Solid State Drive
|
||||
|
||||
### Recommended Workstation
|
||||
* Similar or better than:
|
||||
* Dell Precision Tower 5820
|
||||
* Intel Xeon W-2145 3.7GHz, 4.5GHz Turbo, 8C, 11M Cache, HT, (140W) DDR4-2666
|
||||
* Windows 10 Professional 64-bit
|
||||
* NVIDIA® Quadro® P1000, 4GB, 4 mDP
|
||||
* 16GB (4x4GB) 2133MHz DDR4 RDIMM ECC
|
||||
* 2 x 2.5" 256GB SATA Solid State Drive running RAID1
|
||||
|
||||
|
||||
### BTS Recommended Server Specifications
|
||||
* Dell R640
|
||||
* 2x Intel Xeon Gold 6148 2.40GHz 20-Core Processors. For better performance BTS recommends Intel® Xeon® Platinum 8268 2.9G, 24 Core CPU
|
||||
* 192GB RAM 2666MHz DDR4
|
||||
* 3x 480GB SSD RAID 5 HBA Minicard
|
||||
* iDRAC 9 Enterprise
|
||||
* Embedded Broadcom NIC
|
||||
* Solarflare SFN8522-R2
|
||||
* Redundant Power Supply
|
||||
|
||||
### BTS Minimum Server Specifications
|
||||
* Dell R620
|
||||
* Chassis with up to 8, 2.5” Hard Drives, up to 2 PCIe Slots (With Optional Riser)
|
||||
* 2 x Intel® E5-2670 (16 total cores/ 32 total threads)
|
||||
* 64GB total memory
|
||||
* RAID 1 for H330/H730/H730P
|
||||
* PERC H730 RAID Controller, 1GB NV Cache
|
||||
* 3 x 300GB 10K RPM SATA 6Gbps 2.5in Hot-plug Hard Drive (RAID 5)
|
||||
* iDRAC8 Enterprise, integrated Dell Remote Access Controller, Enterprise (varies by hosting company)
|
||||
* Solarflare Ultra SFN7122F Dual-Port 10GbE (10 GB connectivity requirements, copper vs optical, varies by hosting company).
|
||||
* Dual, Hot-plug, Redundant Power Supply (1+1), 750W
|
||||
* Performance BIOS Setting
|
||||
* ReadyRails Sliding Rails Without Cable Management Arm (varies by hosting company)
|
||||
|
||||
### Edge Tablet Requirements
|
||||
* Similar or better than:
|
||||
* Microsoft Surface Pro 4 Or Motion R12
|
||||
* Intel i7
|
||||
* 8 GB DDR4 RAM
|
||||
@@ -1,6 +1,7 @@
|
||||
#/bin/bash
|
||||
#python -m mkdocs build -d site
|
||||
|
||||
cp -r ../../src/sdk/doc/* ./content/bts_spark_sdk/Server/
|
||||
./run_zola.sh build
|
||||
|
||||
scp -r ./public bts@bluetradesys.com:/home/bts/doc/
|
||||
@@ -13,3 +14,7 @@ sudo mv ./public/* /var/www/documentation/
|
||||
EOF
|
||||
|
||||
rm -r public
|
||||
cd ./content/bts_spark_sdk/server/
|
||||
find . -not -name '_index.md' -delete
|
||||
cd ../..
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
2.14.0
|
||||
- Load Algos in libspark.so automatically (no symlink needed)
|
||||
- Specify commands to run when sparkd starts. These will automatically be killed when sparkd terminates if they are still running.
|
||||
|
||||
1.5.7
|
||||
- Fixed Aggressor coloring and ladder high/low coloring in SIM
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\sp
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_excel", "src\client\spark_excel\spark_excel.csproj", "{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_fix", "src\client\spark_fix\spark_fix.csproj", "{D8031C13-7BEA-430A-BB60-40927D15CFC3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -221,26 +219,6 @@ Global
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|x64.Build.0 = Debug|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|x64.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|x64.Build.0 = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|x86.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,74 +1,91 @@
|
||||
using bts;
|
||||
using bts.api.admin;
|
||||
using bts.api.core;
|
||||
using bts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using bts.api.core;
|
||||
|
||||
namespace mbts.spark {
|
||||
[Export]
|
||||
class AdminModel : IDisposable {
|
||||
public readonly UserTuple user;
|
||||
|
||||
IDisposable _dispose;
|
||||
IReadOnlyDictionary<uint, string> _account_map = DictionaryHelper.empty<uint, string>();
|
||||
readonly string _user_name;
|
||||
public string user_name => _user_name;
|
||||
|
||||
readonly BehaviorSubject<IReadOnlyDictionary<uint, string>>
|
||||
_accounts_subject = new BehaviorSubject<IReadOnlyDictionary<uint, string>>(new Dictionary<uint, string>()),
|
||||
_users_subject = new BehaviorSubject<IReadOnlyDictionary<uint, string>>(new Dictionary<uint, string>());
|
||||
IReadOnlyDictionary<uint, string>
|
||||
_account_map = new Dictionary<uint, string>(),
|
||||
_user_map = new Dictionary<uint, string>();
|
||||
readonly BehaviorSubject<AdminModelWrapper> _wrapper_subject = new BehaviorSubject<AdminModelWrapper>(new AdminModelWrapper());
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
AdminModel(AdminService service, UserTuple user) {
|
||||
this.user = user;
|
||||
// accounts
|
||||
on_accounts = service.subscribei_admin_data()
|
||||
.Select(up => up.all.TryGetFirst(out var ad) && ad.Users.Where(u => u.Name == user.name).TryGetSingle(out var usr) && usr.HasUserData && usr.UserData.HasAccountPermissions ?
|
||||
usr.UserData.AccountPermissions.AccountPermissions
|
||||
.Where(kv => (kv.Value.TradingPermission != null && kv.Value.TradingPermission.HasPermissions) || kv.Value.AdminPermission.HasPermissions)
|
||||
.Select(kv => ad.Accounts.Where(a => a.Id == kv.Key).TryGetSingle(out var acc) ? acc : (BTSAccountImmutable?)null)
|
||||
.Where(acc => acc.HasValue && acc.Value.IsPresent)
|
||||
.Select(acc => acc.Value)
|
||||
.ToDictionary(acc => acc.Id, acc => acc.Name) :
|
||||
new Dictionary<uint, string>(0))
|
||||
.Replay(1)
|
||||
.RefCount();
|
||||
// users
|
||||
on_users = Observable.Return(DictionaryHelper.wrap_value(user.id, user.name));
|
||||
all_user_tuples = user.permissions == UserTuple.Permissions.Admin ?
|
||||
service.subscribei_admin_data()
|
||||
.Select(u => u.all.TryFirst())
|
||||
.Where(ad => ad.HasValue)
|
||||
.Select(ad => ad.Value.Users
|
||||
.Where(u => user.can_access_user_data(u.Id))
|
||||
.Select(u => new UserTuple(u.Id, u.Name))
|
||||
.ToDictionary(UserTuple.key_fn))
|
||||
.Table(UserTuple.key_fn)
|
||||
.Cache() :
|
||||
Observable.Return(TableUpdate<UserTuple, uint>.mk_empty(UserTuple.key_fn).with_added(new[] { user }));
|
||||
_dispose = on_accounts.Subscribe(map => _account_map = map);
|
||||
AdminModel(AdminService service, [Import("username")]string user_name) {
|
||||
_user_name = user_name;
|
||||
_dispose = service.subscribei_admin_data().Select(update => {
|
||||
_wrapper_subject.OnNext(new AdminModelWrapper(update.all.TryFirst(), _user_name));
|
||||
IEnumerable<BTSUserImmutable> active_users =
|
||||
from admin_data in update.all
|
||||
from bts_user in admin_data.Users
|
||||
where bts_user.Name == user_name && bts_user.HasUserData && bts_user.UserData.HasAccountPermissions
|
||||
select bts_user;
|
||||
|
||||
IEnumerable<BTSAccountImmutable> active_accounts =
|
||||
from admin_data in update.all
|
||||
from bts_account in admin_data.Accounts
|
||||
where bts_account.IsPresent && _wrapper_subject.Value.can_view_account(bts_account.Name)
|
||||
join account_id in (
|
||||
from bts_user in active_users
|
||||
from account_id in bts_user.UserData.AccountPermissions.AccountPermissions.Keys
|
||||
select account_id
|
||||
) on bts_account.Id equals account_id
|
||||
select bts_account;
|
||||
|
||||
var users = active_users.ToDictionary(u => u.Id, u => u.Name);
|
||||
var accounts = active_accounts.ToDictionary(a => a.Id, a => a.Name);
|
||||
return (users, accounts);
|
||||
}).Subscribe(t => {
|
||||
_account_map = t.accounts;
|
||||
_user_map = t.users;
|
||||
_users_subject.OnNext(_user_map = t.users);
|
||||
_accounts_subject.OnNext(_account_map = t.accounts);
|
||||
});
|
||||
}
|
||||
|
||||
public IObservable<IReadOnlyDictionary<uint, string>> on_users { get; }
|
||||
public IObservable<IReadOnlyDictionary<uint, string>> on_accounts { get; }
|
||||
public IObservable<TableUpdate<UserTuple, uint>> all_user_tuples { get; }
|
||||
public IObservable<IReadOnlyList<AccountTuple>> on_account_tuples => on_accounts.Select(d => d.Select(kv => new AccountTuple(kv.Key, kv.Value)).ToListSorted(a => a.name));
|
||||
public IObservable<IReadOnlyDictionary<uint, string>> on_users => _users_subject.AsObservable();
|
||||
public IObservable<IReadOnlyDictionary<uint, string>> on_accounts => _accounts_subject.AsObservable();
|
||||
public IObservable<IReadOnlyList<UserTuple>> on_user_tuples => on_users.Select(d => d.Select(kv => new UserTuple(kv.Key, kv.Value)).ToList());
|
||||
public IObservable<IReadOnlyList<AccountTuple>> on_account_tuples => on_accounts.Select(d => d.Select(kv => new AccountTuple(kv.Key, kv.Value)).ToList());
|
||||
public IObservable<AdminModelWrapper> on_admin_data => _wrapper_subject.AsObservable();
|
||||
|
||||
public IObservable<Update<T, TKey>> permission_filter<T, TKey>(IObservable<Update<T, TKey>> positions, Func<T, uint> get_account_id) where TKey : IEquatable<TKey> =>
|
||||
user.permissions == UserTuple.Permissions.Admin ?
|
||||
positions :
|
||||
positions.Filter(on_accounts.Select(map => new Func<T, bool>(p => map.ContainsKey(get_account_id(p)))));
|
||||
public UserTuple? get_current_user() {
|
||||
foreach (var kv in _user_map) {
|
||||
// just for good measure, there should never be > 1 element in _user_map, and it should always match _user_name
|
||||
if (kv.Value == _user_name)
|
||||
return new UserTuple(kv.Key, kv.Value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public AccountTuple? get_default_account() {
|
||||
foreach (var kv in _account_map) {
|
||||
return new AccountTuple(kv.Key, kv.Value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public uint? get_user_id(string user) => _id_for_name(user, _user_map);
|
||||
public uint? get_account_id(string account) => _id_for_name(account, _account_map);
|
||||
public void Dispose() => Disposable.dispose(ref _dispose);
|
||||
|
||||
public IObservable<Update<T, TKey>> permission_filter<T, TKey>(IObservable<Update<T, TKey>> positions, Func<T, string> get_account_name) where TKey : IEquatable<TKey> =>
|
||||
user.permissions == UserTuple.Permissions.Admin ?
|
||||
positions :
|
||||
positions.Filter(on_accounts.Select(map => {
|
||||
var hash = new HashSet<string>(map.Values);
|
||||
return new Func<T, bool>(v => hash.Contains(get_account_name(v)));
|
||||
}));
|
||||
|
||||
public AccountTuple? get_default_account() =>
|
||||
_account_map.Select(kv => new AccountTuple(kv.Key, kv.Value)).TryFirst();
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
static uint? _id_for_name(string name, IReadOnlyDictionary<uint, string> map) {
|
||||
foreach (var kv in map) {
|
||||
if (kv.Value == name)
|
||||
return kv.Key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,7 @@ namespace mbts.ui.shell
|
||||
{
|
||||
Log.Gen.info("Application.OnExit");
|
||||
if (_runtime != null) _runtime.Dispose();
|
||||
utils.BTSNativeMethods.finit_spark_lib();
|
||||
base.OnExit(e);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
@@ -136,11 +137,8 @@ namespace mbts.ui.shell
|
||||
try {
|
||||
if (argv.Contains("-multiple") || _mutex == null || _mutex.WaitOne(TimeSpan.Zero, true))
|
||||
{
|
||||
if(_mutex == null || _mutex.WaitOne(TimeSpan.Zero, true)) {
|
||||
if (!argv.Contains("-nostunnel")) {
|
||||
init_stunnel(argv);
|
||||
}
|
||||
}
|
||||
if(_mutex == null || _mutex.WaitOne(TimeSpan.Zero, true))
|
||||
init_stunnel(argv);
|
||||
return base.Run();
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -4,9 +4,13 @@ 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;
|
||||
|
||||
@@ -18,8 +22,8 @@ namespace bts.ui {
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
public AboutDaemon(IBus bus, UserTuple user) {
|
||||
_user = user.name;
|
||||
public AboutDaemon(IBus bus, [Import("username")]string username) {
|
||||
_user = username;
|
||||
_bus = bus;
|
||||
_dispose = bus.subscribe(SparkTags.About).OnDispatcher().Subscribe(_ => show_about());
|
||||
}
|
||||
@@ -58,4 +62,4 @@ namespace bts.ui {
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,112 +4,43 @@ using mbts;
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace bts {
|
||||
[Export, Export(typeof(IShellDaemon))]
|
||||
class DeleteSyntheticDaemon : IShellDaemon, IDisposable {
|
||||
// request_id is noted in the series of log messages that occur during a particular delete op.
|
||||
static int _request_id = 1;
|
||||
|
||||
readonly OrdersModel _orders_model;
|
||||
readonly ErrorReporter _error_reporter;
|
||||
IReadOnlyDictionary<uint, ExecutionStrategyImmutable> _strategy_map =
|
||||
DictionaryHelper.empty<uint, ExecutionStrategyImmutable>();
|
||||
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
public DeleteSyntheticDaemon(IBus bus, OrdersModel orders_model, ErrorReporter error_reporter) {
|
||||
_orders_model = orders_model;
|
||||
_error_reporter = error_reporter;
|
||||
_dispose = Disposable.Create(
|
||||
bus.subscribe(SparkTags.SyntheticDeleteTag).Subscribe(_delete_synthetic),
|
||||
orders_model.spreader.strategy.Subscribe(map => _strategy_map = map));
|
||||
_dispose = bus.subscribe(SparkTags.SyntheticDeleteTag)
|
||||
.OnDispatcher()
|
||||
.Subscribe(_delete_synthetic);
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
|
||||
async void _delete_synthetic(IImmutableSet<uint> keys) {
|
||||
var log = new LoggerContext(Log.Ui, $"Synthetic Delete Req {unchecked(Interlocked.Increment(ref _request_id))} - ", null);
|
||||
if (keys.is_null_or_empty()) {
|
||||
log.warn("received empty delete request (no securities specified).");
|
||||
return;
|
||||
}
|
||||
log.info($"received request to delete the following {keys.Count} securities: {string.Join(", ", keys)}");
|
||||
var (orders, orders_success) = await _orders_model.security_order_groups.FirstAsyncTask(SparkUtils.DefaultTimeOut);
|
||||
async void _delete_synthetic(uint id) {
|
||||
var (orders, orders_success) = await _orders_model.on_orders.FirstAsyncTask(SparkUtils.DefaultTimeOut);
|
||||
if (!orders_success) {
|
||||
var msg = "Unable to delete synthetic securities: " +
|
||||
$"timed out waiting for orders table (must verify that a synthetic security does not have any working orders before it can be deleted).";
|
||||
_error_reporter.report_error(msg);
|
||||
log.warn(msg);
|
||||
_error_reporter.report_error($"Unable to delete synthetic security ({id}): unable to determine whether or not security ({id}) has working orders (deletion is not permitted while there are working orders).");
|
||||
Log.Ui.warn($"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.order.Def.SecurityKey == id && o.order.is_non_terminal())) {
|
||||
Log.Ui.warn($"Ignoring request to delete synthetic security ({id}) because non-terminal-orders were detected.");
|
||||
} else {
|
||||
var working_orders = new List<uint>();
|
||||
var missing_strategies = new List<uint>();
|
||||
var items = new List<(uint key, ExecutionStrategyImmutable strategy)>();
|
||||
var temp_strats = _strategy_map;
|
||||
foreach (var k in keys) {
|
||||
if (orders.state.TryGetValue(k, out var sec_group) && sec_group.table.state.Values.Any(tup => tup.order.is_active())) {
|
||||
working_orders.Add(k);
|
||||
} else if (!temp_strats.TryGetValue(k, out var strat)) {
|
||||
missing_strategies.Add(k);
|
||||
} else {
|
||||
items.Add((k, strat.with(deleted: true)));
|
||||
}
|
||||
ExecutionStrategyImmutable? strategy = await _orders_model.spreader.lookup_strategy_async(id);
|
||||
if (strategy.HasValue) {
|
||||
ExecutionStrategyImmutable deleted_strategy = strategy.Value.with(deleted: true);
|
||||
await _orders_model.spreader.save_strategy(id, deleted_strategy);
|
||||
}
|
||||
var lines = new List<string>();
|
||||
if (working_orders.Count > 0) {
|
||||
lines.Add($"skipping {working_orders.Count} securities because they have working orders.");
|
||||
}
|
||||
if (missing_strategies.Count > 0) {
|
||||
lines.Add($"skipping {missing_strategies.Count} securities because their execution strategies were not discovered.");
|
||||
}
|
||||
if (lines.Count > 0)
|
||||
log.warn(string.Join("; ", lines));
|
||||
var errors = await _orders_model.spreader.save_strategies(items);
|
||||
int error_count = errors.Count(e => !string.IsNullOrEmpty(e));
|
||||
log.info($"{items.Count - error_count}/{items.Count} attempted deletes were successful (skipped {working_orders.Count + missing_strategies.Count}).");
|
||||
// display results to user
|
||||
const string dialog_title = "Synthetic Deletion";
|
||||
string display_msg;
|
||||
MessageBoxImage icon = MessageBoxImage.None;
|
||||
if (keys.Count > 1) {
|
||||
if (error_count == 0 && working_orders.Count == 0 && missing_strategies.Count == 0) {
|
||||
display_msg = $"Synthetic securities have been deleted.";
|
||||
icon = MessageBoxImage.Information;
|
||||
} else {
|
||||
display_msg = $"{keys.Count - error_count - working_orders.Count - missing_strategies.Count}/{keys.Count} securities were successfully deleted.";
|
||||
icon = MessageBoxImage.Error;
|
||||
}
|
||||
} else {
|
||||
if (error_count == 0 && working_orders.Count == 0 && missing_strategies.Count == 0) {
|
||||
display_msg = "Synthetic security has been deleted.";
|
||||
icon = MessageBoxImage.Information;
|
||||
} else {
|
||||
string reason;
|
||||
if (error_count > 0) {
|
||||
reason = errors[0];
|
||||
} else if (missing_strategies.Count > 0) {
|
||||
reason = "did not find execution strategy.";
|
||||
} else if (working_orders.Count > 0) {
|
||||
reason = "working orders detected.";
|
||||
} else {
|
||||
// unexpected code path
|
||||
reason = "unknown error.";
|
||||
}
|
||||
icon = MessageBoxImage.Error;
|
||||
display_msg = $"Unable to delete synthetic security: " + reason;
|
||||
}
|
||||
}
|
||||
BTSMessageBox.Show(display_msg, dialog_title, BTSMessageBoxButtons.OK, icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,18 @@
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.support;
|
||||
using bts.utils;
|
||||
using mbts;
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using System.Windows;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bts.spark {
|
||||
namespace bts.spark
|
||||
{
|
||||
[Export, Export(typeof(IShellDaemon))]
|
||||
public class ErrorReporter : IShellDaemon, IDisposable {
|
||||
readonly ErrorReportService _svc;
|
||||
@@ -22,9 +20,9 @@ namespace bts.spark {
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
public ErrorReporter(ErrorReportService svc, IBus bus, UserTuple user) {
|
||||
public ErrorReporter(ErrorReportService svc, IBus bus, [Import("username")] string username) {
|
||||
_svc = svc;
|
||||
_username = user.name;
|
||||
_username = username;
|
||||
_dispose = bus.subscribe(SparkTags.Support).OnDispatcher().Subscribe(msg => show_support_window(msg, "Report a problem"));
|
||||
}
|
||||
|
||||
@@ -49,45 +47,6 @@ namespace bts.spark {
|
||||
ErrorMessage = message,
|
||||
});
|
||||
}
|
||||
public async Task report_silently(string contact, string description, string userdata) {
|
||||
var request = append_logs(new ErrorReport {
|
||||
User = _username,
|
||||
ErrorMessage = description,
|
||||
UserDescription = userdata,
|
||||
Contact = contact
|
||||
}.immutable());
|
||||
var reply = await _svc.send_report_async(request);
|
||||
}
|
||||
|
||||
public static ErrorReportImmutable append_logs(ErrorReportImmutable src) {
|
||||
var result = src.CloneToMutable();
|
||||
|
||||
var windows_log = LogUtil.read_windows_event_log();
|
||||
if (!windows_log.IsEmpty) {
|
||||
result.Files.Add(new FileData {
|
||||
Name = "Application.evtx.gz",
|
||||
Contents = windows_log
|
||||
});
|
||||
}
|
||||
|
||||
var (data,date) = LogUtil.read_latest_crash_dump();
|
||||
if (!data.IsEmpty) {
|
||||
result.Files.Add(new FileData {
|
||||
Name = $"spark-{date.ToString("s")}.dmp.gz",
|
||||
Contents = data
|
||||
});
|
||||
}
|
||||
|
||||
var spark_log = LogUtil.read_logs_compressed();
|
||||
if (!spark_log.IsEmpty) {
|
||||
result.Files.Add(new FileData {
|
||||
Name = "log.gz",
|
||||
Contents = spark_log
|
||||
});
|
||||
}
|
||||
return result.immutable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ErrorReporterExtensions {
|
||||
@@ -123,6 +82,7 @@ namespace bts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
//public static async Task<Result<T>>
|
||||
public static async Task<(T value, bool success)> safe_execute<T>(this ErrorReporter error_reporter, Func<Task<Result<T>>> execute, Func<T, bool> get_success, Func<T, string> get_error_msg, string desc) {
|
||||
try {
|
||||
var result = await execute();
|
||||
@@ -141,71 +101,5 @@ namespace bts.spark {
|
||||
void _report_error(string msg) =>
|
||||
error_reporter.report_error($"Error {desc}: {msg}", AlgoStudioWindow.NAME, MessageBoxImage.Warning);
|
||||
}
|
||||
|
||||
public static async Task<TResult> safe_execute<T, TResult>(
|
||||
this ErrorReporter error_reporter,
|
||||
Func<Task<Result<T>>> execute,
|
||||
Func<T, bool> get_success,
|
||||
Func<T, string> get_error_msg,
|
||||
Func<T, bool, TResult> result_selector,
|
||||
string desc) {
|
||||
//
|
||||
try {
|
||||
var result = await execute();
|
||||
if (!result.success) {
|
||||
_report_error(result.error_message);
|
||||
} else if (!get_success(result.value)) {
|
||||
_report_error(get_error_msg(result.value));
|
||||
} else {
|
||||
return result_selector(result.value, true);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
_report_error(ex.ToString());
|
||||
}
|
||||
return result_selector(default, false);
|
||||
//
|
||||
void _report_error(string msg) =>
|
||||
error_reporter.report_error($"Error {desc}: {msg}", AlgoStudioWindow.NAME, MessageBoxImage.Warning);
|
||||
}
|
||||
|
||||
public static async Task<(TResult result, string error_msg)[]> safe_execute_batch<T, TResult>(
|
||||
this ErrorReporter error_reporter,
|
||||
IEnumerable<Task<T>> execute,
|
||||
Func<T, (TResult result, string error_msg)> result_selector,
|
||||
string desc,
|
||||
string title) {
|
||||
//
|
||||
try {
|
||||
var results = await Task.WhenAll(execute as Task<T>[] ?? ArrayHelper.clone_optimized(execute));
|
||||
var result_values = new (TResult, string)[results.Length];
|
||||
StringBuilder error_bd = null;
|
||||
for (int i = 0; i < results.Length; i++) {
|
||||
var r = results[i];
|
||||
var (result, error) = result_selector(r);
|
||||
if (!string.IsNullOrEmpty(error)) {
|
||||
if (error_bd == null) {
|
||||
error_bd = new StringBuilder();
|
||||
} else {
|
||||
error_bd.AppendLine();
|
||||
}
|
||||
error_bd.Append(error);
|
||||
}
|
||||
result_values[i] = (result, error);
|
||||
}
|
||||
if (error_bd != null) {
|
||||
var error_msg = error_bd.ToString();
|
||||
if (!string.IsNullOrEmpty(error_msg))
|
||||
_report_error(error_msg);
|
||||
}
|
||||
return result_values;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_report_error(ex.ToString());
|
||||
}
|
||||
return null;
|
||||
//
|
||||
void _report_error(string msg) =>
|
||||
error_reporter.report_error($"Error {desc}: {msg}", title, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using bts.api;
|
||||
using bts.shell;
|
||||
using mbts;
|
||||
using mbts.persist;
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
using mbts.ui.spark;
|
||||
using mbts.ui.utilities;
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows;
|
||||
using Disposable = mbts.Disposable;
|
||||
|
||||
namespace bts {
|
||||
[Export(typeof(IShellDaemon))]
|
||||
class GlobalAlertsDaemon : IShellDaemon, IDisposable {
|
||||
const string
|
||||
// used for logging/diagnostic purposes
|
||||
_window_name = "Global Alerts Dialog",
|
||||
// actual window title
|
||||
_window_title = "Alerts";
|
||||
|
||||
readonly ThreadedWindowLauncher _launcher;
|
||||
readonly UserSettingsHub _hub;
|
||||
readonly IBus _bus;
|
||||
readonly INotificationService _notification_service;
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
public GlobalAlertsDaemon(IBus bus, UserSettingsHub hub, INotificationService notification_service) {
|
||||
_bus = bus;
|
||||
_hub = hub;
|
||||
_notification_service = notification_service;
|
||||
_launcher = new ThreadedWindowLauncher(_window_name);
|
||||
_dispose = Disposable.Create(
|
||||
bus.subscribe(SparkTags.ShowGlobalAlertsTag)
|
||||
.Subscribe(_ => _launcher.show(_view_factory)),
|
||||
_hub.subscribe_default_settings()
|
||||
.SubscribeEach(s => new CompositeDisposable(
|
||||
s.alerts.trade_alerts.Where(t => t.is_enabled).Select(
|
||||
a => _notification_service.link_to_trades(
|
||||
a.predicate.security_criteria, a.predicate.create(), a.sound)))));
|
||||
}
|
||||
|
||||
Window _view_factory() {
|
||||
var vm = new GlobalAlertsVM();
|
||||
vm.load_from(_hub.current.alerts);
|
||||
vm.request_commit += commit;
|
||||
var sec_sub = _bus.subscribe(SparkTags.SecuritiesTag).OnDispatcher().Subscribe(m => vm.security_map = m);
|
||||
var win = new GlobalAlertsDialog {
|
||||
Title = "Alerts",
|
||||
DataContext = vm
|
||||
};
|
||||
win.Closed += (s, e) => Disposable.dispose(ref sec_sub);
|
||||
return win;
|
||||
void commit() {
|
||||
var s = _hub.current.with(alerts: vm.create());
|
||||
_hub.save_default(s).ignore();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using bts.api;
|
||||
using bts.api.synthetic;
|
||||
using bts.md;
|
||||
using mbts;
|
||||
using mbts.co2;
|
||||
using mbts.spark;
|
||||
@@ -8,10 +7,14 @@ using mbts.ui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using SecurityKey = System.UInt32;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using bts.api.user;
|
||||
using bts.md;
|
||||
|
||||
namespace bts {
|
||||
[Export(typeof(IInitializable))]
|
||||
@@ -21,25 +24,21 @@ namespace bts {
|
||||
readonly Lazy<SyntheticSecurityService> _ss;
|
||||
readonly Dictionary<SecurityKey, SecurityMD> _deleted_synthetics = new Dictionary<SecurityKey, SecurityMD>();
|
||||
|
||||
static uint get_naggle() => mbts.config.Configuration.get<md.RelayOptions>().naggle_ms;
|
||||
|
||||
[ImportingConstructor]
|
||||
public MDDaemon(Lazy<IBus> bus, Lazy<AuthTokenImmutable> token, Lazy<SyntheticSecurityService> ss, UserTuple user)
|
||||
: base(mbts.config.Configuration.get<md.RelayOptions>().naggle_ms, MDSourceOptions.DeferInit, user) {
|
||||
public MDDaemon(Lazy<IBus> bus, Lazy<AuthTokenImmutable> token, Lazy<SyntheticSecurityService> ss) :
|
||||
base(get_naggle(), MDSourceOptions.DeferInit) {
|
||||
_bus = bus;
|
||||
_token = token;
|
||||
_ss = ss;
|
||||
_ss = ss;
|
||||
}
|
||||
|
||||
public int priority => 55;
|
||||
|
||||
[Export]
|
||||
MDConsumer consumer => _consumer;
|
||||
IBus bus => _bus.Value;
|
||||
|
||||
public override void initialize() {
|
||||
override public void initialize() {
|
||||
_relay.set_token(_token.Value);
|
||||
_dispose.Add(
|
||||
_ss.Value.subscribei_metadata()
|
||||
.Select(upd => upd.all.Where(i => i.HasStrategy).ToDictionary(i => i.SecurityKey, i => i.Strategy))
|
||||
.Select(upd => upd.all.ToDictionary(i => i.SecurityKey, i => i.Strategy))
|
||||
.Subscribe(t => {
|
||||
var deleted_synthetic_keys = new HashSet<uint>(t.Where(kv => kv.Value.Deleted).Select(kv => kv.Key));
|
||||
// add back 'undeleted' synthetics
|
||||
@@ -60,8 +59,16 @@ namespace bts {
|
||||
// Post full dictionary of syntheics here
|
||||
bus.post(SparkTags.SyntheticstrategiesTag, t);
|
||||
}));
|
||||
_dispose.Add(on_securities.Subscribe(md => bus.post(SparkTags.SecuritiesTag, md)));
|
||||
_dispose.Add( this.on_securities.Subscribe( (md) => {
|
||||
bus.post(SparkTags.SecuritiesTag, md);
|
||||
}));
|
||||
Task.Run(run);
|
||||
}
|
||||
|
||||
[Export]
|
||||
MDConsumer consumer => _consumer;
|
||||
|
||||
public int priority => 55;
|
||||
IBus bus => _bus.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using mbts.ui;
|
||||
using mbts;
|
||||
using Newtonsoft.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bts.spark {
|
||||
[Export(typeof(IShellDaemon))]
|
||||
class OopsDaemon : IShellDaemon, IDisposable {
|
||||
[ImportingConstructor]
|
||||
public OopsDaemon(ErrorReporter e) {
|
||||
var pid = get_pid();
|
||||
if (pid.HasValue) {
|
||||
handle_unclean_shutdown(e, pid.Value);
|
||||
}
|
||||
save_pid();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
clear_pid();
|
||||
}
|
||||
|
||||
void handle_unclean_shutdown(ErrorReporter e, int oldpid) {
|
||||
string extra = "";
|
||||
try {
|
||||
var conf = mbts.config.Configuration.get<bts.config.System>();
|
||||
extra = JsonConvert.SerializeObject(conf, Formatting.Indented);
|
||||
}
|
||||
catch { }
|
||||
Task.Run(() => e.report_silently(
|
||||
$"Host: {Environment.MachineName}",
|
||||
$"pid: {oldpid}\n{extra}",
|
||||
"Automated crash report")
|
||||
);
|
||||
}
|
||||
|
||||
const string _subkey = @"Software\BTS";
|
||||
private void save_pid() {
|
||||
using (var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(_subkey)) {
|
||||
key.SetValue("pid", System.Diagnostics.Process.GetCurrentProcess().Id, Microsoft.Win32.RegistryValueKind.DWord);
|
||||
}
|
||||
}
|
||||
private void clear_pid() {
|
||||
using (var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(_subkey)) {
|
||||
key.DeleteValue("pid",false);
|
||||
}
|
||||
}
|
||||
private int? get_pid() {
|
||||
using (var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(_subkey)) {
|
||||
return key.GetValue("pid") as int?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows;
|
||||
using LadderSettings = mbts.spark.LadderSettings;
|
||||
|
||||
namespace bts.shell {
|
||||
[Export(typeof(IShellDaemon))]
|
||||
@@ -43,25 +42,20 @@ namespace bts.shell {
|
||||
void _show_order_window(Window window) {
|
||||
foreach (var kv in AlgoStudioModelUtils.get_dynamic_resources(_model.algo_model.ui_configuration))
|
||||
window.Resources[kv.Key] = kv.Value;
|
||||
// the dynamic algo 'SecurityKey' template has a ContractPickerPopup that expects the security map to be available as a DynamicResource.
|
||||
var sub = _bus.subscribe(SparkTags.SecuritiesTag)
|
||||
.OnDispatcher()
|
||||
.Subscribe(sec_map => window.Resources[ResourceKeys.Securities] = sec_map);
|
||||
window.Closed += (s, e) => Disposable.dispose(ref sub);
|
||||
window.Show(-200, -160, true);
|
||||
}
|
||||
|
||||
void _show_order_ticket(SecurityMD smd) =>
|
||||
_show_order_window(new OrderTicket {
|
||||
DataContext = new NewOrderTicketVM(_model, smd,
|
||||
Observable.Return(LadderSettings.Default))
|
||||
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(LadderSettings.Default.calculator_buttons))
|
||||
Observable.Return(_model.factory.default_ladder_settings(smd.security).calculator_buttons))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,7 +66,7 @@ namespace bts.shell {
|
||||
_show_order_window(new OrderModificationDialog {
|
||||
DataContext = new ExistingOrderTicketVM(_model,
|
||||
Observable.Return((md,ori.order)),
|
||||
Observable.Return(LadderSettings.Default.calculator_buttons)
|
||||
Observable.Return(_model.factory.default_ladder_settings(ori.sec.Value).calculator_buttons)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -69,11 +69,10 @@ namespace bts {
|
||||
cpv.Width = double.NaN;
|
||||
cpv.Height = double.NaN;
|
||||
|
||||
vm.ok_action += () => {
|
||||
vm.ok_action = () => {
|
||||
window.Close();
|
||||
message.complete(select_result(vm)).execute(_bus);
|
||||
};
|
||||
vm.cancel_action += () => window.Close();
|
||||
window.move_to_mouse();
|
||||
window.Show();
|
||||
}
|
||||
|
||||
@@ -4,12 +4,15 @@ using mbts;
|
||||
using mbts.config;
|
||||
using mbts.ui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bts.perf {
|
||||
|
||||
[Export, Export(typeof(IShellDaemon))]
|
||||
class ShellLatencyDaemon : IShellDaemon, IDisposable {
|
||||
readonly ShellLatencyService _service;
|
||||
@@ -20,10 +23,10 @@ namespace bts.perf {
|
||||
Ping _pinger = new Ping();
|
||||
|
||||
[ImportingConstructor]
|
||||
public ShellLatencyDaemon(ShellLatencyService service, UserTuple user) {
|
||||
public ShellLatencyDaemon(ShellLatencyService service, [Import("username")] string user) {
|
||||
_service = service;
|
||||
_version = Configuration.get<bts.config.System>().version;
|
||||
_username = user.name;
|
||||
_username = user;
|
||||
_hostname = Environment.MachineName;
|
||||
|
||||
_forever_ping_host(_pinger);
|
||||
@@ -101,4 +104,4 @@ namespace bts.perf {
|
||||
Disposable.dispose(ref _subs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using bts.api.core;
|
||||
using bts.api.md.auxiliary;
|
||||
using bts.api.orderman;
|
||||
using bts.api.orderman.algo;
|
||||
using bts.api.persistence;
|
||||
using bts.api.position;
|
||||
using bts.api.synthetic;
|
||||
@@ -46,11 +45,41 @@ namespace Spark {
|
||||
|
||||
[Export]
|
||||
public MarketDataRelay md_replay => context.locate<MarketDataRelay>();
|
||||
//[Export]
|
||||
//public AlgoService algo_service => context.locate<AlgoService>();
|
||||
|
||||
AlgoServiceWrapper _algo_service_wrapper;
|
||||
[Export]
|
||||
public AlgoDefinitionService algo_definition_service => context.locate<AlgoDefinitionService>();
|
||||
public AlgoServiceWrapper algo_service_wrapper => _algo_service_wrapper ?? (_algo_service_wrapper = new AlgoServiceWrapper(context));
|
||||
|
||||
[Export]
|
||||
public MBOService mbo_service => context.locate<MBOService>();
|
||||
}
|
||||
|
||||
class AlgoServiceWrapper {
|
||||
public enum Mode {
|
||||
None,
|
||||
Hierarchical,
|
||||
Flat
|
||||
}
|
||||
|
||||
public AlgoServiceWrapper(ServiceContext context) {
|
||||
var flat_model_options = mbts.config.Configuration.get<bts.config.AlgoStudioFlatDefinitionModelOptions>();
|
||||
if (flat_model_options.enabled) {
|
||||
flat = context.locate<bts.api.orderman.algo.AlgoDefinitionService>();
|
||||
} else {
|
||||
hierarhical = context.locate<AlgoService>();
|
||||
}
|
||||
}
|
||||
|
||||
public AlgoService hierarhical { get; }
|
||||
public bts.api.orderman.algo.AlgoDefinitionService flat { get; }
|
||||
public Mode mode {
|
||||
get {
|
||||
if (hierarhical != null) return Mode.Hierarchical;
|
||||
if (flat != null) return Mode.Flat;
|
||||
return Mode.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using bts;
|
||||
using mbts.ui.dpi;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -23,15 +22,10 @@ namespace mbts.ui {
|
||||
AddBoxesGeometryKey = nameof(AddBoxesGeometryKey),
|
||||
AddFileGeometryKey = nameof(AddFileGeometryKey),
|
||||
AddFileThinGeometryKey = nameof(AddFileThinGeometryKey),
|
||||
AttachAlgosKey = nameof(AttachAlgosKey),
|
||||
CheckMarkGeometryKey = nameof(CheckMarkGeometryKey),
|
||||
CopyWFGeometryKey = nameof(CopyWFGeometryKey),
|
||||
DataEditGeometryKey = nameof(DataEditGeometryKey),
|
||||
DetachAlgosKey = nameof(DetachAlgosKey),
|
||||
DiskGeometryKey = nameof(DiskGeometryKey),
|
||||
DiskFileGeometryKey = nameof(DiskFileGeometryKey),
|
||||
DocumentGeometryKey = nameof(DocumentGeometryKey),
|
||||
DocumentAddGeometryKey = nameof(DocumentAddGeometryKey),
|
||||
DocumentBrokenGeometryKey = nameof(DocumentBrokenGeometryKey),
|
||||
DocumentCopyGeometryKey = nameof(DocumentCopyGeometryKey),
|
||||
DocumentEmptyGeometryKey = nameof(DocumentEmptyGeometryKey),
|
||||
@@ -41,24 +35,14 @@ namespace mbts.ui {
|
||||
EditDocumentAltGeometryKey = nameof(EditDocumentAltGeometryKey),
|
||||
EditDocumentGeometryKey = nameof(EditDocumentGeometryKey),
|
||||
GearGeometryKey = nameof(GearGeometryKey),
|
||||
HornGeometryKey = nameof(HornGeometryKey),
|
||||
KeyGeometryKey = nameof(KeyGeometryKey),
|
||||
LetterAKey = nameof(LetterAKey),
|
||||
LetterDKey = nameof(LetterDKey),
|
||||
OrdersGeometryKey = nameof(OrdersGeometryKey),
|
||||
PauseGeometryKey = nameof(PauseGeometryKey),
|
||||
PaymentGeometryKey = nameof(PaymentGeometryKey),
|
||||
PencilGeometryKey = nameof(PencilGeometryKey),
|
||||
PlayGeometryKey = nameof(PlayGeometryKey),
|
||||
ProhibitedGeometryKey = nameof(ProhibitedGeometryKey),
|
||||
RubberStampGeometryKey = nameof(RubberStampGeometryKey),
|
||||
SpeakerGeometryKey = nameof(SpeakerGeometryKey),
|
||||
StarGeometryKey = nameof(StarGeometryKey),
|
||||
ToolsGeometryKey = nameof(ToolsGeometryKey),
|
||||
TrashGeometryKey = nameof(TrashGeometryKey),
|
||||
UndoCircularGeometryKey = nameof(UndoCircularGeometryKey),
|
||||
WarningExclamationGeometryKey = nameof(WarningExclamationGeometryKey),
|
||||
WarningGeometryKey = nameof(WarningGeometryKey);
|
||||
UndoCircularGeometryKey = nameof(UndoCircularGeometryKey);
|
||||
|
||||
public static Geometry PlayGeometry => Geometry.Parse(get_geometric_path(PlayGeometryKey).FirstOrDefault() ?? string.Empty);
|
||||
|
||||
@@ -131,7 +115,6 @@ namespace mbts.ui {
|
||||
public static ImageSource AddBoxes => create_icon(AddBoxesGeometryKey);
|
||||
public static ImageSource AddEncircled { get { return load_resource_and_freeze("AddEncircled"); } }
|
||||
public static ImageSource AddFile => create_icon(Smashicons.AddFileGeometryKey);
|
||||
public static ImageSource AttachAlgos => create_icon(AttachAlgosKey);
|
||||
public static ImageSource Beaker { get { return load_resource_and_freeze("Beaker"); } }
|
||||
public static ImageSource Book { get { return load_resource_and_freeze("Book"); } }
|
||||
|
||||
@@ -155,14 +138,10 @@ namespace mbts.ui {
|
||||
public static ImageSource ModifyOrder { get { return load_resource_and_freeze("ModifyOrder"); } }
|
||||
public static ImageSource CheckMark => create_icon(CheckMarkGeometryKey);
|
||||
public static ImageSource Clock { get { return load_resource_and_freeze("Clock"); } }
|
||||
public static ImageSource CopyWF => create_icon(CopyWFGeometryKey);
|
||||
public static ImageSource DataEdit => create_icon(DataEditGeometryKey);
|
||||
public static ImageSource Defrag { get { return load_resource_and_freeze("Defrag"); } }
|
||||
public static ImageSource DetachAlgos => create_icon_and_rotate(DetachAlgosKey, Brushes.Red);
|
||||
public static ImageSource Disk => create_icon(DiskGeometryKey);
|
||||
public static ImageSource DiskFile => create_icon(DiskFileGeometryKey);
|
||||
public static ImageSource Display { get { return load_resource_and_freeze("Display"); } }
|
||||
public static ImageSource DocumentAdd => create_icon(DocumentAddGeometryKey);
|
||||
public static ImageSource DocumentBroken => create_icon(DocumentBrokenGeometryKey);
|
||||
public static ImageSource DocumentCopy => create_icon(DocumentCopyGeometryKey);
|
||||
public static ImageSource DocumentEmpty => create_icon(DocumentEmptyGeometryKey);
|
||||
@@ -175,26 +154,17 @@ namespace mbts.ui {
|
||||
public static ImageSource FilterActive { get { return load_resource_and_freeze("FilterActive"); } }
|
||||
public static ImageSource FilterError { get { return load_resource_and_freeze("FilterError"); } }
|
||||
public static ImageSource Gear => create_icon(GearGeometryKey);
|
||||
public static ImageSource Horn => create_icon(HornGeometryKey);
|
||||
public static ImageSource Import => load_resource_and_freeze("Import");
|
||||
public static ImageSource Key => create_icon(KeyGeometryKey);
|
||||
public static ImageSource Knight { get { return load_resource_and_freeze("Knight"); } }
|
||||
public static ImageSource Pause => create_icon(PauseGeometryKey);
|
||||
public static ImageSource Payment => create_icon(PaymentGeometryKey);
|
||||
public static ImageSource Pencil => create_icon(PencilGeometryKey);
|
||||
public static ImageSource Play => create_icon(PlayGeometryKey);
|
||||
public static ImageSource Prohibited => create_icon(ProhibitedGeometryKey);
|
||||
public static ImageSource RubberStamp => create_icon(RubberStampGeometryKey);
|
||||
public static ImageSource RedoCircular => create_icon(UndoCircularGeometryKey, Brushes.Black, null, new ScaleTransform(-1, 1));
|
||||
public static ImageSource Spawn { get { return load_resource_and_freeze("Spawn"); } }
|
||||
public static ImageSource Speaker => create_icon(SpeakerGeometryKey);
|
||||
public static ImageSource Star => create_icon(StarGeometryKey);
|
||||
public static ImageSource Target { get { return load_resource_and_freeze("Target"); } }
|
||||
public static ImageSource Tetris { get { return load_resource_and_freeze("Tetris"); } }
|
||||
public static ImageSource Tools => create_icon(ToolsGeometryKey);
|
||||
public static ImageSource Trash => create_icon(TrashGeometryKey);
|
||||
public static ImageSource Warning => create_icon(WarningGeometryKey, Brushes.IndianRed);
|
||||
public static ImageSource WarningExclamation => create_icon(WarningExclamationGeometryKey, Brushes.IndianRed);
|
||||
public static ImageSource UndoCircular => create_icon(UndoCircularGeometryKey);
|
||||
public static ImageSource ViewSettings => load_resource_and_freeze("ViewSettings");
|
||||
public static ImageSource Wrench { get { return load_resource_and_freeze("Wrench"); } }
|
||||
@@ -216,19 +186,6 @@ namespace mbts.ui {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static ImageSource create_icon_and_rotate(string geometric_path_key, Brush brush = null, Pen pen = null, Transform transform = null, double degrees = 90) {
|
||||
if (brush == null) {
|
||||
brush = Brushes.Black;
|
||||
}
|
||||
var drawing = create_drawing(geometric_path_key, brush, pen, transform);
|
||||
var dg = new DrawingGroup();
|
||||
dg.Children.Add(drawing);
|
||||
dg.Transform = new RotateTransform(degrees);
|
||||
var rv = new DrawingImage(dg);
|
||||
rv.Freeze();
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static Drawing create_drawing(string geometric_path_key) =>
|
||||
create_drawing(geometric_path_key, Brushes.Black);
|
||||
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mbts="clr-namespace:mbts.ui"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.AttachAlgosKey}">
|
||||
M10.519881,14.945064C11.300896,14.955074,12.079896,15.102078,12.819896,15.386075L10.878893,17.326085C9.6458764,17.201085,8.3688531,17.591071,7.4258485,18.533091L3.5977991,22.360102C1.9327704,24.026093 1.9317786,26.736124 3.5977991,28.402117 5.2638197,30.068108 7.9748359,30.068108 9.6398644,28.402117L13.467914,24.575106C14.410919,23.632109,14.800938,22.355097,14.675937,21.121083L16.615963,19.180096C17.523962,21.546103,17.034943,24.325104,15.126931,26.234108L11.298882,30.061119C8.7138591,32.64612 4.5238051,32.64612 1.9387672,30.062127 -0.64625573,27.477126 -0.64625573,23.287106 1.9387672,20.701098L5.7668166,16.875065C7.077837,15.564055,8.8018727,14.923061,10.519881,14.945064z M19.825993,10.418039L21.580012,12.17305 12.089907,21.665091 10.333873,19.911087z M25.383069,0C27.077088,3.0538786E-08 28.771109,0.64599859 30.063117,1.9390028 32.647133,4.5230274 32.647133,8.7120385 30.062109,11.298047L26.235068,15.125058C24.327055,17.033085,21.547022,17.52207,19.181973,16.614077L21.121998,14.674067C22.356022,14.799068,23.633046,14.409051,24.57605,13.466054L28.403094,9.6400513C30.068121,7.9740295 30.069129,5.2630205 28.403094,3.5980362 26.738064,1.9320143 24.027033,1.9320143 22.362034,3.5980362L18.533986,7.4240398C17.591958,8.3670363,17.201968,9.643042,17.32697,10.877056L15.385937,12.817066C14.478913,10.452035,14.968939,7.6730337,16.875945,5.7660436L20.703019,1.9390028C21.995026,0.64599859,23.689047,3.0538786E-08,25.383069,0z
|
||||
</sys:String>
|
||||
<sys:String x:Key="{x:Static mbts:Icons.DetachAlgosKey}">
|
||||
M19.522852,25.255011L20.920847,25.256994 20.920847,29.729012 19.522852,29.729012z M22.826874,21.952002L25.989905,25.113989 25.001887,26.101996 21.838856,22.941015z M25.269894,19.506992L29.742937,19.509007 29.742937,20.906012 25.269894,20.907995z M10.519729,14.945011C11.300744,14.954991,12.079745,15.103001,12.818766,15.386997L10.878742,17.327C9.6457264,17.200016,8.368704,17.592014,7.4257004,18.532993L3.597655,22.359015C1.9326275,24.025 1.9316508,26.734991 3.597655,28.40299 5.2636887,30.068001 7.9747178,30.066017 9.6397144,28.40299L13.468767,24.575018C14.410794,23.633001,14.800783,22.355993,14.674774,21.122015L16.615807,19.181004C17.523806,21.547003,17.034817,24.325995,15.126776,26.233008L11.298761,30.061012C8.713709,32.644997 4.5236599,32.644997 1.9396465,30.061012 -0.64638097,27.475012 -0.64638097,23.286017 1.9386395,20.702002L5.7666852,16.875004C7.0777046,15.562992,8.8017227,14.922001,10.519729,14.945011z M2.1536381,10.959994L6.6257035,10.959994 6.6266801,12.359988 2.1536381,12.359988z M6.7686803,5.894014L9.9307338,9.0549947 8.9427158,10.044008 5.7806932,6.8819901z M10.976735,2.1390082L12.374761,2.1390082 12.375768,6.6130081 10.975728,6.6130081z M25.382902,0C27.076922,-1.8170738E-08 28.770941,0.6470033 30.063955,1.9389956 32.646992,4.5220043 32.646992,8.7130147 30.061941,11.297L26.234902,15.126011C24.326891,17.032993,21.546862,17.521,19.181845,16.614994L21.121868,14.674015C22.35586,14.798008,23.63389,14.407992,24.575886,13.467013L28.403933,9.6390096C30.067953,7.972994 30.069967,5.2619945 28.403933,3.5960094 26.738905,1.9310002 24.0269,1.9320073 22.361872,3.5960094L18.533827,7.4249893C17.591829,8.3659993,17.201811,9.6440145,17.32782,10.87601L15.385781,12.817996C14.477781,10.453005,14.968784,7.6730062,16.875818,5.7659928L20.702858,1.9379885C21.994864,0.64599622,23.688883,-1.8170738E-08,25.382902,0z
|
||||
</sys:String>
|
||||
|
||||
<!--AddBoxes (the icon is free to use if we include this information in our credit section)
|
||||
Source: https://www.flaticon.com/authors/gregor-cresnar
|
||||
Ttile: Add free icon
|
||||
Credit: Icon made by Gregor Cresnar from www.flaticon.com-->
|
||||
<sys:String x:Key="{x:Static mbts:Icons.AddBoxesGeometryKey}">
|
||||
M 87.5 10 C 80.313542 10 74.400391 15.913151 74.400391 23.099609 V 397.90039 C 74.400391 405.08685 80.313541 411 87.5 411 h 374.80078 c 7.18646 0 13.09961 -5.91315 13.09961 -13.09961 V 23.099609 C 475.40039 15.913151 469.48724 10 462.30078 10 Z m 13 26.199219 H 449.19922 V 384.90039 H 100.5 Z M 21.099609 76.400391 C 13.912943 76.400391 8 82.313333 8 89.5 v 374.80078 c 0 7.18667 5.912943 13.09961 13.099609 13.09961 H 395.90039 c 7.18667 0 13.09961 -5.91294 13.09961 -13.09961 0 -7.18667 -5.91294 -13.10156 -13.09961 -13.10156 H 34.199219 V 89.5 c 0 -7.186667 -5.912943 -13.099609 -13.09961 -13.099609 z M 274.90039 116.5 c -7.18667 0 -13.09961 5.91294 -13.09961 13.09961 V 197.5 h -67.90039 c -7.18667 0 -13.09961 5.91294 -13.09961 13.09961 0 7.18667 5.91294 13.09961 13.09961 13.09961 h 67.90039 v 67.90039 c 0 7.18667 5.91294 13.09961 13.09961 13.09961 7.18667 0 13.09961 -5.91294 13.09961 -13.09961 v -67.90039 h 67.90039 c 7.18667 0 13.09961 -5.91294 13.09961 -13.09961 v -0.0391 -0.0391 C 368.85982 203.37217 363.03372 197.5 355.90039 197.5 H 288 V 129.59961 C 288 122.41294 282.08706 116.5 274.90039 116.5 Z
|
||||
M393,480.3c0-5-4.1-9.1-9.1-9.1H18.2V105.5c0-5-4.1-9.1-9.1-9.1S0,100.5,0,105.5v374.8c0,5,4.1,9.1,9.1,9.1h374.8 C388.9,489.4,393,485.3,393,480.3z
|
||||
M373.9,187.5H302v-71.9c0-5-4.1-9.1-9.1-9.1s-9.1,4.1-9.1,9.1v71.9h-71.9c-5,0-9.1,4.1-9.1,9.1s4.1,9.1,9.1,9.1h71.9v71.9 c0,5,4.1,9.1,9.1,9.1s9.1-4.1,9.1-9.1v-71.9h71.9c5,0,9.1-4.1,9.1-9.1C382.9,191.5,378.9,187.5,373.9,187.5z
|
||||
M105.5,393h374.8c5,0,9.1-4.1,9.1-9.1V9.1c0-5-4.1-9.1-9.1-9.1H105.5c-5,0-9.1,4.1-9.1,9.1v374.8 C96.4,388.9,100.5,393,105.5,393z M114.5,18.2h356.7v356.7H114.5V18.2z
|
||||
</sys:String>
|
||||
|
||||
<!--File (the icon is free to use if we include this information in our credit section)
|
||||
@@ -46,25 +40,6 @@
|
||||
</sys:String>
|
||||
</x:Array>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.CopyWFGeometryKey}">
|
||||
M14.733902,12.084991L9.751783,17.388992 12.982842,17.436005C13.569886,17.462997 14.5229,17.350998 14.876848,17.005005 14.954852,16.929993 15.031879,16.824005 15.02486,16.593002 14.986895,15.457993 14.838883,13.438004 14.733902,12.084991z M22.507753,11.134453C22.480678,11.134323,22.467085,11.135494,22.469961,11.136993L20.64694,11.145004 16.291904,11.192993C16.388891,12.405991 16.596901,15.100998 16.647928,16.539001 16.668924,17.177994 16.448888,17.742004 16.007904,18.168991 15.210897,18.947998 13.893864,19.065002 13.179865,19.065002L9.2818066,19.005005 9.3258129,25.522003 9.3728109,25.528 9.3278271,25.882996 9.3317944,26.395996 9.3107983,26.397995C9.3167797,26.789993,9.3378369,27.552994,9.3958212,29.065994L9.4068075,29.393005C9.4207855,29.819992 9.5648295,29.994995 9.6707884,30.089005 9.9807898,30.365997 10.539817,30.390991 10.717799,30.369003L10.717799,30.375C10.88284,30.354996 11.280855,30.356003 12.823844,30.365997 13.867863,30.371002 15.206869,30.376999 16.594886,30.376999 20.757965,30.376999 23.270998,30.354996 23.862007,30.311005 24.454971,30.268005 24.661029,29.154999 24.690021,28.729996 24.690021,28.729996 24.677997,27.876999 24.661029,26.582993 24.612016,22.671005 24.51198,14.697998 24.472002,12.802002 24.461013,12.302994 24.316969,11.929993 24.034008,11.662003 23.547475,11.200003 22.697284,11.13536 22.507753,11.134453z M8.8867823,2.8410034L2.5417312,10.296997 6.4037791,10.356995C6.8917614,10.390991 8.3258005,10.341003 8.9567896,9.7299957 9.1738335,9.5189972 9.2667919,9.2659912 9.2558046,8.9089966 9.2067934,7.3889923 9.0258213,4.7480011 8.8867823,2.8410034z M10.424826,1.6239929C10.551842,3.302002 10.816799,6.951004 10.876797,8.8560028 10.903836,9.6750031 10.636804,10.360992 10.083818,10.897995 9.0667769,11.882004 7.3527657,11.987991 6.6627546,11.987991 6.4657918,11.987991 6.3367616,11.979004 6.3177796,11.977005L1.6477377,11.905991C1.6387044,14.278992 1.6236895,20.283997 1.6496909,22.358994 1.651705,22.569992 1.6437093,22.780991 1.6366904,22.992004 1.6117265,23.593994 1.5926833,24.112991 1.8537338,24.386002 2.0716933,24.612991 2.6497034,24.886002 4.1457549,24.886002 6.0127832,24.886002 7.0867711,24.876999 7.6967641,24.867004L7.6457993,17.259995 14.853899,9.5849915 16.681924,9.5650024 16.681924,9.5429993 19.454908,9.5289917 19.406934,2.6210022C19.323925,2.3549957,18.960945,1.6239929,17.387928,1.6239929z M9.1738335,0L17.387928,0C19.94692,0,20.874971,1.5299988,21.022983,2.4329987L21.077976,9.5209961 22.446951,9.5139923C22.43395,9.5130005 24.031017,9.4250031 25.148035,10.481995 25.753999,11.054001 26.071996,11.822998 26.092992,12.766998 26.142006,15.065994 26.281044,26.268997 26.307047,28.412003L26.311014,28.764999C26.279029,29.817993 25.750032,31.802002 23.979013,31.931 23.342958,31.977005 20.887972,32 16.683878,32 13.798893,32 11.107818,31.988998 10.808803,31.987991 10.789821,31.990997 9.5147806,32.112 8.6008288,31.309006 8.0858074,30.854996 7.8107797,30.229004 7.7838017,29.444992L7.7728153,29.126999C7.721789,27.759995 7.6978022,26.970993 7.6898061,26.490005 7.0547882,26.5 5.9867817,26.509003 4.1457549,26.509003 2.4377257,26.509003 1.3387128,26.192001 0.68367504,25.509003 -0.055286743,24.742004 -0.017322397,23.742004 0.012707477,22.938004 0.020702986,22.744003 0.028698692,22.559998 0.026684528,22.378998 -0.00029337304,20.240997 0.016674615,13.856995 0.026684528,11.212997L0.026684528,10.867004 0.14167619,10.610992 8.7147823,0.54100037 8.7088009,0.45899963 8.8018194,0.43800354z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.DocumentAddGeometryKey}">
|
||||
M10.830011,12.05L13.334007,12.05 13.334007,16.535997 17.819998,16.535997 17.819998,19.03902 13.334007,19.03902 13.334007,23.525016 10.830988,23.525016 10.830988,19.03902 6.3460046,19.03902 6.3449975,16.53499 10.830988,16.535997z M2.2799975,2.4149805L2.2799975,29.580015 22.121998,29.580015 22.121998,8.500008 15.83599,8.500008 15.83599,2.4149805z M0,0L15.83599,0 17.125998,0 22.681996,5.439977 24.407,7.125007 24.407,32.000001 0,32.000001z
|
||||
</sys:String>
|
||||
|
||||
<!--File (the icon is free to use if we include this information in our credit section)
|
||||
Source: https://www.flaticon.com/authors/chanut
|
||||
Ttile: Cancel free icon
|
||||
Credit: Icon made by Chanut from www.flaticon.com-->
|
||||
<sys:String x:Key="{x:Static mbts:Icons.ProhibitedGeometryKey}">
|
||||
M32.759,0C14.696,0,0,14.695,0,32.759s14.695,32.759,32.759,32.759s32.759-14.695,32.759-32.759S50.822,0,32.759,0z
|
||||
M6,32.759C6,18.004,18.004,6,32.759,6c6.648,0,12.734,2.443,17.419,6.472L12.472,50.178C8.443,45.493,6,39.407,6,32.759z
|
||||
M32.759,59.518c-5.948,0-11.447-1.953-15.895-5.248l37.405-37.405c3.295,4.448,5.248,9.947,5.248,15.895
|
||||
C59.518,47.514,47.514,59.518,32.759,59.518z
|
||||
</sys:String>
|
||||
|
||||
<!--File (the icon is free to use if we include this information in our credit section)
|
||||
Source: https://www.flaticon.com/authors/smashicons
|
||||
Ttile: File free icon
|
||||
@@ -113,9 +88,6 @@
|
||||
s1-0.448,1-1v-5h5c0.552,0,1-0.448,1-1S52.052,46,51.5,46z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.DataEditGeometryKey}">
|
||||
M 22.589844 14.470703 H 0.82421875 C 0.36896661 14.470586 -1.1747368e-4 14.83967 0 15.294922 v 4.669922 c -1.1747368e-4 0.455252 0.36896661 0.824336 0.82421875 0.824218 H 16.940231 l 0.425003 -1.09375 0.554688 -0.554687 H 1.6484375 V 16.119141 H 20.941406 Z M 27.462891 9.5976562 V 8.0742188 A 0.8240064 0.8240064 0 0 0 26.638672 7.25 H 0.82421875 A 0.8240064 0.8240064 0 0 0 0 8.0742188 v 4.6699222 a 0.8240064 0.8240064 0 0 0 0.82421875 0.824218 H 23.492188 l 1.648437 -1.648437 H 1.6484375 V 8.8984375 H 25.814453 V 11.246094 Z M 0.82421878 2.736881e-8 A 0.8240064 0.8240064 0 0 0 2.7433281e-8 0.82421879 V 5.4941406 A 0.8240064 0.8240064 0 0 0 0.82421878 6.3183594 H 26.638672 A 0.8240064 0.8240064 0 0 0 27.46289 5.4941406 V 0.82421879 A 0.8240064 0.8240064 0 0 0 26.638672 2.736881e-8 Z M 1.6484375 1.6484375 H 25.814453 V 4.6699219 H 1.6484375 Z M 31.628051 7.2558423 19.165575 19.718635 23.70324 24.256618 36.166032 11.793823 Z m -0.0013 3.5965607 0.941422 0.94142 -8.866233 8.866232 -0.94142 -0.94142 z m -13.240122 9.708458 -1.636234 6.110706 6.109329 -1.637606 z
|
||||
</sys:String>
|
||||
<sys:String x:Key="{x:Static mbts:Icons.DiskGeometryKey}">
|
||||
M403.213,20H0v472h512V128.787L403.213,20z M131,50h180v100h10h20h10V50h30v130H131V50z M381,462H131V315
|
||||
c0-8.271,6.729-15,15-15h220c8.271,0,15,6.729,15,15V462z M482,462h-71V315c0-24.813-20.187-45-45-45H146
|
||||
@@ -272,22 +244,10 @@
|
||||
M16.000015,9.6000061C12.500012,9.6000061 9.5999844,12.5 9.5999844,16 9.5999844,19.5 12.500012,22.399994 16.000015,22.399994 19.500019,22.399994 22.400015,19.5 22.400015,16 22.400015,12.5 19.500019,9.6000061 16.000015,9.6000061z M14.199995,0L17.800005,0C18.199999,0,18.599993,0.29998779,18.599993,0.79998779L18.599993,4.7999878C19.900013,5.1000061,21.000019,5.6000061,22.099997,6.2999878L25.000023,3.3999939C25.099999,3.2999878 25.300011,3.1999817 25.500025,3.1999817 25.700007,3.1999817 25.900019,3.2999878 26.000025,3.3999939L28.600033,6C28.900021,6.2999878,28.900021,6.7999878,28.600033,7.1000061L25.700007,10C26.400019,11.100006,26.900019,12.299988,27.200007,13.5L31.20001,13.5C31.600037,13.5,31.999998,13.799988,31.999998,14.299988L31.999998,17.899994C31.999998,18.299988,31.700012,18.699982,31.20001,18.699982L27.200007,18.699982C26.900019,20,26.400019,21.100006,25.700007,22.199982L28.600033,25.100006C28.700009,25.199982 28.799984,25.399994 28.799984,25.600006 28.799984,25.799988 28.700009,26 28.600033,26.100006L26.000025,28.600006C25.900019,28.699982 25.700007,28.799988 25.500025,28.799988 25.300011,28.799988 25.099999,28.699982 25.000023,28.600006L22.099997,25.699982C21.000019,26.399994,19.800007,26.899994,18.599993,27.199982L18.599993,31.199982C18.599993,31.600006,18.300005,32,17.800005,32L14.199995,32C13.8,32,13.400006,31.699982,13.400006,31.199982L13.400006,27.199982C12.099987,26.899994,11.000011,26.399994,9.9000027,25.699982L7.0000064,28.600006C6.9000003,28.699982 6.6999881,28.799988 6.5000059,28.799988 6.2999937,28.799988 6.099981,28.699982 6.0000054,28.600006L3.3999967,26C3.0999784,25.699982,3.0999784,25.199982,3.3999967,24.899994L6.2999937,22C5.5999805,20.899994,5.0999801,19.699982,4.7999923,18.5L0.79998828,18.5C0.39999409,18.5,-1.933513E-07,18.199982,0,17.699982L0,14.100006C-1.933513E-07,13.699982,0.2999879,13.299988,0.79998828,13.299988L4.7999923,13.299988C5.0999801,12,5.5999805,10.899994,6.2999937,9.7999878L3.3999967,7C3.2999908,6.8999939 3.1999845,6.6999817 3.1999845,6.5 3.1999845,6.2999878 3.2999908,6.1000061 3.3999967,6L6.0000054,3.3999939C6.099981,3.2999878 6.2999937,3.1999817 6.5000059,3.1999817 6.6999881,3.1999817 6.9000003,3.2999878 7.0000064,3.3999939L9.9000027,6.2999878C11.000011,5.6000061,12.199993,5.1000061,13.400006,4.7999878L13.400006,0.79998779C13.400006,0.29998779,13.8,0,14.199995,0z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.HornGeometryKey}">
|
||||
M4.0499969,7.0870913C2.9519978,7.0870913 2.0249984,8.4780906 2.0249987,10.125091 2.0249984,11.771091 2.9519978,13.162091 4.0499969,13.162091 5.1479961,13.162091 6.0749954,11.771091 6.0749955,10.125091 6.0749954,8.4780906 5.1479961,7.0870913 4.0499969,7.0870913z M29.975016,3.316155C23.883831,8.2016557,11.829888,8.9691842,8.1184387,9.0896781L8.0151367,9.0928462 8.0175586,9.1059306C8.0716033,9.4352315 8.0999939,9.7760909 8.0999942,10.125091 8.0999939,10.473966 8.0716033,10.814716 8.0175586,11.143921L8.0098858,11.185364 8.193316,11.195448C12.163719,11.420399,23.994581,12.458921,29.975016,17.005057z M31.176758,0.00019051835C31.280359,-0.0022594665 31.391857,0.01889403 31.514975,0.065146674 31.908983,0.21413228 31.999985,0.59114302 31.999985,1.0121596L31.999985,19.236969C31.999985,19.653958 31.913988,20.028956 31.525991,20.179955 31.405998,20.226952 31.450981,20.250023 31.32699,20.250023 31.050991,20.250023 30.778992,20.13601 30.583986,19.925928 25.229074,14.140572 9.6001122,13.269665 7.2865356,13.172559L7.2813506,13.172345 7.1739591,13.343056C6.4304952,14.468533 5.3060585,15.187091 4.0499969,15.187091 1.8169985,15.187091 0,12.916091 0,10.125091 0,7.3330911 1.8169985,5.0620912 4.0499969,5.0620912 5.3060585,5.0620912 6.4304952,5.78065 7.1739591,6.9063042L7.2852713,7.0832756 7.3087114,7.0828188C9.6077337,7.036146 25.141474,6.4939421 30.567997,0.34315929 30.75913,0.12521249 30.948835,0.005580858 31.176758,0.00019051835z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.KeyGeometryKey}">
|
||||
M22.399981,2.4000006C22.099982,2.4000006 21.899982,2.5 21.599982,2.6999998 21.199983,3.1000004 21.199983,3.8000002 21.599982,4.2000003L26.199979,8.9000001C26.599978,9.3000002 27.299977,9.3000002 27.699977,8.9000001 28.099977,8.5000002 28.099977,7.8000002 27.699977,7.4000006L23.099981,2.6999998C22.899981,2.5,22.699981,2.4000006,22.399981,2.4000006z M21.499982,0C22.299982,0,23.199981,0.30000019,23.79998,0.90000057L29.299976,6.4000001C30.599975,7.7000003,30.599975,9.7000003,29.299976,11L22.599981,17.7C21.299983,19,19.299984,19,17.999985,17.7L17.299985,17 12.699989,21.6 10.399991,20.900001 10.899991,23.400001 8.4999928,22.8 8.9999924,25.5 6.2999945,25.1 6.7999945,27.6 4.2999964,27 4.7999954,29.6 2.4999971,32 0,26.6 13.499989,13.1 16.999986,16.6 12.699989,12.3C11.399991,11,11.399991,9.0000002,12.699989,7.7000003L19.399984,1C19.899983,0.30000019,20.699983,0,21.499982,0z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.OrdersGeometryKey}">
|
||||
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
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.PauseGeometryKey}">
|
||||
M17.94,0L29.150001,0 29.150001,32 17.94,32z M0,0L11.210002,0 11.210002,32 0,32z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.PaymentGeometryKey}">
|
||||
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
|
||||
</sys:String>
|
||||
@@ -311,10 +271,6 @@
|
||||
M0,0L25.194,16 0,32z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.RubberStampGeometryKey}">
|
||||
M1.8950181,29.607025L24.423994,29.607025 24.423994,31.103027C24.423994,31.601013,24.025009,32,23.526993,32L2.7920208,32C2.2929976,32,1.8950181,31.601013,1.8950181,31.103027z M0,19.838013L26.218001,19.838013 26.218001,27.813019 0,27.813019z M12.960014,0C16.549,0 19.538988,2.9909973 19.538988,6.57901 19.538988,8.0750122 19.041002,9.3710022 18.243,10.46701L18.043995,10.766022C17.345997,11.863007 16.647999,12.76001 16.647999,12.76001 15.052999,15.651001 15.253011,17.745026 15.253011,17.745026L10.667015,17.745026C10.667015,17.745026 10.866997,15.651001 9.2719967,12.76001 9.2719967,12.76001 8.5739996,11.863007 7.8760016,10.766022L7.6759898,10.46701 7.5769908,10.368011C6.7790176,9.3710022 6.3810074,7.9750061 6.3810074,6.57901 6.3810074,2.9909973 9.2719967,0 12.960014,0z
|
||||
</sys:String>
|
||||
|
||||
<!--File (the icon is free to use if we include this information in our credit section)
|
||||
Source: https://www.flaticon.com/authors/smashicons
|
||||
Ttile: File free icon
|
||||
@@ -337,11 +293,6 @@
|
||||
M33.5,4h-6v10h6V4z M31.5,12h-2V6h2V12z
|
||||
</sys:String>
|
||||
</x:Array>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.SpeakerGeometryKey}">
|
||||
M18,12.839666L18,19.159448 18.029955,19.131576C18.848108,18.314159 19.332083,17.192702 19.332083,15.999873 19.332083,14.806357 18.848108,13.684685 18.029955,12.867527z M21.738388,4.748316C21.868353,4.7515661 21.999973,4.7804414 22.126221,4.8376924 26.511095,6.8177201 29.344013,11.199782 29.344013,15.999849 29.344013,20.799915 26.511095,25.181977 22.126221,27.162004 21.992224,27.223004 21.853228,27.251006 21.715233,27.251006 21.333244,27.251006 20.970255,27.032003 20.803259,26.662997 20.575266,26.15899 20.799259,25.566981 21.302244,25.339978 24.973139,23.681956 27.34407,20.015905 27.34407,15.999849 27.34407,11.983792 24.973139,8.3177406 21.302244,6.6597177 20.799259,6.4327146 20.575266,5.8407065 20.803259,5.3366992 20.973503,4.9594442 21.348494,4.7385656 21.738388,4.748316z M16,3.1854247L6.6530151,11.257323C6.4719848,11.414303,6.2399902,11.500301,6,11.500301L1.9999998,11.500301 1.9999998,21.500148 6,21.500148C6.2219848,21.500148,6.4370117,21.573144,6.6110229,21.709129L16,28.964023z M17.000252,1.186163E-08C17.141373,-2.1778678E-05 17.283264,0.02997845 17.416016,0.091477852 17.770996,0.25450047 18,0.60843792 18,1.0004608L18,10.368904 18.170259,10.465408C20.111607,11.612996 21.331976,13.716092 21.331976,15.999873 21.331976,18.282748 20.111607,20.38576 18.170259,21.53334L18,21.629842 18,31.000003C18,31.382016 17.78302,31.728995 17.440002,31.896962 17.301025,31.965991 17.150024,31.99999 17,31.99999 16.78302,31.99999 16.567017,31.929982 16.388977,31.791007L5.65802,23.500117 0.99999966,23.500117C0.44702145,23.500117,-3.9348969E-08,23.053104,3.5527137E-15,22.500133L3.5527137E-15,10.500316C-3.9348969E-08,9.9473459,0.44702145,9.5003311,0.99999966,9.5003311L5.6279907,9.5003311 16.346985,0.24345344C16.531998,0.083467316,16.765053,3.6392792E-05,17.000252,1.186163E-08z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.StarGeometryKey}">
|
||||
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
|
||||
</sys:String>
|
||||
@@ -351,7 +302,7 @@
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.TrashGeometryKey}">
|
||||
M15.000001,8.0000272L17,8.0000272 17,27.000028 15.000001,27.000028z M11.000001,8.0000272L13.000001,8.0000272 13.000001,27.000028 11.000001,27.000028z M7.0000005,8.0000272L9.000001,8.0000272 9.000001,27.000028 7.0000005,27.000028z M3.0790101,5.0000274L4.9959994,29.922999 19.000006,30.000026 20.918949,5.0000274z M13.771989,1.9959999L10.198989,2.0000001C10.158989,2.025,9.9989892,2.241,9.9989892,2.6000001L9.9989892,3.0000258 13.998989,3.0000258 13.998989,2.6000001C13.998989,2.241,13.838988,2.025,13.771989,1.9959999z M10.198989,0L13.798988,0C15.031989,0,15.998989,1.142,15.998989,2.6000001L15.998989,3.0000258 23.07898,3.0000258 24,3.0000272 24,5.0000274 22.925121,5.0000274 20.995976,30.076991C20.999027,31.102992,20.100956,32.000026,18.999029,32.000026L4.9990512,32.000026C3.8960255,32.000026,2.9990543,31.102992,2.999054,30.000026L1.073059,5.0000274 0,5.0000274 0,3.0000272 0.91897895,3.0000272 7.9989887,3.0000258 7.9989887,2.6000001C7.9989887,1.142,8.9659892,0,10.198989,0z
|
||||
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
|
||||
</sys:String>
|
||||
|
||||
<!--UndoCircular (the icon is free to use if we include this information in our credit/about section)
|
||||
@@ -363,18 +314,6 @@
|
||||
c-84.15,0-153-68.85-153-153h-51c0,112.2,91.8,204,204,204s204-91.8,204-204S360.825,89.25,248.625,89.25z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.WarningExclamationGeometryKey}">
|
||||
M15.998999,17.988002C16.551,17.988002 16.999,18.437009 16.999,18.990018 16.999,19.543027 16.551,19.992034 15.998999,19.992034 15.446999,19.992034 14.998999,19.543027 14.998999,18.990018 14.998999,18.437009 15.446999,17.988002 15.998999,17.988002z
|
||||
M15.998999,8.0630169C16.552,8.0630169,16.999,8.5110159,16.999,9.0650149L16.999,16.167001C16.999,16.721 16.552,17.168998 15.998999,17.168998 15.446,17.168998 14.998999,16.721 14.998999,16.167001L14.998999,9.0650149C14.998999,8.5110159,15.446,8.0630169,15.998999,8.0630169z
|
||||
</sys:String>
|
||||
|
||||
<sys:String x:Key="{x:Static mbts:Icons.WarningGeometryKey}">
|
||||
M15.998999,17.988002C16.551,17.988002 16.999,18.437009 16.999,18.990018 16.999,19.543027 16.551,19.992034 15.998999,19.992034 15.446999,19.992034 14.998999,19.543027 14.998999,18.990018 14.998999,18.437009 15.446999,17.988002 15.998999,17.988002z
|
||||
M15.998999,8.0630169C16.552,8.0630169,16.999,8.5110159,16.999,9.0650149L16.999,16.167001C16.999,16.721 16.552,17.168998 15.998999,17.168998 15.446,17.168998 14.998999,16.721 14.998999,16.167001L14.998999,9.0650149C14.998999,8.5110159,15.446,8.0630169,15.998999,8.0630169z
|
||||
M15.999277,2.3337629L2.3830507,22.996989 29.615442,22.996989z
|
||||
M15.999513,0C16.50052,-3.8678991E-07,17.001274,0.21826346,17.288297,0.65479128L31.74151,22.585975C32.057495,23.064982 32.084472,23.677966 31.812494,24.184989 31.541494,24.687009 31.02049,24.999999 30.450475,24.999999L1.5480773,24.999999C0.97903845,24.999999 0.45705819,24.687009 0.18703459,24.184989 -0.085979476,23.677966 -0.057963934,23.064982 0.25704309,22.585975L14.709219,0.65479128C14.997247,0.21826346,15.498506,-3.8678991E-07,15.999513,0z
|
||||
</sys:String>
|
||||
|
||||
<!--
|
||||
'y' for equilateral triangle of side length x:
|
||||
(x/2)^2 + Y^2 = x^2
|
||||
@@ -423,10 +362,10 @@
|
||||
<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
|
||||
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" />
|
||||
@@ -442,10 +381,10 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<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
|
||||
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" />
|
||||
@@ -861,7 +800,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -874,7 +813,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -886,7 +825,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -898,7 +837,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -911,7 +850,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -923,7 +862,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -935,7 +874,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -958,7 +897,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -970,7 +909,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -982,7 +921,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -995,7 +934,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -1007,7 +946,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -1032,7 +971,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -1044,7 +983,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup>
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
<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>
|
||||
@@ -1168,7 +1107,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
<DrawingGroup.Children>
|
||||
<GeometryDrawing
|
||||
Brush="Black"
|
||||
Geometry="M 0.814453 2e-6 C 0.365092 -7.56e-4 3.21e-4 0.36314 0 0.812502 v 23.945313 c 0.788895 1.126154 1.626953 -0.02112 1.626953 -0.02112 V 1.625002 h 16.241843 c 0 0 0.80538 -0.934678 -0.124651 -1.625002 z M 3.750875 3.43624 C 3.301514 3.435482 2.936743 3.799378 2.936422 4.24874 v 23.945313 c -7.6e-4 0.450124 0.364329 0.815213 0.814453 0.814453 h 7.439453 C 11.042745 28.716852 10.90913 28.418337 10.789937 28.113975 10.699431 27.872971 10.617994 27.628659 10.545796 27.381553 H 4.563375 V 5.06124 h 15.304687 v 7.039063 c 0.173002 -0.01023 0.346234 -0.01609 0.519531 -0.01758 0.343731 -2.6e-4 0.68726 0.01669 1.029297 0.05078 0.02606 0.0038 0.0521 0.0077 0.07813 0.01172 V 4.248738 C 21.494699 3.799376 21.129928 3.43548 20.680567 3.436238 Z m 13.332031 6.884766 c -1.226661 0 -2.230469 1.002456 -2.230469 2.228516 v 9.572265 l -0.824219 -0.8125 v 0.002 c -0.991917 -0.9815 -2.60964 -0.982302 -3.603515 0 -0.48293 0.477155 -0.751953 1.119962 -0.751953 1.796875 0 0.67607 0.269215 1.317958 0.751953 1.794922 l 4.841797 4.78711 0.0078 0.0078 c 2.115591 1.851014 4.144077 2.322266 5.615234 2.322266 0.547268 0 1.017683 -0.06414 1.388672 -0.142578 1.701281 -0.360558 3.108561 -1.372782 3.751954 -2.75586 0.419048 -0.9011 0.978455 -2.062137 0.923828 -3.261718 4.09e-4 -0.01025 0.0011 -0.0075 0.002 -0.02344 0.0015 -0.02655 0.0039 -0.01047 0.0039 -0.07813 v -5.113281 c 0 -1.161114 -0.955476 -2.109375 -2.121094 -2.109375 -0.04803 0 -0.09044 0.0088 -0.136719 0.01172 -0.207784 -1.015547 -1.021531 -1.826172 -2.095703 -1.826172 -0.343265 0 -0.63914 0.145124 -0.93164 0.285156 -0.397916 -0.616533 -1.045784 -1.0625 -1.830078 -1.0625 -0.189487 0 -0.354735 0.07615 -0.53125 0.121094 v -3.515625 c 0 -1.22606 -1.003809 -2.228516 -2.230469 -2.228516 z m 0 1.699219 c 0.148476 0 0.278642 0.05997 0.375 0.15625 0.09685 0.09678 0.15625 0.225142 0.15625 0.373047 v 5.625 1.740234 c 0 0.464846 0.384763 0.849609 0.849609 0.849609 0.464527 0 0.84961 -0.383921 0.84961 -0.849609 v -1.740234 c 0 -0.148598 0.05896 -0.275762 0.15625 -0.373047 0.09729 -0.09729 0.228277 -0.158203 0.375 -0.158203 0.146722 0 0.277709 0.06091 0.375 0.158203 0.09729 0.09729 0.15625 0.224449 0.15625 0.373047 v 0.77539 0.4375 c 0 0.465373 0.384236 0.84961 0.849609 0.84961 0.465373 0 0.849609 -0.384239 0.849609 -0.84961 v -0.425781 l 0.0059 -0.06836 c 0.0286 -0.265146 0.249414 -0.472657 0.52539 -0.472657 0.148238 0 0.278481 0.05996 0.375 0.15625 0.09649 0.09627 0.15625 0.225145 0.15625 0.373047 v 1.935547 c 0 0.465371 0.384237 0.84961 0.84961 0.84961 0.465372 0 0.849609 -0.384237 0.849609 -0.84961 v -0.65039 c 0.0016 -9e-6 2.95e-4 0 0.002 0 0.238806 0 0.421875 0.185008 0.421875 0.410156 l 0.002 5.0625 c -4.64e-4 0.0084 -0.0023 0.0401 -0.0039 0.07227 -0.0015 0.03041 -0.0059 0.02687 -0.002 0.101563 0.03253 0.757506 -0.372777 1.677807 -0.765625 2.521484 h -0.002 c -0.194342 0.418116 -0.532821 0.810028 -0.976563 1.126953 -0.443595 0.316821 -0.990203 0.55925 -1.585937 0.685547 -0.515602 0.10823 -1.298166 0.179402 -2.248047 -0.03125 -0.47546 -0.105441 -0.991926 -0.281044 -1.539063 -0.560547 -0.547306 -0.279588 -1.127683 -0.66381 -1.724609 -1.185547 L 11.620061 23.69601 c -0.162198 -0.160763 -0.248047 -0.365899 -0.248047 -0.587891 0 -0.223284 0.08648 -0.426518 0.248047 -0.585937 0.168295 -0.166151 0.386826 -0.249911 0.607422 -0.25 0.220595 -9e-5 0.437432 0.08144 0.605469 0.248047 l 2.240234 2.207031 0.01367 0.02148 0.04687 0.03516 0.03711 0.0332 0.02539 0.01758 0.01563 0.01367 0.01563 0.0098 c 0.114637 0.07747 0.248043 0.126397 0.388672 0.140625 l -0.04883 -0.0078 0.04102 0.0098 0.08594 0.0039 h 0.0078 c 0.06844 0 0.126002 -0.0085 0.169922 -0.01758 l 0.0059 -0.002 0.01953 -0.0039 h 0.02539 l 0.06641 -0.02734 0.02734 -0.0098 0.0098 -0.0039 c 0.102105 -0.04223 0.198238 -0.105586 0.28125 -0.189454 h 0.002 c 0.163006 -0.165519 0.243191 -0.385955 0.242188 -0.599609 v -0.002 -0.01953 -11.580078 c 0 -0.147904 0.0594 -0.276271 0.15625 -0.373047 0.09636 -0.09628 0.226522 -0.15625 0.375 -0.15625 z"
|
||||
Geometry="M17.740002,11.999007C17.254002,11.999007,16.859001,12.394008,16.859001,12.879008L16.859001,24.458791 16.860127,24.479386C16.861003,24.607261 16.813003,24.735511 16.716002,24.834012 16.667502,24.883012 16.611378,24.91995 16.551394,24.944762L16.521562,24.955436 16.507633,24.960536 16.506465,24.960837 16.50574,24.961097 16.49194,24.964574 16.459728,24.972863C16.42719,24.979527,16.393502,24.983027,16.359002,24.983027L16.316763,24.980893 16.315716,24.980851 16.307903,24.980445C16.223895,24.971904,16.146014,24.942538,16.07951,24.897597L16.067752,24.887895 16.047276,24.873078 16.015234,24.844558 16.005502,24.836528 16.001236,24.831357 13.737002,22.600011C13.267003,22.134011 12.502003,22.135011 12.031003,22.600011 11.805003,22.82301 11.680003,23.120011 11.680003,23.436011 11.680003,23.751012 11.805003,24.048011 12.031003,24.272012L16.842003,29.031013C19.311003,31.189013 21.546002,31.119014 22.656003,30.886014 23.939002,30.614013 25.015002,29.846013 25.464002,28.880013 25.857001,28.036012 26.301002,27.080012 26.263001,26.195012 26.262002,26.178012 26.268003,26.074012 26.269002,26.056012L26.268003,20.974011C26.268003,20.55601 25.922002,20.215011 25.496001,20.215011 25.335502,20.215011 25.239001,20.246511 25.179877,20.283135L25.144,20.309762 25.144,21.215013C25.144,21.491012 24.919999,21.715013 24.644,21.715013 24.367999,21.715013 24.144,21.491012 24.144,21.215013L24.144,19.278017C24.144,18.793018 23.749,18.399019 23.263,18.399019 22.808312,18.399019 22.432727,18.745308 22.387555,19.18822L22.383004,19.277944 22.383004,19.716007C22.383004,19.992006 22.159003,20.216004 21.883002,20.216004 21.607003,20.216004 21.383002,19.992006 21.383002,19.716007L21.383002,19.278054 21.383002,18.504013C21.383002,18.018016 20.988002,17.623017 20.502002,17.623017 20.016002,17.623017 19.621001,18.018016 19.621001,18.504013L19.621001,20.24402C19.621001,20.52102 19.397001,20.74402 19.121001,20.74402 18.844001,20.74402 18.621001,20.52102 18.621001,20.24402L18.621001,18.504035 18.621001,12.879008C18.621001,12.394008,18.226001,11.999007,17.740002,11.999007z M17.740002,10.999005C18.777001,10.999005,19.621001,11.843007,19.621001,12.879008L19.621001,16.842839 19.687315,16.808824C19.933955,16.689783 20.210345,16.623022 20.502002,16.623022 21.247346,16.623022 21.892987,17.059031 22.197202,17.689331L22.211675,17.721288 22.212884,17.720384C22.513,17.517568 22.874499,17.399021 23.263,17.399021 24.267594,17.399021 25.091062,18.190155 25.141547,19.181478L25.143222,19.247425 25.174827,19.241074C25.276639,19.223799 25.383876,19.21501 25.496001,19.21501 26.473002,19.21501 27.268003,20.00401 27.268003,20.974011L27.268003,26.087012C27.268003,26.098012 27.262002,26.194013 27.262002,26.205012 27.311002,27.281013 26.790002,28.401013 26.371001,29.302012 25.783002,30.566012 24.472001,31.523013 22.863002,31.864013 22.513001,31.938014 22.067002,31.999013 21.547002,31.999013 20.149003,31.999013 18.216002,31.561013 16.161002,29.763013L11.328003,24.983012C10.910003,24.570012 10.680003,24.020011 10.680003,23.436011 10.680003,22.85101 10.910003,22.302011 11.328003,21.88901 12.187003,21.040011 13.583003,21.041011 14.440002,21.88901L15.859002,23.287391 15.859002,12.879008C15.859002,11.843007,16.703002,10.999005,17.740002,10.999005z M6.8659983,4.0500388L19.083997,4.0500388C20.668996,4.0500388,21.957997,5.3460296,21.957997,6.9390478L21.957997,14.653042C21.957997,14.93005 21.734998,15.153042 21.457997,15.153042 21.181996,15.153042 20.957997,14.93005 20.957997,14.653042L20.957997,6.9390478C20.957997,5.8980318,20.116998,5.0500394,19.083997,5.0500394L6.8659983,5.0500394C5.8319979,5.0500394,4.9909983,5.8980318,4.9909984,6.9390478L4.9909984,26.116061C4.9909983,27.157046,5.8319979,28.00504,6.8659983,28.00504L11.696996,28.00504C11.972997,28.00504 12.196996,28.229039 12.196996,28.50504 12.196996,28.781041 11.972997,29.00504 11.696996,29.00504L6.8659983,29.00504C5.2809954,29.00504,3.9909983,27.70905,3.9909983,26.116061L3.9909983,6.9390478C3.9909983,5.3460296,5.2809954,4.0500388,6.8659983,4.0500388z M6.4360008,0L17.467001,0C17.743001,0 17.967001,0.22300029 17.967001,0.50000024 17.967001,0.77600098 17.743001,1.0000012 17.467001,1.0000012L6.4360008,1.0000012C3.4380004,1.0000012,1.0000002,3.4210042,1.0000002,6.3970079L1.0000002,20.617026C1.0000002,20.893025 0.77600026,21.117026 0.50000048,21.117026 0.22400022,21.117026 2.3841858E-07,20.893025 0,20.617026L0,6.3970079C2.3841858E-07,2.8700035,2.8870004,0,6.4360008,0z"
|
||||
/>
|
||||
</DrawingGroup.Children>
|
||||
</DrawingGroup>
|
||||
@@ -1176,10 +1115,10 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
|
||||
</DrawingImage>
|
||||
|
||||
|
||||
<!-- Pin
|
||||
<!-- 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
|
||||
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>
|
||||
</ResourceDictionary>
|
||||
@@ -12,11 +12,13 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using static mbts.ui.shell.ProtoBufSerializationHelper;
|
||||
|
||||
namespace bts.shell {
|
||||
namespace bts.shell
|
||||
{
|
||||
[Export(typeof(IShellModule))]
|
||||
class MarketShellModule : IShellModule {
|
||||
class MarketShellModule : IShellModule
|
||||
{
|
||||
[ImportingConstructor]
|
||||
public MarketShellModule(IBus bus, MDConsumer consumer, UserSettingsHub settings_hub, OrdersModel orders_model) {
|
||||
public MarketShellModule(IBus bus, MDConsumer consumer, UserSettingsHub settings_hub, OrdersModel orders_model, [Import("username")]string user_name) {
|
||||
_tsf = new TimeAndSalesWindowFactory(this, bus, consumer, settings_hub);
|
||||
_mvf = new MarketViewWindowFactory(this, bus, settings_hub, orders_model);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.collections;
|
||||
using mbts.co2;
|
||||
using mbts.collections;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
@@ -26,7 +26,6 @@ namespace mbts.spark {
|
||||
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<bool> _last_price_from_spread;
|
||||
readonly CellProperty<int> _position;
|
||||
readonly CellProperty<uint> _last_size;
|
||||
readonly CellProperty<ulong> _volume;
|
||||
@@ -37,7 +36,6 @@ namespace mbts.spark {
|
||||
readonly MyOrderSummarizer _order_summarizer = new MyOrderSummarizer();
|
||||
readonly MDDisplayHelper.SizeFormatter _size_formatter = MDDisplayHelper.get_formatter(MarketSizeDisplay.get_default());
|
||||
Property<uint> _bid_direct_size, _bid_merged_size, _ask_direct_size, _ask_merged_size;
|
||||
double _raw_day_position;
|
||||
string _bid_merged_size_text, _ask_merged_size_text;
|
||||
ulong _bbo_ref, _last_ref;
|
||||
|
||||
@@ -55,7 +53,6 @@ namespace mbts.spark {
|
||||
_day_change = backing(nameof(day_change), double.NaN);
|
||||
_session_low = backing(nameof(session_low), double.NaN);
|
||||
_session_high = backing(nameof(session_high), double.NaN);
|
||||
_last_price_from_spread = backing(nameof(last_price_from_spread), false);
|
||||
_settlement = backing(nameof(settlement), double.NaN);
|
||||
_volume = new CellProperty<ulong>(this, nameof(volume), 0);
|
||||
_inside_bids = new CellProperty<bool>(this, nameof(inside_bids));
|
||||
@@ -92,10 +89,6 @@ namespace mbts.spark {
|
||||
_dispose = Disposable.Create(
|
||||
_orders_model.on_security_root_orders(security.Id).OnDispatcher().Subscribe(_on_orders),
|
||||
_position.OnDispatcher().Subscribe(v => _animation.animate_position(v.newval > v.oldval)),
|
||||
_orders_model.on_security_positions(security.Id).OnDispatcher().Subscribe(t => {
|
||||
if (Set(ref _raw_day_position, t.state.Values.Sum(p => p.Item2.raw_day_pos()), nameof(raw_day_position)))
|
||||
raise_invalidated();
|
||||
}),
|
||||
_inside_bids.OnDispatcher().Subscribe(v => _animation.animate_working_bids_inside(v.newval)),
|
||||
_inside_asks.OnDispatcher().Subscribe(v => _animation.animate_working_asks_inside(v.newval)),
|
||||
_day_change.OnDispatcher().Subscribe(v => _animation.animate_day_change(v.newval > v.oldval)),
|
||||
@@ -109,9 +102,7 @@ namespace mbts.spark {
|
||||
public bool inside_bids => _inside_bids.value;
|
||||
public bool inside_asks => _inside_asks.value;
|
||||
public int position => _position.value;
|
||||
public double raw_day_position => _raw_day_position;
|
||||
public double last_price => _last_price.Value;
|
||||
public bool last_price_from_spread => _last_price_from_spread.Value;
|
||||
public uint last_size => _last_size.value;
|
||||
public double bid_price => _bid_price.Value;
|
||||
public uint bid_direct_size => _bid_direct_size.Value;
|
||||
@@ -170,17 +161,15 @@ namespace mbts.spark {
|
||||
_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, out bool from_spread)) {
|
||||
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
|
||||
_last_price.set(ps.price);
|
||||
_last_price_from_spread.set(from_spread);
|
||||
_last_size.on_next_distinct(ps.size, ref dirty);
|
||||
_volume.on_next_distinct(v, ref dirty);
|
||||
}
|
||||
dirty |= _settlement.set_new(md.md.settlement_price);
|
||||
dirty |= _session_low.set_new(md.md.session_low);
|
||||
dirty |= _session_high.set_new(md.md.session_high);
|
||||
dirty |= _day_change.set_new(last_price - settlement);
|
||||
_volume.on_next_distinct(md.md.total_volume, 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();
|
||||
|
||||
@@ -215,15 +204,13 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
void _show_order_book(Side side) {
|
||||
var ob_settings = bts.shell.orderbook.OrderBookStartupData.Default;
|
||||
ob_settings.filters = new bts.shell.orderbook.FilterStates {
|
||||
statuses = new[] { OrderStatus.Working },
|
||||
sides = new[] { side },
|
||||
security_criteria = new SecurityCriteria(security)
|
||||
};
|
||||
_bus.post(SparkTags.ShowOrderBookTag, ob_settings);
|
||||
}
|
||||
void _show_order_book(Side side) =>
|
||||
_bus.post(SparkTags.ShowOrderBookTag, new bts.shell.OrderBookWindowFactory.OrderBookStartupData(
|
||||
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);
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using bts.api;
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
using mbts.persist;
|
||||
using mbts.spark.filters;
|
||||
using mbts.ui;
|
||||
@@ -9,7 +7,9 @@ using mbts.ui.utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using static bts.shell.MarketViewWindowFactory;
|
||||
@@ -22,12 +22,13 @@ namespace mbts.spark {
|
||||
readonly OrdersModel _orders_model;
|
||||
IWindowSettingsManager<GridSettings> _settings_manager;
|
||||
|
||||
|
||||
public MarketViewVM(IBus bus, OrdersModel orders_model, IObservable<StartupData> state, IWindowSettingsManager<GridSettings> settings_manager )
|
||||
: this(bus, orders_model, state, state.SelectManyInSeries(s => s.security_criteria.subscribe_md(bus)), settings_manager) { }
|
||||
|
||||
// securities_connectable should NOT be connected already.
|
||||
MarketViewVM(IBus bus, OrdersModel orders_model, IObservable<StartupData> state, IObservable<IEnumerable<SecurityMD>> securities_source, IWindowSettingsManager<GridSettings> settings_manager)
|
||||
: base(RXCollection.Create(securities_source, SecurityDataHelper.EqualityComparer.MDComparer), null) {
|
||||
MarketViewVM(IBus bus, OrdersModel orders_model, IObservable<StartupData> state, IConnectableObservable<IEnumerable<SecurityMD>> securities_connectable, IWindowSettingsManager<GridSettings> settings_manager)
|
||||
: base(RXCollection.Create(securities_connectable, SecurityDataHelper.EqualityComparer.MDComparer), null) {
|
||||
_bus = bus;
|
||||
_orders_model = orders_model;
|
||||
security_filter = new RegexFilterVM<Row>(r => r.security.ToString(), nameof(Row.security));
|
||||
@@ -38,17 +39,15 @@ namespace mbts.spark {
|
||||
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), DefaultColumnWidths.Volume, volume_filter, DataGridFilterKnownTemplates.ULongMinMax);
|
||||
add_col(Columns.LastSpd, "Spd", r => r.last_price_from_spread ? "S" : "", nameof(Row.last_price_from_spread), DefaultColumnWidths.Side, last_price_from_spread_filter, DataGridFilterKnownTemplates.Regex);
|
||||
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, merged_size_col_header, r => r.last_size.ToString(), nameof(Row.last_size), DefaultColumnWidths.Size, last_size_filter, DataGridFilterKnownTemplates.UIntMinMax, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
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, merged_size_col_header, r => r.last_size.ToString(), nameof(Row.last_size), DefaultColumnWidths.Size, last_size_filter, DataGridFilterKnownTemplates.UShortMinMax, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.Position, "Pos", r => r.position.ToString(), nameof(Row.position), DefaultColumnWidths.Size, position_filter, DataGridFilterKnownTemplates.IntMinMax, true, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.RawDayPosition, "Raw Day Pos", r => SparkUtils.fmt_position(r.raw_day_position), nameof(Row.raw_day_position), DefaultColumnWidths.Size, raw_day_position_filter, DataGridFilterKnownTemplates.DoubleMinMax, true, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
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, System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.BidImpliedSize, implied_size_col_header, r => r.bid_implied_size.ToString(), nameof(Row.bid_implied_size), DefaultColumnWidths.ImpliedDirectMergedSize, bid_implied_size_filter, DataGridFilterKnownTemplates.UIntMinMax, font_color: BTSColors.MarketData.bid, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.BidDirectSize, direct_size_col_header, r => r.bid_direct_size.ToString(), nameof(Row.bid_direct_size), DefaultColumnWidths.ImpliedDirectMergedSize, bid_direct_size_filter, DataGridFilterKnownTemplates.UIntMinMax, font_color: BTSColors.MarketData.bid, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_hl_merged_size_col(Columns.BidMergedSize, merged_size_col_header, nameof(Row.bid_merged_size), nameof(Row.bid_merged_size_text), nameof(Row.bid_merged_size_click), bid_merged_size_filter, BTSColors.MarketData.bid, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_hl_price_col(Columns.Bid, "Bid", nameof(Row.bid_price), nameof(Row.bid_price_click), bid_price_filter, BTSColors.header_text, BTSColors.MarketData.bid, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_hl_price_col(Columns.Ask, "Ask", nameof(Row.ask_price), nameof(Row.ask_price_click), ask_price_filter, BTSColors.header_text, BTSColors.MarketData.ask, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_hl_price_col(Columns.Bid, "Bid", nameof(Row.bid_price), nameof(Row.bid_price_click), bid_price_filter, BTSColors.header_text, BTSColors.MarketData.bid_brush, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_hl_price_col(Columns.Ask, "Ask", nameof(Row.ask_price), nameof(Row.ask_price_click), ask_price_filter, BTSColors.header_text, BTSColors.MarketData.ask_brush, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_hl_merged_size_col(Columns.AskMergedSize, merged_size_col_header, nameof(Row.ask_merged_size), nameof(Row.ask_merged_size_text), nameof(Row.ask_merged_size_click), ask_merged_size_filter, BTSColors.MarketData.ask, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.AskDirectSize, direct_size_col_header, r => r.ask_direct_size.ToString(), nameof(Row.ask_direct_size), DefaultColumnWidths.ImpliedDirectMergedSize, ask_direct_size_filter, DataGridFilterKnownTemplates.UIntMinMax, font_color: BTSColors.MarketData.ask, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.AskImpliedSize, implied_size_col_header, r => r.ask_implied_size.ToString(), nameof(Row.ask_implied_size), DefaultColumnWidths.ImpliedDirectMergedSize, ask_implied_size_filter, DataGridFilterKnownTemplates.UIntMinMax, font_color: BTSColors.MarketData.ask, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
@@ -59,12 +58,12 @@ namespace mbts.spark {
|
||||
add_col(Columns.SessionHigh, "High", r => r.format_price(r.session_high), nameof(Row.session_high), DefaultColumnWidths.Price, session_high_filter, DataGridFilterKnownTemplates.DoubleMinMax, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.SecurityKey, "Security Key", r => r.security_key.ToString(), nameof(Row.security_key), DefaultColumnWidths.SecurityKey, security_key_filter, DataGridFilterKnownTemplates.Regex);
|
||||
|
||||
add_col(Columns.MarketDescription, "Market Description", r => r.security.market_description(), nameof(Row.market_description), DefaultColumnWidths.SecurityKey, market_description_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.ClearedAlias, "Cleared Alias", r => r.security.cleared_alias(), nameof(Row.cleared_alias), DefaultColumnWidths.SecurityKey, cleared_alias_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.ProductDescription, "Product Description", r => r.security.product_name(), nameof(Row.product_description), DefaultColumnWidths.SecurityKey, product_description_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.HubAlias, "Hub Alias", r => r.security.hub_alias(), nameof(Row.hub_alias), DefaultColumnWidths.SecurityKey, hub_alias_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.StripName, "Strip Name", r => r.security.strip_name(), nameof(Row.strip_name), DefaultColumnWidths.SecurityKey, strip_name_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.MicCode, "Mic Code", r => r.security.mic_code(), nameof(Row.mic_code), DefaultColumnWidths.SecurityKey, mic_code_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.MarketDescription, "Market Description", r => r.md.security.HasIce ? r.md.security.Ice.MarketDescription : string.Empty, nameof(Row.market_description), DefaultColumnWidths.SecurityKey, market_description_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.ClearedAlias, "Cleared Alias", r => r.md.security.HasIce ? r.md.security.Ice.ClearedAlias : string.Empty, nameof(Row.cleared_alias), DefaultColumnWidths.SecurityKey, cleared_alias_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.ProductDescription, "Product Description", r => r.md.security.HasIce ? r.md.security.Ice.ProductName : string.Empty, nameof(Row.product_description), DefaultColumnWidths.SecurityKey, product_description_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.HubAlias, "Hub Alias", r => r.md.security.HasIce ? r.md.security.Ice.HubAlias : string.Empty, nameof(Row.hub_alias), DefaultColumnWidths.SecurityKey, hub_alias_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.StripName, "Strip Name", r => r.md.security.HasIce ? r.md.security.Ice.StripName : string.Empty, nameof(Row.strip_name), DefaultColumnWidths.SecurityKey, strip_name_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.MicCode, "Mic Code", r => r.md.security.HasIce ? r.md.security.Ice.MicCode : string.Empty, nameof(Row.mic_code), DefaultColumnWidths.SecurityKey, mic_code_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, Color? font_color = null, System.Windows.HorizontalAlignment h_alignment = System.Windows.HorizontalAlignment.Left) =>
|
||||
columns.Add(new RenderTextColumn<Row, Columns>(col_key, get_text, filter, filter_template) {
|
||||
@@ -78,18 +77,18 @@ namespace mbts.spark {
|
||||
horizontal_alignment = h_alignment
|
||||
});
|
||||
|
||||
void add_hl_price_col(Columns col_key, string header, string prop, string command_prop, IDataGridColumnFilter filter, Color foreground, Color? background, System.Windows.HorizontalAlignment h_alignment) =>
|
||||
add_hl_col(col_key, header, price_binding(prop), prop, command_prop, filter, DataGridFilterKnownTemplates.DoubleMinMax, DefaultColumnWidths.MViewPrice, foreground, background, h_alignment);
|
||||
void add_hl_price_col(Columns col_key, string header, string prop, string command_prop, IDataGridColumnFilter filter, Color foreground, Brush background, System.Windows.HorizontalAlignment h_alignment) =>
|
||||
add_hl_col(col_key, header, price_binding(prop), prop, command_prop, filter, DataGridFilterKnownTemplates.DoubleMinMax, DefaultColumnWidths.MViewPrice, foreground, background, DefaultSelectionHighlight, h_alignment);
|
||||
|
||||
void add_hl_merged_size_col(Columns col_key, string header, string sort_prop, string text_prop, string command_prop, IDataGridColumnFilter filter, Color foreground, System.Windows.HorizontalAlignment h_alignment) =>
|
||||
add_hl_col(col_key, header, new Binding(text_prop), sort_prop, command_prop, filter, DataGridFilterKnownTemplates.UIntMinMax, DefaultColumnWidths.ImpliedDirectMergedSize, foreground, null, h_alignment);
|
||||
add_hl_col(col_key, header, new Binding(text_prop), sort_prop, command_prop, filter, DataGridFilterKnownTemplates.UShortMinMax, DefaultColumnWidths.ImpliedDirectMergedSize, foreground, null, null, h_alignment);
|
||||
|
||||
void add_hl_working_orders_col(Columns col_key, string header, string text_prop, string sort_prop, string command_prop, IDataGridColumnFilter filter, Color foreground, System.Windows.HorizontalAlignment h_alignment) =>
|
||||
add_hl_col(col_key, header, new Binding(text_prop), sort_prop, command_prop, filter, DataGridFilterKnownTemplates.IntMinMax, working_orders_col_width, foreground, null, h_alignment);
|
||||
add_hl_col(col_key, header, new Binding(text_prop), sort_prop, command_prop, filter, DataGridFilterKnownTemplates.IntMinMax, working_orders_col_width, foreground, null, null, h_alignment);
|
||||
|
||||
void add_hl_col(
|
||||
Columns col_key, string header, BindingBase binding, string prop, string command_prop,
|
||||
IDataGridColumnFilter filter, string filter_template, double width, Color foreground, Color? background, System.Windows.HorizontalAlignment h_alignment = System.Windows.HorizontalAlignment.Left) =>
|
||||
IDataGridColumnFilter filter, string filter_template, double width, Color foreground, Brush background, Brush background_overlay, System.Windows.HorizontalAlignment h_alignment = System.Windows.HorizontalAlignment.Left) =>
|
||||
columns.Add(new HyperlinkElementColumn<Row, Columns>(
|
||||
col_key, binding, new Binding(command_prop), filter, filter_template) {
|
||||
// it's necessary to have this id populated for grid settings
|
||||
@@ -97,7 +96,8 @@ namespace mbts.spark {
|
||||
Header = header,
|
||||
sort_member_path = prop,
|
||||
font_color_override = foreground,
|
||||
background_color_override = background,
|
||||
background = background,
|
||||
background_overlay = background_overlay,
|
||||
Width = DefaultColumnWidths.Price,
|
||||
horizontal_alignment = h_alignment
|
||||
});
|
||||
@@ -111,8 +111,14 @@ namespace mbts.spark {
|
||||
//
|
||||
// make font-color immutable for Side, Size, (the font-color rule is hard-coded: MarketData.bid for Buy orders, MarketData.ask for Sells)
|
||||
var col_settings_flags = new Dictionary<string, GridColumnSettingsFeatureFlags> {
|
||||
{ Columns.Bid.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor | GridColumnSettingsFeatureFlags.ImmutableBackgroundColor },
|
||||
{ Columns.Ask.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor | GridColumnSettingsFeatureFlags.ImmutableBackgroundColor},
|
||||
{ Columns.Bid.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.Ask.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.BidImpliedSize.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.BidDirectSize.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.BidMergedSize.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.AskImpliedSize.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.AskDirectSize.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.AskMergedSize.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.WorkingAsks.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor },
|
||||
{ Columns.WorkingBids.ToString(), GridColumnSettingsFeatureFlags.ImmutableFontColor }
|
||||
};
|
||||
@@ -139,14 +145,12 @@ namespace mbts.spark {
|
||||
ask_direct_size_filter.load_state(filters.ask_direct_size);
|
||||
ask_implied_size_filter.load_state(filters.ask_implied_size);
|
||||
last_price_filter.load_state(filters.last_price);
|
||||
last_price_from_spread_filter.load_state(filters.last_price_from_spread);
|
||||
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);
|
||||
raw_day_position_filter.load_state(filters.raw_day_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);
|
||||
@@ -157,8 +161,9 @@ namespace mbts.spark {
|
||||
}), DataGridFilterHelper.hook_filters(rows_view, security_filter,
|
||||
bid_price_filter, bid_merged_size_filter, bid_direct_size_filter, bid_implied_size_filter,
|
||||
ask_price_filter, ask_merged_size_filter, ask_direct_size_filter, ask_implied_size_filter,
|
||||
last_price_filter, last_price_from_spread_filter, last_size_filter, day_change_filter, settlement_filter,
|
||||
session_low_filter, session_high_filter, position_filter, raw_day_position_filter, working_bid_volume_filter, working_ask_volume_filter, volume_filter, security_key_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),
|
||||
securities_connectable.Connect(),
|
||||
settings_manager.subscribe_current().OnDispatcher().Subscribe(grid_settings_manager),
|
||||
WorkLoop.Start("MarketView", _refresh)
|
||||
);
|
||||
@@ -175,40 +180,6 @@ namespace mbts.spark {
|
||||
return grid_settings_manager.create();
|
||||
}
|
||||
|
||||
public static IComparer<Row> get_column_comparer(Columns column) {
|
||||
switch (column) {
|
||||
case Columns.Security: return wrap(r => r.security);
|
||||
case Columns.SecurityKey: return wrap(r => r.security.Id);
|
||||
case Columns.Volume: return wrap(r => r.volume);
|
||||
case Columns.Last: return wrap(r => r.last_price);
|
||||
case Columns.LastSize: return wrap(r => r.last_size);
|
||||
case Columns.Position: return wrap(r => r.position);
|
||||
case Columns.WorkingBids: return wrap(r => r.working_bid_volume);
|
||||
case Columns.BidImpliedSize: return wrap(r => r.bid_implied_size);
|
||||
case Columns.BidDirectSize: return wrap(r => r.bid_direct_size);
|
||||
case Columns.BidMergedSize: return wrap(r => r.bid_merged_size);
|
||||
case Columns.Bid: return wrap(r => r.bid_price);
|
||||
case Columns.Ask: return wrap(r => r.ask_price);
|
||||
case Columns.AskMergedSize: return wrap(r => r.ask_merged_size);
|
||||
case Columns.AskDirectSize: return wrap(r => r.ask_direct_size);
|
||||
case Columns.AskImpliedSize: return wrap(r => r.ask_implied_size);
|
||||
case Columns.WorkingAsks: return wrap(r => r.working_ask_volume);
|
||||
case Columns.Settlement: return wrap(r => r.settlement);
|
||||
case Columns.DayChange: return wrap(r => r.day_change);
|
||||
case Columns.SessionLow: return wrap(r => r.session_low);
|
||||
case Columns.SessionHigh: return wrap(r => r.session_high);
|
||||
case Columns.MarketDescription: return wrap(r => r.market_description);
|
||||
case Columns.ClearedAlias: return wrap(r => r.security.cleared_alias());
|
||||
case Columns.ProductDescription: return wrap(r => r.security.product_name());
|
||||
case Columns.HubAlias: return wrap(r => r.security.hub_alias());
|
||||
case Columns.StripName: return wrap(r => r.security.strip_name());
|
||||
case Columns.MicCode: return wrap(r => r.security.mic_code());
|
||||
default: return null;
|
||||
}
|
||||
IComparer<Row> wrap<T>(Func<Row, T> selector) =>
|
||||
Comparer<T>.Default.wrap(selector);
|
||||
}
|
||||
|
||||
#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));
|
||||
@@ -220,14 +191,12 @@ namespace mbts.spark {
|
||||
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> ask_direct_size_filter { get; } = new UIntMinMax<Row>(r => r.ask_direct_size, nameof(Row.ask_direct_size));
|
||||
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> ask_implied_size_filter { get; } = new UIntMinMax<Row>(r => r.ask_implied_size, nameof(Row.ask_implied_size));
|
||||
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> last_price_filter { get; } = new DoubleMinMax<Row>(r => r.last_price, nameof(Row.last_price));
|
||||
public IDataGridColumnPersistentFilter<Row, string> last_price_from_spread_filter { get; } = new RegexFilterVM<Row>(r => r.last_price_from_spread.ToString(), nameof(Row.last_price_from_spread));
|
||||
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> last_size_filter { get; } = new UIntMinMax<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, DoubleMinMaxState> raw_day_position_filter { get; } = new DoubleMinMax<Row>(r => r.raw_day_position, nameof(Row.raw_day_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));
|
||||
@@ -253,14 +222,12 @@ namespace mbts.spark {
|
||||
ask_direct_size = ask_direct_size_filter.get_state(),
|
||||
ask_implied_size = ask_implied_size_filter.get_state(),
|
||||
last_price = last_price_filter.get_state(),
|
||||
last_price_from_spread = last_price_from_spread_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(),
|
||||
raw_day_position = raw_day_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(),
|
||||
|
||||
@@ -8,35 +8,8 @@ namespace mbts.ui.spark {
|
||||
/// Interaction logic for MarketSheetsView.xaml
|
||||
/// </summary>
|
||||
partial class MarketViewView : UserControl {
|
||||
public enum Columns {
|
||||
Security,
|
||||
Volume,
|
||||
Last,
|
||||
LastSpd,
|
||||
LastSize,
|
||||
Position,
|
||||
RawDayPosition,
|
||||
WorkingBids,
|
||||
Bid,
|
||||
BidMergedSize,
|
||||
BidDirectSize,
|
||||
BidImpliedSize,
|
||||
Ask,
|
||||
AskMergedSize,
|
||||
AskDirectSize,
|
||||
AskImpliedSize,
|
||||
WorkingAsks,
|
||||
Settlement,
|
||||
DayChange,
|
||||
SessionLow,
|
||||
SessionHigh,
|
||||
SecurityKey,
|
||||
MarketDescription,
|
||||
ClearedAlias,
|
||||
ProductDescription,
|
||||
HubAlias,
|
||||
StripName,
|
||||
MicCode
|
||||
public enum Columns { Security, Volume, Last, LastSize, Position, WorkingBids, Bid, BidMergedSize, BidDirectSize, BidImpliedSize, Ask, AskMergedSize, AskDirectSize, AskImpliedSize, WorkingAsks, Settlement, DayChange, SessionLow, SessionHigh, SecurityKey,
|
||||
MarketDescription, ClearedAlias, ProductDescription, HubAlias, StripName, MicCode
|
||||
}
|
||||
|
||||
public MarketViewView() {
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.shell;
|
||||
using bts.shell.fills;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
using mbts.persist;
|
||||
using mbts.ui;
|
||||
using mbts.ui.settings;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.spark;
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace mbts.spark {
|
||||
class MarketViewWindow : SparkWindow<MarketViewWindowFactory.StartupData>, ISharedWindow, ISlowMeasureContentSize {
|
||||
const string _window_type = "MarketView", _window_type_display_name = "Market View";
|
||||
class MarketViewWindow : SparkWindow<MarketViewWindowFactory.StartupData>, ISharedWindow {
|
||||
const string _window_type = "MarketView", _thread_id = "MarketView", _window_type_display_name = "Market View";
|
||||
readonly OrdersModel _orders_model;
|
||||
readonly AllowOnce _init_guard = new AllowOnce("MarketView");
|
||||
readonly IWindowSettingsManager<GridSettings> _settings_manager;
|
||||
@@ -29,17 +25,13 @@ namespace mbts.spark {
|
||||
MarketViewWindowFactory.StartupData _state;
|
||||
IReadOnlyList<SparkCommand> _commands;
|
||||
IDisposable _subscriptions;
|
||||
SecurityCriteria
|
||||
_selected_security_criteria_backing,
|
||||
_sorted_selected_security_criteria_backing;
|
||||
|
||||
public MarketViewWindow(MarketViewWindowFactory factory, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state, IWindowSettingsManager<GridSettings> settings_manager)
|
||||
public MarketViewWindow(MarketViewWindowFactory factory, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state, WindowSettingsManager<GridSettings> settings_manager)
|
||||
: base("Market View", bus, factory, SparkCommands.ShowMarketView.icon) {
|
||||
_orders_model = orders_model;
|
||||
_state = state;
|
||||
_settings_manager = settings_manager;
|
||||
Icon.Freeze();
|
||||
thread_id = config.Configuration.get<bts.config.MultiThreadedWindows>().market_view ? "MarketView" : null;
|
||||
}
|
||||
|
||||
event Action<MarketViewWindowFactory.StartupData> _state_changed;
|
||||
@@ -50,53 +42,12 @@ namespace mbts.spark {
|
||||
public override MarketViewWindowFactory.StartupData SaveState =>
|
||||
_state = new MarketViewWindowFactory.StartupData(_state.security_criteria, _vm.get_filter_states(), _vm.get_grid_save_state(), _vm.rows_view.get_sorting_criteria(_vm.columns));
|
||||
|
||||
public override double MinWidth => MarketViewWindowFactory.StartupData.DefaultGridSettings.columns.Where(c => c.is_visible).Sum(gcs => gcs.width)
|
||||
public override double MinWidth => MarketViewWindowFactory.StartupData.DefaultGridSettings.columns.Sum(gcs => gcs.width)
|
||||
+ SPARK_MENU_COLLAPSED_WIDTH
|
||||
+ LAUNCHER_BUTTON_BORDER_WIDTH
|
||||
+ EXTRA_FOR_NO_HORIZONTAL_SCROLLBAR_WIDTH;
|
||||
|
||||
public string thread_id { get; }
|
||||
|
||||
SecurityCriteria _selected_security_criteria {
|
||||
get {
|
||||
if (_selected_security_criteria_backing == null) {
|
||||
if (_sorted_selected_security_criteria_backing != null) {
|
||||
_selected_security_criteria_backing = _sorted_selected_security_criteria_backing;
|
||||
} else if (_vm != null)
|
||||
_selected_security_criteria_backing = new SecurityCriteria(_vm.selected_rows.Select(r => r.security));
|
||||
}
|
||||
return _selected_security_criteria_backing;
|
||||
}
|
||||
}
|
||||
SecurityCriteria _sorted_selected_security_criteria {
|
||||
get {
|
||||
if (_sorted_selected_security_criteria_backing == null) {
|
||||
if (_vm != null) {
|
||||
var sorting_criteria = _vm.rows_view.get_sorting_criteria(_vm.columns);
|
||||
var comp_builder = new ComparerBuilder<MarketViewVM.Row>();
|
||||
foreach (var sc in sorting_criteria) {
|
||||
if (_vm.columns.TryGetFirst(col => string.Equals(col.id, sc.col_name, StringComparison.CurrentCultureIgnoreCase), out var match)) {
|
||||
if (match is ui.controls.DIYGrid.IKeyedColumn<MarketViewView.Columns> kcol) {
|
||||
var col_comp = MarketViewVM.get_column_comparer(kcol.key);
|
||||
if (col_comp != null) {
|
||||
comp_builder.add(sc.is_ascending ? col_comp : col_comp.reverse());
|
||||
} else {
|
||||
Log.Ui.warn($"{_window_type} is unable to find the row comparer for the '{sc.col_name}' column.");
|
||||
}
|
||||
} else {
|
||||
Log.Ui.warn($"{_window_type} is unable find a column with id '{sc.col_name}.'");
|
||||
}
|
||||
}
|
||||
}
|
||||
var comp = comp_builder.to_comparer();
|
||||
_sorted_selected_security_criteria_backing = new SecurityCriteria(_vm.selected_rows.Ordered(comp).Select(r => r.security));
|
||||
}
|
||||
}
|
||||
return _sorted_selected_security_criteria_backing;
|
||||
}
|
||||
}
|
||||
|
||||
bool _has_selected_rows() => _vm != null && _vm.selected_rows.Count > 0;
|
||||
public string thread_id => _thread_id;
|
||||
|
||||
public void thread_init() {
|
||||
_init_guard.check_access();
|
||||
@@ -104,85 +55,39 @@ namespace mbts.spark {
|
||||
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, _settings_manager);
|
||||
_view = new MarketViewView { DataContext = _vm };
|
||||
_view._grid.Sorting += on_grid_sorting;
|
||||
/// The 'CanExecute' plumbing for the cmds below is designed to avoid potentially costly .ToList() operations on the selected_rows/securities.
|
||||
/// Some of the cmds post ITags with data that is, or has, a SecurityCriteria member; the SecurityCriteria constructor creates a new List of the specified securities.
|
||||
/// For these commands, the objective is to evaluate 'CanExecute' without instantiating the SecurityCriteria (or more importantly, without creating a new List).
|
||||
// show time and sales
|
||||
var show_tas_cmd = new DelegateCommand(() => {
|
||||
var sc = _selected_security_criteria;
|
||||
if (sc.is_defined())
|
||||
_bus.post(SparkTags.ShowTimeAndSalesTag, sc);
|
||||
}, _has_selected_rows);
|
||||
var show_tas_actual_cmd = SparkCommands.ShowTimeAndSales;
|
||||
var show_tas_cmd_wrapper = new SparkCommandCommand(show_tas_actual_cmd.title, show_tas_actual_cmd.icon, show_tas_cmd);
|
||||
// show fills
|
||||
var show_fills_cmd = new DelegateCommand(() => {
|
||||
var sc = _selected_security_criteria;
|
||||
_bus.post(SparkTags.ShowFillsTag, new FillsSettings(
|
||||
new FillsFilterStates {
|
||||
security = sc.is_defined() ? sc : _state.security_criteria
|
||||
}));
|
||||
});
|
||||
var show_fills_actual_cmd = SparkCommands.ShowFills();
|
||||
var show_fills_cmd_wrapper = new SparkCommandCommand(show_fills_actual_cmd.title, show_fills_actual_cmd.icon, show_fills_cmd, SparkCommands.KeyGestures.ShowFills);
|
||||
// show synthetic create
|
||||
var show_synth_create_cmd = new DelegateCommand(() => {
|
||||
var sc = _sorted_selected_security_criteria;
|
||||
if (sc.is_defined())
|
||||
_bus.post(SparkTags.ShowSyntheticCreateTag, sc);
|
||||
}, () => _vm.selected_rows.Count > 0 && _vm.selected_rows.Count <= 24);
|
||||
var show_synth_create_actual_cmd = SparkCommands.ShowSyntheticCreate();
|
||||
var show_synth_create_cmd_wrapper = new SparkCommandCommand(show_synth_create_actual_cmd.title, show_synth_create_actual_cmd.icon, show_synth_create_cmd, SparkCommands.KeyGestures.ShowSyntheticCreate);
|
||||
|
||||
var update_securities_cmd = SparkCommands.change_securities_callback(_window_type_display_name);
|
||||
// commands
|
||||
_commands = new List<SparkCommand> {
|
||||
SparkCommands.ShowLadders(SparkCommands.KeyGestures.ShowLadder).complete(_vm.selected_security_mds_observable(), smds => smds.Count > 0),
|
||||
SparkCommands.ShowOrderTicketFromSecurity(SparkCommands.KeyGestures.ShowOrderTicket).complete(_vm.current_security_md, md => md.HasValue, ConvertUtils.ValueOrDefault),
|
||||
show_fills_cmd_wrapper,
|
||||
show_tas_cmd_wrapper,
|
||||
show_synth_create_cmd_wrapper,
|
||||
SparkCommands.ShowLadders.complete(_vm.selected_security_mds_observable(), smds => smds.Count > 0),
|
||||
SparkCommands.ShowOrderTicketFromSecurity.complete(_vm.current_security_md, md => md.HasValue, ConvertUtils.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.sorted_selected_securities_observable(), secs => secs.Count > 0 && secs.Count <= 24, secs => new SecurityCriteria(secs)),
|
||||
SparkCommands.change_securities_command(() => (update_securities_cmd, _state.security_criteria)),
|
||||
// wrap the grid settings view factory in a dialogCommand here since the vm is destroyed/recreated when the security criteria changes
|
||||
SparkCommands.window_settings_command(new DialogCommand(() => {
|
||||
var vm = new ShellSettingsDialogVM<GridSettings, SimpleGridSettingsVM>(
|
||||
var vm = new WindowSettingsDialogVM<GridSettings, SimpleGridSettingsVM>(
|
||||
_settings_manager,
|
||||
us => us.market_view_grid,
|
||||
UserSettings.FileExtensions.GRID,
|
||||
s => _vm.grid_settings_manager.create_vm(
|
||||
// we need to get the most up to date GridSettings when launching b/c users may
|
||||
// have changed some settings on the grid directly, like column widths.
|
||||
s.with(_vm.columns.Select(c => c.create()))
|
||||
s.with(_vm.columns.Select( c => c.create())),
|
||||
this.observe_title()
|
||||
)
|
||||
);
|
||||
vm.SubscribeDisposed(literal_title_source.OnDispatcher().Subscribe(t => vm.title = t));
|
||||
var dialog = new ShellSettingsDialog { DataContext = vm };
|
||||
// TODO: bind to main window's Title
|
||||
var dialog = new SimpleGridSettingsDialog { Title = "Market View Grid Settings", DataContext = vm };
|
||||
vm.RequestClose += (s, e) => WindowUtilities.force_close(dialog);
|
||||
return dialog;
|
||||
}))
|
||||
};
|
||||
//
|
||||
_vm.selection_changed += on_selection_changed;
|
||||
_subscriptions = new CompositeDisposable(_bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(c =>
|
||||
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.get_filter_states(), _vm.grid_settings_manager.create())))) {
|
||||
() => {
|
||||
_vm.selection_changed -= on_selection_changed;
|
||||
_view._grid.Sorting -= on_grid_sorting;
|
||||
}
|
||||
};
|
||||
|
||||
void on_selection_changed((IEnumerable<MarketViewVM.Row> removed, IEnumerable<MarketViewVM.Row> added) change) {
|
||||
// invalidate selected security criteria
|
||||
_selected_security_criteria_backing = null;
|
||||
_sorted_selected_security_criteria_backing = null;
|
||||
show_tas_cmd.RaiseCanExecuteChanged();
|
||||
show_fills_cmd.RaiseCanExecuteChanged();
|
||||
show_synth_create_cmd.RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
void on_grid_sorting(object sender, ui.controls.DIYGridSortingEventArgs e) =>
|
||||
_sorted_selected_security_criteria_backing = null;
|
||||
_subscriptions = _bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(c =>
|
||||
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.get_filter_states(), _vm.grid_settings_manager.create())));
|
||||
}
|
||||
|
||||
public override void Dispose() {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using bts.api;
|
||||
using bts.proto;
|
||||
using bts.settings;
|
||||
using mbts.persist;
|
||||
using mbts.spark;
|
||||
using mbts.spark.filters;
|
||||
@@ -9,7 +7,6 @@ using mbts.ui.settings;
|
||||
using ProtoBuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -38,8 +35,13 @@ namespace bts.shell {
|
||||
void _show(SecurityCriteria criteria) =>
|
||||
_bus.post(SparkTags.ShowWindow, _create(StartupData.Default(criteria)));
|
||||
|
||||
IShellWindow _create(StartupData state) =>
|
||||
new MarketViewWindow(this, _bus, _orders_model, state, _settings_hub.create_mview_settings_manager(state.grid));
|
||||
IShellWindow _create(StartupData state) {
|
||||
var settings_manager = new WindowSettingsManager<GridSettings>(_settings_hub,
|
||||
state.grid,
|
||||
get: us => us.market_view_grid,
|
||||
set: (us, gs) => us.with(provided_market_view_gridsettings: gs));
|
||||
return new MarketViewWindow(this, _bus, _orders_model, state, settings_manager);
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class StartupData {
|
||||
@@ -66,29 +68,7 @@ namespace bts.shell {
|
||||
_sorting_criteria = sort;
|
||||
}
|
||||
|
||||
public static GridSettings sanitize(GridSettings s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// column upgrade
|
||||
var columns = s.columns.ToList();
|
||||
var bid_col_index = columns.FindIndex(x => x.id == col_id(Columns.Bid));
|
||||
var ask_col_index = columns.FindIndex(x => x.id == col_id(Columns.Ask));
|
||||
if (bid_col_index > -1 && ask_col_index > -1) {
|
||||
if (!columns[bid_col_index].background_color_override.HasValue) {
|
||||
columns[bid_col_index] = columns[bid_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.bid.ToUint()));
|
||||
}
|
||||
if (!columns[ask_col_index].background_color_override.HasValue) {
|
||||
columns[ask_col_index] = columns[ask_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.ask.ToUint()));
|
||||
}
|
||||
}
|
||||
// and enable background color upgrade
|
||||
return s.with(columns, enable_background_color: true);
|
||||
}
|
||||
|
||||
|
||||
public static GridSettings DefaultGridSettings => GridSettings.Default.with(DefaultColumns.all, DefaultColumns.default_sorting_criterion, enable_background_color: true);
|
||||
public static GridSettings DefaultGridSettings => GridSettings.Default.with(DefaultColumns.all, DefaultColumns.default_sorting_criterion);
|
||||
|
||||
public IReadOnlyList<SortingCriteria> sorting_criterion => _sorting_criteria ?? (_sorting_criteria = DefaultColumns.default_sorting_criterion.ToList());
|
||||
|
||||
@@ -100,16 +80,14 @@ namespace bts.shell {
|
||||
public static GridColumnSettings security => new GridColumnSettings(col_id(Columns.Security), DefaultColumnHeaders.Security, width: DefaultColumnWidths.Security);
|
||||
public static GridColumnSettings volume => new GridColumnSettings(col_id(Columns.Volume), DefaultColumnHeaders.Volume, width: DefaultColumnWidths.Volume);
|
||||
public static GridColumnSettings last => new GridColumnSettings(col_id(Columns.Last), DefaultColumnHeaders.Last, width: DefaultColumnWidths.Price);
|
||||
public static GridColumnSettings last_from_spread => new GridColumnSettings(col_id(Columns.LastSpd), DefaultColumnHeaders.S, width: DefaultColumnWidths.Price, is_visible: false);
|
||||
public static GridColumnSettings last_size => new GridColumnSettings(col_id(Columns.LastSize), DefaultColumnHeaders.Size, width: DefaultColumnWidths.Size, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings position => new GridColumnSettings(col_id(Columns.Position), DefaultColumnHeaders.Pos, width: DefaultColumnWidths.Size, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings raw_day_position => new GridColumnSettings(col_id(Columns.RawDayPosition), DefaultColumnHeaders.RawDayPos, width: DefaultColumnWidths.Size, horizontal_alignment: System.Windows.HorizontalAlignment.Right, is_visible: false);
|
||||
public static GridColumnSettings working_bids => new GridColumnSettings(col_id(Columns.WorkingBids), DefaultColumnHeaders.Working, font_color_override: BTSColors.MarketData.bid, width: DefaultColumnWidths.Working, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings bid_implied_size => new GridColumnSettings(col_id(Columns.BidImpliedSize), DefaultColumnHeaders.ImpliedSize, font_color_override: BTSColors.MarketData.bid, width: DefaultColumnWidths.ImpliedDirectMergedSize, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings bid_direct_size => new GridColumnSettings(col_id(Columns.BidDirectSize), DefaultColumnHeaders.DirectSize, font_color_override: BTSColors.MarketData.bid, width: DefaultColumnWidths.ImpliedDirectMergedSize, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings bid_merged_size => new GridColumnSettings(col_id(Columns.BidMergedSize), DefaultColumnHeaders.MergedSize, font_color_override: BTSColors.MarketData.bid, width: DefaultColumnWidths.ImpliedDirectMergedSize, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings bid => new GridColumnSettings(col_id(Columns.Bid), DefaultColumnHeaders.Bid, font_color_override: BTSColors.header_text, width:DefaultColumnWidths.MViewPrice, horizontal_alignment: System.Windows.HorizontalAlignment.Right, background_color_override: BTSColors.MarketData.bid);
|
||||
public static GridColumnSettings ask => new GridColumnSettings(col_id(Columns.Ask), DefaultColumnHeaders.Ask, font_color_override: BTSColors.header_text, width: DefaultColumnWidths.MViewPrice, horizontal_alignment: System.Windows.HorizontalAlignment.Right, background_color_override: BTSColors.MarketData.ask);
|
||||
public static GridColumnSettings bid => new GridColumnSettings(col_id(Columns.Bid), DefaultColumnHeaders.Bid, font_color_override: BTSColors.header_text, width:DefaultColumnWidths.MViewPrice, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings ask => new GridColumnSettings(col_id(Columns.Ask), DefaultColumnHeaders.Ask, font_color_override: BTSColors.header_text, width: DefaultColumnWidths.MViewPrice, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings ask_merged_size => new GridColumnSettings(col_id(Columns.AskMergedSize), DefaultColumnHeaders.MergedSize, font_color_override: BTSColors.MarketData.ask, width: DefaultColumnWidths.ImpliedDirectMergedSize, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings ask_direct_size => new GridColumnSettings(col_id(Columns.AskDirectSize), DefaultColumnHeaders.DirectSize, font_color_override: BTSColors.MarketData.ask, width: DefaultColumnWidths.ImpliedDirectMergedSize, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings ask_implied_size => new GridColumnSettings(col_id(Columns.AskImpliedSize), DefaultColumnHeaders.ImpliedSize, font_color_override: BTSColors.MarketData.ask, width: DefaultColumnWidths.ImpliedDirectMergedSize, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
@@ -139,10 +117,8 @@ namespace bts.shell {
|
||||
yield return security;
|
||||
yield return volume;
|
||||
yield return last;
|
||||
yield return last_from_spread;
|
||||
yield return last_size;
|
||||
yield return position;
|
||||
yield return raw_day_position;
|
||||
yield return working_bids;
|
||||
yield return bid_implied_size;
|
||||
yield return bid_direct_size;
|
||||
@@ -197,8 +173,6 @@ namespace bts.shell {
|
||||
public DoubleMinMaxState session_high;
|
||||
[ProtoMember(12)]
|
||||
public IntMinMaxState position;
|
||||
[ProtoMember(27)]
|
||||
public DoubleMinMaxState raw_day_position;
|
||||
[ProtoMember(13)]
|
||||
public IntMinMaxState working_bid_volume;
|
||||
[ProtoMember(14)]
|
||||
@@ -226,50 +200,7 @@ namespace bts.shell {
|
||||
[ProtoMember(25)]
|
||||
public string strip_name;
|
||||
[ProtoMember(26)]
|
||||
public string last_price_from_spread;
|
||||
[ProtoMember(28)]
|
||||
public string mic_code;
|
||||
}
|
||||
|
||||
// migration rules
|
||||
[Export(typeof(IMarketViewGridSettingsMigrationRule))]
|
||||
class AddMissingColumnsMigrationRule : IMarketViewGridSettingsMigrationRule {
|
||||
public bool apply(GridSettings settings, out GridSettings new_settings) =>
|
||||
settings.add_missing_columns(StartupData.DefaultGridSettings.columns, out new_settings);
|
||||
}
|
||||
|
||||
[Export(typeof(IMarketViewGridSettingsMigrationRule))]
|
||||
class InitBidAskBackgroundOverrideMigrationRule : IMarketViewGridSettingsMigrationRule {
|
||||
public bool apply(GridSettings s, out GridSettings new_settings) {
|
||||
var columns = s.columns.ToList();
|
||||
var bid_col_index = columns.FindIndex(x => x.id == col_id(Columns.Bid));
|
||||
var ask_col_index = columns.FindIndex(x => x.id == col_id(Columns.Ask));
|
||||
bool applied = false;
|
||||
if (bid_col_index > -1 && ask_col_index > -1) {
|
||||
if (!columns[bid_col_index].background_color_override.HasValue) {
|
||||
columns[bid_col_index] = columns[bid_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.bid.ToUint()));
|
||||
applied = true;
|
||||
}
|
||||
if (!columns[ask_col_index].background_color_override.HasValue) {
|
||||
columns[ask_col_index] = columns[ask_col_index].with(background_color_override: new NullableColorProto(BTSColors.MarketData.ask.ToUint()));
|
||||
applied = true;
|
||||
}
|
||||
}
|
||||
new_settings = applied ? s.with(columns) : default;
|
||||
return applied;
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(IMarketViewGridSettingsMigrationRule))]
|
||||
class InitBackgroundOverrideMigrationRule : IMarketViewGridSettingsMigrationRule {
|
||||
public bool apply(GridSettings settings, out GridSettings new_settings) {
|
||||
if (!settings.enable_background_color) {
|
||||
new_settings = settings.with(enable_background_color: true);
|
||||
return true;
|
||||
}
|
||||
new_settings = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,23 @@
|
||||
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 : IDisposable {
|
||||
internal readonly SecurityCriteria security_criteria;
|
||||
|
||||
|
||||