Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bbe9cfd98 | ||
|
|
ba633532eb | ||
|
|
7bf50415ca | ||
|
|
edbaa9c435 | ||
|
|
7789f39c9d | ||
|
|
6e188b4f73 | ||
|
|
93abf315a3 | ||
|
|
33e8ff58c5 | ||
|
|
24ae03a9f8 | ||
|
|
0d706efb10 | ||
|
|
73fe142904 | ||
|
|
8668c54784 | ||
|
|
f29e04751d | ||
|
|
f9f64c23c1 | ||
|
|
d3e9f15e99 | ||
|
|
6dba376e8b | ||
|
|
5fe0335e1a | ||
|
|
99b380a9f3 | ||
|
|
175061a81e | ||
|
|
3daad4f7e7 | ||
|
|
6cbf707094 | ||
|
|
8bcf2fde87 | ||
|
|
a5d20157f0 | ||
|
|
d3deac46d4 | ||
|
|
7e4ad55d9d | ||
|
|
288e8a364a | ||
|
|
35a0074014 | ||
|
|
61c6d0513c | ||
|
|
b0f2b8e906 | ||
|
|
c194e76e46 | ||
|
|
e7f8cfaec1 | ||
|
|
0aa4f80752 | ||
|
|
b8eecfd853 | ||
|
|
2960ff0996 | ||
|
|
a071b62560 | ||
|
|
b8dd5c119d | ||
|
|
95004adbad | ||
|
|
f28334f551 | ||
|
|
718a12200b | ||
|
|
d6dab59254 | ||
|
|
9e6bdf74f6 | ||
|
|
030a8d5614 | ||
|
|
39946baf94 | ||
|
|
19be7d7740 | ||
|
|
37856b9768 | ||
|
|
dd2067802f | ||
|
|
de6c53a765 | ||
|
|
b2a20b47ff | ||
|
|
be16bc2a27 | ||
|
|
71c66f127d | ||
|
|
4987fc9fc1 | ||
|
|
16a4c315a2 | ||
|
|
71619c2e15 | ||
|
|
5392b706df | ||
|
|
8ada73aa64 | ||
|
|
cbda28c8b7 | ||
|
|
a16ff30873 | ||
|
|
3956455e81 | ||
|
|
76eb541878 | ||
|
|
d17c56b799 | ||
|
|
e3795f9498 | ||
|
|
8da2569a27 | ||
|
|
a598188c14 | ||
|
|
3648f18a09 | ||
|
|
736e051225 | ||
|
|
e007958afd | ||
|
|
1682513af1 | ||
|
|
cc7e66aa61 | ||
|
|
cea153df5a | ||
|
|
9903b340a6 | ||
|
|
f07b272cff | ||
|
|
9d74a9d114 | ||
|
|
e8f9bb8226 | ||
|
|
033c1ec5de | ||
|
|
7fd2c075a1 | ||
|
|
125773b840 | ||
|
|
4cb743004b | ||
|
|
9dbc9df2a4 | ||
|
|
7c1016d940 | ||
|
|
43198f9602 | ||
|
|
8b1a195121 | ||
|
|
1cde234be4 | ||
|
|
bba6da76fb | ||
|
|
0f68a7f56b | ||
|
|
a4963f8bd9 | ||
|
|
58a762a18a | ||
|
|
90c13d526a | ||
|
|
743d8e0e81 | ||
|
|
eb7a79488f | ||
|
|
3dd7b9638b | ||
|
|
771d4976e9 | ||
|
|
f0a08c6f83 | ||
|
|
c7097faba2 | ||
|
|
e9a341a013 | ||
|
|
15839ba75d | ||
|
|
cd0b24c16a | ||
|
|
7151619645 | ||
|
|
684c4037b6 | ||
|
|
97a50faf16 | ||
|
|
ca2a6a1e60 | ||
|
|
61a112c221 | ||
|
|
8e079a970f | ||
|
|
a4bc22fc3b | ||
|
|
0f81ce1716 | ||
|
|
97deb63deb | ||
|
|
a3b91a4363 | ||
|
|
2551a0f11e | ||
|
|
2f5b06b628 | ||
|
|
575195c67a | ||
|
|
9c20fe892e | ||
|
|
4b626a160d | ||
|
|
bfef852de7 | ||
|
|
dbb859cce9 | ||
|
|
abb451349c | ||
|
|
e77ecaa48c | ||
|
|
1895a75bc7 | ||
|
|
0da184ab73 | ||
|
|
f9357d0860 | ||
|
|
f7bd209efa | ||
|
|
f794ffdace | ||
|
|
504323d5b7 | ||
|
|
9450a952d4 | ||
|
|
62394d0e71 | ||
|
|
8d9697d06d | ||
|
|
d4744d300b | ||
|
|
9b7275e713 | ||
|
|
51ed3a4c2c | ||
|
|
d9e967610e | ||
|
|
2cfbd655cb | ||
|
|
3ed5e5275e | ||
|
|
d997aeca1e | ||
|
|
3b371f3588 | ||
|
|
256b296521 | ||
|
|
38668f8de1 | ||
|
|
b68aaa0a00 | ||
|
|
36e58378e4 | ||
|
|
0ef2378dc9 | ||
|
|
d1d4a1bfb7 | ||
|
|
e22649c19d | ||
|
|
25f749bb0c | ||
|
|
e45ee1730e | ||
|
|
6bd3c6b0ca | ||
|
|
6f65a958ae | ||
|
|
53a4ab4974 | ||
|
|
6e4ed3f328 | ||
|
|
4a292c8030 | ||
|
|
29fbfd4479 | ||
|
|
500e5d508a | ||
|
|
396ac023c4 | ||
|
|
e32f40caee | ||
|
|
4b3cdf9ca4 | ||
|
|
2fc4c8bd60 | ||
|
|
47e7d69897 | ||
|
|
4f830cdd40 | ||
|
|
00e9de3b1e | ||
|
|
ddb4e55d13 | ||
|
|
7e0d79ac68 | ||
|
|
c2dfcbe343 | ||
|
|
582fffb1f4 | ||
|
|
e67756d055 | ||
|
|
42b73006a8 | ||
|
|
2fc85d6810 | ||
|
|
141e1a4ea0 | ||
|
|
097db2f340 | ||
|
|
b49c764c54 | ||
|
|
385387b739 | ||
|
|
87218962e1 | ||
|
|
88d8248f63 | ||
|
|
ffbda10200 | ||
|
|
7eb8b21cea | ||
|
|
986a791801 | ||
|
|
c834a6e840 | ||
|
|
f14c36223f | ||
|
|
d66c8e0ad8 | ||
|
|
8673f366d7 | ||
|
|
88e48ebcf7 | ||
|
|
ea3eacbbae | ||
|
|
9f3941d1a1 | ||
|
|
1a6a10a834 | ||
|
|
d780e2aab2 | ||
|
|
a4bc34e633 | ||
|
|
9c8bb7efeb | ||
|
|
d9b37efbbd | ||
|
|
d23b7942b6 | ||
|
|
f41c3a5334 | ||
|
|
d8e8f90131 | ||
|
|
0358afccf9 | ||
|
|
9f58327d0a | ||
|
|
d3ed6e21e4 | ||
|
|
a171abb741 | ||
|
|
52825e0e59 | ||
|
|
de83f19388 | ||
|
|
4d993f2ef7 | ||
|
|
ca81be3865 | ||
|
|
19ae05cb7d | ||
|
|
79ec41556e | ||
|
|
088377582d | ||
|
|
c8b3973b8f | ||
|
|
efc490cc0d | ||
|
|
82a2ba4a86 | ||
|
|
ccbe20eb57 | ||
|
|
70a2feb92a | ||
|
|
a4d542067a | ||
|
|
efd222133e | ||
|
|
361491ebd2 | ||
|
|
6aeba4f599 | ||
|
|
559ab69940 | ||
|
|
b35dae9fab | ||
|
|
9d96fcaa45 | ||
|
|
e75be340e2 | ||
|
|
523f02b4c2 | ||
|
|
a5b7332fa4 | ||
|
|
edb4ed02c9 | ||
|
|
96da8e3276 | ||
|
|
c056bfcf7a | ||
|
|
2ddf1a1762 | ||
|
|
8a9ddfded7 | ||
|
|
a83f97e1ef | ||
|
|
3630bf5b9a | ||
|
|
b9d3a4d04c | ||
|
|
c7fb636e49 | ||
|
|
c7ea6c4ca4 | ||
|
|
1ffda9c413 | ||
|
|
e2f314d007 | ||
|
|
80d8307822 | ||
|
|
1ca5ed4520 | ||
|
|
8115f9df74 | ||
|
|
306cbaa837 | ||
|
|
efa31059d9 | ||
|
|
73089634f9 | ||
|
|
a84e5e3460 | ||
|
|
eca11d0317 | ||
|
|
ced485856e | ||
|
|
08c54f75eb | ||
|
|
6c0cc76773 | ||
|
|
4d53bfb3f0 | ||
|
|
e332edb36b | ||
|
|
70b5d9adc6 | ||
|
|
23ee9508c2 | ||
|
|
717391afb3 | ||
|
|
38e0d40364 | ||
|
|
7053c2ee03 | ||
|
|
cdde730fc5 | ||
|
|
95b0119d22 | ||
|
|
07a965a3e0 | ||
|
|
eba153e289 | ||
|
|
fc5238c56f | ||
|
|
bc367b9f56 | ||
|
|
8adcc98ff1 | ||
|
|
ba07041c26 | ||
|
|
d3101b1cd8 | ||
|
|
3a9a86020b | ||
|
|
42afdc2994 | ||
|
|
1dc87de975 | ||
|
|
6c93208e11 | ||
|
|
49ba2e72a9 | ||
|
|
bf1ca4e5fa | ||
|
|
3f9e64016b | ||
|
|
c672967caf | ||
|
|
1e0dac0fbc | ||
|
|
aec8de54bd | ||
|
|
a960093cf6 | ||
|
|
4601e49106 | ||
|
|
7e65db38cf | ||
|
|
d70bd63659 | ||
|
|
47dc0d579b | ||
|
|
ef6662d4f8 | ||
|
|
246f9240e7 | ||
|
|
a8ebb9cdcb | ||
|
|
bdb2d6cf9e | ||
|
|
b9aaaa7d37 | ||
|
|
ec43039b94 | ||
|
|
4939b85819 | ||
|
|
fab7596d06 | ||
|
|
81d67f640b | ||
|
|
b8e298c524 | ||
|
|
3233187fd9 | ||
|
|
02d1badf0d | ||
|
|
fe8f217587 | ||
|
|
b69958007d | ||
|
|
f433a3163b | ||
|
|
bb82590e5e | ||
|
|
1855fe3045 | ||
|
|
e3dba306a7 | ||
|
|
74f79a2f52 | ||
|
|
2c384af157 | ||
|
|
99fd77c1f1 | ||
|
|
7b0e3edfcf | ||
|
|
99b71ad2aa | ||
|
|
58c5eeb6d1 | ||
|
|
cbb638ff7a | ||
|
|
9cd2518853 | ||
|
|
2db8d717d4 | ||
|
|
df56c85e7b | ||
|
|
fb12d429cb |
No files matched your search
Vendored
+5
-5
@@ -33,12 +33,12 @@
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "SDK Launch",
|
||||
"name": "FIX Launch",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/Debug/bin/net471/spark_sdk.exe",
|
||||
"args": ["md","GLBX","Future","ZN", "ZNU8"],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"program": "${workspaceRoot}/build/Debug/bin/net471/sparkcmd.exe",
|
||||
"args": ["fix","-f","spark_fix.cfg","-d"],
|
||||
"cwd": "${workspaceRoot}/build/Debug/bin/net471/",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
@@ -209,7 +209,7 @@
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"args": ["test","Co2RelayTests"],
|
||||
"args": ["test","Co2Tests"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
|
||||
"environment": [],
|
||||
|
||||
+1
-1
@@ -41,6 +41,7 @@ else ()
|
||||
-Wno-missing-braces -Wno-ignored-qualifiers \
|
||||
--std=c++17 -fdiagnostics-color")
|
||||
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -DNDEBUG -O3")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wno-undef")
|
||||
add_subdirectory(src/server/sparkd)
|
||||
add_subdirectory(src/lib)
|
||||
add_subdirectory(src/web)
|
||||
@@ -51,7 +52,6 @@ else ()
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/server/sparkd/sparkd ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/server/sparkd/defaults ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/web ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/data_files ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
|
||||
|
||||
@@ -25,3 +25,47 @@
|
||||
***** FillStore
|
||||
***** SecuritySrc
|
||||
* Benchmarks
|
||||
* OrderMan
|
||||
** OrderServices
|
||||
*** callbacks
|
||||
**** standard
|
||||
- update
|
||||
- cancel
|
||||
- crack
|
||||
- activate
|
||||
- book
|
||||
- settlement
|
||||
- child order state
|
||||
- timer
|
||||
**** low level
|
||||
- exe reports
|
||||
- cancel rejects
|
||||
- gateway status
|
||||
*** services
|
||||
**** standard
|
||||
- secdb
|
||||
- get time
|
||||
- schedule actions
|
||||
- order builder
|
||||
- activate
|
||||
- update
|
||||
- cancel
|
||||
- crack
|
||||
**** low level
|
||||
- governor
|
||||
- send fix
|
||||
- get time str
|
||||
- limiter
|
||||
** Internalize plan
|
||||
- change order initiated update/cancel/crack/activate/report_state to
|
||||
use direct method calls
|
||||
- need to watch out for reentrancy
|
||||
- need to also report state externally
|
||||
- also want to separate active from non active orders in map to speed
|
||||
up look ups
|
||||
- want to use direct references in orders to avoid lookups
|
||||
- want to change how time is captured, the trace is too big to copy
|
||||
around
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# The BTS Development Process #
|
||||
|
||||
## The Big Picture ##
|
||||
|
||||
Our development work is organized in projects. A project is an effort
|
||||
to specifiy, develop and validate a related set of additions to our
|
||||
Spark platform. A project can be assigned to one more developers and a
|
||||
developer might concurrently be assigned to multiple
|
||||
projects. Projects typically start out with specification work,
|
||||
proceed to implementation and finish with validation efforts. At any
|
||||
given time there will be multiple projects being worked on
|
||||
concurrently. A project is concluded when the features it implements
|
||||
are merged into the product and deployed to customers.
|
||||
|
||||
## The Details ##
|
||||
Typically project ideas come from sales interactions, opposition
|
||||
research and customer feedback, alltough on occasion development or
|
||||
operational requirements will also suggest potentially valuable
|
||||
ideas. Whatever the source of a project idea the final decision of
|
||||
which projects to pursue is always done by management. Once a project
|
||||
idea has been selected for implementation the corresponding project
|
||||
will go through several phases: inception, specification, development
|
||||
and merge. We detail each of these phases below.
|
||||
|
||||
* Inception. In this phase we create the infrastructure for the
|
||||
project. Typically this means selecting a team, creating a project
|
||||
case in Jira (that is a case assigned to the team@bluetradesys.com
|
||||
Jira user) and possibly creating a new branch for the project. This
|
||||
phase is mostly mechanical and the responsibility of Pedro.
|
||||
|
||||
* Specification. The specification phase turns a usually vague and
|
||||
ill-considered idea project idea into a concrete, implementable
|
||||
specification that attempts to maximize the value/cost ratio of the
|
||||
project. It is hard to exaggerate the impact of a this phase on the
|
||||
rest of the project. *Nothing* has more impact on our ability to
|
||||
quickly deliver value to customers than good specification
|
||||
work. Specification typically take the form of shared google docs,
|
||||
using a mix of text and UI mockups to capture both user requirements
|
||||
and suggested implementation strategies. Taha is responsible for this
|
||||
phase.
|
||||
|
||||
* Development. Once a specification is complete, a team of developers
|
||||
will use a project specific branch to implement the
|
||||
specification. Periodically, typically once a week, progress on the
|
||||
project is assessed by Pedro, possibly with the help of others. This
|
||||
assessment takes the form of code reviews, demos, or just one-on-one
|
||||
conversations. To ensure development does not go off on sub-optimal
|
||||
tangents, developers are expected to continuously merge master into
|
||||
the project branch as well as encouraged to create Pull Requests (PRs)
|
||||
early in the project implementation, so that their work is kept
|
||||
visible and integrated with that of the rest of the group. During the
|
||||
implementation phase developers should reach out to Pedro for UI
|
||||
reviews, architecture and design concerns as well as specification
|
||||
trade off concerns.
|
||||
|
||||
* Merge. Once a project is considered complete by developers, a PR
|
||||
that includes Pedro should be created (unless, as mentioned above, an
|
||||
early PR was already created in the development phase). Whether the PR
|
||||
already existed or not, its description should be changed to start
|
||||
with the "Ready To Merge" statement. This marks the project as ready
|
||||
to be merged into master. Once a week, typically on Mondays, Pedro
|
||||
will go through every PR marked as "Ready To Merge", build it, check
|
||||
it out and if everything looks good merge it to master. At the end of
|
||||
the day the resulting master will be tagged with a new version
|
||||
number. This version will be go through some additional testing by
|
||||
Brian and will then be deployed by Karl and Pete to customers
|
||||
throughout the rest of the week.
|
||||
|
||||
## Tools ##
|
||||
* Pre-Merge checklist
|
||||
* Code Review tutorial
|
||||
@@ -0,0 +1 @@
|
||||
set(sources /home/ppinto/Dropbox/bts/spark/doc/user/build.sh;/home/ppinto/Dropbox/bts/spark/doc/user/mkdocs.yml;bts-help-theme/404.html;bts-help-theme/base.html;bts-help-theme/content.html;bts-help-theme/css/base.css;bts-help-theme/css/bts.css;bts-help-theme/css/font-awesome.min.css;bts-help-theme/css/highlight.css;bts-help-theme/css/local.css;bts-help-theme/fonts/fontawesome-webfont.eot;bts-help-theme/fonts/glyphicons-halflings-regular.eot;bts-help-theme/img/favicon.ico;bts-help-theme/js/base.js;bts-help-theme/js/bootstrap-3.0.3.min.js;bts-help-theme/js/highlight.pack.js;bts-help-theme/js/jquery-1.10.2.min.js;bts-help-theme/keyboard-modal.html;bts-help-theme/main.html;bts-help-theme/nav-sub.html;bts-help-theme/nav.html;bts-help-theme/search-modal.html;bts-help-theme/toc.html;docs/Help.md;docs/Launcher.md;docs/Logging-In-to-the-System.md;docs/Market.md;docs/My-Windows.md;docs/Settings.md;docs/Spreader.md;docs/Trading.md;docs/images/image1.png;docs/images/image10.png;docs/images/image11.png;docs/images/image12.png;docs/images/image13.png;docs/images/image14.png;docs/images/image15.png;docs/images/image16.png;docs/images/image17.png;docs/images/image18.png;docs/images/image19.png;docs/images/image2.png;docs/images/image20.png;docs/images/image21.png;docs/images/image22.png;docs/images/image23.png;docs/images/image24.png;docs/images/image25.png;docs/images/image26.png;docs/images/image27.png;docs/images/image28.png;docs/images/image29.png;docs/images/image3.png;docs/images/image30.png;docs/images/image31.png;docs/images/image32.png;docs/images/image33.png;docs/images/image34.png;docs/images/image35.png;docs/images/image36.png;docs/images/image37.png;docs/images/image38.png;docs/images/image39.png;docs/images/image4.png;docs/images/image40.png;docs/images/image41.png;docs/images/image42.png;docs/images/image43.png;docs/images/image44.png;docs/images/image45.png;docs/images/image46.png;docs/images/image47.png;docs/images/image48.png;docs/images/image49.png;docs/images/image5.png;docs/images/image50.png;docs/images/image51.png;docs/images/image52.png;docs/images/image53.png;docs/images/image54.png;docs/images/image55.png;docs/images/image56.png;docs/images/image57.png;docs/images/image58.png;docs/images/image59.png;docs/images/image6.png;docs/images/image60.png;docs/images/image61.png;docs/images/image62.png;docs/images/image63.png;docs/images/image64.png;docs/images/image65.png;docs/images/image66.png;docs/images/image67.png;docs/images/image68.png;docs/images/image69.png;docs/images/image7.png;docs/images/image70.png;docs/images/image71.png;docs/images/image72.png;docs/images/image73.png;docs/images/image74.png;docs/images/image76.png;docs/images/image8.png;docs/images/image9.png;docs/index.md;docs/release_notes.md)
|
||||
@@ -16,6 +16,7 @@ set(DOC_GLOBS
|
||||
favicon.ico
|
||||
)
|
||||
file (GLOB_RECURSE All_Deps RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${DOC_GLOBS})
|
||||
set (All_Deps ${All_Deps} ${CMAKE_CURRENT_SOURCE_DIR}/build.sh ${CMAKE_CURRENT_SOURCE_DIR}/mkdocs.yml)
|
||||
update_deps_file("${All_Deps}")
|
||||
# END DEPENDENCIES
|
||||
|
||||
|
||||
+10
-1
@@ -1,2 +1,11 @@
|
||||
#!/bin/bash
|
||||
python -m mkdocs build -d $1
|
||||
tmpfile=$(mktemp /tmp/quiet_build_log.XXXX)
|
||||
python -m mkdocs build -d $1 >$tmpfile 2>&1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
rm $tmpfile
|
||||
exit 0
|
||||
else
|
||||
cat $tmpfile
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,5 +1,9 @@
|
||||
#Help
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/yGQfr_puT3w" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
##Report a Problem
|
||||
If there is any issue at all, you can click here
|
||||
and it’ll bring up a “Report a Problem” window, which you can type
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#Module Launcher
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/OxVqQBKFIDw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- The module launcher is the first item that will come up after
|
||||
logging in to Spark.
|
||||
- This is your central control for all modules
|
||||
@@ -9,7 +13,7 @@
|
||||
|
||||

|
||||
|
||||
- If you right click anywhere on the launcher you can modify
|
||||
- If you right-click anywhere on the launcher you can modify
|
||||
various display settings including:
|
||||
- Vertical layout, instead of horizontal
|
||||
- Showing the text of the individual modules
|
||||
@@ -25,5 +29,5 @@
|
||||
Some common features within BTS Spark
|
||||
|
||||
- All Windows are tabbed so they can be combined or separated to organize your workspace
|
||||
- Some Spark windows have a menu on the left hand side where you can launch related modules or change settings. You can see the menu item names either by hovering your mouse over the icon, or clicking on the right edge of the menu (a blue bar will appear).
|
||||
- Some Spark windows have a menu on the left-hand side where you can launch related modules or change settings. You can see the menu item names either by hovering your mouse over the icon or clicking on the right edge of the menu (a blue bar will appear).
|
||||
- Some table columns have filtering capabilities, where if you hover over the column header, it will display a filter icon, which enables you to filter the table based on the information in that column.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The shortcut icon will appear on your desktop like below:
|
||||
|
||||

|
||||

|
||||
|
||||
Simply double click or single click and hit enter to launch the
|
||||
login screen:
|
||||
|
||||
+16
-8
@@ -9,6 +9,10 @@
|
||||
|
||||
##Market View
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/Y54S1uscT_g" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- This provides a grid of outright, spread, and synthetic products
|
||||
showing real-time market data all in one place
|
||||
- You can create multiple market view grids and customize the
|
||||
@@ -29,7 +33,7 @@
|
||||
and all securities will be displayed. This will show up in the
|
||||
selected securities window as “<symbol> future at
|
||||
<exchange>”
|
||||
- Synthetic’s can be displayed by clicking on exchange “BTS”, then
|
||||
- Synthetics can be displayed by clicking on exchange “BTS”, then
|
||||
synthetic, symbol, and finally under the securities window.
|
||||
- Below is an example of an outright, spread, all futures, and
|
||||
synthetic chosen:
|
||||
@@ -98,10 +102,10 @@
|
||||
either the Bid or Ask price and volume.
|
||||
- Highlighting a single security and clicking on the order ticket
|
||||
 icon
|
||||
on the left hand browser window of the market view
|
||||
on the left-hand browser window of the market view
|
||||
|
||||
- Launch a ladder for 1 security
|
||||
- You can double click on any security in the market view, besides
|
||||
- You can double-click on any security in the market view, besides
|
||||
the Bid Qty, Bid Price, Ask Price, or Ask Qty columns to launch a
|
||||
ladder for that Security.
|
||||
|
||||
@@ -110,7 +114,7 @@
|
||||
- If you hold down the Ctrl key and select multiple securities, you
|
||||
can then click on the ladder icon
|
||||
 on
|
||||
the left hand side to bring up the selected ladders all at
|
||||
the left-hand side to bring up the selected ladders all at
|
||||
once.
|
||||
|
||||
- Launching a Fills window for 1 or many securities
|
||||
@@ -118,7 +122,7 @@
|
||||
- This is done by either highlighting 1 or many securities and then
|
||||
clicking on the Fills icon
|
||||
 on
|
||||
the left hand side to bring up a fill window for the selected
|
||||
the left-hand side to bring up a fill window for the selected
|
||||
securities.
|
||||
|
||||
- Please note - If there haven’t been any fills for the day in that
|
||||
@@ -129,14 +133,14 @@
|
||||
- This is accomplished by highlighting 1 or many securities and then
|
||||
clicking on the time and sales icon
|
||||
 on
|
||||
the left hand side
|
||||
the left-hand side
|
||||
|
||||
- Launching the synthetic window to create a synthetic product
|
||||
|
||||
- This is accomplished by highlighting either 1 or 2 securities and
|
||||
clicking on the Synthetic icon
|
||||
 on
|
||||
the lower left hand side
|
||||
the lower left-hand side
|
||||
|
||||
- Please note - If only 1 security is chosen, a create synthetic
|
||||
window will appear, and you will be required to add another leg from
|
||||
@@ -144,7 +148,11 @@
|
||||
|
||||
##Time and Sales
|
||||
|
||||
- Provides a display of real time fills as they happen for 1 or many
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/nEkSGacjt0s" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- Provides a display of real-time fills as they happen for 1 or many
|
||||
securities
|
||||
- You can create multiple time and sale windows and customize the
|
||||
security selection to fit your needs
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#My Windows
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/pjm1JJ9Q3jM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
This is the housing of the windows that you have manually named and
|
||||
creates a place where you can quickly and easily launch windows
|
||||
which you’ve customized.
|
||||
@@ -18,9 +22,9 @@ section of the module launcher.
|
||||
|
||||

|
||||
|
||||
Right clicking on a tab that has already had its default title modified
|
||||
Right-clicking on a tab that has already had its default title modified
|
||||
will show the following which will allow you to rename the modified
|
||||
title or remove it from the my windows, which will then restore the
|
||||
title or remove it from the My Windows, which will then restore the
|
||||
default standard title.
|
||||
|
||||

|
||||
@@ -1,6 +1,10 @@
|
||||
|
||||
#Settings
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/yGQfr_puT3w" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
##Workspaces
|
||||
|
||||
This is where your workspaces can be saved or switched
|
||||
|
||||
+34
-14
@@ -1,14 +1,35 @@
|
||||
|
||||
#Spreader
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/XEZpuPAgMC0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/EVFK2yNQFS4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/d5ywlHen6yo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/Mmw8PNJA0Dw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/QK-bBSH6Rc0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- Launching the spreader from the module launcher will bring up the
|
||||
synthetic management browser which appears like below:
|
||||
|
||||

|
||||
|
||||
- From this window it’ll show any synthetics that you have already
|
||||
- From this window, it will show any synthetics that you have already
|
||||
created as well as various other options of both managing the
|
||||
synthetics and other tasks all from the left hand side pane within
|
||||
synthetics and other tasks all from the left-hand side pane within
|
||||
the window, including:
|
||||
|
||||
- Adding a new synthetic 
|
||||
@@ -30,7 +51,7 @@
|
||||
- From the main module launcher, you can go to spreader, then
|
||||
synthetics, then click add
|
||||
- Highlighting one or more securities in a market view and clicking
|
||||
on create synthetic
|
||||
on Create Synthetic
|
||||
- Cloning an existing security
|
||||
|
||||
- An empty synthetic browser will look like below without any legs
|
||||
@@ -43,10 +64,10 @@
|
||||
- Upon adding legs, you can then go through each of the parameters to
|
||||
customize how you would like the spread to be worked in the
|
||||
market
|
||||
- We’ll start at the top of create synthetic window and work our way
|
||||
- We will start at the top of the Create Synthetic window and work our way
|
||||
down:
|
||||
|
||||
- At the very top of the create synthetic window you will have to
|
||||
- At the very top of the Create Synthetic window you will have to
|
||||
name your synthetic product. By default, it will auto-populate
|
||||
based on the symbols you have chosen:
|
||||
|
||||
@@ -73,16 +94,15 @@
|
||||
exchange
|
||||
- Furthermore, if you are ever unsure of what a parameter’s function
|
||||
is and how it is controlled you can hover over the parameter’s title
|
||||
and a “?” will be shown. Clicking on this will expand built in
|
||||
and a “?” will be shown. Clicking on this will expand built-in
|
||||
details of how that parameter functions. Below is an example of the
|
||||
throttle details displayed:
|
||||
|
||||

|
||||
|
||||
- Main parameters - these are the top 4 rows in the create synthetic
|
||||
- Main parameters - these are the top 4 rows in the Create Synthetic
|
||||
window which all synthetics will be required to have set.
|
||||
Everything below these are custom to a traders needs, however the
|
||||
top 4 are the main foundational aspects used for the calculation of
|
||||
Everything below these can be customized to a trader's needs, however, the top 4 are the main foundational aspects used for the calculation of
|
||||
the synthetic:
|
||||
|
||||

|
||||
@@ -95,7 +115,7 @@
|
||||
be priced, by default, it’ll be based on the same as the quantity of
|
||||
the synthetic produced, but you can change it to modify the balance
|
||||
of the price, giving more weighting to one leg over another.
|
||||
- Enable quoting - This parameter is in the form of a check box,
|
||||
- Enable quoting - This parameter is in the form of a checkbox,
|
||||
where if the box is checked the leg will be quoted versus not
|
||||
checked, it will not be shown in the market. If it is not actively
|
||||
quoted in the market, the leg will still be used for calculation of
|
||||
@@ -107,7 +127,7 @@
|
||||
If your Hedge Ratio is 3 on the NQ leg, then you’ll work the ES
|
||||
order based on where you could fill 6 (2 (Qty of NQ) \* 3 (Hedge
|
||||
Ratio)).
|
||||
- The next 6 parameters are all completely custom to a traders needs
|
||||
- The next 6 parameters are all completely custom to a trader's needs
|
||||
and can further define how a synthetic is worked. As previously
|
||||
mentioned, if you hover over any of these parameters a “?” will be
|
||||
displayed and click on such will display further details on how this
|
||||
@@ -118,7 +138,7 @@
|
||||
- Quote
|
||||
|
||||
- Throttle - This can be enabled or disabled based on if the box is
|
||||
checked per leg. It’s main function is to reduce re-quoting updates
|
||||
checked per leg. Its main function is to reduce re-quoting updates
|
||||
by defining a region on either side of the working quote order,
|
||||
inside which quote updates will not be sent:
|
||||
|
||||
@@ -148,8 +168,8 @@
|
||||
|
||||

|
||||
|
||||
- Time Based Cross - Basically the exact same as ticks away cross,
|
||||
however this is based on time (in ms) on when to automatically cross
|
||||
- Time Based Cross - Basically the same as Ticks Away Cross,
|
||||
however, this is based on time (in ms) on when to automatically cross
|
||||
(fill) the market if they get too far away from the opposite inside
|
||||
market. If a legged hedge order’s price gets X amount of “ticks”
|
||||
away from the opposite inside market, it is re-priced to cross the
|
||||
|
||||
+57
-50
@@ -9,7 +9,11 @@
|
||||
|
||||
##Order Book
|
||||
|
||||
- This provides list of all orders a user has placed, by default it
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/ygMFkjBBGeU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- This provides a list of all orders a user has placed, by default it
|
||||
will display only working orders
|
||||
- You can create multiple order books filtered however you would
|
||||
like
|
||||
@@ -44,39 +48,39 @@
|
||||
- Anytime
|
||||
- Today
|
||||
- Since Open
|
||||
- A specific user defined period of time
|
||||
- A specific user-defined period of time
|
||||
|
||||

|
||||
|
||||
- The left hand box within an order book provides users with further
|
||||
- The left-hand box within an order book provides users with further
|
||||
functionality to quickly perform various tasks with live orders as
|
||||
well as launch other modules. It’s appears like the below:
|
||||
well as launch other modules. It appears like the below:
|
||||
|
||||

|
||||
|
||||
- ][Fills -
|
||||
- Fills -
|
||||
clicking on this will launch a fills window
|
||||
- ][ Modify -
|
||||
-  Modify -
|
||||
clicking on this will launch an order ticket for a live order
|
||||
highlighted in the Order Book.
|
||||
- ][Cancel
|
||||
- Cancel
|
||||
selected - clicking on this will cancel the selected orders you have
|
||||
highlighted in the order book. You can choose more than one by
|
||||
holding hold the Ctrl key when click on each row of orders
|
||||
- ][Cancel
|
||||
holding hold the Ctrl key when clicking on each row of orders
|
||||
- Cancel
|
||||
buys - clicking on this will cancel all the buy orders you have in
|
||||
the order book
|
||||
- ][Cancel
|
||||
- Cancel
|
||||
sells - clicking on this will cancel all the sell orders you have in
|
||||
the order book
|
||||
- ][Cancel
|
||||
- Cancel
|
||||
all - clicking on this will cancel all working orders you have the
|
||||
order book
|
||||
|
||||
##Fills
|
||||
|
||||
- This provides list of all fills a user has had for a given time
|
||||
period, by default it will open up with “since open” time frame
|
||||
- This provides a list of all fills a user has had for a given time
|
||||
period, by default it will open up with “since open” timeframe
|
||||
selected showing you fills on the day thus far
|
||||
- You can create multiple fill windows, filtered however you
|
||||
like
|
||||
@@ -85,8 +89,12 @@
|
||||
|
||||
##P&L
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/xj6cEQ6By34" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- This provides a running ledger of a users account(s) profit and
|
||||
loss broken down per symbol
|
||||
loss, broken down per symbol
|
||||
- You can create multiple P&L windows, filtered however you would
|
||||
like
|
||||
- All P&L windows are brought up as tabs and can be combined with all
|
||||
@@ -101,6 +109,10 @@
|
||||
|
||||
##Ladder
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/Q0qsyc1nvYo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- The ladder was designed to be the most logically produced ladder on
|
||||
the market, engineered and designed by professional traders for
|
||||
professional traders
|
||||
@@ -112,8 +124,8 @@
|
||||
|
||||

|
||||
|
||||
- The ladder consist of 2 major parts, the Ladder itself and the
|
||||
information and control section on the left hand side
|
||||
- The ladder consists of 2 major parts, the Ladder itself and the
|
||||
information and control section on the left-hand side
|
||||
|
||||
- The information section on the left contains the following: 
|
||||
- Day - showing the current price of the security on the day
|
||||
@@ -126,17 +138,17 @@
|
||||
|
||||
|
||||
- The control section right underneath the information section on the
|
||||
left hand side offers the following:
|
||||
left-hand side offers the following:
|
||||
|
||||

|
||||
|
||||
- Account in which the orders will flow into when trading this
|
||||
- The account in which the orders will flow into when trading this
|
||||
security
|
||||
- Length of time the order will remain in market, either DAY or
|
||||
- Length of time the order will remain in the market, either DAY or
|
||||
GTC
|
||||
- Order type, by default orders will go in as Limit, however all of
|
||||
- Order type, by default, orders will go in as Limit, however all of
|
||||
the following are offered out of the box. The top 5 are all fairly
|
||||
standard order types, however the bottom 5 are all specialized
|
||||
standard order types, however, the bottom 5 are all specialized
|
||||
algos. They are only offered by BTS and require specialized
|
||||
parameters. Please see below for each order type:
|
||||
|
||||
@@ -147,8 +159,8 @@
|
||||
|
||||
- Limit
|
||||
|
||||
- This is a buy or sell order designed to take place on the exact
|
||||
price level you have entered the order at.
|
||||
- This is a buy or sell order designed to take place on the
|
||||
price level where you entered the order.
|
||||
|
||||
- Stop
|
||||
|
||||
@@ -168,10 +180,10 @@
|
||||
- Iceberg
|
||||
|
||||
- This is a buy or sell order where the order is divided into a
|
||||
visible or “show” portion which is seen at the exchange. ][The
|
||||
visible or “show” portion which is seen at the exchange. The
|
||||
rest of the order is hidden and will remain hidden until the show
|
||||
quantity is filled, essentially reloading the order back to the show
|
||||
quantity. You will need to ][define what type of order that will
|
||||
quantity. You will need to define what type of order that will
|
||||
be used for the child order to be sent.
|
||||
|
||||

|
||||
@@ -198,7 +210,7 @@
|
||||
|
||||

|
||||
|
||||
- Tick
|
||||
- Lean
|
||||
|
||||
- This is a specialized algo order which allows the user to
|
||||
essentially watch the opposite-inside market size and cross when
|
||||
@@ -207,16 +219,9 @@
|
||||
buying into the asks. This is often referred to as “paying up” as
|
||||
well
|
||||
|
||||

|
||||

|
||||
|
||||
- Lean
|
||||
|
||||
- This is a specialized algo order which allows the user to enter an
|
||||
order which will watch the opposite-inside market size and cross
|
||||
when that size goes below the threshold defined in the
|
||||
parameters
|
||||
|
||||

|
||||
|
||||
- Join
|
||||
|
||||
@@ -225,8 +230,7 @@
|
||||
market flips and has at least threshold size as defined.
|
||||
- “Flip” refers to the event where the best offer becomes the best
|
||||
bid or the market trades away from you, i.e. the line moves up in
|
||||
the GUI. This is all true in the reverse way as well if
|
||||
selling.
|
||||
the GUI. The reverse is true if selling.
|
||||
|
||||

|
||||
|
||||
@@ -248,7 +252,7 @@
|
||||
|
||||
- You can manually type in a quantity here as well
|
||||
- Furthermore, if you have a value in the volume bar, you can
|
||||
increase this size by right clicking and the value will increase
|
||||
increase this size by right-clicking and the value will increase
|
||||
incrementally by 1. The same is true if you would like to decrease
|
||||
this value by left click and the value will decrease.
|
||||
- By having the auto clear box checked, it will bring the value back
|
||||
@@ -259,12 +263,12 @@
|
||||
- The bottom section of the control area of a ladder has 4 aspects
|
||||
to it
|
||||
|
||||
- Cancel Buys - which will cancel all buys currently working on the
|
||||
- Cancel Buys, which will cancel all buys currently working on the
|
||||
ladder
|
||||
- Cancel Sells - which will cancel all sells currently working on the
|
||||
- Cancel Sells, which will cancel all sells currently working on the
|
||||
ladder
|
||||
- Cancel All - which will cancel all orders on the ladder
|
||||
- Settings - this will launch the ladder settings window which
|
||||
- Cancel All, which will cancel all orders on the ladder
|
||||
- Settings, which will launch the ladder settings window which
|
||||
appears like below
|
||||
|
||||

|
||||
@@ -276,27 +280,26 @@
|
||||
|
||||
- There are 5 main columns
|
||||
|
||||
- Orders - which display current orders working in the market
|
||||
- Bid - which displays the current bid volumes at each price
|
||||
- Orders, which display current orders working in the market
|
||||
- Bid, which displays the current bid volumes at each price
|
||||
level
|
||||
- Price - which displays the price levels of the symbol shown
|
||||
- Ask - which displays the current ask volumes at each price
|
||||
- Price, which displays the price levels of the symbol shown
|
||||
- Ask, which displays the current ask volumes at each price
|
||||
level
|
||||
- Last Trade - which displays where the price level and volume of
|
||||
- Last Trade, which displays the price level and volume
|
||||
where the last trade occurred
|
||||
|
||||
- Functionality of the ladder
|
||||
|
||||
- To enter an order directly by clicking in the ladder, left click on
|
||||
either the bid or ask volume with a volume greater than 0 on the
|
||||
predefined value box on the left hand section
|
||||
predefined value box on the left-hand section
|
||||
- A badge will be displayed within the orders column of the value you
|
||||
have chosen and the quantity filled as displayed below
|
||||
|
||||

|
||||
|
||||
- To change the price level you wish to work the order, you can right
|
||||
click and hold on the badge to move it up or down the ladder for the
|
||||
- To change the price level you wish to work the order, you can right-click and hold on the badge to move it up or down the ladder for the
|
||||
desired price
|
||||
- To cancel the order, left click on the badge
|
||||
- Furthermore, you can click down on the scroll wheel of your mouse
|
||||
@@ -305,6 +308,10 @@
|
||||
|
||||
## Order Ticket
|
||||
|
||||
<div>
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/bdC5pZ6T35I" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
- The order ticket was designed to provide another means other than
|
||||
the ladder to enter orders into the market
|
||||
- You can bring up an order ticket directly from the module launcher,
|
||||
@@ -314,7 +321,7 @@
|
||||
|
||||

|
||||
|
||||
- On the top left you have the price for the order as well as the
|
||||
- On the top left, you have the price for the order as well as the
|
||||
volume
|
||||
- Beneath are the predefined volumes as well as a clear button to
|
||||
clear out the volume
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
@@ -1,3 +1,3 @@
|
||||
|
||||
Click on the headings on the the left to expand their contents. If you need specific information quickly use the Search button in the top right of this page.
|
||||
Click on the headings on the left to expand their contents. If you need specific information quickly use the Search button in the top right of this page.
|
||||
|
||||
@@ -1,4 +1,54 @@
|
||||
# Release Notes
|
||||
## 1.4.2
|
||||
|
||||
### User Interface Improvements
|
||||
- When creating a synthetic from the Market View window, securities are now added to the Create Synthetic dialog in the same sort order as they appear in grid
|
||||
### Bug Fixes
|
||||
- Shell no longer crashes when removing a security from the synthetics window
|
||||
- It is now possible to create a new synthetic using the same name as a previously deleted synthetic
|
||||
### SDK Improvements
|
||||
- Improved Client and Server SDK clarity and documentation
|
||||
### Performance Improvements
|
||||
- Synthetic calculation speed was improved by 400%.
|
||||
### Risk / Entitlement System
|
||||
- Risk Admin UI
|
||||
- Spark users now have separate Trading, RiskAdmin, and/or MDAdmin permissions
|
||||
- Spark users can now only add other users or accounts if permissioned to do so.
|
||||
- Market Data Entitlement
|
||||
- Automated market data reporting
|
||||
|
||||
|
||||
## 1.4.1
|
||||
|
||||
### Tabs
|
||||
- Tabs now shrink and expand to make better use of horizontal space
|
||||
### Bug Fixes
|
||||
- Fixed a bug that could cause excessive CPU usage when a connection broke
|
||||
- Fixed a layout bug in hedging/requoting performance reports
|
||||
- Fixed account name mismatching bug for old fills
|
||||
### Absolute Position limits
|
||||
- Positions can now be netted or absolute for purposes of limit enforcing
|
||||
|
||||
## 1.4.0
|
||||
|
||||
### Speed Enhancements
|
||||
- Improved requoting and hedging performance
|
||||
- Improved order book form performance
|
||||
### Server Side SDK
|
||||
- Added a beta version of the server side SDK
|
||||
### Front End
|
||||
- Added status bars to all UI grids
|
||||
### Reporting
|
||||
- Added reporting of hedging and requoting performance
|
||||
|
||||
## 1.3.8
|
||||
|
||||
### Speed Enhancements
|
||||
- Further speed enhancements
|
||||
### Conditional (new quoting parameter)
|
||||
- Reduces re-quoting updates by only quoting if N ticks away from the opposite inside market.
|
||||
- Quotes are canceled when it gets further away.
|
||||
- "Price Type" dictates if this logic applies to the quoting market or to the synthetic spread market.
|
||||
|
||||
## 1.3.7
|
||||
|
||||
@@ -21,7 +71,7 @@
|
||||
### Synthetic creation option to choose Merged or Direct
|
||||
- The ability to choose Merged or Direct per leg when creating a synthetic
|
||||
### Volume at price
|
||||
- Within a ladder you can now see a volume at price graph
|
||||
- Within a ladder, you can now see a volume at price graph
|
||||
- This is configurable from a ladder's settings as well
|
||||
### Customized settings in all windows
|
||||
- All windows now contain a settings page where grid settings (font color, size, etc) are applied
|
||||
@@ -39,7 +89,7 @@
|
||||
|
||||
### Order Book
|
||||
- Many visual facets of the Order Book grid can now be customized
|
||||
- The Order Book settings page can be access from the gears icon in the Order Book toolbar or from the right-click menu
|
||||
- The Order Book settings page can be accessed from the gears icon in the Order Book toolbar or from the right-click menu
|
||||
- The Expand/Collapse All button has been separated into two different buttons on the toolbar
|
||||
|
||||
### Sound Alerts
|
||||
@@ -75,13 +125,13 @@
|
||||
### Synthetics
|
||||
- Hedge Ratio parameter has been renamed to Lean Qty Factor
|
||||
- Spreader now includes a Hidden mode parameter
|
||||
- A quoting leg can be hidden, ie an order will not sent out until the market crosses the computed quoting price. When that happens, the quote is sent out as an IOC order.
|
||||
- A quoting leg can be hidden, ie an order will not be sent out until the market crosses the computed quoting price. When that happens, the quote is sent out as an IOC order.
|
||||
|
||||
### Algos
|
||||
- Trigger orders now can contain a Trigger Exit parameter based on time or price; once the exit condition has been met the Trigger order will cancel
|
||||
- IOC/FAK order type added
|
||||
- Cover order type added
|
||||
- Cancelling a synthetic order no longer cancels any working hedge orders
|
||||
- Canceling a synthetic order no longer cancels any working hedge orders
|
||||
|
||||
### General
|
||||
- A manual page has been added to the launcher Help menu
|
||||
@@ -89,18 +139,18 @@
|
||||
- Various cash per point values updated
|
||||
- Time-based grid filters now have tick up/down buttons
|
||||
- Numerous performance improvements and stability enhancements
|
||||
- Automated position and orderbook maintenance during daily recycle
|
||||
- Individual fills be compacted into start of day position records
|
||||
- Automated position and Order Book maintenance during daily recycle
|
||||
- Individual fills will be compacted into the Start of Day position records
|
||||
- Orders from the day before the recycle will be deleted
|
||||
|
||||
|
||||
##1.1
|
||||
|
||||
###1.1.22
|
||||
- Orderbook: Orders in Error status can now be recreated
|
||||
- Orderbook: Orders containing child orders will now be collapsed by default.
|
||||
- Orderbook: Expand / Collapse All button added to the right-click menu and window action pane, denoted by ▲ icon
|
||||
- Orderbook: Symbol column added to allow for filtering based on group symbol
|
||||
- Order Book: Orders in Error status can now be recreated
|
||||
- Order Book: Orders containing child orders will now be collapsed by default.
|
||||
- Order Book: Expand / Collapse All button added to the right-click menu and window action pane, denoted by ▲ icon
|
||||
- Order Book: Symbol column added to allow for filtering based on group symbol
|
||||
- Time filters now have a quick Set Last Hour hyperlink which will set the Period Begin filter to (Now - 1 hour)
|
||||
|
||||
###1.1.20
|
||||
@@ -119,15 +169,15 @@
|
||||
- Fixed occasional crash when filtering fills
|
||||
- Fixed several cash per point multipliers
|
||||
- Colored time of sales row with aggressor side
|
||||
- Iceberg orders now cancel (rathern than error) when a child is canceled
|
||||
- Iceberg orders now cancel (rather than an error) when a child is canceled
|
||||
|
||||
###1.1.0
|
||||
- Added per user self match protection, location and self match protection FIX tag settings
|
||||
- Implemented a new "Trigger Order" algo
|
||||
- Corrected tick formatting for a number of products
|
||||
- Added the hability to recreate canceled orders
|
||||
- Added leg fills to facilitate futured based PnL
|
||||
- PnL report now has PnL columns calculated based on your start of day, current day, and total position
|
||||
- Added the ability to recreate canceled orders
|
||||
- Added leg fills to facilitate futures based PnL
|
||||
- PnL report now has PnL columns calculated based on your Start of Day, current day, and total position
|
||||
- Start, Day and Total PnL columns are painted with a red or green background color based on if the pnl value is negative or positive respectively
|
||||
- Corrected cash per point values, used in pnl calculations, for a number of products
|
||||
- PnL report will now remember any customizations you make to filtering and/or sorting criteria
|
||||
- PnL report will now remember any customizations you make to filtering and/or sorting criteria
|
||||
+1
-1
Submodule docker/linux updated: aedfd79e02...8ee9692597.
@@ -1,3 +1,10 @@
|
||||
1.4.2
|
||||
- Be sure the system has a bts user before deployment. bts is the superuser, he has all permissions and can see all market data
|
||||
- After deployment re-permission all existing users for trading, riskadmin, and/or md admin permissions as appropriate
|
||||
- Also note which users can add other users and accounts and permission them appropriately (Can Add?)
|
||||
- Permission users for appropriate market data entitlements; this has monetary consequences so ask Kevin if you aren't sure.
|
||||
- MIC reporting needs to be added to audit Jenkins job (https://bluetradesys.atlassian.net/browse/SPARK-1900)
|
||||
|
||||
1.3.5
|
||||
- Change in market data wire format. Old shell will get only direct market data instead of merged which may not match what the servers is driving from.
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ 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
|
||||
@@ -219,6 +221,26 @@ 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,5 +1,6 @@
|
||||
using bts;
|
||||
using bts.api.admin;
|
||||
using bts.api.core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
@@ -36,7 +37,7 @@ namespace mbts.spark {
|
||||
IEnumerable<BTSAccountImmutable> active_accounts =
|
||||
from admin_data in update.all
|
||||
from bts_account in admin_data.Accounts
|
||||
where bts_account.IsPresent
|
||||
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
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace bts {
|
||||
.Subscribe(t => {
|
||||
var deleted_synthetic_keys = new HashSet<uint>(t.Where(kv => kv.Value.Deleted).Select(kv => kv.Key));
|
||||
// add back 'undeleted' synthetics
|
||||
foreach (var kvp in _deleted_synthetics) {
|
||||
foreach (var kvp in _deleted_synthetics.ToList()) {
|
||||
if (!deleted_synthetic_keys.Contains(kvp.Key)) {
|
||||
_exchange_sec_map.TryAdd(kvp.Key, kvp.Value);
|
||||
_deleted_synthetics.Remove(kvp.Key);
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace bts.perf {
|
||||
if (response.Status == IPStatus.Success) {
|
||||
_current_missed_ping_count = 0;
|
||||
if (response.RoundtripTime > config.logging_milliseconds_threshold) {
|
||||
Log.Ui.warn($"Ping response not recieved in a timely manner:\n" +
|
||||
Log.Ui.warn($"Ping response not received in a timely manner:\n" +
|
||||
$"\tAddress:\t{response.Address}\n" +
|
||||
$"\tRoundTrip:\t{response.RoundtripTime} ms");
|
||||
}
|
||||
|
||||
@@ -48,14 +48,12 @@
|
||||
</c:DIYGrid>
|
||||
<StatusBar Grid.Row="1" DockPanel.Dock="Bottom">
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="Securities: "/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding ElementName=_grid, Path=Rows.Count}"/>
|
||||
</Grid>
|
||||
<TextBlock>
|
||||
<Run Text="Securities:"/>
|
||||
<Run Text="{Binding ElementName=_grid, Path=Rows.Count, Mode=OneWay}" />
|
||||
<Run Text="of"/>
|
||||
<Run Text="{Binding rows_view.SourceCollection.Count, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
|
||||
@@ -58,14 +58,14 @@ namespace mbts.spark {
|
||||
var update_securities_cmd = SparkCommands.change_securities_callback(_window_type_display_name);
|
||||
_commands = new List<SparkCommand> {
|
||||
SparkCommands.ShowLadders.complete(_vm.selected_security_mds_observable(), smds => smds.Count > 0),
|
||||
SparkCommands.ShowOrderTicketFromSecurity.complete(_vm.current_security_md, md => md.HasValue, ObjectHelper.ValueOrDefault),
|
||||
SparkCommands.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.selected_securities_observable(), secs => secs.Count > 0 && secs.Count <= 24, secs => new SecurityCriteria(secs)),
|
||||
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(() => {
|
||||
|
||||
@@ -49,13 +49,7 @@
|
||||
</c:DIYGrid>
|
||||
<StatusBar Grid.Row="1" DockPanel.Dock="Bottom">
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text=" "/>
|
||||
</Grid>
|
||||
<TextBlock Text=" "/>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
|
||||
@@ -62,8 +62,8 @@ namespace mbts.spark {
|
||||
var current_smd_source = connectable_builder.create(vm => vm.current_security_md_observable(_bus)).OnDispatcher();
|
||||
var selected_secs_source = connectable_builder.create(vm => vm.selected_securities_observable()).OnDispatcher();
|
||||
_commands = new SparkCommand[] {
|
||||
SparkCommands.ShowLadder.complete(current_smd_source, md => md.HasValue, ObjectHelper.ValueOrDefault),
|
||||
SparkCommands.ShowOrderTicketFromSecurity.complete(current_smd_source, md => md.HasValue, ObjectHelper.ValueOrDefault),
|
||||
SparkCommands.ShowLadder.complete(current_smd_source, md => md.HasValue, ConvertUtils.ValueOrDefault),
|
||||
SparkCommands.ShowOrderTicketFromSecurity.complete(current_smd_source, md => md.HasValue, ConvertUtils.ValueOrDefault),
|
||||
SparkCommands.ShowFills.complete(selected_secs_source, always_true, get_fills_startup_data),
|
||||
SparkCommands.ShowMarketView.complete(selected_secs_source, always_true, secs => secs.Count > 0 ? new SecurityCriteria(secs) : _state.security_criteria),
|
||||
SparkCommands.change_securities_command(() => (update_securities_cmd, _state.security_criteria)),
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
UIntTemplate="{StaticResource SimpleValueTextTemplate}"
|
||||
MarketDataTypeTemplate="{StaticResource SimpleValueTextTemplate}"
|
||||
MarketDataCalculationTemplate="{StaticResource SimpleValueTextTemplate}"
|
||||
ConditionalPriceTypeTemplate="{StaticResource SimpleValueTextTemplate}"
|
||||
>
|
||||
<usp:DataGridParameterCellTemplateConverter.BooleanTemplate>
|
||||
<DataTemplate>
|
||||
@@ -122,6 +123,11 @@
|
||||
<ComboBox SelectedItem="{Binding value}" ItemsSource="{u:EnumBindingSource {u:Nested sp:LegSpreaderParams.Types.LegMarketDataCalculation}}" ItemTemplate="{StaticResource EnumDescriptionTemplate}"/>
|
||||
</DataTemplate>
|
||||
</usp:DataGridParameterCellTemplateConverter.MarketDataCalculationTemplate>
|
||||
<usp:DataGridParameterCellTemplateConverter.ConditionalPriceTypeTemplate>
|
||||
<DataTemplate>
|
||||
<ComboBox SelectedItem="{Binding value}" ItemsSource="{u:EnumBindingSource {u:Nested sp:ConditionalQuoting.Types.PriceType}}" ItemTemplate="{StaticResource EnumDescriptionTemplate}"/>
|
||||
</DataTemplate>
|
||||
</usp:DataGridParameterCellTemplateConverter.ConditionalPriceTypeTemplate>
|
||||
<usp:DataGridParameterCellTemplateConverter.QuantityMeasureTemplate>
|
||||
<DataTemplate>
|
||||
<Grid IsEnabled="{Binding enabled}">
|
||||
|
||||
@@ -304,6 +304,7 @@ namespace mbts.ui.spark {
|
||||
public DataTemplate QuantityMeasureTemplate { get; set; }
|
||||
public DataTemplate MarketDataTypeTemplate { get; set; }
|
||||
public DataTemplate MarketDataCalculationTemplate { get; set; }
|
||||
public DataTemplate ConditionalPriceTypeTemplate { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
Type t = (Type)value;
|
||||
@@ -314,6 +315,7 @@ namespace mbts.ui.spark {
|
||||
else if (t == typeof(QuantityMeasure)) return QuantityMeasureTemplate;
|
||||
else if (t == typeof(LegSpreaderParams.Types.MarketDataType)) return MarketDataTypeTemplate;
|
||||
else if (t == typeof(LegSpreaderParams.Types.LegMarketDataCalculation)) return MarketDataCalculationTemplate;
|
||||
else if (t == typeof(ConditionalQuoting.Types.PriceType)) return ConditionalPriceTypeTemplate;
|
||||
else return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using mbts.ui;
|
||||
using mbts.ui.spark;
|
||||
using mbts.ui.utility;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
@@ -43,8 +44,23 @@ namespace bts.shell {
|
||||
name + "(1)";
|
||||
}
|
||||
|
||||
async void _show_synthetic_create(SecurityCriteria security_criteria) =>
|
||||
_show_synthetic_create((await security_criteria.securities(_bus)).ToList());
|
||||
async void _show_synthetic_create(SecurityCriteria security_criteria) {
|
||||
var found_securities = await security_criteria.securities(_bus);
|
||||
var respect_clause_security_ordering_is_possible = security_criteria.clauses.Any(clause => clause.security_keys != null && clause.security_keys.Count > 0);
|
||||
if (!respect_clause_security_ordering_is_possible) {
|
||||
_show_synthetic_create(found_securities.Values.ToList());
|
||||
} else {
|
||||
List<SecurityImmutable> ordered_security_list = new List<SecurityImmutable>();
|
||||
foreach (var clause in security_criteria.clauses) {
|
||||
foreach (var sec_key in clause.security_keys) {
|
||||
if (found_securities.TryGetValue(sec_key, out SecurityImmutable found_result)) {
|
||||
ordered_security_list.Add(found_result);
|
||||
}
|
||||
}
|
||||
_show_synthetic_create(ordered_security_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _show_synthetic_create(IReadOnlyCollection<SecurityImmutable> securities) {
|
||||
if (securities.Count == 1) {
|
||||
|
||||
@@ -103,6 +103,11 @@ namespace bts.shell {
|
||||
OutsideTicks = 3,
|
||||
Priority = RulePriority
|
||||
};
|
||||
public static ConditionalQuoting ConditionalQuoting => new ConditionalQuoting
|
||||
{
|
||||
NTicks = 2,
|
||||
PriceType = ConditionalQuoting.Types.PriceType.Leg
|
||||
};
|
||||
public static QuoteInsideMarketDistanceWithTravel QuoteInsideMarketDistanceWithTravel => new QuoteInsideMarketDistanceWithTravel { Priority = RulePriority };
|
||||
public static QuoteInsideMarketDistance QuoteInsideMarketDistance => new QuoteInsideMarketDistance { Priority = RulePriority };
|
||||
#endregion
|
||||
|
||||
@@ -46,14 +46,12 @@
|
||||
</c:DIYGrid>
|
||||
<StatusBar Grid.Row="1" DockPanel.Dock="Bottom">
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="Synthetics: "/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding ElementName=_grid, Path=Rows.Count}"/>
|
||||
</Grid>
|
||||
<TextBlock>
|
||||
<Run Text="Synthetics:"/>
|
||||
<Run Text="{Binding ElementName=_grid, Path=Rows.Count, Mode=OneWay}" />
|
||||
<Run Text="of"/>
|
||||
<Run Text="{Binding rows_view.SourceCollection.Count, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace mbts.spark {
|
||||
current_row_connectable_builder.create(observe_row_strategy),
|
||||
rs => rs.HasValue, select_row_strategy_tuple
|
||||
), SparkCommands.ShowLadder.complete(
|
||||
vm_connectable_builder.create(vm => vm.current_security_md), md => md.HasValue, ObjectHelper.ValueOrDefault
|
||||
vm_connectable_builder.create(vm => vm.current_security_md), md => md.HasValue, ConvertUtils.ValueOrDefault
|
||||
), SparkCommands.ShowOrders.complete(() => new OrderBookWindowFactory.OrderBookStartupData {
|
||||
filters = new OrderBookWindowFactory.FilterStates {
|
||||
security_criteria = new SecurityCriteria(_vm.value.row_vms.Select(r => r.security))
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using mbts.ui.spark;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class SyntheticEditorVM {
|
||||
class EnableHedgeModel : RowModelBase<bool> {
|
||||
public override string display_name { get; } = "Enable Hedging";
|
||||
public override string help_text { get; } = "Send a hedge for this leg?";
|
||||
public override string man_page { get; } = string.Empty;
|
||||
|
||||
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.EnableHedging;
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) =>
|
||||
leg_tup.leg_params.EnableHedging = value;
|
||||
|
||||
public override bool has_errors(IReadOnlyCollection<LegSpreaderParamsTuple> leg_tups) =>
|
||||
!leg_tups.Any(lt => lt.leg_params.EnableHedging);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using mbts.ui.spark;
|
||||
using System;
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class SyntheticEditorVM {
|
||||
class MinLeanQtyModel : RowModelBase<System.UInt32> {
|
||||
public override string display_name { get; } = "Min Lean Qty";
|
||||
public override string help_text { get; } = "Minimum Quantity required at this leg to quote";
|
||||
public override string man_page { get; } = string.Empty;
|
||||
|
||||
public override System.UInt32 get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.QuoteParams.MinLeanQty;
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, System.UInt32 value) =>
|
||||
leg_tup.leg_params.QuoteParams.MinLeanQty = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
using bts.shell;
|
||||
using mbts.ui.spark;
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class SyntheticEditorVM {
|
||||
class ConditionalQuoteEnabledModel : RowModelBase<bool> {
|
||||
readonly ConditionalQuotingTicksModel _ticks;
|
||||
readonly ConditionalQuotingPriceTypeModel _price_type;
|
||||
|
||||
public ConditionalQuoteEnabledModel(ConditionalQuotingTicksModel ticks, ConditionalQuotingPriceTypeModel price_type)
|
||||
{
|
||||
_ticks = ticks;
|
||||
_price_type = price_type;
|
||||
}
|
||||
|
||||
public override string display_name { get; } = string.Empty;
|
||||
public override string help_text { get; } = string.Empty;
|
||||
public override string man_page { get; } = string.Empty;
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.Conditional };
|
||||
|
||||
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.QuoteParams.ConditionalQuoting != null;
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
|
||||
if (value) {
|
||||
if (leg_tup.leg_params.QuoteParams.ConditionalQuoting == null) {
|
||||
leg_tup.leg_params.QuoteParams.ConditionalQuoting = SyntheticDataHelper.Defaults.ConditionalQuoting;
|
||||
_ticks.apply_value(leg_tup);
|
||||
_price_type.apply_value(leg_tup);
|
||||
}
|
||||
} else {
|
||||
leg_tup.leg_params.QuoteParams.ConditionalQuoting = null;
|
||||
}
|
||||
_ticks.set_enabled(leg_tup, value);
|
||||
_price_type.set_enabled(leg_tup, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using mbts.ui.spark;
|
||||
using bts.spark;
|
||||
using PriceType = bts.spark.ConditionalQuoting.Types.PriceType;
|
||||
using mbts.collections.extensions;
|
||||
using System.Collections.Generic;
|
||||
using bts.shell;
|
||||
|
||||
namespace mbts.spark
|
||||
{
|
||||
partial class SyntheticEditorVM
|
||||
{
|
||||
class ConditionalQuotingPriceTypeModel : RowModelBase<PriceType>
|
||||
{
|
||||
IDictionary<uint, PriceType> _value_store = new Dictionary<uint, PriceType>();
|
||||
|
||||
public override string display_name { get; } = "Price Type";
|
||||
public override string help_text { get; } = string.Empty;
|
||||
public override string man_page { get; } = string.Empty;
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.Conditional };
|
||||
|
||||
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_value(leg_tup).PriceType = _value_from_store(leg_tup);
|
||||
|
||||
public override PriceType get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_value(leg_tup) is ConditionalQuoting cond ?
|
||||
cond.PriceType :
|
||||
_value_from_store(leg_tup);
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, PriceType value)
|
||||
{
|
||||
_value_store[leg_tup.SecurityKey] = value;
|
||||
if (_get_value(leg_tup) is ConditionalQuoting cond)
|
||||
cond.PriceType = value;
|
||||
}
|
||||
|
||||
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) => _get_value(leg_tup) != null; //TAHA_SPREADER
|
||||
|
||||
ConditionalQuoting _get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.QuoteParams.ConditionalQuoting;
|
||||
|
||||
PriceType _value_from_store(LegSpreaderParamsTuple leg_tup) =>
|
||||
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.ConditionalQuoting.PriceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
using bts.shell;
|
||||
using bts.spark;
|
||||
using mbts.collections.extensions;
|
||||
using mbts.ui.spark;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class SyntheticEditorVM {
|
||||
class ConditionalQuotingTicksModel : RowModelBase<int> {
|
||||
IDictionary<uint, int> _value_store = new Dictionary<uint, int>();
|
||||
|
||||
public override string display_name { get; } = "Ticks";
|
||||
public override string help_text { get; } = string.Empty;
|
||||
public override string man_page { get; } = string.Empty;
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote, Subsections.Conditional };
|
||||
|
||||
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_value(leg_tup).NTicks = _value_from_store(leg_tup);
|
||||
|
||||
public override int get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_value(leg_tup) is ConditionalQuoting cond ?
|
||||
cond.NTicks :
|
||||
_value_from_store(leg_tup);
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, int value) {
|
||||
_value_store[leg_tup.SecurityKey] = value;
|
||||
if (_get_value(leg_tup) is ConditionalQuoting cond)
|
||||
cond.NTicks = value;
|
||||
}
|
||||
|
||||
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_value(leg_tup) != null;
|
||||
|
||||
ConditionalQuoting _get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.QuoteParams.ConditionalQuoting;
|
||||
|
||||
int _value_from_store(LegSpreaderParamsTuple leg_tup) =>
|
||||
_value_store.GetValueOrDefault(leg_tup.SecurityKey, _ => SyntheticDataHelper.Defaults.ConditionalQuoting.NTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,13 @@ namespace mbts.spark {
|
||||
"Reduces re-quoting updates by defining a region on either side " +
|
||||
"of the working quoting order, inside which quote updates will not be sent.");
|
||||
|
||||
public static ParameterSection Conditional =>
|
||||
new ParameterSection("Conditional", true,
|
||||
"Reduces re-quoting updates by only quoting if N ticks away from the opposite " +
|
||||
"inside market. Quotes are cancelled when it gets further away. 'Price Type' " +
|
||||
"dictates if this logic applies to the quoting market or to the synthetic spread " +
|
||||
"market");
|
||||
|
||||
public static ParameterSection InsideMarketThrottleThresholds =>
|
||||
new ParameterSection("Inside Market Throttle Thresholds", true,
|
||||
"Reduces re-quoting for quotes that are moving toward the inside market. " +
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using bts.shell;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.spark;
|
||||
@@ -110,7 +109,7 @@ namespace mbts.spark {
|
||||
_validate_leg_count();
|
||||
};
|
||||
|
||||
async Task commit_async(){
|
||||
async Task commit_async() {
|
||||
RequestUpdate?.Invoke();
|
||||
bool valid = true;
|
||||
if (string.IsNullOrWhiteSpace(name)) {
|
||||
@@ -125,8 +124,7 @@ namespace mbts.spark {
|
||||
valid = false;
|
||||
}
|
||||
if (valid) {
|
||||
_synthetic.Synthetic.Legs.Clear();
|
||||
_synthetic.Synthetic.Legs.AddRange(leg_tuples.Select(l => l.leg).OrderBy(l => l.Security, SecurityHelper.Comparer.Instance));
|
||||
_synthetic.Synthetic.Legs.SetItems(leg_tuples.Select(l => l.leg));
|
||||
_synthetic.Symbol = _deduce_symbol(_synthetic);
|
||||
double tick_frac = _tick_factors.tick_unit / _tick_factors.tick_base;
|
||||
_synthetic.ContractSpec.LowTick = tick_frac;
|
||||
@@ -180,6 +178,9 @@ namespace mbts.spark {
|
||||
var quote_throttle_outside_ticks = new QuoteThrottleOutsideTicksModel();
|
||||
var quote_throttle_inside_ticks = new QuoteThrottleInsideTicksModel();
|
||||
|
||||
var conditional_quoting_ticks = new ConditionalQuotingTicksModel();
|
||||
var conditional_quoting_price_type = new ConditionalQuotingPriceTypeModel();
|
||||
|
||||
var quote_inside_market_throttle_ticks = new QuoteInsideMarketThrottleTicksModel();
|
||||
var quote_inside_market_throttle_min_move = new QuoteInsideMarketThrottleMinMoveModel();
|
||||
|
||||
@@ -201,13 +202,18 @@ namespace mbts.spark {
|
||||
_quantity_model,
|
||||
_price_mult_model,
|
||||
new IsQuoteModel(),
|
||||
//new EnableHedgeModel(), //TAHA_SPREADER
|
||||
new HedgeRatioModel(),
|
||||
//new MinLeanQtyModel(), //TAHA_SPREADER
|
||||
new QuoteHiddenModel(),
|
||||
new MarketDataTypeModel(),
|
||||
new MarketDataCalculationModel(),
|
||||
new QuoteThrottleEnabledModel(quote_throttle_inside_ticks, quote_throttle_outside_ticks),
|
||||
quote_throttle_inside_ticks,
|
||||
quote_throttle_outside_ticks,
|
||||
new ConditionalQuoteEnabledModel(conditional_quoting_ticks, conditional_quoting_price_type),
|
||||
conditional_quoting_ticks,
|
||||
conditional_quoting_price_type,
|
||||
//new QuoteInsideMarketThrottleEnabledModel(quote_inside_market_throttle_ticks, quote_inside_market_throttle_min_move),
|
||||
//quote_inside_market_throttle_ticks,
|
||||
//quote_inside_market_throttle_min_move,
|
||||
@@ -296,7 +302,6 @@ namespace mbts.spark {
|
||||
|
||||
static IEnumerable<LegSpreaderParamsTuple> _get_legs(Security synthetic, ExecutionStrategyImmutable strategy) =>
|
||||
synthetic.Synthetic.Legs
|
||||
.OrderBy(l => l.Security, SecurityHelper.Comparer.Instance)
|
||||
.Select(l => new LegSpreaderParamsTuple(l, strategy.LegParamsMap[l.Security.Id].Clone()));
|
||||
|
||||
void _close_new_leg_popup() {
|
||||
@@ -339,4 +344,4 @@ namespace mbts.spark {
|
||||
else clear_error(nameof(leg_count));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,14 +49,12 @@
|
||||
</c:DIYGrid>
|
||||
<StatusBar Grid.Row="1" DockPanel.Dock="Bottom">
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="Fills: "/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding ElementName=_grid, Path=Rows.Count}"/>
|
||||
</Grid>
|
||||
<TextBlock>
|
||||
<Run Text="Fills:"/>
|
||||
<Run Text="{Binding ElementName=_grid, Path=Rows.Count, Mode=OneWay}" />
|
||||
<Run Text="of"/>
|
||||
<Run Text="{Binding rows_view.SourceCollection.Count, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
|
||||
@@ -423,7 +423,8 @@ namespace mbts.spark {
|
||||
base.InsertItem(index, item);
|
||||
} catch {
|
||||
_unhook(col);
|
||||
} finally { }
|
||||
throw;
|
||||
}
|
||||
} else {
|
||||
Log.Ui.warn($"{nameof(OrderBookColumnCollection)} added a column that is not of type {nameof(ICVOrderBookColumn)}");
|
||||
base.InsertItem(index, item);
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace mbts.spark {
|
||||
if (old_order.order_type() != order.order_type())
|
||||
RaisePropertyChanged(nameof(order_type), nameof(order_metadata));
|
||||
if (!had_security && _security_md.HasValue) {
|
||||
RaisePropertyChanged(nameof(security));
|
||||
RaisePropertyChanged(nameof(security), nameof(security_text));
|
||||
// need to raise invalidated to refresh the price cells (the security.ContractSpec determines how they are formatted - Ticks!)
|
||||
invalidate = true;
|
||||
}
|
||||
|
||||
@@ -155,18 +155,12 @@
|
||||
</c:DIYGrid>
|
||||
<StatusBar Grid.Row="1" DockPanel.Dock="Bottom">
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="Orders: "/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding ElementName=_grid, Path=Rows.Count}"/>
|
||||
<TextBlock Grid.Column="2" Text=" of "/>
|
||||
<TextBlock Grid.Column="3" Text="{Binding rows_view.SourceCollection.Count}"/>
|
||||
</Grid>
|
||||
<TextBlock>
|
||||
<Run Text="Orders:"/>
|
||||
<Run Text="{Binding rows.Count, Mode=OneWay}" />
|
||||
<Run Text="of"/>
|
||||
<Run Text="{Binding rows.total_row_count, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace mbts.spark {
|
||||
// data cache
|
||||
readonly Dictionary<uint, OrderRecordTuple> _state = new Dictionary<uint, OrderRecordTuple>();
|
||||
readonly SetMap<uint, uint> _security_orders = new SetMap<uint, uint>();
|
||||
readonly IDictionary<uint, SecurityMD> _security_md_cache = new Dictionary<uint, SecurityMD>(0);
|
||||
IReadOnlyDictionary<uint, OrderRecordImmutable> _orders_cache = new Dictionary<uint, OrderRecordImmutable>(0);
|
||||
IReadOnlyDictionary<uint, SecurityMD> _security_md_cache = new Dictionary<uint, SecurityMD>(0);
|
||||
IDisposable _dispose;
|
||||
|
||||
public OrderRecordTupleSource(IObservable<IReadOnlyDictionary<uint, SecurityMD>> securities, IObservable<TableUpdate<OrderRecordImmutable, uint>> orders) =>
|
||||
@@ -92,11 +92,14 @@ namespace mbts.spark {
|
||||
Dictionary<uint, OrderRecordTuple> added = new Dictionary<uint, OrderRecordTuple>(), removed = new Dictionary<uint, OrderRecordTuple>();
|
||||
Dictionary<uint, SecurityMD> added_securities = new Dictionary<uint, SecurityMD>(), removed_securities = new Dictionary<uint, SecurityMD>();
|
||||
_security_md_cache.Keys.difference(securities.Keys, out IEnumerable<uint> added_keys, out IEnumerable<uint> removed_keys);
|
||||
foreach (var k in removed_keys) {
|
||||
/// Warning: <see cref="_security_md_cache"/> must NOT be reassigned with <see cref="securities"/>; the latter is always the same object.
|
||||
/// This would mean that the <see cref="GlobalExtensions.difference{T}(IEnumerable{T}, IEnumerable{T}, out IEnumerable{T}, out IEnumerable{T})"/>
|
||||
/// call above would literally be calculating the difference between the keys of the same dictionary!
|
||||
foreach (var k in removed_keys.ToList()) {
|
||||
if (_security_orders.try_lookup(k, out ISet<uint> order_keys)) {
|
||||
removed_securities.Add(k, _security_md_cache[k]);
|
||||
IEnumerable<OrderRecordImmutable> orders = order_keys.Select(fk => _orders_cache[fk]);
|
||||
SecurityMD old_sec_md = _security_md_cache[k];
|
||||
removed_securities.Add(k, old_sec_md);
|
||||
IEnumerable<OrderRecordImmutable> orders = order_keys.Select(fk => _orders_cache[fk]);
|
||||
foreach (OrderRecordImmutable order in orders) {
|
||||
OrderRecordTuple old_ft = new OrderRecordTuple(order, old_sec_md);
|
||||
removed.Add(old_ft.order.Key, old_ft);
|
||||
@@ -104,12 +107,13 @@ namespace mbts.spark {
|
||||
added.Add(new_ft.order.Key, new_ft);
|
||||
}
|
||||
}
|
||||
_security_md_cache.Remove(k);
|
||||
}
|
||||
foreach (var k in added_keys) {
|
||||
foreach (var k in added_keys.ToList()) {
|
||||
SecurityMD new_sec_md = securities[k];
|
||||
if (_security_orders.try_lookup(k, out ISet<uint> order_keys)) {
|
||||
added_securities.Add(k, securities[k]);
|
||||
added_securities.Add(k, new_sec_md);
|
||||
IEnumerable<OrderRecordImmutable> orders = order_keys.Select(fk => _orders_cache[fk]);
|
||||
SecurityMD new_sec_md = securities[k];
|
||||
foreach (OrderRecordImmutable order in orders) {
|
||||
OrderRecordTuple old_ft = new OrderRecordTuple(order, null);
|
||||
removed.Add(old_ft.order.Key, old_ft);
|
||||
@@ -117,8 +121,8 @@ namespace mbts.spark {
|
||||
added.Add(new_ft.order.Key, new_ft);
|
||||
}
|
||||
}
|
||||
_security_md_cache.Add(k, new_sec_md);
|
||||
}
|
||||
_security_md_cache = securities;
|
||||
_apply_changes(added, removed, added_securities, removed_securities);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace mbts.spark
|
||||
cross_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
|
||||
new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1}, false);
|
||||
max_chase_ticks = new InlineUserProperty<uint>(2, false);
|
||||
trade_toward_behavior = new InlineUserProperty<LeanOrderDefinition.Types.OnToward>(LeanOrderDefinition.Types.OnToward.Cancel, false);
|
||||
trade_toward_behavior = new InlineUserProperty<LeanOrderDefinition.Types.OnToward>(LeanOrderDefinition.Types.OnToward.NoChange, false);
|
||||
}
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
@@ -47,7 +47,7 @@ namespace mbts.spark
|
||||
|
||||
public bts.spark.QuantityMeasure cross_threshold { get; set; } = new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1 };
|
||||
public uint max_chase_ticks { get; set; } = 2;
|
||||
public LeanOrderDefinition.Types.OnToward trade_toward_behavior { get; set; } = LeanOrderDefinition.Types.OnToward.Cancel;
|
||||
public LeanOrderDefinition.Types.OnToward trade_toward_behavior { get; set; } = LeanOrderDefinition.Types.OnToward.NoChange;
|
||||
|
||||
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace mbts.spark {
|
||||
_dynamic_helper = dynamic_helper;
|
||||
var scheduler = ThreadPoolScheduler.Instance;
|
||||
var interval = TimeSpan.FromMilliseconds(100);
|
||||
on_orders = _service.subscribei_orders().Naggle(interval, scheduler).PermissionFilter(admin_model).Table().Cache();
|
||||
on_positions = _position_service.subscribei_position_data().Naggle(interval, scheduler).PermissionFilter(admin_model).Table().Cache();
|
||||
on_orders = _service.subscribei_orders().Naggle(interval, scheduler).PermissionFilter(admin_model.on_admin_data).Table().Cache();
|
||||
on_positions = _position_service.subscribei_position_data().Naggle(interval, scheduler).PermissionFilter(admin_model.on_admin_data).Table().Cache();
|
||||
working_orders =
|
||||
on_orders.Scan(
|
||||
ImmutableDictionary<uint,OrderRecordImmutable>.Empty,
|
||||
@@ -55,7 +55,7 @@ namespace mbts.spark {
|
||||
on_order_tuples = order_record_tuple_source.subscribe_incremental_update();
|
||||
on_order_tuples_table = order_record_tuple_source.subscribe_incremental_table_update();
|
||||
on_order_securities = order_record_tuple_source.subscribe_order_securities();
|
||||
on_fills = _service.subscribei_fills().Naggle(interval, scheduler).PermissionFilter(admin_model).Table().Cache();
|
||||
on_fills = _service.subscribei_fills().Naggle(interval, scheduler).PermissionFilter(admin_model.on_admin_data).Table().Cache();
|
||||
_activity = new OrderActivitySummarizer(bus, on_orders);
|
||||
on_fill_tuples = FillTupleSource.create_observable(bus.subscribe(SparkTags.SecuritiesTag), on_orders, on_fills);
|
||||
_security_orders_demuxer = new TableUpdateDemuxer<OrderRecordImmutable, uint, uint>(o => o.Key, o => o.security_key());
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>x64</Platforms>
|
||||
<RuntimeIdentifiers>win7-x64</RuntimeIdentifiers>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<LanguageTargets>$(MSBuildExtensionsPath)\$(VisualStudioVersion)\Bin\Microsoft.CSharp.targets</LanguageTargets>
|
||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
@@ -82,9 +81,4 @@
|
||||
</ItemGroup>
|
||||
<Target Name="diagnostic" AfterTargets="PreBuildEvent">
|
||||
</Target>
|
||||
<Target Name="copy_defaults" AfterTargets="PostBuildEvent">
|
||||
<!-- this feels like the wrong place to copy defaults but it works alright -->
|
||||
<!-- <Message Importance="High" Text="copy defaults :: @(ConfigDefaults)" /> -->
|
||||
<Copy SourceFiles="@(ConfigDefaults)" DestinationFolder="$(OutputPath)\defaults\" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -42,7 +42,7 @@ namespace mbts.ui {
|
||||
public bool CanExecute(object parameter) {
|
||||
if (!allow_concurrent_executions && _n_executing > 0)
|
||||
return false;
|
||||
else return _can_execute(ObjectHelper.try_convert<T>(parameter));
|
||||
else return _can_execute(ConvertUtils.try_convert<T>(parameter));
|
||||
}
|
||||
|
||||
public async Task Execute(object parameter) {
|
||||
@@ -51,7 +51,7 @@ namespace mbts.ui {
|
||||
if (!allow_concurrent_executions)
|
||||
RaiseCanExecuteChanged();
|
||||
}
|
||||
await _execute(ObjectHelper.try_convert<T>(parameter));
|
||||
await _execute(ConvertUtils.try_convert<T>(parameter));
|
||||
if (--_n_executing == 0) {
|
||||
_raise_is_executing_changed();
|
||||
if (!allow_concurrent_executions)
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace mbts.ui
|
||||
if (_can_execute == null)
|
||||
return true;
|
||||
else
|
||||
return _can_execute(ObjectHelper.try_convert<T>(parameter));
|
||||
return _can_execute(ConvertUtils.try_convert<T>(parameter));
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public void Execute(object parameter) =>
|
||||
_execute(ObjectHelper.try_convert<T>(parameter));
|
||||
_execute(ConvertUtils.try_convert<T>(parameter));
|
||||
}
|
||||
|
||||
public class DelegateCommand : DelegateCommand<object> {
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace mbts.ui {
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public bool CanExecute(object parameter) => _can_execute;
|
||||
public void Execute(object parameter) => _execute(ObjectHelper.try_convert<T>(parameter));
|
||||
public void Execute(object parameter) => _execute(ConvertUtils.try_convert<T>(parameter));
|
||||
|
||||
public void OnCompleted() { }
|
||||
public void OnError(Exception error) { }
|
||||
|
||||
@@ -364,7 +364,7 @@ namespace System.Collections.Generic {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses <see cref="ObjectHelper.try_convert{TResult}(object)"/> to convert the elements of an <see cref="IEnumerable"/> to the specified type.
|
||||
/// Uses <see cref="ConvertUtils.try_convert{TResult}(object)"/> to convert the elements of an <see cref="IEnumerable"/> to the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">The type to convert the elements of source to.</typeparam>
|
||||
/// <param name="source">The <see cref="IEnumerable"/> that contains the elements to be cast to type <typeparamref name="TResult"/></param>
|
||||
@@ -373,7 +373,7 @@ namespace System.Collections.Generic {
|
||||
public static IEnumerable<TResult> convert<TResult>(this IEnumerable source) {
|
||||
ExceptionAssert.Argument.NotNull(source, nameof(source));
|
||||
foreach (object obj in source)
|
||||
yield return ObjectHelper.try_convert<TResult>(obj);
|
||||
yield return ConvertUtils.try_convert<TResult>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,12 +131,6 @@ namespace mbts
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int safe_compare<T>(this T a, T b, Func<T, T, int> compare) =>
|
||||
a == null ? (b == null ? 0 : -1) : (b == null ? 1 : compare(a, b));
|
||||
|
||||
public static int safe_compare<T>(this T a, T b) where T : IComparable<T> =>
|
||||
a == null ? (b == null ? 0 : -1) : (b == null ? 1 : a.CompareTo(b));
|
||||
|
||||
public static bool safe_equals<T>(this T a, T b, Func<T, T, bool> equals) =>
|
||||
a == null ? b == null : b != null && equals(a, b);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using bts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mbts.utils {
|
||||
|
||||
@@ -32,8 +32,11 @@ namespace mbts.utils {
|
||||
// need to lock bc simultaneous callbacks on diff threads could generate 2 subscriptions at once,
|
||||
// only 1 of which would get disposed in the next callback.
|
||||
Disposable.dispose(ref _current_key_sub);
|
||||
if (!_is_disposed)
|
||||
_current_key_sub = _selector(key)?.Subscribe(_value_subject);
|
||||
if (!_is_disposed) {
|
||||
// IMPORTANT: do NOT subscribe _value_subject directly to the inner sequences. Subscribe with a callback delegate instead (e.g. _value_subject.OnNext).
|
||||
// Reason: If a sequence 'completes' while _value_subject's subscription is active, it will enter a 'Terminated' state, and forever cease notifying observers of subsequent updates.
|
||||
_current_key_sub = _selector(key)?.Subscribe(_value_subject.OnNext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ namespace mbts.ui.controls {
|
||||
|
||||
class BadgeTextLinesConverter : IMultiValueConverter {
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
|
||||
if (ObjectHelper.try_convert_args(values, out Side side, out uint quantity, out uint filled, out mbts.spark.LadderSettings.BadgeStyle style))
|
||||
if (ConvertUtils.try_convert_args(values, out Side side, out uint quantity, out uint filled, out mbts.spark.LadderSettings.BadgeStyle style))
|
||||
return BadgeRender.format(side, quantity, filled, style);
|
||||
else return new string[0];
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace mbts.ui.controls.color_picker {
|
||||
public DataTemplate EditableTemplate { get; set; }
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
|
||||
if (ObjectHelper.try_convert_args(values, out ColorPaletteVM vm, out bool is_selected)) {
|
||||
if (ConvertUtils.try_convert_args(values, out ColorPaletteVM vm, out bool is_selected)) {
|
||||
if (vm.can_user_edit && is_selected)
|
||||
return EditableTemplate;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace mbts.ui.controls.color_picker {
|
||||
|
||||
class NamedColorItemToolTipConverter : IMultiValueConverter {
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) =>
|
||||
ObjectHelper.try_convert_args(values, out string name, out bool can_user_edit) ?
|
||||
ConvertUtils.try_convert_args(values, out string name, out bool can_user_edit) ?
|
||||
$"{name} (Alt + Click for info{(can_user_edit ? ", Ctrl + Click to assign" : string.Empty)})" :
|
||||
string.Empty;
|
||||
|
||||
|
||||
@@ -109,6 +109,6 @@ namespace mbts.spark.filters {
|
||||
protected virtual void _validate() { }
|
||||
|
||||
bool IDataGridColumnFilter.filter(object row) =>
|
||||
filter(ObjectHelper.try_convert<TRow>(row));
|
||||
filter(ConvertUtils.try_convert<TRow>(row));
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,6 @@ namespace mbts.spark.filters {
|
||||
|
||||
|
||||
bool IDataGridColumnFilter.filter(object row) =>
|
||||
filter(ObjectHelper.try_convert<TRow>(row));
|
||||
filter(ConvertUtils.try_convert<TRow>(row));
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
Content="Apply"
|
||||
CommandParameter="{TemplateBinding ApplyCommandParameter}"
|
||||
Command="{TemplateBinding ApplyCommand}"
|
||||
CommandTarget="{TemplateBinding ApplyCommandTarget}"
|
||||
IsDefault="True"
|
||||
Focusable="False"
|
||||
Style="{StaticResource CommonButton}"
|
||||
|
||||
@@ -24,6 +24,11 @@ namespace mbts.ui.spark {
|
||||
public object ApplyCommandParameter { get => GetValue(ApplyCommandParameterProperty); set => SetValue(ApplyCommandParameterProperty, value); }
|
||||
#endregion
|
||||
|
||||
#region ApplyCommandTarget
|
||||
public static readonly DependencyProperty ApplyCommandTargetProperty = WPFHelper.create_dp<IInputElement, FilterContentControl>(nameof(ApplyCommandTarget));
|
||||
public IInputElement ApplyCommandTarget { get => GetValue(ApplyCommandTargetProperty) as IInputElement; set => SetValue(ApplyCommandTargetProperty, value); }
|
||||
#endregion
|
||||
|
||||
#region ClearCommand
|
||||
public static readonly DependencyProperty ClearCommandProperty = DependencyProperty.Register(
|
||||
nameof(ClearCommand), typeof(ICommand), typeof(FilterContentControl));
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
<usp:FilterContentControl
|
||||
ApplyCommandParameter="{Binding}"
|
||||
ApplyCommand="{x:Static c:DataGridFilterProperties.CommitCommand}"
|
||||
ApplyCommandTarget="{Binding ElementName=Filter}"
|
||||
ClearCommandParameter="{Binding}"
|
||||
ClearCommand="{x:Static c:DataGridFilterProperties.ClearCommand}"
|
||||
>
|
||||
@@ -115,6 +116,9 @@
|
||||
Begin="{Binding begin}"
|
||||
End="{Binding end}"
|
||||
>
|
||||
<c:TimeFilterControl.CommandBindings>
|
||||
<CommandBinding Command="{x:Static c:DataGridFilterProperties.CommitCommand}" Executed="{x:Static c:TimeFilterControl.CommitExecuted}"/>
|
||||
</c:TimeFilterControl.CommandBindings>
|
||||
<u:Behavior.BindingUpdateGroups>
|
||||
<u:BindingUpdateGroupCollection>
|
||||
<u:BindingUpdateGroup Source="{Binding DataContext, Source={u:DirectReference Filter}}" Target="{Binding Source={u:DirectReference Filter}}">
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mbts.ui.controls {
|
||||
@@ -14,6 +15,18 @@ namespace mbts.ui.controls {
|
||||
/// Interaction logic for TimeFilterControl.xaml
|
||||
/// </summary>
|
||||
public class TimeFilterControl : Control {
|
||||
public static readonly ExecutedRoutedEventHandler CommitExecuted = (s, e) => {
|
||||
if (s is TimeFilterControl tfc) {
|
||||
tfc.get_template_child<DateTimePicker>(_begin_dtp_name)?.flush_pending_changes();
|
||||
tfc.get_template_child<DateTimePicker>(_end_dtp_name)?.flush_pending_changes();
|
||||
(e.Parameter as IDataGridColumnFilter)?.apply.TryExecuteIfCan(null);
|
||||
e.Handled = true;
|
||||
}
|
||||
};
|
||||
const string
|
||||
_begin_dtp_name = "PART_Begin_DateTimePicker",
|
||||
_end_dtp_name = "PART_End_DateTimePicker";
|
||||
|
||||
static TimeFilterControl() =>
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(TimeFilterControl), new FrameworkPropertyMetadata(typeof(TimeFilterControl)));
|
||||
|
||||
@@ -45,17 +58,17 @@ namespace mbts.ui.controls {
|
||||
var clear_begin_time = this.assert_template_child<Hyperlink>("ClearBeginLink");
|
||||
var clear_end_time = this.assert_template_child<Hyperlink>("ClearEndLink");
|
||||
var set_last_hour = this.assert_template_child<Hyperlink>("SetLastHourLink");
|
||||
clear_begin_time.Command = new DelegateCommand(() => Begin = default);
|
||||
clear_end_time.Command = new DelegateCommand(() => End = default);
|
||||
set_last_hour.Command = new DelegateCommand(() => Begin = TimeTextTuple.FromDateTime(DateTime.Now.AddHours(-1)));
|
||||
clear_begin_time.Command = new DelegateCommand(() => SetCurrentValue(BeginProperty, default(TimeTextTuple)));
|
||||
clear_end_time.Command = new DelegateCommand(() => SetCurrentValue(EndProperty, default(TimeTextTuple)));
|
||||
set_last_hour.Command = new DelegateCommand(() => SetCurrentValue(BeginProperty, TimeTextTuple.FromDateTime(DateTime.Now.AddHours(-1))));
|
||||
}
|
||||
|
||||
class TimeFilterErrorAdorner : NotifyDataErrorAdorner<TimeFilterControl, ITimeFilterVM>, IDisposable {
|
||||
readonly ChildProperty<DateTimePicker> _begin_picker, _end_picker;
|
||||
|
||||
public TimeFilterErrorAdorner(TimeFilterControl view) : base(view) {
|
||||
_begin_picker = child_property<DateTimePicker>("PART_Begin_DateTimePicker");
|
||||
_end_picker = child_property<DateTimePicker>("PART_End_DateTimePicker");
|
||||
_begin_picker = child_property<DateTimePicker>(_begin_dtp_name);
|
||||
_end_picker = child_property<DateTimePicker>(_end_dtp_name);
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawing_context) {
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace mbts.ui.controls
|
||||
protected DataGridExRow() { }
|
||||
|
||||
public abstract object get_cell(TColKey col_key);
|
||||
public object get_cell(object col_key) { return get_cell(ObjectHelper.try_convert<TColKey>(col_key)); }
|
||||
public object get_cell(object col_key) { return get_cell(ConvertUtils.try_convert<TColKey>(col_key)); }
|
||||
|
||||
|
||||
}
|
||||
@@ -60,6 +60,6 @@ namespace mbts.ui.controls
|
||||
public abstract class DataGridExCell<TData> : ViewModelBase, IDataGridExCell<TData>, IDataGridExCell
|
||||
{
|
||||
public abstract void update(TData data);
|
||||
public void update(object data) { update(ObjectHelper.try_convert<TData>(data)); }
|
||||
public void update(object data) { update(ConvertUtils.try_convert<TData>(data)); }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using mbts.ui.utility;
|
||||
using mbts.ui.utility.text;
|
||||
using mbts.utils;
|
||||
using bts.utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
@@ -77,7 +77,7 @@ namespace mbts.ui.controls {
|
||||
|
||||
class FontFamilySupportsWeightConverter : IMultiValueConverter {
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
|
||||
if (ObjectHelper.try_convert_args(values, out FontFamily ff, out FontWeight fw))
|
||||
if (ConvertUtils.try_convert_args(values, out FontFamily ff, out FontWeight fw))
|
||||
return TextUtils.available_weights(ff).Contains(fw);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using mbts.utils;
|
||||
using bts.utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -223,7 +223,7 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -231,13 +231,37 @@
|
||||
<ColumnDefinition Width="12"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="1" VerticalAlignment="Center">Cross Thresh</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="1"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Cross Thresh</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="When the size of the opposite-inside market falls below this size threshold the order will payup." />
|
||||
</StackPanel>
|
||||
<uag:QuantityMeasureControl Grid.Row="1" Grid.Column="2" QuantityMeasure="{Binding cross_threshold}"/>
|
||||
<TextBlock Grid.Row="3" VerticalAlignment="Center">Max Chase Ticks</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="3"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Max Chase Ticks</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="The max number of ticks the order will continue to pay up after the initial payup." />
|
||||
</StackPanel>
|
||||
<c:TickUpDownUInt Grid.Row="3" Grid.Column="2" Value="{Binding max_chase_ticks}"/>
|
||||
<TextBlock Grid.Row="5">On Toward</TextBlock>
|
||||
<ComboBox Grid.Row="5" Grid.Column="2" ItemsSource="{Binding trade_toward_types}" ItemTemplate="{StaticResource EnumDescriptionTemplate}" SelectedItem="{Binding trade_toward_behavior}"/>
|
||||
<TextBlock Grid.Row="7">Child</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="5"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">On Toward</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="What should happen when the market moves toward the order." />
|
||||
</StackPanel>
|
||||
<ComboBox Grid.Row="5" Grid.Column="2" ItemsSource="{Binding trade_toward_types}" ItemTemplate="{StaticResource EnumDescriptionTemplate}" SelectedItem="{Binding trade_toward_behavior}"/>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="7"
|
||||
>
|
||||
<TextBlock >Child</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of order to be placed when the algo is triggered" />
|
||||
</StackPanel>
|
||||
<uag:OrderDetailsPopupControl
|
||||
Grid.Row="7" Grid.Column="2"
|
||||
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
|
||||
@@ -266,9 +290,21 @@
|
||||
<ColumnDefinition Width="12"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="1" VerticalAlignment="Center">Join Thresh</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="1"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Join Thresh</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="The Threshold at which the order will join the market when the market flips (the event where the best offer becomes the best bid in the buy case)." />
|
||||
</StackPanel>
|
||||
<uag:QuantityMeasureControl Grid.Row="1" Grid.Column="2" QuantityMeasure="{Binding join_threshold}"/>
|
||||
<TextBlock Grid.Row="3">Child</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="3"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Child</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of order to be placed when the algo is triggered" />
|
||||
</StackPanel>
|
||||
<uag:OrderDetailsPopupControl
|
||||
Grid.Row="3" Grid.Column="2"
|
||||
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
|
||||
@@ -295,9 +331,22 @@
|
||||
<ColumnDefinition Width="12"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="1" VerticalAlignment="Center">Top Thresh</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="1"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Top Thresh</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="If the order is at the top of book, the quantity remaining below which the order will be canceled." />
|
||||
</StackPanel>
|
||||
<uag:QuantityMeasureControl Grid.Row="1" Grid.Column="2" QuantityMeasure="{Binding top_threshold}"/>
|
||||
<TextBlock Grid.Row="3">Child</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="3"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Child</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of order to be placed when the algo is triggered." />
|
||||
</StackPanel>
|
||||
|
||||
<uag:OrderDetailsPopupControl
|
||||
Grid.Row="3" Grid.Column="2"
|
||||
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
|
||||
@@ -326,9 +375,21 @@
|
||||
<ColumnDefinition Width="12"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="1" VerticalAlignment="Center" >Hedge Ticks</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="1"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center" >Hedge Ticks</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the number of ticks to offset the hedge." />
|
||||
</StackPanel>
|
||||
<c:TickUpDownInt Grid.Row="1" Grid.Column="2" Value="{Binding hedge_ticks}"/>
|
||||
<TextBlock Grid.Row="3">Hedge</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="3"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Hedge</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of the hedge order to send for each fill of Child Order." />
|
||||
</StackPanel>
|
||||
<uag:OrderDetailsPopupControl
|
||||
Grid.Row="3" Grid.Column="2"
|
||||
IsOpen="{Binding hedge_order.editable_properties_open, FallbackValue=False}"
|
||||
@@ -336,7 +397,14 @@
|
||||
SelectedItem="{Binding hedge_order}"
|
||||
HasEditableProperties="{Binding hedge_order.has_editable_properties, FallbackValue=False}"
|
||||
/>
|
||||
<TextBlock Grid.Row="5">Child</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="5"
|
||||
>
|
||||
<TextBlock VerticalAlignment="Center">Child</TextBlock>
|
||||
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of order to be placed when the algo is triggered." />
|
||||
</StackPanel>
|
||||
|
||||
<uag:OrderDetailsPopupControl
|
||||
Grid.Row="5" Grid.Column="2"
|
||||
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
|
||||
@@ -377,7 +445,7 @@
|
||||
/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:OrderModificationTemplateSelector.OffsetOrderTemplate>
|
||||
</usp:OrderModificationTemplateSelector.OffsetOrderTemplate>
|
||||
<usp:OrderModificationTemplateSelector.TriggerOrderTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Grid.IsSharedSizeScope="True">
|
||||
@@ -458,7 +526,7 @@
|
||||
<GroupBox.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock FontWeight="SemiBold" Margin="0,0,4,0">Price</TextBlock>
|
||||
<c:HelpButton ToolTip="The child order, resulting from the trigger condition being met, can be sent either at a specified price specified price (Fixed) price or payup/less ticks from the Trigger Price" />
|
||||
<c:HelpButton ToolTip="The child order, resulting from the trigger condition being met, can be sent either at a specified price (Fixed) price or payup/less ticks from the Trigger Price" />
|
||||
</StackPanel>
|
||||
</GroupBox.Header>
|
||||
<Grid>
|
||||
@@ -634,8 +702,8 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding descriptor.ParamName}"/>
|
||||
<CheckBox HorizontalAlignment="Stretch" Grid.Column="2" IsChecked="{Binding param.AsBool, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.BoolTemplate>
|
||||
<usp:DynamicOrderParamTemplateSelector.DoubleTemplate>
|
||||
<DataTemplate>
|
||||
@@ -647,9 +715,9 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding descriptor.ParamName}"/>
|
||||
<c:TickUpDownDouble Grid.Column="2" Value="{Binding param.AsDouble, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.DoubleTemplate>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.DoubleTemplate>
|
||||
<usp:DynamicOrderParamTemplateSelector.IntTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
@@ -660,9 +728,9 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding descriptor.ParamName}"/>
|
||||
<c:TickUpDownInt Grid.Column="2" Value="{Binding param.AsInt32, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.IntTemplate>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.IntTemplate>
|
||||
<usp:DynamicOrderParamTemplateSelector.UIntTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
@@ -673,9 +741,9 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding descriptor.ParamName}"/>
|
||||
<c:TickUpDownUInt Grid.Column="2" Value="{Binding param.AsUint32, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.UIntTemplate>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.UIntTemplate>
|
||||
<usp:DynamicOrderParamTemplateSelector.StringTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
@@ -686,9 +754,9 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding descriptor.ParamName}"/>
|
||||
<TextBox HorizontalAlignment="Stretch" Grid.Column="2" Text="{Binding param.AsString, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.StringTemplate>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.StringTemplate>
|
||||
<usp:DynamicOrderParamTemplateSelector.EnumTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
@@ -699,11 +767,11 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding descriptor.ParamName}"/>
|
||||
<ComboBox Grid.Column="2" ItemsSource="{Binding descriptor.ParamType.Enumerated.Element}" SelectedItem="{Binding param.AsEnumerated.EnumValue}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.EnumTemplate>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector.EnumTemplate>
|
||||
</usp:DynamicOrderParamTemplateSelector>
|
||||
</ItemsControl.ItemTemplateSelector>
|
||||
</ItemsControl.ItemTemplateSelector>
|
||||
</ItemsControl>
|
||||
<TextBlock Grid.Row="3">Child</TextBlock>
|
||||
<uag:OrderDetailsPopupControl
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<cv:KeyValue Key="{x:Null}" Value="{u:Visibility Visible}"/>
|
||||
</cv:ValueMap>
|
||||
|
||||
<ControlTemplate x:Key="HoverButtonOverlayTemplate2" TargetType="c:TickUpDown">
|
||||
<ControlTemplate x:Key="HoverButtonOverlayTemplate" TargetType="c:TickUpDown">
|
||||
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
@@ -86,8 +86,8 @@
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="38"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<c:TickUpDown x:Name="PART_time_tick" HorizontalAlignment="Stretch" EnableArrowKeyTick="False" Template="{StaticResource HoverButtonOverlayTemplate2}">
|
||||
<TextBox x:Name="PART_time_text" Height="20" u:TextBoxBehavior.EnableArrowKeyTraverse="True" u:Behavior.DisablePaste="True">
|
||||
<c:TickUpDown x:Name="PART_time_tick" HorizontalAlignment="Stretch" EnableArrowKeyTick="False" Template="{StaticResource HoverButtonOverlayTemplate}">
|
||||
<TextBox x:Name="PART_time_text" u:TextBoxBehavior.CommitOnEnter="True" Height="20" u:TextBoxBehavior.EnableArrowKeyTraverse="True" u:Behavior.DisablePaste="True">
|
||||
<TextBox.InputBindings>
|
||||
<KeyBinding Key="Up" Command="{x:Static c:DateTimePicker.TickTimeComponentCommand}" CommandParameter="{u:Int 1}"/>
|
||||
<KeyBinding Key="Down" Command="{x:Static c:DateTimePicker.TickTimeComponentCommand}" CommandParameter="{u:Int -1}"/>
|
||||
@@ -95,15 +95,15 @@
|
||||
</TextBox.InputBindings>
|
||||
</TextBox>
|
||||
</c:TickUpDown>
|
||||
<c:TickUpDown x:Name="PART_month_tick" Margin="2,0,0,0" Grid.Column="1" Template="{StaticResource HoverButtonOverlayTemplate2}">
|
||||
<c:TickUpDown x:Name="PART_month_tick" Margin="2,0,0,0" Grid.Column="1" Template="{StaticResource HoverButtonOverlayTemplate}">
|
||||
<TextBox x:Name="PART_month_text" Height="20" u:TextBoxBehavior.EnableArrowKeyTraverse="True" u:Behavior.DisablePaste="True"/>
|
||||
</c:TickUpDown>
|
||||
<TextBlock Grid.Column="2" Margin="2,0">/</TextBlock>
|
||||
<c:TickUpDown x:Name="PART_day_tick" Grid.Column="3" Template="{StaticResource HoverButtonOverlayTemplate2}">
|
||||
<c:TickUpDown x:Name="PART_day_tick" Grid.Column="3" Template="{StaticResource HoverButtonOverlayTemplate}">
|
||||
<TextBox x:Name="PART_day_text" Height="20" u:TextBoxBehavior.EnableArrowKeyTraverse="True" u:Behavior.DisablePaste="True"/>
|
||||
</c:TickUpDown>
|
||||
<TextBlock Grid.Column="4" Margin="2,0">/</TextBlock>
|
||||
<c:TickUpDown x:Name="PART_year_tick" Grid.Column="5" Template="{StaticResource HoverButtonOverlayTemplate2}">
|
||||
<c:TickUpDown x:Name="PART_year_tick" Grid.Column="5" Template="{StaticResource HoverButtonOverlayTemplate}">
|
||||
<TextBox x:Name="PART_year_text" Height="20" u:TextBoxBehavior.EnableArrowKeyTraverse="True" u:Behavior.DisablePaste="True"/>
|
||||
</c:TickUpDown>
|
||||
<TextBlock Grid.Column="0" Text="hh:mm tt" Style="{StaticResource TextPromptStyle}" Visibility="{Binding Text, ElementName=PART_time_text, Converter={StaticResource NullOrEmptyVisibilityConverter}}"/>
|
||||
|
||||
@@ -18,6 +18,11 @@ namespace mbts.ui.controls {
|
||||
public static readonly RoutedCommand TickTimeComponentCommand = new RoutedCommand();
|
||||
|
||||
DTPController _controller;
|
||||
TextBox
|
||||
_month_text,
|
||||
_day_text,
|
||||
_year_text,
|
||||
_time_text;
|
||||
bool _suspend_notify_vm;
|
||||
|
||||
static DateTimePicker() =>
|
||||
@@ -34,18 +39,25 @@ namespace mbts.ui.controls {
|
||||
|
||||
IList<IDisposable> _hooks = new List<IDisposable>();
|
||||
|
||||
public void flush_pending_changes() {
|
||||
_month_text?.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
|
||||
_day_text?.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
|
||||
_year_text?.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
|
||||
_time_text?.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate() {
|
||||
var month = this.assert_template_child<TickUpDown>("PART_month_tick");
|
||||
var month_text = this.assert_template_child<TextBox>("PART_month_text");
|
||||
_month_text = this.assert_template_child<TextBox>("PART_month_text");
|
||||
var day = this.assert_template_child<TickUpDown>("PART_day_tick");
|
||||
var day_text = this.assert_template_child<TextBox>("PART_day_text");
|
||||
_day_text = this.assert_template_child<TextBox>("PART_day_text");
|
||||
var year = this.assert_template_child<TickUpDown>("PART_year_tick");
|
||||
var year_text = this.assert_template_child<TextBox>("PART_year_text");
|
||||
_year_text = this.assert_template_child<TextBox>("PART_year_text");
|
||||
var time = this.assert_template_child<TickUpDown>("PART_time_tick");
|
||||
var time_text = this.assert_template_child<TextBox>("PART_time_text");
|
||||
_time_text = this.assert_template_child<TextBox>("PART_time_text");
|
||||
|
||||
if (_controller != null) _controller.PropertyChanged -= _vm_PropertyChanged;
|
||||
_controller = new DTPController(time_text);
|
||||
_controller = new DTPController(_time_text);
|
||||
_controller.result = TimeTuple;
|
||||
_controller.PropertyChanged += _vm_PropertyChanged;
|
||||
time.CommandBindings.Add(new CommandBinding(TickTimeComponentCommand, (s, e) => {
|
||||
@@ -53,53 +65,52 @@ namespace mbts.ui.controls {
|
||||
}));
|
||||
time.CommandBindings.Add(new CommandBinding(TextBoxBehavior.SelectAllCommand, TextBoxBehavior.SelectAllCommandExecutedHandler));
|
||||
|
||||
const int delay = 500;
|
||||
time.SetBinding(TickUpDown.TickCommandProperty, new Binding("tick_time") { Source = _controller });
|
||||
time.TickUpParameter = 1;
|
||||
time.TickDownParameter = -1;
|
||||
time.TickUpAltParameter = 60;
|
||||
time.TickDownAltParameter = -60;
|
||||
time_text.SetBinding(TextBox.TextProperty, new Binding("time_text") { Source = _controller, Delay = delay, ValidatesOnExceptions = true });
|
||||
_hooks.Add(time_text.SubscribePreviewTextInput((s, e) => {
|
||||
string preview = time_text.PeekText(e);
|
||||
_time_text.SetBinding(TextBox.TextProperty, new Binding("time_text") { Source = _controller, ValidatesOnExceptions = true });
|
||||
_hooks.Add(_time_text.SubscribePreviewTextInput((s, e) => {
|
||||
string preview = _time_text.PeekText(e);
|
||||
if (RegexFilters.Time.StandardTimeOptionalSeconds.IsMatch(preview)) {
|
||||
_controller.use_military_time = false;
|
||||
} else if (RegexFilters.Time.MilitaryTimeOptionalSeconds.IsMatch(preview)) {
|
||||
_controller.use_military_time = true;
|
||||
} else {
|
||||
e.Handled = true;
|
||||
e.Handled = !RegexFilters.Time.FlexibleTime.IsMatch(preview);
|
||||
}
|
||||
}));
|
||||
|
||||
month.SetBinding(TickUpDown.TickCommandProperty, new Binding("tick_month") { Source = _controller });
|
||||
month.TickUpParameter = 1;
|
||||
month.TickDownParameter = -1;
|
||||
month_text.SetBinding(TextBox.TextProperty, new Binding("month_text") { Source = _controller, Delay = delay });
|
||||
_hooks.Add(month_text.SubscribePreviewTextInput((s, e) =>
|
||||
e.Handled = !RegexFilters.Time.MonthAbbrev.IsMatch(month_text.PeekText(e))
|
||||
_month_text.SetBinding(TextBox.TextProperty, new Binding("month_text") { Source = _controller });
|
||||
_hooks.Add(_month_text.SubscribePreviewTextInput((s, e) =>
|
||||
e.Handled = !RegexFilters.Time.MonthAbbrev.IsMatch(_month_text.PeekText(e))
|
||||
));
|
||||
|
||||
day.SetBinding(TickUpDown.TickCommandProperty, new Binding("tick_day") { Source = _controller });
|
||||
day.TickUpParameter = 1;
|
||||
day.TickDownParameter = -1;
|
||||
day_text.SetBinding(TextBox.TextProperty, new Binding("day_text") { Source = _controller, Delay = delay });
|
||||
_hooks.Add(day_text.SubscribePreviewTextInput((s, e) =>
|
||||
e.Handled = !RegexFilters.Time.DaysInMonth.IsMatch(day_text.PeekText(e))
|
||||
_day_text.SetBinding(TextBox.TextProperty, new Binding("day_text") { Source = _controller });
|
||||
_hooks.Add(_day_text.SubscribePreviewTextInput((s, e) =>
|
||||
e.Handled = !RegexFilters.Time.DaysInMonth.IsMatch(_day_text.PeekText(e))
|
||||
));
|
||||
|
||||
year.SetBinding(TickUpDown.TickCommandProperty, new Binding("tick_year") { Source = _controller });
|
||||
year.TickUpParameter = 1;
|
||||
year.TickDownParameter = -1;
|
||||
year_text.SetBinding(TextBox.TextProperty, new Binding("year_text") { Source = _controller, Delay = delay });
|
||||
_hooks.Add(year_text.SubscribePreviewTextInput((s, e) =>
|
||||
e.Handled = !RegexFilters.Time.Year.IsMatch(year_text.PeekText(e))
|
||||
_year_text.SetBinding(TextBox.TextProperty, new Binding("year_text") { Source = _controller });
|
||||
_hooks.Add(_year_text.SubscribePreviewTextInput((s, e) =>
|
||||
e.Handled = !RegexFilters.Time.Year.IsMatch(_year_text.PeekText(e))
|
||||
));
|
||||
}
|
||||
|
||||
void _vm_PropertyChanged(object sender, PropertyChangedEventArgs e) {
|
||||
if (e.PropertyName == nameof(DTPController.result)) {
|
||||
_suspend_notify_vm = true;
|
||||
TimeTuple = _controller.result;
|
||||
SetCurrentValue(TimeTupleProperty, _controller.result);
|
||||
_suspend_notify_vm = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using bts;
|
||||
using mbts.spark.filters;
|
||||
using mbts.ui.controls.adorners;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace mbts.ui.controls {
|
||||
public class UniformTabGrid : UniformGrid {
|
||||
public UniformTabGrid () {
|
||||
this.IsItemsHost = true;
|
||||
this.Rows = 1;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size constraint) {
|
||||
var child_tabs = this.Children.OfType<TabItem>();
|
||||
var child_tabs_max_width = child_tabs.Sum(t => t.MaxWidth);
|
||||
// I noticed when debugging that this can sometimes be infinty,
|
||||
// especially when a TabItem has not been set with a MaxWidth.
|
||||
if (!double.IsInfinity(child_tabs_max_width)) {
|
||||
// if the window width is greater than the total tab width, then
|
||||
// there is more than enough space for all the tabs. If this
|
||||
// is set to the default of Stretch and the window has only 1
|
||||
// tab or few tabs, the tab appears in the middle, which is not good.
|
||||
// i.e. we want tabs to added left to right, so align left
|
||||
//
|
||||
// When the window is less than the total tab width, then align
|
||||
// can be set to stretch b/c the UniformGrid will take care of
|
||||
// sizing each tab accordingly.
|
||||
this.HorizontalAlignment = (constraint.Width > child_tabs_max_width)
|
||||
? HorizontalAlignment.Left
|
||||
: HorizontalAlignment.Stretch;
|
||||
|
||||
// this bit here is necessary because when the window is expanded
|
||||
// beyond the maxwidth of all the tabs, we switch to Left and the
|
||||
// headers snap to some smaller than MaxWidth size, which is not
|
||||
// the behavior we want
|
||||
foreach (var child in child_tabs) {
|
||||
child.Width = this.HorizontalAlignment == HorizontalAlignment.Left
|
||||
? child.MaxWidth
|
||||
: double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
return base.MeasureOverride(constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,8 @@ namespace mbts.ui.converters {
|
||||
private readonly Func<TIn, TOut> _convert;
|
||||
private readonly Func<TOut, TIn> _convert_back;
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return _convert(ObjectHelper.try_convert<TIn>(value)); }
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return _convert_back(ObjectHelper.try_convert<TOut>(value)); }
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return _convert(ConvertUtils.try_convert<TIn>(value)); }
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return _convert_back(ConvertUtils.try_convert<TOut>(value)); }
|
||||
}
|
||||
|
||||
public class AnonymousMultiValueConverter<TIn1, TIn2, TOut> : IMultiValueConverter {
|
||||
@@ -49,7 +49,7 @@ namespace mbts.ui.converters {
|
||||
public TOut ErrorValue { get; set; }
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) =>
|
||||
ObjectHelper.try_convert_args(values, out TIn1 a, out TIn2 b) ? _convert(a, b) : ErrorValue;
|
||||
ConvertUtils.try_convert_args(values, out TIn1 a, out TIn2 b) ? _convert(a, b) : ErrorValue;
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
||||
}
|
||||
@@ -62,7 +62,7 @@ namespace mbts.ui.converters {
|
||||
public TOut ErrorValue { get; set; }
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) =>
|
||||
ObjectHelper.try_convert_args(values, out TIn1 a, out TIn2 b, out TIn3 c) ? _convert(a, b, c) : ErrorValue;
|
||||
ConvertUtils.try_convert_args(values, out TIn1 a, out TIn2 b, out TIn3 c) ? _convert(a, b, c) : ErrorValue;
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using mbts.utils;
|
||||
using bts.utils;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
@@ -19,7 +19,7 @@ namespace mbts.ui.converters
|
||||
}
|
||||
|
||||
public class DynamicValueEquals<T> : DynamicValueEquals {
|
||||
protected override bool ValuesEqual(object x, object y) { return ObjectHelper.try_convert(x, out T tx) && ObjectHelper.try_convert(y, out T ty) && ValuesEqual(tx, ty); }
|
||||
protected override bool ValuesEqual(object x, object y) { return ConvertUtils.try_convert(x, out T tx) && ConvertUtils.try_convert(y, out T ty) && ValuesEqual(tx, ty); }
|
||||
protected virtual bool ValuesEqual(T x, T y) { return CompareUtils.NullCheckEquals(x, y); }
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace mbts.ui.converters
|
||||
}
|
||||
|
||||
public class StaticValueEqualsConverter<T> : StaticValueEqualsConverter {
|
||||
protected override bool ValueEquals(object value) { return ObjectHelper.try_convert(value, out T result) && ValueEquals(result); }
|
||||
protected override bool ValueEquals(object value) { return ConvertUtils.try_convert(value, out T result) && ValueEquals(result); }
|
||||
protected virtual bool ValueEquals(T value) { return base.ValueEquals(value); }
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace mbts.ui
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public bool CanExecute(object parameter) {
|
||||
return !_is_executing && (_can_execute == null || _can_execute(ObjectHelper.try_convert<T>(parameter)));
|
||||
return !_is_executing && (_can_execute == null || _can_execute(ConvertUtils.try_convert<T>(parameter)));
|
||||
}
|
||||
|
||||
public void RaiseCanExecuteChanged() {
|
||||
@@ -45,7 +45,7 @@ namespace mbts.ui
|
||||
_is_executing = true;
|
||||
RaiseCanExecuteChanged();
|
||||
try {
|
||||
var w = await _factory(ObjectHelper.try_convert<T>(parameter));
|
||||
var w = await _factory(ConvertUtils.try_convert<T>(parameter));
|
||||
if (w != null) {
|
||||
if (_off_x.HasValue && _off_y.HasValue)
|
||||
w.move_to_mouse(_off_x.Value, _off_x.Value);
|
||||
|
||||
@@ -28,12 +28,12 @@ namespace mbts.ui
|
||||
private IDisposable _dialog;
|
||||
public Predicate<T> can_execute { get; set; }
|
||||
|
||||
public bool CanExecute(object parameter) { return can_execute == null ? true : can_execute(ObjectHelper.try_convert<T>(parameter)); }
|
||||
public bool CanExecute(object parameter) { return can_execute == null ? true : can_execute(ConvertUtils.try_convert<T>(parameter)); }
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public void Execute(object parameter) {
|
||||
Disposable.dispose(ref _dialog);
|
||||
Window w = _factory(ObjectHelper.try_convert<T>(parameter));
|
||||
Window w = _factory(ConvertUtils.try_convert<T>(parameter));
|
||||
if (w != null) {
|
||||
if (_try_dispose_vm_on_close) {
|
||||
w.Closed += (s, e) => {
|
||||
|
||||
@@ -101,10 +101,10 @@ namespace mbts.ui {
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public bool CanExecute(object parameter) => _can_execute(ObjectHelper.try_convert<TParam>(parameter));
|
||||
public bool CanExecute(object parameter) => _can_execute(ConvertUtils.try_convert<TParam>(parameter));
|
||||
public void Execute(object parameter) {
|
||||
_safe_close_dialog();
|
||||
TParam tparam = ObjectHelper.try_convert<TParam>(parameter);
|
||||
TParam tparam = ConvertUtils.try_convert<TParam>(parameter);
|
||||
_dialog = _dialog_factory(tparam);
|
||||
if (_dialog.ShowDialog() == DialogResult.OK)
|
||||
_commit(tparam, _dialog.FileName);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace mbts.ui {
|
||||
|
||||
public static T get_template_child<T>(this Control control, string name) {
|
||||
object obj = get_template_child(control, name);
|
||||
return ObjectHelper.try_convert<T>(obj);
|
||||
return ConvertUtils.try_convert<T>(obj);
|
||||
}
|
||||
|
||||
public static bool try_get_template_child(this Control control, string name, out object result) {
|
||||
@@ -40,7 +40,7 @@ namespace mbts.ui {
|
||||
|
||||
public static bool try_get_template_child<T>(this Control control, string name, out T result) {
|
||||
if (try_get_template_child(control, name, out object obj))
|
||||
return ObjectHelper.try_convert(obj, out result);
|
||||
return ConvertUtils.try_convert(obj, out result);
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
|
||||
xmlns:ui="clr-namespace:mbts.ui"
|
||||
xmlns:c="clr-namespace:mbts.ui.controls"
|
||||
mc:Ignorable="d" AllowDrop="True"
|
||||
Style="{StaticResource BTSFloatingWindow}"
|
||||
d:DesignHeight="300" d:DesignWidth="300"
|
||||
@@ -25,18 +26,25 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<WrapPanel x:Name="HeaderPanel" Orientation="Horizontal" Margin="0,0,100,0"
|
||||
<!-- This stack panel serves as the area between the last tab and the widget control on right side of title bar (below).
|
||||
It allows the region in between (if such a region exists) to be grabbed to move the window.
|
||||
-->
|
||||
<StackPanel Grid.Row="0" Margin="0,0,100,0" Background="Transparent" ui:WindowStyle.IsNonClientArea="True">
|
||||
<c:UniformTabGrid x:Name="HeaderPanel"
|
||||
Grid.Row="0"
|
||||
Panel.ZIndex="1"
|
||||
IsItemsHost="True"
|
||||
KeyboardNavigation.TabIndex="1"
|
||||
Background="Transparent" ui:WindowStyle.IsNonClientArea="True">
|
||||
</WrapPanel>
|
||||
Background="Transparent"
|
||||
ui:WindowStyle.IsNonClientArea="True"
|
||||
>
|
||||
</c:UniformTabGrid>
|
||||
</StackPanel>
|
||||
<Border Grid.Row="1" BorderThickness="0"
|
||||
Padding="{Binding Path=Padding, RelativeSource={RelativeSource AncestorType=Window}}" ui:WindowStyle.IsNonClientArea="False" >
|
||||
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" />
|
||||
</Border>
|
||||
<Border Grid.Row="0" Width="100" HorizontalAlignment="Right" VerticalAlignment="Stretch" Panel.ZIndex="2" Background="Transparent" ui:WindowStyle.IsNonClientArea="True">
|
||||
<!-- Window widget control area-->
|
||||
<Border Grid.Row="0" MinWidth="100" HorizontalAlignment="Right" Panel.ZIndex="2" Background="Transparent" ui:WindowStyle.IsNonClientArea="True">
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Panel.ZIndex="2" Background="Transparent" Margin="5">
|
||||
<Button Style="{StaticResource RoundMinimizeButton}" HorizontalAlignment="Right" Command="{x:Static SystemCommands.MinimizeWindowCommand}" />
|
||||
<Button Style="{StaticResource RoundMaximizeButton}" HorizontalAlignment="Right" Command="{x:Static SystemCommands.MaximizeWindowCommand}" />
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
</TabItem.RenderTransform>
|
||||
<TabItem.Template>
|
||||
<ControlTemplate TargetType="{x:Type TabItem}">
|
||||
<Border x:Name="bd" BorderBrush="Black" BorderThickness="0,0,0.5,0" Background="#d6d6d6" Width="{DynamicResource TabWidth}" Height="{DynamicResource TabHeight}" MinWidth="40" Margin="0" SnapsToDevicePixels="True" DockPanel.Dock="Left">
|
||||
<Border x:Name="bd" BorderBrush="Black" BorderThickness="0,0,0.5,0" Background="#d6d6d6" Height="{DynamicResource TabHeight}" MinWidth="40" Margin="0" SnapsToDevicePixels="True" DockPanel.Dock="Left">
|
||||
<Border.ToolTip>
|
||||
<TextBlock Text="{Binding Title}" />
|
||||
</Border.ToolTip>
|
||||
@@ -90,6 +90,7 @@
|
||||
</TabItem.Template>
|
||||
<TabItem.Style>
|
||||
<Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
|
||||
<Setter Property="MaxWidth" Value="{DynamicResource TabWidth}" />
|
||||
<Setter Property="HeaderTemplate" Value="{StaticResource _template}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding EditMode}" Value="True">
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace mbts.ui.shell
|
||||
{
|
||||
public class WorkspaceViewModel : ViewModelBase
|
||||
{
|
||||
private const string INITIAL_VISUAL_STATE = "Normal";
|
||||
|
||||
WorkspacesModel _parent;
|
||||
public WorkspaceViewModel(WorkspacesModel parent, string name, WorkspaceDefinition definition) {
|
||||
_parent = parent;
|
||||
@@ -22,8 +24,23 @@ namespace mbts.ui.shell
|
||||
get { return Icons.Window; }
|
||||
}
|
||||
|
||||
private string _vstate = "Normal";
|
||||
public string VisualState { get { return _vstate; } set { _vstate = value; RaisePropertyChanged("VisualState"); } }
|
||||
private string _vstate = INITIAL_VISUAL_STATE;
|
||||
public string VisualState {
|
||||
get {
|
||||
// this unconventional getter acts as a reset after the VisualStateManager has played
|
||||
// i.e. if we overwrite a workspace then save, then close the window, when we open the
|
||||
// window back up, we'll see item animate b/c it has never been reset from the animate
|
||||
// state. This is necessary b/c the lifetime of Workspaces is not tied to the lifetime
|
||||
// of the View, rather it lives in the Model and is only instantiated on startup via MEF
|
||||
var return_val = _vstate;
|
||||
_vstate = INITIAL_VISUAL_STATE;
|
||||
return return_val;
|
||||
}
|
||||
set {
|
||||
_vstate = value;
|
||||
RaisePropertyChanged("VisualState");
|
||||
}
|
||||
}
|
||||
|
||||
internal WorkspaceDefinition Definition { get; private set; }
|
||||
|
||||
|
||||
@@ -45,13 +45,13 @@ namespace mbts.ui.shell
|
||||
{
|
||||
clear_error("SaveName");
|
||||
}
|
||||
var save_candidate_already_exists = Workspaces.Any(x => x.Name == SaveName);
|
||||
var save_candidate_already_exists = Workspaces.Any(x => x.Name.Replace(WorkspacesModel.SHARED_MONIKER, string.Empty) == SaveName && x.IsShared == IsPublicWorkspace);
|
||||
// Save
|
||||
_work_model.save_workspace(SaveName, ispublic: IsPublicWorkspace);
|
||||
|
||||
// if we just overwrote something, have the vm reflect it
|
||||
if (save_candidate_already_exists)
|
||||
Workspaces.Where(x => x.Name == SaveName).ForEach(x => x.VisualState = "Overridden");
|
||||
Workspaces.Where(x => x.Name.Replace(WorkspacesModel.SHARED_MONIKER, string.Empty) == SaveName && x.IsShared == IsPublicWorkspace).ForEach(x => x.VisualState = "Overridden");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace mbts.ui.shell
|
||||
{
|
||||
internal const string WORKSPACE_NAMESPACE = "workspace";
|
||||
internal const string ACTIVE_WORKSPACE_PREFIX = "Where I left off on ";
|
||||
public const string SHARED_MONIKER = " (shared)";
|
||||
public static string ACTIVE_WORKSPACE_NAME { get { return ACTIVE_WORKSPACE_PREFIX + Environment.MachineName; } }
|
||||
|
||||
private ISettingsCollector _settings_collector;
|
||||
@@ -178,7 +179,7 @@ namespace mbts.ui.shell
|
||||
public void save_workspace(string name, bool persist=true, bool ispublic=false) {
|
||||
WorkspaceDefinition workspace = get_workspace();
|
||||
workspace.is_shared = ispublic;
|
||||
if (ispublic) { name += " (shared)"; }
|
||||
if (ispublic) { name += SHARED_MONIKER; }
|
||||
|
||||
// Remove the old one if a workspace by this name exists already
|
||||
var old = Workspaces.SingleOrDefault(w => w.Name == name && ispublic == w.IsShared);
|
||||
|
||||
@@ -18,10 +18,10 @@ namespace mbts.spark {
|
||||
return self == null ? all.Values : all.Values.Where(md => ContractPickerModel.security_in_criteria(self, md.security));
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<SecurityImmutable>> securities(this SecurityCriteria self, IBus bus) {
|
||||
public static async Task<IDictionary<uint,SecurityImmutable>> securities(this SecurityCriteria self, IBus bus) {
|
||||
var md_map = await bus.subscribe(SparkTags.SecuritiesTag).FirstAsync();
|
||||
var all_secs = md_map.Values.Select(md => md.security);
|
||||
return self == null ? all_secs : all_secs.Where(s => ContractPickerModel.security_in_criteria(self, s));
|
||||
var all_secs = md_map.Values.Select(md => md.security).ToDictionary(key => key.Id);
|
||||
return self == null ? all_secs : all_secs.Values.Where(s => ContractPickerModel.security_in_criteria(self, s)).ToDictionary(key => key.Id);
|
||||
}
|
||||
|
||||
public static IObservable<IEnumerable<SecurityImmutable>> subscribe(this SecurityCriteria self, IBus bus) {
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace mbts.spark {
|
||||
Comparer<double>.Create(_compare_unit);
|
||||
|
||||
public static IComparer<TickFactors> base_unit_comparer =>
|
||||
Comparer<TickFactors>.Create(utils.CompareUtils.safe_comparison<TickFactors>(compare_base_unit));
|
||||
Comparer<TickFactors>.Create(bts.utils.CompareUtils.safe_comparison<TickFactors>(compare_base_unit));
|
||||
|
||||
public static int compare_base_unit(TickFactors a, TickFactors b) {
|
||||
int comp = _compare_base(a.tick_base, b.tick_base);
|
||||
|
||||
@@ -122,6 +122,21 @@ namespace mbts.spark
|
||||
where TRow : class, ISecurityRow =>
|
||||
security_grid.selected_securities.ObserveSelf();
|
||||
|
||||
public static IObservable<IReadOnlyList<SecurityImmutable>> sorted_selected_securities_observable<TRow, TRowModel>(this SecurityGridBase<TRow, TRowModel> security_grid)
|
||||
where TRow : class, ISecurityRow =>
|
||||
security_grid.selected_rows
|
||||
.ObserveSelf()
|
||||
.Select(rows =>
|
||||
rows.Select(
|
||||
row => (security: row.security, row_index: security_grid.rows_view.indexOf(row))
|
||||
)
|
||||
.OrderBy(sec_vs_index => sec_vs_index.row_index)
|
||||
.Select(sec_vs_index => sec_vs_index.security)
|
||||
.ToReadOnlyList()
|
||||
);
|
||||
|
||||
|
||||
|
||||
public static IObservable<IReadOnlyList<SecurityMD>> selected_security_mds_observable<TRow, TRowModel>(this SecurityMDGrid<TRow, TRowModel> security_md_grid)
|
||||
where TRow : class, ISecurityMDRow =>
|
||||
security_md_grid.selected_rows.ObserveSelf(true).Select(rows => rows.Select(r => r.md).ToReadOnlyList());
|
||||
|
||||
@@ -853,11 +853,11 @@ namespace mbts.spark {
|
||||
LadderSettings _settings => _owner._settings;
|
||||
|
||||
public void refresh() {
|
||||
bid_dirty = ObjectHelper.update_value_type(ref _bid, _settings.bid_break_line.show ? _owner._get_bid_market_break() : double.NaN);
|
||||
ask_dirty = ObjectHelper.update_value_type(ref _ask, _settings.ask_break_line.show ? _owner._get_ask_market_break() : double.NaN);
|
||||
mid_dirty = ObjectHelper.update_value_type(ref _mid, _settings.mid_break_line.show ? _owner._get_mid_market_break() : double.NaN);
|
||||
session_low_dirty = ObjectHelper.update_value_type(ref _session_low, (_settings.session_low_line.show || _settings.session_range_fill.show) ? _owner._get_session_low() : double.NaN);
|
||||
session_high_dirty = ObjectHelper.update_value_type(ref _session_high, (_settings.session_high_line.show || _settings.session_range_fill.show) ? _owner._get_session_high() : double.NaN);
|
||||
bid_dirty = ConvertUtils.update_value_type(ref _bid, _settings.bid_break_line.show ? _owner._get_bid_market_break() : double.NaN);
|
||||
ask_dirty = ConvertUtils.update_value_type(ref _ask, _settings.ask_break_line.show ? _owner._get_ask_market_break() : double.NaN);
|
||||
mid_dirty = ConvertUtils.update_value_type(ref _mid, _settings.mid_break_line.show ? _owner._get_mid_market_break() : double.NaN);
|
||||
session_low_dirty = ConvertUtils.update_value_type(ref _session_low, (_settings.session_low_line.show || _settings.session_range_fill.show) ? _owner._get_session_low() : double.NaN);
|
||||
session_high_dirty = ConvertUtils.update_value_type(ref _session_high, (_settings.session_high_line.show || _settings.session_range_fill.show) ? _owner._get_session_high() : double.NaN);
|
||||
if (session_low_dirty)
|
||||
_low_index = null;
|
||||
if (session_high_dirty)
|
||||
@@ -871,7 +871,7 @@ namespace mbts.spark {
|
||||
else new_origin = mid;
|
||||
if (double.IsNaN(new_origin))
|
||||
new_origin = _owner._get_bid_market_break();
|
||||
origin_dirty = ObjectHelper.update_value_type(ref _origin, new_origin);
|
||||
origin_dirty = ConvertUtils.update_value_type(ref _origin, new_origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ namespace mbts.ui.utility.text {
|
||||
StandardTimeOptionalSeconds = new Regex(@"^((\d?|0\d|1[0-2])|((\d|0\d|1[0-2])(:?|(:([0-5]?|[0-5]\d(( ?|( ([aApP]?|[aApP][mM])))(:?|(: ?)|(: [aApP]?[mM]?)|(:[0-5]?\d? ?[aApP]?[mM]?))|:([0-5]?|([0-5]\d( ?|( ([aApP]?|([aApP][mM]))))))))))))$"),
|
||||
MilitaryTime = new Regex(@"^(([0-1]?[0-9])|(2?[0-3]?))(:?|:([0-5]?|[0-5][0-9]?))$"),
|
||||
MilitaryTimeOptionalSeconds = new Regex(@"^((\d?|[0-1]\d|2[0-3])|((\d|[0-1]\d|2[0-3])(:?|(:([0-5]?|[0-5]\d(:?|:([0-5]?|[0-5]\d)))))))$"),
|
||||
FlexibleTime = new Regex(@"^[0-9:aApPmM ]*$"),
|
||||
DaysInMonth = new Regex(@"^([0-9]?|[0-2][0-9]|3[0-1])?$"),
|
||||
MonthAbbrev = new Regex(@"^(?i)(a(ug?|pr?)?|d(e|ec)?|f(e?b)?|j(an?|u[nl]?)?|m(a[ry]?)?|(o(ct?)?)|s(ep?)?|n(ov?)?)?$"),
|
||||
Year = new Regex(@"^\d{0,4}$"),
|
||||
|
||||
@@ -259,13 +259,13 @@ namespace mbts.ui {
|
||||
}
|
||||
|
||||
public static PropertyChangedCallback prop_changed_callback<TValue, TOwner>(PropertyChangedCallback<TValue, TOwner> callback) =>
|
||||
(d, e) => callback(ObjectHelper.try_convert<TOwner>(d), ObjectHelper.try_convert<TValue>(e.OldValue), ObjectHelper.try_convert<TValue>(e.NewValue));
|
||||
(d, e) => callback(ConvertUtils.try_convert<TOwner>(d), ConvertUtils.try_convert<TValue>(e.OldValue), ConvertUtils.try_convert<TValue>(e.NewValue));
|
||||
|
||||
public static PropertyChangedCallback prop_changed_callback<TValue, TOwner>(Action<TOwner, TValue> callback) =>
|
||||
(d, e) => callback(ObjectHelper.try_convert<TOwner>(d), ObjectHelper.try_convert<TValue>(e.NewValue));
|
||||
(d, e) => callback(ConvertUtils.try_convert<TOwner>(d), ConvertUtils.try_convert<TValue>(e.NewValue));
|
||||
|
||||
public static CoerceValueCallback coerce_value_callback<TValue, TOwner>(Func<TOwner, TValue, TValue> coerce_value) =>
|
||||
(d, obj) => coerce_value(ObjectHelper.try_convert<TOwner>(d), ObjectHelper.try_convert<TValue>(obj));
|
||||
(d, obj) => coerce_value(ConvertUtils.try_convert<TOwner>(d), ConvertUtils.try_convert<TValue>(obj));
|
||||
|
||||
public static double control_base_width(Thickness border_thickness, Thickness padding) =>
|
||||
border_thickness.Left + padding.Left + padding.Right + border_thickness.Right;
|
||||
|
||||
@@ -3,4 +3,5 @@ using System.Runtime.CompilerServices;
|
||||
[assembly: InternalsVisibleTo("spark_core")]
|
||||
[assembly: InternalsVisibleTo("sparkcmd")]
|
||||
[assembly: InternalsVisibleTo("spark_test")]
|
||||
[assembly: InternalsVisibleTo("spark_fix")]
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
|
||||
namespace bts.api
|
||||
{
|
||||
public class Authenticator
|
||||
{
|
||||
readonly static Lazy<user.UserService> _auth = new Lazy<user.UserService>(() => Locator.locate<user.UserService>(), true);
|
||||
user.AuthToken _token = null;
|
||||
public Authenticator() { }
|
||||
|
||||
public user.AuthToken last_token => _token;
|
||||
public async Task<user.AuthToken> login(string login, string password)
|
||||
{
|
||||
var res = await _auth.Value.authenticate_login_async(new user.AuthenticateLoginRequest { Login = login, Password = password });
|
||||
if (res.success)
|
||||
_token = res.value.Token;
|
||||
return _token;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bts
|
||||
{
|
||||
public class AsyncLazy<T> : Lazy<Task<T>>
|
||||
{
|
||||
public AsyncLazy(Func<T> valueFactory) :
|
||||
base(() => Task.Factory.StartNew(valueFactory))
|
||||
{ }
|
||||
|
||||
public AsyncLazy(Func<Task<T>> taskFactory) :
|
||||
base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap())
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
|
||||
namespace bts.api
|
||||
{
|
||||
public static class Locator
|
||||
{
|
||||
readonly static Lazy<ServiceContext> _context = new Lazy<ServiceContext>(() => new ServiceContext(), true);
|
||||
public static T locate<T>(string qualifier="") where T : class, IApiClient
|
||||
{
|
||||
return _context.Value.locate<T>(qualifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,50 +33,54 @@ namespace bts.api.md
|
||||
readonly ConcurrentDictionary<security_key, Data> _data = new ConcurrentDictionary<security_key, Data>();
|
||||
readonly ConcurrentDictionary<security_key, string> _security_key_to_desc= new ConcurrentDictionary<security_key, string>();
|
||||
readonly ConcurrentDictionary<string, security_key> _security_desc_to_key = new ConcurrentDictionary<string, security_key>();
|
||||
readonly Lazy<MDRequest> _subscription;
|
||||
readonly MDRequest _subscription;
|
||||
readonly Venue _venue;
|
||||
|
||||
readonly static Lazy<MarketDataRelay> _md = new Lazy<MarketDataRelay>(() => locate(), true);
|
||||
readonly static Lazy<MarketDataRelay> _md = new Lazy<MarketDataRelay>(() => Locator.locate<MarketDataRelay>(), true);
|
||||
readonly static ConcurrentDictionary<api.Venue, MarketDataClient> _venue_cache = new ConcurrentDictionary<api.Venue, api.md.MarketDataClient>();
|
||||
static readonly List<Product> _all_products;
|
||||
static MarketDataClient()
|
||||
{
|
||||
_all_products = _md.Value.request_products(new VoidMessage()).Products.ToList();
|
||||
}
|
||||
public static bool create_or_get(api.Venue exchange, out MarketDataClient md)
|
||||
|
||||
public static IEnumerable<api.Venue> cached_exchanges => _venue_cache.Keys;
|
||||
public static bool create_or_get(api.Venue exchange, out MarketDataClient md, user.AuthToken token = null)
|
||||
{
|
||||
if (!_venue_cache.TryGetValue(exchange, out md))
|
||||
{
|
||||
_venue_cache[exchange] = md = new MarketDataClient(exchange);
|
||||
_venue_cache[exchange] = md = new MarketDataClient(exchange, token);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public MarketDataClient(bts.api.Venue exchange = Venue.Unset)
|
||||
public MarketDataClient(bts.api.Venue exchange = Venue.Unset, user.AuthToken token = null)
|
||||
{
|
||||
_venue = exchange;
|
||||
_subscription = new Lazy<MDRequest>(() => load_request(exchange));
|
||||
_subscription = load_request(exchange, token);
|
||||
}
|
||||
|
||||
MDRequest load_request(bts.api.Venue exchange)
|
||||
public void set_auth_token(user.AuthToken toke)
|
||||
{
|
||||
var req = new MDRequest();
|
||||
_subscription.Token = toke?.Token ?? string.Empty;
|
||||
}
|
||||
|
||||
MDRequest load_request(bts.api.Venue exchange, user.AuthToken token)
|
||||
{
|
||||
var req = new MDRequest() { Token = token?.Token ?? string.Empty } ;
|
||||
var prods = _all_products.Where(x=>x.Exchange == exchange || exchange == bts.api.Venue.Unset);
|
||||
foreach(var prod in prods)
|
||||
req.Channels.Add(new SecurityChannel() { Exchange = prod.Exchange, Type = prod.Type, Symbol = prod.Symbol, Flags = 0 });
|
||||
return req;
|
||||
}
|
||||
|
||||
static MarketDataRelay locate()
|
||||
public IEnumerable<SecurityImmutable> get_securities()
|
||||
{
|
||||
using (var ctx = new api.core.ServiceContext())
|
||||
{
|
||||
return ctx.locate<MarketDataRelay>();
|
||||
}
|
||||
return _data.Values.Select(x => new SecurityImmutable(x.data.Security));
|
||||
}
|
||||
|
||||
public Security lookup(security_key key)
|
||||
public SecurityImmutable? lookup(security_key key)
|
||||
{
|
||||
Data value;
|
||||
if(_data.TryGetValue(key, out value))
|
||||
@@ -217,7 +221,7 @@ namespace bts.api.md
|
||||
|
||||
bool check_subscriptions(uint flags, Func<SecurityChannel, bool> selector)
|
||||
{
|
||||
foreach (var sub in _subscription.Value.Channels)
|
||||
foreach (var sub in _subscription.Channels)
|
||||
{
|
||||
if (selector(sub))
|
||||
{
|
||||
@@ -234,6 +238,11 @@ namespace bts.api.md
|
||||
/// <param name="interval"></param>
|
||||
/// <returns></returns>
|
||||
public async Task start_pump(TimeSpan? interval = null)
|
||||
{
|
||||
await _start_pump(interval);
|
||||
}
|
||||
|
||||
async Task _start_pump(TimeSpan? interval = null, int num_pumps = -1)
|
||||
{
|
||||
var rep = await _md.Value.request_names_async(new VoidMessage());
|
||||
int count = 0;
|
||||
@@ -249,9 +258,10 @@ namespace bts.api.md
|
||||
}
|
||||
}
|
||||
while (!rep.success && count++ < 5);
|
||||
while (true)
|
||||
count = 0;
|
||||
while (num_pumps < 0 || count++ < num_pumps)
|
||||
{
|
||||
var reply = await _md.Value.requestmd_async(_subscription.Value);
|
||||
var reply = await _md.Value.requestmd_async(_subscription);
|
||||
if (reply.success)
|
||||
{
|
||||
foreach (var channel in reply.value.Channels)
|
||||
@@ -299,6 +309,19 @@ namespace bts.api.md
|
||||
await this.start_pump(interval);
|
||||
}
|
||||
|
||||
public void pump_once()
|
||||
{
|
||||
if (_pump_task == null)
|
||||
{
|
||||
_pump_task = this._start_pump(null, 1)
|
||||
.ContinueWith(ex =>
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(ex == null, ex.ToString());
|
||||
}
|
||||
, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
public void Dispose()
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using static bts.api.Security;
|
||||
|
||||
namespace bts.api {
|
||||
struct FutureLeg {
|
||||
public struct FutureLeg {
|
||||
public readonly Venue exchange;
|
||||
public readonly string symbol, exchange_desc;
|
||||
public readonly FutureContractImmutable future;
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using static bts.api.Security;
|
||||
|
||||
namespace bts.api {
|
||||
internal static class SecurityHelper {
|
||||
public static class SecurityHelper {
|
||||
public static IEnumerable<FutureLeg> get_flat_future_legs(SecurityImmutable sec) {
|
||||
switch (sec.ContractCase) {
|
||||
case ContractOneofCase.Spread: return _get_flat_future_legs(sec.Spread.Legs, 1);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace bts
|
||||
{
|
||||
public static class APIExtensions
|
||||
{
|
||||
public static T? TryFirst<T>(this IEnumerable<T> src) where T : struct
|
||||
{
|
||||
foreach (var v in src)
|
||||
return v;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,12 +32,15 @@ namespace bts {
|
||||
Testing,
|
||||
Latency,
|
||||
DataFlow,
|
||||
Plugin
|
||||
Plugin,
|
||||
ClientSdk,
|
||||
Fix
|
||||
// Please keep this list in sync with logging.h/logging.cpp
|
||||
}
|
||||
readonly struct Logger {
|
||||
|
||||
public readonly struct Logger {
|
||||
readonly Subsystem _sys;
|
||||
public Logger(Subsystem sys) {
|
||||
internal Logger(Subsystem sys) {
|
||||
_sys = sys;
|
||||
}
|
||||
|
||||
@@ -61,19 +64,21 @@ namespace bts {
|
||||
static extern void Logger_log (Level level, Subsystem subsystem, string message, string file, int line);
|
||||
}
|
||||
|
||||
static class Log {
|
||||
public static Logger Gen => new Logger(Subsystem.gen);
|
||||
public static Logger Config => new Logger(Subsystem.Config);
|
||||
public static Logger QBus => new Logger(Subsystem.QBus);
|
||||
public static Logger Md => new Logger(Subsystem.md);
|
||||
public static Logger Api => new Logger(Subsystem.Api);
|
||||
public static Logger Persist => new Logger(Subsystem.Persist);
|
||||
public static Logger User => new Logger(Subsystem.User);
|
||||
public static Logger OrderMan => new Logger(Subsystem.OrderMan);
|
||||
public static Logger Assert => new Logger(Subsystem.Assert);
|
||||
public static Logger Ui => new Logger(Subsystem.Ui);
|
||||
public static Logger Testing => new Logger(Subsystem.Testing);
|
||||
public static Logger DataFlow => new Logger(Subsystem.DataFlow);
|
||||
public static class Log {
|
||||
internal static Logger Gen => new Logger(Subsystem.gen);
|
||||
internal static Logger Config => new Logger(Subsystem.Config);
|
||||
internal static Logger QBus => new Logger(Subsystem.QBus);
|
||||
internal static Logger Md => new Logger(Subsystem.md);
|
||||
internal static Logger Api => new Logger(Subsystem.Api);
|
||||
internal static Logger Persist => new Logger(Subsystem.Persist);
|
||||
internal static Logger User => new Logger(Subsystem.User);
|
||||
internal static Logger OrderMan => new Logger(Subsystem.OrderMan);
|
||||
internal static Logger Assert => new Logger(Subsystem.Assert);
|
||||
internal static Logger Ui => new Logger(Subsystem.Ui);
|
||||
internal static Logger Testing => new Logger(Subsystem.Testing);
|
||||
internal static Logger DataFlow => new Logger(Subsystem.DataFlow);
|
||||
public static Logger ClientSdk => new Logger(Subsystem.ClientSdk);
|
||||
internal static Logger FIX => new Logger(Subsystem.Fix);
|
||||
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
@@ -99,10 +104,10 @@ namespace bts {
|
||||
assert(o == null);
|
||||
}
|
||||
delegate void on_crash_callback([MarshalAs(UnmanagedType.LPStr)]string msg, [MarshalAs(UnmanagedType.LPStr)] string details);
|
||||
public static void system_is_crashing(string message, object details) {
|
||||
internal static void system_is_crashing(string message, object details) {
|
||||
OnSystemCrashing?.Invoke(message, details);
|
||||
}
|
||||
public static event Action<string, object> OnSystemCrashing;
|
||||
internal static event Action<string, object> OnSystemCrashing;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -57,8 +58,23 @@ namespace bts.collections {
|
||||
_replace(node, item);
|
||||
return false;
|
||||
} else {
|
||||
node = _init_node(item);
|
||||
_insert_node(node);
|
||||
if (_nursery.TryPopValue(k, out SortedList<Node> children)) {
|
||||
// remove orphans from _tree (orphan-nodes must reside in the main _tree until parents arrive)
|
||||
foreach (var n in children)
|
||||
_tree.Remove(n);
|
||||
node = new Node(item, children);
|
||||
} else node = new Node(item, _comparer);
|
||||
var pk = parent(item);
|
||||
if (pk.Equals(_root_id))
|
||||
_tree.Add(node);
|
||||
else if (_index.TryGetValue(pk, out Node pnode))
|
||||
pnode.children.Add(node);
|
||||
else {
|
||||
if (!_nursery.TryGetValue(pk, out SortedList<Node> l))
|
||||
_nursery.Add(pk, l = new SortedList<Node>(_comparer));
|
||||
l.Add(node);
|
||||
_tree.Add(node);
|
||||
}
|
||||
_index.Add(k, node);
|
||||
return true;
|
||||
}
|
||||
@@ -93,7 +109,10 @@ namespace bts.collections {
|
||||
_remove_from_nursery(pk, node);
|
||||
}
|
||||
if (node.children.Count > 0) {
|
||||
// any children left behind are orphans now, add them to the main _tree and _nursery
|
||||
_nursery.Add(k, node.children);
|
||||
foreach (var n in node.children)
|
||||
_tree.Add(n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,17 +134,22 @@ namespace bts.collections {
|
||||
// We are sure it is in the index because we just added it
|
||||
var node = _index[id(item)];
|
||||
if (_nursery.TryPopValue(id(item), out SortedList<Node> nl)) {
|
||||
// remove orphans from _tree (orphan-nodes must reside in the main _tree until parents arrive)
|
||||
foreach (var n in nl)
|
||||
_tree.Remove(n);
|
||||
if (node.children.Count == 0) {
|
||||
node.children = nl;
|
||||
} else if (node.children.Count > nl.Count) {
|
||||
// merge nl into node.children
|
||||
foreach (var cn in nl)
|
||||
node.children.Add(cn);
|
||||
} else {
|
||||
// merge node.children into nl
|
||||
foreach (var cn in node.children)
|
||||
nl.Add(cn);
|
||||
node.children = nl;
|
||||
if (node.children.Count > nl.Count) {
|
||||
// merge nl into node.children
|
||||
foreach (var cn in nl)
|
||||
node.children.Add(cn);
|
||||
} else {
|
||||
// merge node.children into nl
|
||||
foreach (var cn in node.children)
|
||||
nl.Add(cn);
|
||||
node.children = nl;
|
||||
}
|
||||
}
|
||||
}
|
||||
TKey pk = parent(item);
|
||||
@@ -137,6 +161,7 @@ namespace bts.collections {
|
||||
if (!_nursery.TryGetValue(pk, out nl))
|
||||
_nursery.Add(pk, nl = new SortedList<Node>(_comparer));
|
||||
nl.Add(node);
|
||||
_tree.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +197,6 @@ namespace bts.collections {
|
||||
} else if (!_nursery.TryGetValue(pk, out node_list)) {
|
||||
throw new KeyNotFoundException($"Replace was called with a parent-key ({pk}) that was not found in _index or _nursery; item-key was ({id(newval)}).");
|
||||
}
|
||||
//var node_list = pk.Equals(_root_id) ? _tree : _index.TryGetValue(pk, out Node pnode) ? pnode.children : _nursery[pk];
|
||||
node_list.Remove(node);
|
||||
node.value = newval;
|
||||
node_list.Add(node);
|
||||
@@ -187,32 +211,24 @@ namespace bts.collections {
|
||||
}
|
||||
}
|
||||
node.value = newval;
|
||||
_insert_node(node);
|
||||
}
|
||||
}
|
||||
|
||||
Node _init_node(T item) =>
|
||||
_nursery.TryPopValue(id(item), out SortedList<Node> nursery_list) ? new Node(item, nursery_list) : new Node(item, _comparer);
|
||||
|
||||
/// <summary>
|
||||
/// Inserts the node into the appropriate SortedList (i.e. roots, parent.inner, or nursery), but does NOT add it to <see cref="_index"/>, NOR check the nursery for any child-nodes waiting on this item.
|
||||
/// </summary>
|
||||
void _insert_node(Node node) {
|
||||
TKey pk = parent(node.value);
|
||||
if (pk.Equals(_root_id)) {
|
||||
_tree.Add(node);
|
||||
} else if (_index.TryGetValue(pk, out Node pnode)) {
|
||||
pnode.children.Add(node);
|
||||
} else {
|
||||
if (!_nursery.TryGetValue(pk, out SortedList<Node> nursery_list)) {
|
||||
_nursery.Add(pk, nursery_list = new SortedList<Node>(_comparer));
|
||||
if (pk.Equals(_root_id)) {
|
||||
_tree.Add(node);
|
||||
} else if (_index.TryGetValue(pk, out Node pnode)) {
|
||||
pnode.children.Add(node);
|
||||
} else {
|
||||
if (!_nursery.TryGetValue(pk, out SortedList<Node> nursery_list)) {
|
||||
_nursery.Add(pk, nursery_list = new SortedList<Node>(_comparer));
|
||||
}
|
||||
nursery_list.Add(node);
|
||||
_tree.Add(node);
|
||||
}
|
||||
nursery_list.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
void _remove_from_nursery(TKey pk, Node node) =>
|
||||
void _remove_from_nursery(TKey pk, Node node) {
|
||||
_nursery.TryPopValueIf(pk, nl => nl.Remove(node) && nl.Count == 0);
|
||||
_tree.Remove(node);
|
||||
}
|
||||
|
||||
IEnumerable<T> iterate(SortedList<Node> nodes) {
|
||||
foreach (var n in nodes) {
|
||||
@@ -259,10 +275,6 @@ namespace bts.collections {
|
||||
public IEnumerator<T> GetEnumerator() {
|
||||
foreach (T item in iterate(_tree))
|
||||
yield return item;
|
||||
foreach (var kv in _nursery) {
|
||||
foreach (T item in iterate(kv.Value))
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
|
||||
Loaded 100 of 337 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user