Compare commits

..
68 Commits
Author SHA1 Message Date
John Colvin 3b320a1075 MDConsumerHandle - don't convert LLDateTimes to System.DateTimes 2018-09-17 12:55:54 -04:00
John Colvin e838413541 minor refactoring in DispatcherUpdateMaster 2018-09-17 11:42:17 -04:00
John Colvin 7d6d72b423 mview - perform update work in parallel with new DispatcherUpdateMaster 2018-09-16 17:17:43 -04:00
John Colvin 891d674ca4 overload MDConsumerHandle.get_last_trade to avoid creating unused timestamp via ll_to_parts 2018-09-16 14:54:32 -04:00
Taha Afzal 92c1508b8c Put the VolumeAtPrice behind a toggle config 2018-09-14 14:58:35 -04:00
Jake Norbut 466915f6e9 Updating MICS conf to use unquoted enum string rather than enum value 2018-09-14 13:57:37 -05:00
Pedro Pinto 1c68cfa08e Fixed clang warning. 2018-09-13 20:44:28 +00:00
Pedro Pinto cc75872c04 Fixed crashing bug in order plugin. 2018-09-13 20:28:48 +00:00
Pedro Pinto 7e93866596 Tweaks to metrics tools. 2018-09-13 20:28:48 +00:00
Taha Afzal f4213eefe9 fixing header inclusions 2018-09-13 16:26:06 -04:00
Taha Afzal 72bfafb376 Merge branch 'master' of bitbucket.org:bluetradesys/spark 2018-09-13 15:24:58 -04:00
Taha Afzal 5dbacfddd5 SPARK-1672(Volume at price) 2018-09-13 15:24:49 -04:00
Pedro Pinto e29ea5d89b SPARK-1514, Server side SDK code complete. 2018-09-12 18:43:17 +00:00
Eric Harding 2885d929a8 Safe me from my own mistyping 2018-09-11 15:19:10 -04:00
Eric Harding a3e5bc4fba Prune unused script from tools 2018-09-11 12:50:20 -04:00
Eric Harding 7944338516 add test watching script (linux) 2018-09-11 16:15:39 +00:00
Taha Afzal bb19f737d5 SPARK-1672 hooked up the timer for polling 2018-09-10 22:28:48 -04:00
John Colvin 77854a3cf0 SPARK-1714 Ladder account - unable to pick a selection on server restart 2018-09-10 18:56:41 -04:00
Taha Afzal d29ec26beb SPARK-1672 scaffolding 2018-09-10 15:11:18 -04:00
Michael Harding d64810e234 Merged in SPARK-1678 (pull request #72)
SPARK-1678
2018-09-10 17:44:43 +00:00
Taha Afzal f3d2c9e5b9 SPARK-1672 VAP initial check in 2018-09-10 12:39:22 -04:00
Eric Harding 63ac084a17 Merge branch 'prod' of bitbucket.org:bluetradesys/spark 2018-09-10 11:24:37 -04:00
Eric Harding 29f7c24a00 Merge branch 'prod' of bitbucket.org:bluetradesys/spark 2018-09-10 10:40:33 -04:00
Taha Afzal 58c298fed8 Changing the AdminService -> OrderService call to async 2018-09-10 10:18:05 -04:00
Taha Afzal ee825f76c7 SPARK-1696 completed 2018-09-09 21:27:54 -04:00
Taha Afzal dfb33efd45 SPARK-1696 util functions added 2018-09-09 11:00:51 -04:00
Taha Afzal dd7ebc54a2 Permissions functions in AminServiceUtils 2018-09-07 19:22:32 -04:00
Kevin Darby 8f99d8d9ca Merge branch 'master' of bitbucket.org:bluetradesys/spark 2018-09-07 17:37:57 -04:00
Kevin Darby c411a0c792 Merge branch 'order-def-templates' of bitbucket.org:bluetradesys/spark 2018-09-07 17:37:17 -04:00
Michael Harding bc8513778b Move Account controls into tab contents 2018-09-07 17:33:20 -04:00
Michael Harding 501dc37e94 F# type system is less resilient than it thinks it is 2018-09-07 17:17:42 -04:00
Michael Harding c58b5fb0e6 SPARK-1678: Cancel orders for account 2018-09-07 17:10:19 -04:00
Michael Harding f89f2b8ad0 Remove Beta from SparkAdmin 2018-09-07 17:10:18 -04:00
Pedro Pinto 5e3e85641d Merged from prod 2018-09-07 21:00:35 +00:00
John Colvin 4a5f71e7f2 fix build 2018-09-07 16:37:23 -04:00
Kevin Darby 92d7503528 cmake? 2018-09-07 16:18:46 -04:00
Kevin Darby 773f3db976 Merge branch 'prod' of bitbucket.org:bluetradesys/spark 2018-09-07 16:17:47 -04:00
Eric Harding dd5b489e8f SPARK-1659 Update producer api to handle implied markets (push early for emumba) 2018-09-07 09:29:41 -04:00
Taha Afzal 7bda1cc1cc Permissions proto and service member added 2018-09-06 21:51:10 -04:00
Eric Harding 58e88812b1 SPARK-1693 - Code quota reached. Have to delete some. 2018-09-06 13:54:02 -04:00
Eric Harding db80631901 Fix "some projects had trouble loading" in vscode 2018-09-06 12:21:05 -04:00
Taha Afzal 593944266d merging 2018-09-06 10:47:29 -04:00
Taha Afzal b8883fc8ae SPARK-1668 reporting stream is done 2018-09-06 10:31:33 -04:00
Taha Afzal efac4a6077 SPARK-1668 foundation 2018-09-06 10:31:33 -04:00
Jake Norbut cb22d21f70 Merged parsing_mics into master 2018-09-06 07:57:15 -05:00
Jake Norbut f6b17d9541 Merge branch 'master' of bitbucket.org:bluetradesys/spark into parsing_mics 2018-09-06 07:56:18 -05:00
Pedro Pinto 7a1298e015 Merge from QA 2018-09-05 18:36:49 -04:00
Jake Norbut 0a81521e6e changing to Taha's proto, not int32, silly man 2018-09-05 13:56:27 -05:00
Jake Norbut 8771281954 Updating script to parse and dump mics 2018-09-05 13:26:50 -05:00
Jake Norbut b50381d386 adding an unset enum state to CMEMics 2018-09-05 12:38:12 -05:00
Jake Norbut 91345cf9d2 renaming cpp_config proto and conf to cme_reference_data 2018-09-05 12:37:25 -05:00
Taha Afzal 19b3ba6615 SPARK-1668 MIC enums added 2018-09-05 12:41:03 -04:00
Taha Afzal 6b68029b6d adding comments to SPARK-1679 protos 2018-09-05 10:03:38 -04:00
Taha Afzal 15c8a8bf28 SPARK-1679 done ! 2018-09-05 09:55:05 -04:00
Taha Afzal 2b2fe02315 SPARK-1679 get_order_summary done 2018-09-04 22:13:25 -04:00
Taha Afzal 1f4c91a344 SPARK-1679 2018-09-04 10:37:45 -04:00
Taha Afzal 92f8f74d8f SPARK-1679 2018-09-04 08:51:50 -04:00
John Colvin ad2869ea6f OrderPropertiesEditor - use id and order-type to match selected orderdef in inlineprops 2018-09-02 13:06:29 -04:00
John Colvin 979506d5be OrderTemplateKey/Header - override ToString 2018-09-02 12:38:13 -04:00
John Colvin bc6e792855 SPARK-1684 ladder/ticket - infrastructure for order definition templates 2018-09-01 21:25:20 -04:00
Eric Harding 5df90f27c8 Update onixs license 2018-08-29 10:47:07 -04:00
Pedro Pinto d571642454 Removed test code from SDK example 2018-08-28 10:21:16 -04:00
Pedro Pinto 0695ddc33e Moved subrepo ptr 2018-08-28 13:24:08 +00:00
Pedro Pinto c97e7675fd Testing SDK 2018-08-28 13:20:56 +00:00
Pedro Pinto 526805680a Updated cmake files 2018-08-24 18:14:24 +00:00
Pedro Pinto 03e3549895 Merged 2018-08-24 13:56:35 -04:00
Pedro Pinto ebbc48771b Merge 2018-08-19 13:26:56 -04:00
Pedro Pinto 2d6fb5c15c cleaned up build 2018-08-19 17:24:40 +00:00
283 changed files with 7805 additions and 6998 deletions

No files matched your search

-1
View File
@@ -25,4 +25,3 @@ src/server/sparkd/orderman/perf_analysis/data
src/server/sparkd/orderman/perf_analysis/logs/
src/server/sparkd/orderman/perf_analysis/trace_data/
src/lib/orderman/perf_analysis/logs/latency_data/
trace_data/
+3 -1
View File
@@ -40,7 +40,7 @@ else ()
-fPIC -Wall -pedantic -Wextra -Werror \
-Wno-missing-braces -Wno-ignored-qualifiers \
--std=c++17 -fdiagnostics-color")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -DNDEBUG -O3")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -DNDEBUG -O3")
add_subdirectory(src/server/sparkd)
add_subdirectory(src/lib)
add_subdirectory(src/web)
@@ -54,6 +54,8 @@ else ()
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/web ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/data_files ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
COMMENT "Creating server runtime layout"
DEPENDS sparkd data_files_dir)
-301
View File
@@ -1,301 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<!-- 2018-10-08 Mon 18:50 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>&lrm;</title>
<meta name="generator" content="Org mode" />
<meta name="author" content="ppinto" />
<style type="text/css">
<!--/*--><![CDATA[/*><!--*/
.title { text-align: center;
margin-bottom: .2em; }
.subtitle { text-align: center;
font-size: medium;
font-weight: bold;
margin-top:0; }
.todo { font-family: monospace; color: red; }
.done { font-family: monospace; color: green; }
.priority { font-family: monospace; color: orange; }
.tag { background-color: #eee; font-family: monospace;
padding: 2px; font-size: 80%; font-weight: normal; }
.timestamp { color: #bebebe; }
.timestamp-kwd { color: #5f9ea0; }
.org-right { margin-left: auto; margin-right: 0px; text-align: right; }
.org-left { margin-left: 0px; margin-right: auto; text-align: left; }
.org-center { margin-left: auto; margin-right: auto; text-align: center; }
.underline { text-decoration: underline; }
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
p.verse { margin-left: 3%; }
pre {
border: 1px solid #ccc;
box-shadow: 3px 3px 3px #eee;
padding: 8pt;
font-family: monospace;
overflow: auto;
margin: 1.2em;
}
pre.src {
position: relative;
overflow: visible;
padding-top: 1.2em;
}
pre.src:before {
display: none;
position: absolute;
background-color: white;
top: -10px;
right: 10px;
padding: 3px;
border: 1px solid black;
}
pre.src:hover:before { display: inline;}
/* Languages per Org manual */
pre.src-asymptote:before { content: 'Asymptote'; }
pre.src-awk:before { content: 'Awk'; }
pre.src-C:before { content: 'C'; }
/* pre.src-C++ doesn't work in CSS */
pre.src-clojure:before { content: 'Clojure'; }
pre.src-css:before { content: 'CSS'; }
pre.src-D:before { content: 'D'; }
pre.src-ditaa:before { content: 'ditaa'; }
pre.src-dot:before { content: 'Graphviz'; }
pre.src-calc:before { content: 'Emacs Calc'; }
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
pre.src-fortran:before { content: 'Fortran'; }
pre.src-gnuplot:before { content: 'gnuplot'; }
pre.src-haskell:before { content: 'Haskell'; }
pre.src-hledger:before { content: 'hledger'; }
pre.src-java:before { content: 'Java'; }
pre.src-js:before { content: 'Javascript'; }
pre.src-latex:before { content: 'LaTeX'; }
pre.src-ledger:before { content: 'Ledger'; }
pre.src-lisp:before { content: 'Lisp'; }
pre.src-lilypond:before { content: 'Lilypond'; }
pre.src-lua:before { content: 'Lua'; }
pre.src-matlab:before { content: 'MATLAB'; }
pre.src-mscgen:before { content: 'Mscgen'; }
pre.src-ocaml:before { content: 'Objective Caml'; }
pre.src-octave:before { content: 'Octave'; }
pre.src-org:before { content: 'Org mode'; }
pre.src-oz:before { content: 'OZ'; }
pre.src-plantuml:before { content: 'Plantuml'; }
pre.src-processing:before { content: 'Processing.js'; }
pre.src-python:before { content: 'Python'; }
pre.src-R:before { content: 'R'; }
pre.src-ruby:before { content: 'Ruby'; }
pre.src-sass:before { content: 'Sass'; }
pre.src-scheme:before { content: 'Scheme'; }
pre.src-screen:before { content: 'Gnu Screen'; }
pre.src-sed:before { content: 'Sed'; }
pre.src-sh:before { content: 'shell'; }
pre.src-sql:before { content: 'SQL'; }
pre.src-sqlite:before { content: 'SQLite'; }
/* additional languages in org.el's org-babel-load-languages alist */
pre.src-forth:before { content: 'Forth'; }
pre.src-io:before { content: 'IO'; }
pre.src-J:before { content: 'J'; }
pre.src-makefile:before { content: 'Makefile'; }
pre.src-maxima:before { content: 'Maxima'; }
pre.src-perl:before { content: 'Perl'; }
pre.src-picolisp:before { content: 'Pico Lisp'; }
pre.src-scala:before { content: 'Scala'; }
pre.src-shell:before { content: 'Shell Script'; }
pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
/* additional language identifiers per "defun org-babel-execute"
in ob-*.el */
pre.src-cpp:before { content: 'C++'; }
pre.src-abc:before { content: 'ABC'; }
pre.src-coq:before { content: 'Coq'; }
pre.src-groovy:before { content: 'Groovy'; }
/* additional language identifiers from org-babel-shell-names in
ob-shell.el: ob-shell is the only babel language using a lambda to put
the execution function name together. */
pre.src-bash:before { content: 'bash'; }
pre.src-csh:before { content: 'csh'; }
pre.src-ash:before { content: 'ash'; }
pre.src-dash:before { content: 'dash'; }
pre.src-ksh:before { content: 'ksh'; }
pre.src-mksh:before { content: 'mksh'; }
pre.src-posh:before { content: 'posh'; }
/* Additional Emacs modes also supported by the LaTeX listings package */
pre.src-ada:before { content: 'Ada'; }
pre.src-asm:before { content: 'Assembler'; }
pre.src-caml:before { content: 'Caml'; }
pre.src-delphi:before { content: 'Delphi'; }
pre.src-html:before { content: 'HTML'; }
pre.src-idl:before { content: 'IDL'; }
pre.src-mercury:before { content: 'Mercury'; }
pre.src-metapost:before { content: 'MetaPost'; }
pre.src-modula-2:before { content: 'Modula-2'; }
pre.src-pascal:before { content: 'Pascal'; }
pre.src-ps:before { content: 'PostScript'; }
pre.src-prolog:before { content: 'Prolog'; }
pre.src-simula:before { content: 'Simula'; }
pre.src-tcl:before { content: 'tcl'; }
pre.src-tex:before { content: 'TeX'; }
pre.src-plain-tex:before { content: 'Plain TeX'; }
pre.src-verilog:before { content: 'Verilog'; }
pre.src-vhdl:before { content: 'VHDL'; }
pre.src-xml:before { content: 'XML'; }
pre.src-nxml:before { content: 'XML'; }
/* add a generic configuration mode; LaTeX export needs an additional
(add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
pre.src-conf:before { content: 'Configuration File'; }
table { border-collapse:collapse; }
caption.t-above { caption-side: top; }
caption.t-bottom { caption-side: bottom; }
td, th { vertical-align:top; }
th.org-right { text-align: center; }
th.org-left { text-align: center; }
th.org-center { text-align: center; }
td.org-right { text-align: right; }
td.org-left { text-align: left; }
td.org-center { text-align: center; }
dt { font-weight: bold; }
.footpara { display: inline; }
.footdef { margin-bottom: 1em; }
.figure { padding: 1em; }
.figure p { text-align: center; }
.inlinetask {
padding: 10px;
border: 2px solid gray;
margin: 10px;
background: #ffffcc;
}
#org-div-home-and-up
{ text-align: right; font-size: 70%; white-space: nowrap; }
textarea { overflow-x: auto; }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00; }
.org-info-js_info-navigation { border-style: none; }
#org-info-js_console-label
{ font-size: 10px; font-weight: bold; white-space: nowrap; }
.org-info-js_search-highlight
{ background-color: #ffff00; color: #000000; font-weight: bold; }
.org-svg { width: 90%; }
/*]]>*/-->
</style>
<script type="text/javascript">
/*
@licstart The following is the entire license notice for the
JavaScript code in this tag.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
The JavaScript code in this tag is free software: you can
redistribute it and/or modify it under the terms of the GNU
General Public License (GNU GPL) as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version. The code is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
As additional permission under GNU GPL version 3 section 7, you
may distribute non-source (e.g., minimized or compacted) forms of
that code without the copy of the GNU GPL normally required by
section 4, provided you include this license notice and a URL
through which recipients can access the Corresponding Source.
@licend The above is the entire license notice
for the JavaScript code in this tag.
*/
<!--/*--><![CDATA[/*><!--*/
function CodeHighlightOn(elem, id)
{
var target = document.getElementById(id);
if(null != target) {
elem.cacheClassElem = elem.className;
elem.cacheClassTarget = target.className;
target.className = "code-highlighted";
elem.className = "code-highlighted";
}
}
function CodeHighlightOff(elem, id)
{
var target = document.getElementById(id);
if(elem.cacheClassElem)
elem.className = elem.cacheClassElem;
if(elem.cacheClassTarget)
target.className = elem.cacheClassTarget;
}
/*]]>*///-->
</script>
</head>
<body>
<div id="content">
<p>
We are going to experiment with our development process, getting away
from cycles and towards more continuous development. The main idea is
to get rid of the prod and QA branches and instead deploy directly
from master, which we keep deployment ready at all times. Development
occurs on private branches, each branch mapped to a separately
deploy-able project. Each of projects will be managed more or less
independently and will include specification, development and
validation stages. At any particular time we might have anywhere from
1 to 6 projects in flight each of which continuously pulls from master,
but does not push back to master until the code is ready to be
deployed to production. The point at which a project is ready to be
deployed then takes roughly the place of the QA phase of our old cycle
mode. At this time, we will do a PR, and go through a series of
validation steps, to make sure the work meets our standards. This
validation includes:
</p>
<ul class="org-ul">
<li>Code Reviews</li>
<li>Acceptance Testing (including UI and business tests)</li>
<li>Automated System testing (to be developed)</li>
<li>A mini-qa, focused on the feature, by someone not directly involved
in its implementation</li>
<li>If possible, deployment to a beta customer.</li>
</ul>
<p>
Once these QA gates are passed, we will update the release notes, tag
a new version, integrate to master and then ideally immediately deploy
to a customer.
</p>
<p>
The main goal with this change is to reduce the latency from feature
specification to production roll out. We also hope to improve
throughput by making more efficient use of QA time and reducing idle
cycles. We expect people to participate in more than one project
depending on their area of expertise and work load. This does not mean
people will work on two things at the same time, rather that people
come into and leave projects as they free up and not when the project
starts or ends.
</p>
<p>
This new scheme will come into full effect when we finish 1.3
although to some degree 1.3 was already setup like this. At the
moment, we have 3 major projects, vap/settlments/implied, grid
settings and speed work, which are in branches of prod. We will merge
these back to prod and then master this week. We have 3 other projects
that are in master, the excel API, the server side SDK and the MIC
administration and enforcement components. These we hope to stabilize
as soon as possible so that we can merge them to prod and deploy them
along with the rest. Once we have all this, prod and master should be
identical and we will delete prod and operate exclusively out of
master. Please avoid committing anything new to master so we can
complete this transition as soon as possible.
</p>
<p>
Let me know if you have any question
</p>
</div>
<div id="postamble" class="status">
<p class="author">Author: ppinto</p>
<p class="date">Created: 2018-10-08 Mon 18:50</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
</body>
</html>
-55
View File
@@ -1,55 +0,0 @@
We are going to experiment with our development process, getting away
from cycles and towards more continuous development. The main idea is
to get rid of the prod and QA branches and instead deploy directly
from master, which we keep deployment ready at all times. Development
occurs on private branches, each branch mapped to a separately
deploy-able project. Each of projects will be managed more or less
independently and will include specification, development and
validation stages. At any particular time we might have anywhere from
1 to 6 projects in flight each of which continuously pulls from master,
but does not push back to master until the code is ready to be
deployed to production. The point at which a project is ready to be
deployed then takes roughly the place of the QA phase of our old cycle
mode. At this time, we will do a PR, and go through a series of
validation steps, to make sure the work meets our standards. This
validation includes:
- Code Reviews
- Acceptance Testing (including UI and business tests)
- Automated System testing (to be developed)
- A mini-qa, focused on the feature, by someone not directly involved
in its implementation
- If possible, deployment to a beta customer.
Once these QA gates are passed, we will update the release notes, tag
a new version, integrate to master and then ideally immediately deploy
to a customer.
The main goal with this change is to reduce the latency from feature
specification to production roll out. We also hope to improve
throughput by making more efficient use of QA time and reducing idle
cycles. We expect people to participate in more than one project
depending on their area of expertise and work load. This does not mean
people will work on two things at the same time, rather that people
come into and leave projects as they free up and not when the project
starts or ends.
This new scheme will come into full effect when we finish 1.3
although to some degree 1.3 was already setup like this. At the
moment, we have 3 major projects, vap/settlments/implied, grid
settings and speed work, which are in branches of prod. We will merge
these back to prod and then master this week. We have 3 other projects
that are in master, the excel API, the server side SDK and the MIC
administration and enforcement components. These we hope to stabilize
as soon as possible so that we can merge them to prod and deploy them
along with the rest. Once we have all this, prod and master should be
identical and we will delete prod and operate exclusively out of
master. Please avoid committing anything new to master so we can
complete this transition as soon as possible.
Let me know if you have any question
-9
View File
@@ -1,12 +1,3 @@
1.3.1
- Improved server side logging
- Fixed leaking of market data subscriptions on market view form closing
1.3.0
- Significantly improved order execution latency
- Added latency monitoring tools
- Provided core binding controls to system admins so as to reduce latency jitter
1.1.22
- Orderbook: Orders in Error status can now be recreated
- Orderbook: Orders containing child orders will now be collapsed by default.
+59 -55
View File
@@ -4,7 +4,7 @@ VisualStudioVersion = 15.0.27130.2024
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
EndProject
@@ -12,11 +12,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\spar
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{9AD1A867-93A9-301D-BF77-0113E18E9E39}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
ProjectSection(ProjectDependencies) = postProject
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3} = {8530E0E8-3768-37EC-B1E1-8248C5A92FE3}
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C} = {69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
@@ -57,22 +57,22 @@ Global
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.Build.0 = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|Any CPU.ActiveCfg = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x64.ActiveCfg = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x64.Build.0 = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x86.ActiveCfg = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|Any CPU.ActiveCfg = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x64.ActiveCfg = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x64.Build.0 = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x86.ActiveCfg = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|Any CPU.ActiveCfg = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x64.ActiveCfg = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x64.Build.0 = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x86.ActiveCfg = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|Any CPU.ActiveCfg = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x64.ActiveCfg = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x64.Build.0 = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x86.ActiveCfg = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|Any CPU.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
@@ -93,26 +93,30 @@ Global
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|Any CPU.ActiveCfg = Debug|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
@@ -133,22 +137,22 @@ Global
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.Build.0 = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|Any CPU.ActiveCfg = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x64.ActiveCfg = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x64.Build.0 = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x86.ActiveCfg = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|Any CPU.ActiveCfg = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x64.ActiveCfg = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x64.Build.0 = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x86.ActiveCfg = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|Any CPU.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.Build.0 = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x86.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|Any CPU.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.Build.0 = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x86.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|Any CPU.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
@@ -5,11 +5,9 @@ using mbts.collections;
using mbts.spark.utilities;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.settings;
using mbts.ui.spark;
using mbts.ui.utility;
using mbts.utils;
using bts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -18,7 +16,6 @@ using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
namespace mbts.spark {
partial class MarketViewVM {
public class Row : SecurityMDRow, IDisposable, IEquatable<Row>, DIYGrid.IRowVM, DIYGrid.IActionableRowVM {
@@ -78,16 +75,29 @@ namespace mbts.spark {
ask_price_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.Ask));
ask_size_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.AskSize));
working_asks_click = new DelegateCommand(() => _show_order_book(MarketViewView.Columns.WorkingAsks));
_position.value_set += position_value_set;
_inside_bids.value_set += inside_bids_value_set;
_inside_asks.value_set += inside_asks_value_set;
_day_change.Changed += day_change_Changed;
_animation.AnimationsChanged += on_animations_changed;
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
_dispose = Disposable.Create(
_orders_model.on_security_root_orders(security.Id).OnDispatcher().Subscribe(_on_orders),
_position.OnDispatcher().Subscribe(v => _animation.animate_position(v.newval > v.oldval)),
_inside_bids.OnDispatcher().Subscribe(v => _animation.animate_working_bids_inside(v.newval)),
_inside_asks.OnDispatcher().Subscribe(v => _animation.animate_working_asks_inside(v.newval)),
_day_change.OnDispatcher().Subscribe(v => _animation.animate_day_change(v.newval > v.oldval)),
Disposable.Create(() => _animation.AnimationsChanged -= on_animations_changed)
Disposable.Create(() => {
_position.value_set -= position_value_set;
_inside_bids.value_set -= inside_bids_value_set;
_inside_asks.value_set -= inside_asks_value_set;
_day_change.Changed -= day_change_Changed;
_animation.AnimationsChanged -= on_animations_changed;
})
);
void position_value_set((int oldval, int newval) v) => _animation.animate_position(v.newval > v.oldval);
void inside_bids_value_set((bool oldval, bool newval) v) => _animation.animate_working_bids_inside(v.newval);
void inside_asks_value_set((bool oldval, bool newval) v) => _animation.animate_working_asks_inside(v.newval);
void day_change_Changed(double oldval, double newval) => _animation.animate_day_change(newval > oldval);
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
}
public event Action invalidated;
@@ -129,27 +139,52 @@ namespace mbts.spark {
public void raise_invalidated() => invalidated?.Invoke();
public void refresh() {
/// <summary>
/// Returns a list of IDisposable 'update jobs.' Each item represents a job that will be executed when disposed; all jobs should be executed on the dispatcher thread.
/// </summary>
// Note: not guarenteed to be on the dispatcher thread, so all view-notifying actions should be wrapped in a IDisposable.
// Having said that, perform as much work as possible locally.
public List<IDisposable> refresh() {
var update_jobs = new List<IDisposable>();
bool dirty = false;
if (md.md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
_bid_price.set(b.price);
_bid_size.set(b.size);
_ask_price.set(a.price);
_ask_size.set(a.size);
_inside_bids.on_next_distinct(_bid_price.Value >= _working_best_bid.value, ref dirty);
_inside_asks.on_next_distinct(_ask_price.Value <= _working_best_ask.value, ref dirty);
prop_job(_bid_price, b.price);
prop_job(_bid_size, b.size);
prop_job(_ask_price, a.price);
prop_job(_ask_size, a.size);
cell_prop_job(_inside_bids, b.price >= _working_best_bid.value);
cell_prop_job(_inside_asks, a.price >= _working_best_ask.value);
}
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
_last_price.set(ps.price);
_last_size.on_next_distinct(ps.size, ref dirty);
_volume.on_next_distinct(v, ref dirty);
double new_last_price = last_price;
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
new_last_price = ps.price;
prop_job(_last_price, new_last_price);
cell_prop_job(_last_size, ps.size);
cell_prop_job(_volume, v);
}
double new_settlement = md.md.settlement_price;
prop_job(_settlement, new_settlement);
prop_job(_session_low, md.md.session_low);
prop_job(_session_high, md.md.session_high);
prop_job(_day_change, new_last_price - new_settlement);
if (dirty) {
update_jobs.Add(Disposable.Create(() => {
invalidated?.Invoke();
}));
}
return update_jobs;
void prop_job<T>(Property<T> p, T newval) {
var uj = p.set_as_job(newval);
if (uj != null)
update_jobs.Add(uj);
}
void cell_prop_job<T>(CellProperty<T> p, T newval) {
var uj = p.on_next_distinct_as_job(newval, ref dirty);
if (uj != null)
update_jobs.Add(uj);
}
_settlement.set(md.md.settlement_price);
_session_low.set(md.md.session_low);
_session_high.set(md.md.session_high);
_day_change.set(last_price - settlement);
if (dirty)
invalidated?.Invoke();
}
public bool Equals(Row other) =>
@@ -3,10 +3,13 @@ using mbts.spark.filters;
using mbts.ui;
using mbts.ui.utility;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media;
using static bts.shell.MarketViewWindowFactory;
@@ -14,7 +17,7 @@ using static mbts.ui.controls.DIYGrid;
using static mbts.ui.spark.MarketViewView;
namespace mbts.spark {
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD> {
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD>, IPrepareUpdateForDispatcher {
readonly IBus _bus;
readonly OrdersModel _orders_model;
@@ -112,8 +115,7 @@ namespace mbts.spark {
}), DataGridFilterHelper.hook_filters(rows_view,
security_filter, bid_price_filter, bid_size_filter, ask_price_filter, ask_size_filter, last_price_filter, last_size_filter, day_change_filter, settlement_filter,
session_low_filter, session_high_filter, position_filter, working_bid_volume_filter, working_ask_volume_filter, volume_filter, security_key_filter),
securities_connectable.Connect(),
WorkLoop.Start("MarketView", _refresh)
securities_connectable.Connect()
);
}
@@ -159,6 +161,25 @@ namespace mbts.spark {
}
#endregion
public IDisposable prepare_update() {
ConcurrentBag<List<IDisposable>> to_update = new ConcurrentBag<List<IDisposable>>();
try {
Parallel.For(0, _row_vms.Count, i => {
var r = _row_vms[i];
var update_jobs = r.refresh();
if (update_jobs.Count > 0)
to_update.Add(update_jobs);
});
} catch (IndexOutOfRangeException) {
// since rows (securities) will only be added/removed through rare user intervention,
// it is worth catching the occassional exception in exchange for lock-free code.
// if a row misses an update, or gets updated more than once, that's okay too;
// in 100ms it will tick again, so the data should never be more than a few 100 ms old, and rarely older than 100.
}
// return null, rather than an empty IDisposable; this signals to the UpdateMaster that it may skip the call to Dispatcher.InvokeAsync() as there is nothing to dispose.
return to_update.Count == 0 ? null : Disposable.Create(() => to_update.SelectMany(_ => _).DisposeAll());
}
protected override Row row_factory(SecurityMD smd) => new Row(_bus, smd, _orders_model);
protected override void on_row_removed(Row row) => row.Dispose();
protected override IEnumerable<SortingCriteria> get_default_sorting() { yield return new SortingCriteria(nameof(Row.security), true); }
@@ -167,4 +188,4 @@ namespace mbts.spark {
foreach (var r in _row_vms) r.refresh();
}
}
}
}
@@ -14,16 +14,18 @@ using System.Windows;
namespace mbts.spark {
class MarketViewWindow : SparkWindow<MarketViewWindowFactory.StartupData>, ISharedWindow {
const string _window_type = "MarketView", _thread_id = "MarketView", _window_type_display_name = "Market View";
readonly DispatcherUpdateMaster _dispatcher_update_master;
readonly OrdersModel _orders_model;
readonly AllowOnce _init_guard = new AllowOnce("MarketView");
MarketViewVM _vm;
MarketViewView _view;
MarketViewWindowFactory.StartupData _state;
IReadOnlyList<SparkCommand> _commands;
IDisposable _subscriptions;
IDisposable _resources;
public MarketViewWindow(MarketViewWindowFactory factory, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
public MarketViewWindow(MarketViewWindowFactory factory, DispatcherUpdateMaster dispatcher_update_master, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
: base("Market View", bus, factory, SparkCommands.ShowMarketView.icon) {
_dispatcher_update_master = dispatcher_update_master;
_orders_model = orders_model;
_state = state;
Icon.Freeze();
@@ -57,12 +59,14 @@ namespace mbts.spark {
SparkCommands.ShowSyntheticCreate.complete(_vm.selected_securities_observable(), secs => secs.Count > 0 && secs.Count <= 24, secs => new SecurityCriteria(secs)),
SparkCommands.change_securities_command(() => (update_securities_cmd, _state.security_criteria))
};
_subscriptions = _bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(c =>
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states())));
_resources = Disposable.Create(
_bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(
c => _state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states()))),
_dispatcher_update_master.attach(_vm));
}
public override void Dispose() {
Disposable.dispose(ref _subscriptions);
Disposable.dispose(ref _resources);
_vm.Dispose();
Commands.OfType<IDisposable>().DisposeAll();
}
@@ -12,6 +12,7 @@ namespace bts.shell {
class MarketViewWindowFactory : ShellWindowFactory<MarketViewWindowFactory.StartupData> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
readonly DispatcherUpdateMaster _dispatcher_update_master = new DispatcherUpdateMaster("MarketView DispatcherUpdateMaster");
public MarketViewWindowFactory(MarketShellModule module, IBus bus, OrdersModel orders_model) : base(module, "MarketView") {
_bus = bus;
@@ -25,7 +26,7 @@ namespace bts.shell {
void _show(SecurityCriteria criteria) =>
_bus.post(SparkTags.ShowWindow, _create(new StartupData(criteria, new List<SortingCriteria> { new SortingCriteria(nameof(MarketViewVM.Row.security), true) }, null)));
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _bus, _orders_model, state);
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _dispatcher_update_master, _bus, _orders_model, state);
[ProtoContract]
public class StartupData {
@@ -121,7 +121,7 @@ namespace mbts.spark {
public Row(TimeAndSalesVM parent, SecurityImmutable security, TradeMessageImmutable trade) : base(security) {
_trade_key = trade.Key;
time = ((ulong)trade.Time).lldatetime().ToLocalTime();
time = trade.Time.lldatetime();
price = trade.Mantissa * Math.Pow(10, trade.Exponent);
size = trade.Size;
aggressor_side = trade.AggressorSide;
@@ -1,6 +1,7 @@
using bts;
using bts.api;
using bts.api.orderman;
using bts.utils;
using mbts.ui;
using mbts.ui.shell;
using System;
@@ -11,6 +12,60 @@ using System.Linq;
using System.Reactive.Linq;
namespace mbts.spark {
struct OrderTemplateKey : IEquatable<OrderTemplateKey> {
public readonly CustomOrderDefinition.CustomOneofCase type;
public readonly string name;
public OrderTemplateKey(CustomOrderDefinition.CustomOneofCase type)
: this(type, OrderUtils.order_type_display_name(type)) { }
public OrderTemplateKey(CustomOrderDefinition.CustomOneofCase type, string name) {
this.type = type;
this.name = name;
}
public bool Equals(OrderTemplateKey other) =>
type == other.type &&
name == other.name;
public override bool Equals(object obj) =>
obj is OrderTemplateKey other && Equals(other);
public override int GetHashCode() =>
EqualityComparer.aggregate_hash(
type.GetHashCode(),
name == null ? 0 : name.GetHashCode());
public override string ToString() => $"{name}:{type}";
public static bool operator ==(OrderTemplateKey a, OrderTemplateKey b) => a.Equals(b);
public static bool operator !=(OrderTemplateKey a, OrderTemplateKey b) => !a.Equals(b);
}
struct OrderTemplateHeader : IEquatable<OrderTemplateHeader> {
public readonly OrderTemplateKey key;
// Note: display_name is NOT part of EQUALITY
public readonly string display_name;
public OrderTemplateHeader(CustomOrderDefinition.CustomOneofCase type)
: this(new OrderTemplateKey(type), OrderUtils.order_type_display_name(type)) { }
public OrderTemplateHeader(OrderTemplateKey key, string display_name) {
this.key = key;
this.display_name = display_name;
}
public bool Equals(OrderTemplateHeader other) =>
key.Equals(other.key);
public override bool Equals(object obj) =>
obj is OrderTemplateHeader other && Equals(other);
public override int GetHashCode() => key.GetHashCode();
public override string ToString() => $"{display_name} ({key})";
}
class InlineOrderProperties {
public readonly InlineUserProperty<AccountTuple> account;
public readonly InlineUserProperty<TimeInForce> time_in_force;
@@ -39,7 +94,7 @@ namespace mbts.spark {
class OrderPropertiesEditorVM : DisposableViewModelBase {
readonly OrdersModel _model;
readonly Property<SecurityImmutable> _security;
readonly SelectorProperty<AccountTuple> _accounts;
readonly SelectorProperty<AccountTuple, AccountTuple?> _accounts;
readonly SelectorProperty<TimeInForce> _time_in_force;
readonly SelectorProperty<IOrderTypeVM> _order_type;
IDisposable _order_type_param_errors_sub;
@@ -58,14 +113,21 @@ namespace mbts.spark {
nameof(selected_account),
model.factory.subscribe_account_tuples(),
order_properties.Select(ops => ops.account),
() => accounts?.FirstOrDefault() ?? default,
val => (!string.IsNullOrWhiteSpace(val.name) && accounts.Contains(val), "Please select an account"));
a => new AccountTuple?(a),
() => {
foreach (var a in accounts) {
return a;
}
return new AccountTuple?();
},
EqualityComparer<AccountTuple?>.Default,
new[] { new PropertyValidation<AccountTuple?>(a => (a.HasValue && !string.IsNullOrWhiteSpace(a.Value.name) && accounts.Contains(a.Value), "Please select an account")) }.ToReadOnlyList());
_order_type = backing(
nameof(selected_order_type),
security_source.Select(s => model.factory.default_order_type_defs(s).Select(create_order_type_vm)),
security_source.Select(s => model.factory.default_order_type_templates(s).Select(kv => create_order_type_vm(kv.Value, kv.Key.key.name, kv.Key.display_name))),
order_properties.Select(get_order_type_vm_prop),
get_default_order_type_vm,
(a, b) => a.order_type == b.order_type);
EqualityComparer.null_check_wrapper(OrderTypeVMExtensions.key_comparer));
_order_type.Changed += on_selected_order_type_changed;
_time_in_force = backing(
nameof(selected_time_in_force),
@@ -77,19 +139,22 @@ namespace mbts.spark {
tif => time_in_forces.Contains(tif));
_dispose = Disposable.Create(() => _order_type.Changed -= on_selected_order_type_changed);
// local methods
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable cd) {
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable cd, string id, string display_name) {
IOrderTypeVM vm = null;
if(cd.CustomCase == CustomOrderDefinition.CustomOneofCase.Dynamic)
vm = OrderTypeVMFactory.create(cd.CustomCase, model, security_md_source, cd.Dynamic.DynamicOrderType);
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source, cd.Dynamic.DynamicOrderType);
else
vm = OrderTypeVMFactory.create(cd.CustomCase, model, security_md_source);
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source);
vm.load_from(cd);
return vm;
}
InlineUserProperty<IOrderTypeVM> get_order_type_vm_prop(InlineOrderProperties p) {
if (!p.order_type_def.has_value)
return new InlineUserProperty<IOrderTypeVM>();
return new InlineUserProperty<IOrderTypeVM>(create_order_type_vm(p.order_type_def.value), p.order_type_def.force_override);
return new InlineUserProperty<IOrderTypeVM>(
create_order_type_vm(p.order_type_def.value, p.order_type_def.value.CustomCase.ToString(),
OrderUtils.order_type_display_name(p.order_type_def.value.CustomCase)),
p.order_type_def.force_override);
}
IOrderTypeVM get_default_order_type_vm() {
var ot = model.factory.default_order_type(security);
@@ -114,13 +179,13 @@ namespace mbts.spark {
public SecurityImmutable security => _security.Value;
public ReadOnlyObservableCollection<AccountTuple> accounts => _accounts.items;
public AccountTuple selected_account { get => _accounts.selected_item; set => _accounts.selected_item = value; }
public AccountTuple? selected_account { get => _accounts.selected_item; set => _accounts.selected_item = value; }
public ReadOnlyObservableCollection<TimeInForce> time_in_forces => _time_in_force.items;
public TimeInForce selected_time_in_force { get => _time_in_force.selected_item; set => _time_in_force.selected_item = value; }
public ReadOnlyObservableCollection<IOrderTypeVM> order_types => _order_type.items;
public IOrderTypeVM selected_order_type { get => _order_type.selected_item; set => _order_type.selected_item = value; }
public IObservable<AccountTuple> observe_account(bool start_immediately = false) =>
public IObservable<AccountTuple?> observe_account(bool start_immediately = false) =>
_accounts.observe_current(start_immediately);
public IObservable<TimeInForce> observe_time_in_force(bool start_immediately = false) =>
@@ -17,22 +17,22 @@ namespace mbts.spark
{
class InlineCoverOrderProperties
{
public InlineCoverOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
public InlineCoverOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
var hedgetype = CustomOneofCase.Limit;
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
hedge_ticks = new InlineUserProperty<int>(1, false);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_hedge_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> hedge_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_hedge_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> hedge_order_types;
public readonly InlineUserProperty<int> hedge_ticks;
@@ -42,25 +42,25 @@ namespace mbts.spark
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineCoverOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _hedge_order_choices;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
IOrderTypeVM _hedge_order;
IDisposable _hedge_order_errors_sub;
public int hedge_ticks { get; set; } = 1;
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineCoverOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
new InlineCoverOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name)
{ }
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineCoverOrderProperties> inline_properties) : base(model)
IObservable<InlineCoverOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -75,11 +75,11 @@ namespace mbts.spark
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
{
_select_hedge_order(p.selected_hedge_order_type.value);
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
}
if (p.hedge_ticks.force_override)
{
@@ -116,7 +116,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
@@ -126,7 +126,7 @@ namespace mbts.spark
get
{
if (_hedge_order_choices == null)
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _hedge_order_choices;
}
}
@@ -200,7 +200,7 @@ namespace mbts.spark
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -216,7 +216,7 @@ namespace mbts.spark
void _select_hedge_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_hedge_order_type.has_value ?
_inline_props.selected_hedge_order_type.value :
_inline_props.selected_hedge_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_hedge_order(ot);
}
@@ -20,23 +20,23 @@ namespace mbts.spark
public static void add_dynamic_order_defs(List<CustomOrderDefinitionImmutable> defs,
Func<CustomOrderDefinition.CustomOneofCase, CustomOrderDefinition> factory)
{
var dyntypes = _list.Value;
foreach (var d in dyntypes.dynamic_orders)
{
var dorder = factory(CustomOrderDefinition.CustomOneofCase.Dynamic);
dorder.Dynamic.DynamicOrderType = d.type_name;
foreach (var p in d.parameter_keys)
dorder.Dynamic.Parameters.Add(p, string.Empty);
defs.Add(new CustomOrderDefinitionImmutable(dorder));
}
// var dyntypes = _list.Value;
// foreach (var d in dyntypes.dynamic_orders)
// {
// var dorder = factory(CustomOrderDefinition.CustomOneofCase.Dynamic);
// dorder.Dynamic.DynamicOrderType = d.type_name;
// foreach (var p in d.parameter_keys)
// dorder.Dynamic.Parameters.Add(p, string.Empty);
// defs.Add(new CustomOrderDefinitionImmutable(dorder));
// }
}
internal static List<NameValueVM> get_parameters(string dyntype)
{
List<NameValueVM> par = new List<NameValueVM>();
var order = _list.Value.dynamic_orders.FirstOrDefault(x => x.type_name == dyntype);
if (order != null)
par.AddRange(order.parameter_keys.Select(x => new NameValueVM() { name = x, value = string.Empty }));
// var order = _list.Value.dynamic_orders.FirstOrDefault(x => x.type_name == dyntype);
// if (order != null)
// par.AddRange(order.parameter_keys.Select(x => new NameValueVM() { name = x, value = string.Empty }));
return par;
}
}
@@ -53,14 +53,14 @@ namespace mbts.spark
{
class InlineDynamicOrderProperties
{
public InlineDynamicOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
public InlineDynamicOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
}
class DynamicOrderVM : OrderTypeVMBase<DynamicOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
@@ -68,8 +68,8 @@ namespace mbts.spark
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineDynamicOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
@@ -77,13 +77,13 @@ namespace mbts.spark
string _dyn_type;
List<NameValueVM> _parameters;
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type)
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type, string id, string display_name)
: this(model, security_md_source, dyn_type, security_md_source.Select(smd =>
new InlineDynamicOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
new InlineDynamicOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name)
{ }
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type,
IObservable<InlineDynamicOrderProperties> inline_properties) : base(model)
IObservable<InlineDynamicOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dyn_type = dyn_type;
@@ -100,7 +100,7 @@ namespace mbts.spark
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
_inline_props = p;
_validate();
@@ -115,17 +115,17 @@ namespace mbts.spark
public override void assign_to(CustomOrderDefinition value)
{
if (_child_order == null)
_select_child_order(model.factory.default_order_type(_security.Value, true));
_validate();
if (!HasErrors)
{
var i = factory.dynamic_order();
i.DynamicOrderType = _dyn_type;
set_parameter_dictionary(i.Parameters);
child_order.assign_to(i.Child);
value.Dynamic = i;
}
// if (_child_order == null)
// _select_child_order(model.factory.default_order_type(_security.Value, true));
// _validate();
// if (!HasErrors)
// {
// var i = factory.dynamic_order();
// i.DynamicOrderType = _dyn_type;
// set_parameter_dictionary(i.Parameters);
// child_order.assign_to(i.Child);
// value.Dynamic = i;
// }
}
void set_parameter_dictionary(Google.Protobuf.Collections.MapField<string, string> par)
@@ -139,7 +139,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
@@ -185,7 +185,7 @@ namespace mbts.spark
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -208,4 +208,4 @@ namespace mbts.spark
}
}
}
}
}
@@ -1,11 +1,13 @@
using bts.api.orderman;
using bts.spark;
using bts.utils;
using System.Collections.Generic;
using System.Windows.Input;
using static bts.api.orderman.CustomOrderDefinition;
namespace mbts.spark {
interface IOrderTypeVM : IPropertyWrapperVM<CustomOrderDefinition, CustomOrderDefinitionImmutable> {
string id { get; }
CustomOneofCase order_type { get; }
string type_name { get; }
bool is_bts_type { get; }
@@ -21,4 +23,12 @@ namespace mbts.spark {
ICollection<IOrderTypeVM> child_order_types { get; }
IOrderTypeVM child_order { get; }
}
static class OrderTypeVMExtensions {
public static IEqualityComparer<IOrderTypeVM> key_comparer =>
EqualityComparer.Create<IOrderTypeVM, OrderTemplateKey>(a => a.key());
public static OrderTemplateKey key(this IOrderTypeVM vm) =>
new OrderTemplateKey(vm.order_type, vm.id);
}
}
@@ -14,34 +14,34 @@ using static bts.api.orderman.CustomOrderDefinition;
namespace mbts.spark {
static partial class OrderTypeVMFactory {
class InlineIcebergOrderProperties {
public InlineIcebergOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types) {
public InlineIcebergOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
show_quantity = new InlineUserProperty<double>(1, true);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<double> show_quantity;
}
class IcebergOrderVM : OrderTypeVMBase<IcebergOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable {
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineIcebergOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
public IcebergOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public IcebergOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineIcebergOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
new InlineIcebergOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
public IcebergOrderVM(OrdersModel model,
IObservable<SecurityMD> security_md_source,
IObservable<InlineIcebergOrderProperties> inline_properties)
: base(model) {
IObservable<InlineIcebergOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_md_source.OnDispatcher()
@@ -52,7 +52,7 @@ namespace mbts.spark {
_order_types.SetItems(p.child_order_types.value);
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override)) {
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (p.show_quantity.force_override) {
show_quantity = p.show_quantity.value;
@@ -68,7 +68,7 @@ namespace mbts.spark {
public ICollection<IOrderTypeVM> child_order_types {
get {
if (_child_order_choices == null) {
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
}
return _child_order_choices;
}
@@ -122,7 +122,7 @@ namespace mbts.spark {
void _select_child_order() {
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -17,19 +17,19 @@ namespace mbts.spark
{
class InlineJoinOrderProperties
{
public InlineJoinOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
public InlineJoinOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
var hedgetype = CustomOneofCase.Lean;
if(!child_order_types.Contains(hedgetype))
if(!child_order_types.Any(t => t.key.type == hedgetype))
hedgetype = CustomOneofCase.Limit;
//ExceptionAssert.InvalidOperation.That(child_order_types.Contains(hedgetype), $"Hedge order type {hedgetype} is not in hedge_order_types");
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
tick_offset_on_deploy = new InlineUserProperty<uint>(0, false);
join_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
@@ -37,10 +37,10 @@ namespace mbts.spark
enable_hedge = new InlineUserProperty<bool>(false, false);
hedge_ticks = new InlineUserProperty<int>(1, false);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_hedge_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> hedge_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_hedge_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> hedge_order_types;
public readonly InlineUserProperty<uint> tick_offset_on_deploy;
@@ -55,13 +55,13 @@ namespace mbts.spark
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineJoinOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _hedge_order_choices;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
IOrderTypeVM _hedge_order;
IDisposable _hedge_order_errors_sub;
@@ -79,12 +79,12 @@ namespace mbts.spark
}
public int hedge_ticks { get; set; } = 1;
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineJoinOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
new InlineJoinOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineJoinOrderProperties> inline_properties) : base(model)
IObservable<InlineJoinOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -98,11 +98,11 @@ namespace mbts.spark
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
{
_select_hedge_order(p.selected_hedge_order_type.value);
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
}
if (p.tick_offset_on_deploy.force_override)
{
@@ -157,7 +157,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
@@ -167,7 +167,7 @@ namespace mbts.spark
get
{
if (_hedge_order_choices == null)
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _hedge_order_choices;
}
}
@@ -241,7 +241,7 @@ namespace mbts.spark
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -257,7 +257,7 @@ namespace mbts.spark
void _select_hedge_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_hedge_order_type.has_value ?
_inline_props.selected_hedge_order_type.value :
_inline_props.selected_hedge_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_hedge_order(ot);
}
@@ -17,44 +17,41 @@ namespace mbts.spark
{
class InlineLeanOrderProperties
{
public InlineLeanOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
public InlineLeanOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
max_chase_ticks = new InlineUserProperty<uint>(10, false);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<bts.spark.QuantityMeasure> cross_threshold;
public readonly InlineUserProperty<uint> max_chase_ticks;
public readonly InlineUserProperty<LeanOrderDefinition.Types.OnToward> trade_toward_behavior;
}
class LeanOrderVM : OrderTypeVMBase<LeanOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineLeanOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
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 uint max_chase_ticks { get; set; } = 10;
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineLeanOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
new InlineLeanOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineLeanOrderProperties> inline_properties) : base(model)
IObservable<InlineLeanOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -68,7 +65,7 @@ namespace mbts.spark
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (p.cross_threshold.force_override)
{
@@ -80,11 +77,6 @@ namespace mbts.spark
max_chase_ticks = p.max_chase_ticks.value;
RaisePropertyChanged(nameof(max_chase_ticks));
}
if (p.trade_toward_behavior.force_override)
{
trade_toward_behavior = p.trade_toward_behavior.value;
RaisePropertyChanged(nameof(trade_toward_behavior));
}
_inline_props = p;
_validate();
})
@@ -102,20 +94,17 @@ namespace mbts.spark
var i = factory.lean_order();
i.CrossThreshold = cross_threshold;
i.MaxChaseTicks = max_chase_ticks;
i.TradeTowardBehavior = trade_toward_behavior;
child_order.assign_to(i.Child);
value.Lean = i;
}
}
public IEnumerable<LeanOrderDefinition.Types.OnToward> trade_toward_types => EnumHelper.get_values_except<LeanOrderDefinition.Types.OnToward>();
}
public ICollection<IOrderTypeVM> child_order_types
{
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
@@ -161,7 +150,7 @@ namespace mbts.spark
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -3,7 +3,7 @@
namespace mbts.spark {
static partial class OrderTypeVMFactory {
private class LimitOrderVM : OrderTypeVMBase<LimitOrderDefinition> {
internal LimitOrderVM(OrdersModel model) : base(model) { }
internal LimitOrderVM(OrdersModel model) : base(model, "Limit", OrderUtils.order_type_display_name(CustomOrderDefinition.CustomOneofCase.Limit)) { }
public override void assign_to(CustomOrderDefinition value) =>
value.Limit = factory.limit_order();
@@ -3,7 +3,7 @@
namespace mbts.spark {
static partial class OrderTypeVMFactory {
private class MarketOrderVM : OrderTypeVMBase<MarketOrderDefinition> {
internal MarketOrderVM(OrdersModel model) : base(model) { }
internal MarketOrderVM(OrdersModel model) : base(model, "Market", OrderUtils.order_type_display_name(CustomOrderDefinition.CustomOneofCase.Market)) { }
public override void assign_to(CustomOrderDefinition parent) =>
parent.Market = factory.market_order();
@@ -12,36 +12,36 @@ namespace mbts.spark {
static partial class OrderTypeVMFactory {
public static IOrderTypeVM market(OrdersModel model) => new MarketOrderVM(model);
public static IOrderTypeVM limit(OrdersModel model) => new LimitOrderVM(model);
public static IOrderTypeVM stop(OrdersModel model) => new StopOrderVM(model);
public static IOrderTypeVM stop_limit(OrdersModel model, IObservable<SecurityMD> security_md_source) => new StopLimitOrderVM(model, security_md_source);
public static IOrderTypeVM time_box(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TimeBoxOrderVM(model, security_md_source);
public static IOrderTypeVM tick(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TickOrderVM(model, security_md_source);
public static IOrderTypeVM lean(OrdersModel model, IObservable<SecurityMD> security_md_source) => new LeanOrderVM(model, security_md_source);
public static IOrderTypeVM join(OrdersModel model, IObservable<SecurityMD> security_md_source) => new JoinOrderVM(model, security_md_source);
public static IOrderTypeVM top(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TopOrderVM(model, security_md_source);
public static IOrderTypeVM cover(OrdersModel model, IObservable<SecurityMD> security_md_source) => new CoverOrderVM(model, security_md_source);
public static IOrderTypeVM trigger(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TriggerOrderVM(model, security_md_source);
public static IOrderTypeVM iceberg(OrdersModel model, IObservable<SecurityMD> security_md_source) => new IcebergOrderVM(model, security_md_source);
public static IOrderTypeVM spreader(OrdersModel model, IObservable<SecurityImmutable> security_source) => new SpreaderOrderVM(model, security_source);
public static IOrderTypeVM dynamic(OrdersModel model, IObservable<SecurityMD> security_md_source, string type) => new DynamicOrderVM(model, security_md_source, type);
public static IOrderTypeVM stop(OrdersModel model, string id, string display_name) => new StopOrderVM(model, id, display_name);
public static IOrderTypeVM stop_limit(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new StopLimitOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM time_box(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TimeBoxOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM tick(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TickOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM lean(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new LeanOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM join(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new JoinOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM top(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TopOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM cover(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new CoverOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM trigger(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TriggerOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM iceberg(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new IcebergOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM spreader(OrdersModel model, IObservable<SecurityImmutable> security_source, string id, string display_name) => new SpreaderOrderVM(model, security_source, id, display_name);
public static IOrderTypeVM dynamic(OrdersModel model, IObservable<SecurityMD> security_md_source, string dynamic_type, string id, string display_name) => new DynamicOrderVM(model, security_md_source, dynamic_type, id, display_name);
public static IOrderTypeVM create(CustomOneofCase order_type, OrdersModel model,
public static IOrderTypeVM create(CustomOneofCase order_type, string id, string display_name, OrdersModel model,
IObservable<SecurityMD> security_md_source, string dynamic_type = null ) {
switch (order_type) {
case CustomOneofCase.Market: return market(model);
case CustomOneofCase.Limit: return limit(model);
case CustomOneofCase.Stop: return stop(model);
case CustomOneofCase.StopLimit: return stop_limit(model, security_md_source);
case CustomOneofCase.TimeBox: return time_box(model, security_md_source);
case CustomOneofCase.Tick: return tick(model, security_md_source);
case CustomOneofCase.Lean: return lean(model, security_md_source);
case CustomOneofCase.Join: return join(model, security_md_source);
case CustomOneofCase.Top: return top(model, security_md_source);
case CustomOneofCase.Cover: return cover(model, security_md_source);
case CustomOneofCase.Trigger: return trigger(model, security_md_source);
case CustomOneofCase.Iceberg: return iceberg(model, security_md_source);
case CustomOneofCase.Spreader: return spreader(model, security_md_source.Select(smd => smd.security));
case CustomOneofCase.Dynamic: return dynamic(model, security_md_source, dynamic_type);
case CustomOneofCase.Stop: return stop(model, id, display_name);
case CustomOneofCase.StopLimit: return stop_limit(model, security_md_source, id, display_name);
case CustomOneofCase.TimeBox: return time_box(model, security_md_source, id, display_name);
case CustomOneofCase.Tick: return tick(model, security_md_source, id, display_name);
case CustomOneofCase.Lean: return lean(model, security_md_source, id, display_name);
case CustomOneofCase.Join: return join(model, security_md_source, id, display_name);
case CustomOneofCase.Top: return top(model, security_md_source, id, display_name);
case CustomOneofCase.Cover: return cover(model, security_md_source, id, display_name);
case CustomOneofCase.Trigger: return trigger(model, security_md_source, id, display_name);
case CustomOneofCase.Iceberg: return iceberg(model, security_md_source, id, display_name);
case CustomOneofCase.Spreader: return spreader(model, security_md_source.Select(smd => smd.security), id, display_name);
case CustomOneofCase.Dynamic: return dynamic(model, security_md_source, dynamic_type, id, display_name);
default: throw new NotImplementedException();
}
}
@@ -51,12 +51,17 @@ namespace mbts.spark {
protected readonly OrdersModel model;
protected OrderFactory factory => model.factory;
protected OrderTypeVMBase(OrdersModel model) => this.model = model;
protected OrderTypeVMBase(OrdersModel model, string id, string display_name) {
this.model = model;
this.id = id;
this.display_name = display_name;
}
public abstract CustomOneofCase order_type { get; }
public abstract string type_name { get; }
public bool is_bts_type => display_name.StartsWith("BTS");
public string display_name => OrderUtils.order_type_display_name(order_type);
public string id { get; }
public string display_name { get; }
public OrderMetadata meta => factory.get_metadata(order_type);
public virtual bool has_editable_properties => !meta.NoProps;
public virtual bool editable_properties_open { get; set; }
@@ -76,7 +81,7 @@ namespace mbts.spark {
}
private abstract class OrderTypeVMBase<T> : OrderTypeVMBase where T : Google.Protobuf.IMessage, new() {
protected OrderTypeVMBase(OrdersModel model) : base(model) { }
protected OrderTypeVMBase(OrdersModel model, string id, string display_name) : base(model, id, display_name) { }
public override CustomOneofCase order_type =>
OrderDataHelper.get_order_type(new T());
@@ -13,20 +13,20 @@ namespace mbts.spark {
readonly StrategyEditorWrapper _strategy_editor_wrapper;
IDisposable _dispose;
public SpreaderOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
public SpreaderOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source, string id, string display_name)
: this(model, security_source, security_source.SelectMany(s => model.spreader.security_strategy(s.Id)
.Select(strategy => {
var so = model.factory.spreader_order();
so.Security = s.CloneToMutable();
so.ExecutionStrategy = strategy.CloneToMutable();
return new InlineUserProperty<SpreaderOrderDefinitionImmutable>(so, true);
}))) { }
})), id, display_name) { }
public SpreaderOrderVM(
OrdersModel model,
IObservable<SecurityImmutable> security_source,
IObservable<InlineUserProperty<SpreaderOrderDefinitionImmutable>> order_template_source)
: base(model) {
IObservable<InlineUserProperty<SpreaderOrderDefinitionImmutable>> order_template_source, string id, string display_name)
: base(model, id, display_name) {
_template = backing(nameof(template), new SpreaderOrderDefinitionImmutable?());
_strategy_editor_wrapper = new StrategyEditorWrapper(this);
_dispose = Disposable.Create(
@@ -29,10 +29,11 @@ namespace mbts.spark {
InlineStopLimitOrderProperties _inline_props;
IDisposable _dispose;
internal StopLimitOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source.Select(smd => smd.security.spec_or_default()), InlineStopLimitOrderProperties.subscribe(security_md_source)) { }
internal StopLimitOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source.Select(smd => smd.security.spec_or_default()), InlineStopLimitOrderProperties.subscribe(security_md_source), id, display_name) { }
internal StopLimitOrderVM(OrdersModel model, IObservable<ContractSpecificationImmutable> spec_source, IObservable<InlineStopLimitOrderProperties> inline_properties) : base(model) {
internal StopLimitOrderVM(OrdersModel model, IObservable<ContractSpecificationImmutable> spec_source, IObservable<InlineStopLimitOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
_stop_price = new UserProperty<double>(backing(nameof(stop_price), double.NaN));
_dispose = Disposable.Create(
spec_source.OnDispatcher().Subscribe(s => {
@@ -6,8 +6,7 @@ namespace mbts.spark {
private class StopOrderVM : OrderTypeVMBase<StopOrderDefinition> {
double _stop_price = 0;
internal StopOrderVM(OrdersModel model) : base(model) { }
internal StopOrderVM(OrdersModel model, string id, string display_name) : base(model, id, display_name) { }
public double stop_price {
get => _stop_price;
@@ -17,11 +17,11 @@ namespace mbts.spark
{
class InlineTickOrderProperties
{
public InlineTickOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
public InlineTickOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
tick_offset_on_deploy = new InlineUserProperty<uint>(0, false);
cross_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1}, false);
@@ -29,8 +29,8 @@ namespace mbts.spark
max_chase_ticks = new InlineUserProperty<uint>(10, false);
detach_on_toward = new InlineUserProperty<bool>(true, false);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<uint> tick_offset_on_deploy;
public readonly InlineUserProperty<bts.spark.QuantityMeasure> cross_threshold;
@@ -43,8 +43,8 @@ namespace mbts.spark
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineTickOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
@@ -55,12 +55,12 @@ namespace mbts.spark
public uint max_chase_ticks { get; set; } = 10;
public bool detach_on_toward { get; set; } = true;
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTickOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
new InlineTickOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTickOrderProperties> inline_properties) : base(model)
IObservable<InlineTickOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -74,7 +74,7 @@ namespace mbts.spark
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (p.tick_offset_on_deploy.force_override)
{
@@ -131,7 +131,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
@@ -177,7 +177,7 @@ namespace mbts.spark
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -14,15 +14,15 @@ using static bts.api.orderman.CustomOrderDefinition;
namespace mbts.spark {
static partial class OrderTypeVMFactory {
class InlineTimeBoxOrderProperties {
public InlineTimeBoxOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types) {
public InlineTimeBoxOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
start = new InlineUserProperty<DateTime>(DateTime.Now, true);
stop = new InlineUserProperty<DateTime>(DateTime.Now.AddMinutes(5), true);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<DateTime> start, stop;
}
@@ -30,8 +30,8 @@ namespace mbts.spark {
const double _start_immediately_delay_ms = 500;
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineTimeBoxOrderProperties _inline_props;
TimeTextTuple _absolute_start = TimeTextTuple.FromDateTime(DateTime.Now.AddMinutes(5)), _absolute_stop = TimeTextTuple.FromDateTime(DateTime.Now.AddMinutes(10));
TimeSpan? _relative_start = TimeSpan.FromMinutes(5), _relative_stop = TimeSpan.FromMinutes(5);
@@ -40,14 +40,14 @@ namespace mbts.spark {
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
public TimeBoxOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public TimeBoxOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTimeBoxOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
new InlineTimeBoxOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
public TimeBoxOrderVM(OrdersModel model,
IObservable<SecurityMD> security_md_source,
IObservable<InlineTimeBoxOrderProperties> inline_properties)
: base(model) {
IObservable<InlineTimeBoxOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_md_source.OnDispatcher()
@@ -58,7 +58,7 @@ namespace mbts.spark {
_order_types.SetItems(p.child_order_types.value);
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override)) {
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (p.start.force_override) {
absolute_start = TimeTextTuple.FromDateTime(p.start.value);
@@ -94,7 +94,7 @@ namespace mbts.spark {
public ICollection<IOrderTypeVM> child_order_types {
get {
if (_child_order_choices == null) {
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
}
return _child_order_choices;
}
@@ -173,7 +173,7 @@ namespace mbts.spark {
void _select_child_order() {
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -17,17 +17,17 @@ namespace mbts.spark
{
class InlineTopOrderProperties
{
public InlineTopOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
public InlineTopOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
var hedgetype = CustomOneofCase.Lean;
if(!child_order_types.Contains(hedgetype))
if(!child_order_types.Any(ct => ct.key.type == hedgetype))
hedgetype = CustomOneofCase.Limit;
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
watch_level_tick_offset = new InlineUserProperty<uint>(0, false);
top_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
@@ -35,10 +35,10 @@ namespace mbts.spark
enable_hedge = new InlineUserProperty<bool>(false, false);
hedge_ticks = new InlineUserProperty<int>(1, false);
}
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_hedge_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> hedge_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_hedge_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> hedge_order_types;
public readonly InlineUserProperty<uint> watch_level_tick_offset;
@@ -53,13 +53,13 @@ namespace mbts.spark
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineTopOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _hedge_order_choices;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
IOrderTypeVM _hedge_order;
IDisposable _hedge_order_errors_sub;
@@ -77,13 +77,13 @@ namespace mbts.spark
}
public int hedge_ticks { get; set; } = 1;
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTopOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
new InlineTopOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name)
{ }
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTopOrderProperties> inline_properties) : base(model)
IObservable<InlineTopOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -98,11 +98,11 @@ namespace mbts.spark
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
{
_select_hedge_order(p.selected_hedge_order_type.value);
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
}
if (p.watch_level_tick_offset.force_override)
{
@@ -157,7 +157,7 @@ namespace mbts.spark
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
@@ -167,7 +167,7 @@ namespace mbts.spark
get
{
if (_hedge_order_choices == null)
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _hedge_order_choices;
}
}
@@ -241,7 +241,7 @@ namespace mbts.spark
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -257,7 +257,7 @@ namespace mbts.spark
void _select_hedge_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_hedge_order_type.has_value ?
_inline_props.selected_hedge_order_type.value :
_inline_props.selected_hedge_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_hedge_order(ot);
}
@@ -14,8 +14,8 @@ using static bts.api.orderman.CustomOrderDefinition;
namespace mbts.spark {
static partial class OrderTypeVMFactory {
class InlineTriggerOrderProperties {
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<TriggerPriceType> trigger_price_type;
public readonly InlineUserProperty<TriggerPayupPrice.Types.TriggerPayupPriceType> payup_price_type;
public readonly InlineUserProperty<double> fixed_price;
@@ -23,10 +23,10 @@ namespace mbts.spark {
public readonly InlineUserProperty<bool> use_fixed_price, is_priceout_checked, is_timeout_checked;
public readonly InlineUserProperty<int> timeout_secs;
public InlineTriggerOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types) {
public InlineTriggerOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
trigger_price_type = new InlineUserProperty<TriggerPriceType>(TriggerPriceType.Bid, false);
payup_price_type = new InlineUserProperty<TriggerPayupPrice.Types.TriggerPayupPriceType>();
use_fixed_price = new InlineUserProperty<bool>(false);
@@ -47,19 +47,20 @@ namespace mbts.spark {
readonly UserProperty<bool> _use_fixed_price, _is_timeout_checked, _is_priceout_checked;
SecurityMD? _security_md;
SecurityImmutable? _security => _security_md.security();
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineTriggerOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ulong _bbo_ref = 0, _last_trade_ref = 0;
double _best_bid = double.NaN, _best_ask = double.NaN, _last_trade_price = double.NaN;
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTriggerOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
new InlineTriggerOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineTriggerOrderProperties> inline_properties) : base(model) {
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineTriggerOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
_trigger_price_type = create_user_prop(nameof(trigger_price_type), TriggerPriceType.Bid);
_use_fixed_price = create_user_prop(nameof(use_fixed_price), true);
_fixed_price = create_user_prop(nameof(fixed_price), double.NaN);
@@ -88,7 +89,7 @@ namespace mbts.spark {
_order_types.SetItems(p.child_order_types.value);
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override)) {
_select_child_order(p.selected_child_order_type.value);
_select_child_order(p.selected_child_order_type.value.key.type);
}
// trigger price
_trigger_price_type.on_inline_prop(p.trigger_price_type);
@@ -135,7 +136,7 @@ namespace mbts.spark {
public ICollection<IOrderTypeVM> child_order_types {
get {
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
@@ -210,13 +211,13 @@ namespace mbts.spark {
_security_md.Value.md.get_bbo(ref _bbo_ref, out co2.NativePriceSize bid, out co2.NativePriceSize ask);
_best_bid = bid.price;
_best_ask = ask.price;
_security_md.Value.md.get_last_trade(ref _last_trade_ref, out co2.NativePriceSize ps, out DateTime ts, out ulong v);
_security_md.Value.md.get_last_trade(ref _last_trade_ref, out co2.NativePriceSize ps, out ulong v);
}
}
void _select_child_order() {
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value :
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -0,0 +1,99 @@
using bts;
using bts.utils;
using mbts.collections;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace mbts.spark {
interface IPrepareUpdateForDispatcher {
IDisposable prepare_update();
}
class DispatcherUpdateMaster : IDisposable {
readonly string _name;
readonly DispatcherPriority _invocation_priority;
SetMap<Dispatcher, IPrepareUpdateForDispatcher> _vms;
int _state = States.ReadyForUpdate;
IDisposable _dispose;
public DispatcherUpdateMaster(string name)
: this(name, WorkLoop.default_interval, WorkLoop.default_priority) { }
public DispatcherUpdateMaster(string name, TimeSpan period, DispatcherPriority invocation_priority) {
_name = name;
_vms = new SetMap<Dispatcher, IPrepareUpdateForDispatcher>(EqualityComparer.Create<Dispatcher, int>(d => d.Thread.ManagedThreadId));
_dispose = ThreadPoolScheduler.Instance.SchedulePeriodic(period, _update_async);
_invocation_priority = invocation_priority;
}
public IDisposable attach(IPrepareUpdateForDispatcher vm, Dispatcher dispatcher) {
var clone = _vms.clone();
clone.add(dispatcher, vm);
_vms = clone;
return Disposable.Create(() => _detach(vm, dispatcher));
}
public void Dispose() {
Thread.VolatileWrite(ref _state, States.Disposed);
Disposable.dispose(ref _dispose);
}
void _detach(IPrepareUpdateForDispatcher preper, Dispatcher dispatcher) {
var clone = _vms.clone();
clone.remove(dispatcher, preper);
_vms = clone;
}
async void _update_async() {
if (Interlocked.CompareExchange(ref _state, States.UpdateInProgress, States.ReadyForUpdate) != States.ReadyForUpdate) {
return;
}
var temp = _vms;
try {
ConcurrentBag<(Dispatcher dispatcher, ConcurrentBag<IDisposable> update)> update_jobs =
new ConcurrentBag<(Dispatcher dispatcher, ConcurrentBag<IDisposable> update_jobs)>();
await Task.Run(() => {
Parallel.ForEach(temp, dispatcher_group => {
ConcurrentBag<IDisposable> update = new ConcurrentBag<IDisposable>();
Parallel.ForEach(dispatcher_group, vm => {
// need to check for null, that indicates an empty update (rather than an actual empty enumerable)
var ujs = vm.prepare_update();
if (ujs != null)
update.Add(ujs);
});
if (update.Count > 0)
update_jobs.Add((dispatcher_group.Key, update));
});
});
await Task.WhenAll(update_jobs.Select(_update_dispatcher_group_async));
} catch (Exception ex) {
Log.Ui.error($"{_name} error during parallel update: {ex}");
} finally {
// signal that the update is complete, and we are ready for another
Interlocked.CompareExchange(ref _state, States.ReadyForUpdate, States.UpdateInProgress);
}
}
async Task _update_dispatcher_group_async((Dispatcher dispatcher, ConcurrentBag<IDisposable> update_jobs) t) =>
await t.dispatcher.InvokeAsync(() => t.update_jobs.DisposeAll(), _invocation_priority);
static class States {
public const int
ReadyForUpdate = 0,
UpdateInProgress = 1,
Disposed = 2;
}
}
static class DispatcherUpdateMasterExtensions {
public static IDisposable attach(this DispatcherUpdateMaster dum, IPrepareUpdateForDispatcher preparer) =>
dum.attach(preparer, Dispatcher.CurrentDispatcher);
}
}
@@ -1,156 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bts;
using bts.api;
namespace mbts.ui.utility
{
class ExpirationFormatter
{
private static class DateFormatter
{
private static string[] month_codes = new string[] { "F", "G", "H", "J", "K", "M", "N", "Q", "U", "V", "X", "Z" };
private static string[] month_three_letters = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
public static string format_condensed(DateTime date, bool use_month_code, bool show_year)
{
return String.Format("{0}{1}{2}", date.Day, month_codes[date.Month - 1], show_year ? (date.Year - 2000).ToString() : String.Empty);
}
public static string format(DateTime date, bool use_month_code, bool show_day) {
string month_text = use_month_code ? "{0}{1:00}".fmt(month_codes[date.Month - 1], date.Year - 2000) : "{0} {1:00}".fmt(month_three_letters[date.Month - 1], date.Year - 2000);
return show_day ? "{0} {1}".fmt(date.Day, month_text) : month_text;
}
public static string format_standard(DateTime date) { return "{0} {1} {2:00}".fmt(date.Day, month_three_letters[date.Month - 1], date.Year - 2000); }
public static string format_coded(DateTime date) { return "{0} {1}{2:00}".fmt(date.Day, month_codes[date.Month - 1], date.Year - 2000); }
public static string format_coded_hide_day(DateTime date) { return "{0}{1}".fmt(month_codes[date.Month - 1], date.Year - 2000); }
public static DateTime parse_standard(string date_text) {
string[] split = date_text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
int year = 0;
int month = Array.IndexOf(month_three_letters, split[1]) + 1;
int day = 0;
int.TryParse(split[2], out year);
int.TryParse(split[0], out day);
return new DateTime(year + 2000, month, day);
}
public static DateTime parse_coded(string date_text) {
string[] split = date_text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string year_text = split[1].Substring(1);
string month_text = split[1].Substring(0, 1);
string day_text = split[0];
int month = Array.IndexOf(month_codes, month_text) + 1;
int day, year;
int.TryParse(year_text, out year);
int.TryParse(day_text, out day);
return new DateTime(year + 2000, month, day);
}
public static DateTime parse_coded_hide_day(string date_text) {
string year_text = date_text.Substring(1);
string month_text = date_text.Substring(0, 1);
int month = Array.IndexOf(month_codes, month_text) + 1;
int year;
int.TryParse(year_text, out year);
return new DateTime(year + 2000, month, 0);
}
}
private static IDictionary<SecurityType, IDictionary<string, bts.config.ExpirationDisplayOffsetEntry>> _offset_map;
static ExpirationFormatter()
{
try
{
_offset_map = new Dictionary<SecurityType, IDictionary<string, bts.config.ExpirationDisplayOffsetEntry>>();
_offset_map[SecurityType.Option] = new Dictionary<string, bts.config.ExpirationDisplayOffsetEntry>();
_offset_map[SecurityType.Future] = new Dictionary<string, bts.config.ExpirationDisplayOffsetEntry>();
bts.config.ExpirationDisplayOffset offset_list = mbts.config.Configuration.get<bts.config.ExpirationDisplayOffset>();
foreach (bts.config.ExpirationDisplayOffsetEntry e in offset_list.entries)
{
string security_name = e.security_name;
string security_type_text = e.security_type;
SecurityType security_type = SecurityType.Unset;
Enum.TryParse<SecurityType>(security_type_text, true, out security_type);
if (security_type == SecurityType.Option || security_type == SecurityType.Future)
_offset_map[security_type][security_name] = e;
}
}
catch (Exception ex)
{
Log.Ui.error(String.Format("Exception message = {0}", ex.Message));
}
}
private static bts.config.ExpirationDisplayOffsetEntry _get_offset_entry(SecurityType security_type, string security_name)
{
bts.config.ExpirationDisplayOffsetEntry rv = null;
IDictionary<string, bts.config.ExpirationDisplayOffsetEntry> this_security_type_map = null;
if (_offset_map.TryGetValue(security_type, out this_security_type_map))
if (this_security_type_map.TryGetValue(security_name, out rv))
return rv;
return rv;
}
public static DateTime convert_real_to_mapped(SecurityType security_type, string security_name, DateTime security_expiration)
{
bts.config.ExpirationDisplayOffsetEntry offset_entry = _get_offset_entry(security_type, security_name);
DateTime rv = security_expiration;
if (offset_entry != null)
{
if (offset_entry.addition_type == bts.config.ExpirationOffsetType.type.Month)
rv = security_expiration.AddMonths(offset_entry.addition_count);
else if (offset_entry.addition_type == bts.config.ExpirationOffsetType.type.MonthMoveToStart)
{
rv = security_expiration.AddMonths(offset_entry.addition_count);
rv = new DateTime(rv.Year, rv.Month, 1);
}
}
return rv;
}
public static string format_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration) {
return format_expiration_standard(security_type, security_name, security_expiration, map_expiration, false);
}
public static string format_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool use_month_code) {
return format_expiration_standard(security_type, security_name, security_expiration, map_expiration, use_month_code, true);
}
public static string format_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool use_month_code, bool show_day) {
DateTime mapped_expiration = map_expiration ? convert_real_to_mapped(security_type, security_name, security_expiration) : security_expiration;
return DateFormatter.format(mapped_expiration, use_month_code, show_day);
}
public static string format_symbol_expiration_standard (SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration) {
return format_symbol_expiration_standard(security_type, security_name, security_expiration, map_expiration, false, false, true);
}
public static string format_symbol_expiration_standard (SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool show_security_type) {
return format_symbol_expiration_standard(security_type, security_name, security_expiration, map_expiration, show_security_type, false, true);
}
public static string format_symbol_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool show_security_type, bool use_month_code) {
return format_symbol_expiration_standard(security_type, security_name, security_expiration, map_expiration, show_security_type, use_month_code, true);
}
public static string format_symbol_expiration_standard (SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool show_security_type, bool use_month_code, bool show_day) {
string exp_text = format_expiration_standard(security_type, security_name, security_expiration, map_expiration, use_month_code, show_day);
return !show_security_type ? String.Format("{0} {1}", security_name, exp_text) : String.Format("{0} {1} {2}", security_type.ToString().ToUpper(), security_name, exp_text);
}
public static string format_option_expiration_condensed(string option_name, DateTime option_expiration, bool map_expiration, bool show_symbol_name, bool show_year)
{
DateTime mapped_expiration = map_expiration ? convert_real_to_mapped(SecurityType.Option, option_name, option_expiration) : option_expiration;
return String.Format("{0}{1}", show_symbol_name ? option_name : String.Empty, DateFormatter.format_condensed(mapped_expiration, true, show_year));
}
public static DateTime parse_standard_formatted_expiration(SecurityType security_type, string security_name, string security_expiration) { return DateFormatter.parse_standard(security_expiration); }
}
}
@@ -66,73 +66,15 @@ namespace mbts.utils {
class AnonymousConnectable<TResult> : IConnectableObservable<TResult> {
readonly IObservable<TSource> _source;
readonly Func<TSource, IObservable<TResult>> _select_next;
List<LazySubscription> _lazy_subs = new List<LazySubscription>();
KeyDrivenObservableSeries<TSource, TResult> _driver;
IDisposable _driver_sub;
bool _is_connected = false;
readonly KeyDrivenObservableSeries<TSource, TResult> _driver;
public AnonymousConnectable(IObservable<TSource> source, Func<TSource, IObservable<TResult>> select_next) {
_source = source;
_select_next = select_next;
_driver = new KeyDrivenObservableSeries<TSource, TResult>(select_next);
}
// idempotent
public IDisposable Connect() {
lock (this) {
if (!_is_connected) {
_driver = new KeyDrivenObservableSeries<TSource, TResult>(_select_next);
foreach (var ls in _lazy_subs)
ls.attach();
_lazy_subs.Clear();
_driver_sub = _source.Subscribe(_driver);
_is_connected = true;
}
}
return Disposable.Create(_deconnect);
}
void _deconnect() {
lock (this) {
if (_is_connected) {
_driver_sub.Dispose();
_driver.Dispose();
_is_connected = false;
}
}
}
public IDisposable Subscribe(IObserver<TResult> observer) {
lock (this) {
if (_is_connected)
return _driver.Subscribe(observer);
var ls = new LazySubscription(this, observer);
_lazy_subs.Add(ls);
return ls;
}
throw new InvalidOperationException();
}
class LazySubscription : IDisposable {
readonly IObserver<TResult> _observer;
readonly AnonymousConnectable<TResult> _owner;
IDisposable _sub;
public LazySubscription(AnonymousConnectable<TResult> owner, IObserver<TResult> observer) {
_owner = owner;
_observer = observer;
}
public void attach() =>
_sub = _owner._driver.Subscribe(_observer);
public void Dispose() {
lock (_owner) {
Disposable.dispose(ref _sub);
_owner._lazy_subs.Remove(this);
}
}
}
public IDisposable Connect() => _source.Subscribe(_driver);
public IDisposable Subscribe(IObserver<TResult> observer) => _driver.Subscribe(observer);
}
}
+85 -57
View File
@@ -156,15 +156,13 @@ namespace mbts.ui.shell
public string name => _propname;
public void set(T value) {
if (!Equals(value, _value)) {
Changing?.Invoke(_value, value);
var old = _value;
_value = value;
Changed?.Invoke(old, value);
_owner.RaisePropertyChanged(_propname);
}
if (!Equals(value, _value))
_apply_new_value(value);
}
public IDisposable set_as_job(T value) =>
Equals(value, _value) ? null : Disposable.Create(() => _apply_new_value(value));
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
Changed += pch;
return Disposable.Create(() => Changed -= pch);
@@ -182,6 +180,14 @@ namespace mbts.ui.shell
get { return _value; }
set { set(value); }
}
void _apply_new_value(T new_value) {
Changing?.Invoke(_value, new_value);
var old = _value;
_value = new_value;
Changed?.Invoke(old, new_value);
_owner.RaisePropertyChanged(_propname);
}
}
protected class DelegateProperty<T> : Property<T> {
@@ -529,7 +535,7 @@ namespace mbts.ui.shell
/// <para/>If the user has not selected an item, but the current items do not contain the desired item, it will re-evaluate whether or not to select the item when new items arrive.
/// </summary>
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IReadOnlyList<PropertyValidation<T>> validation_steps) =>
backing(name, items, desired_item, select_default, null, validation_steps);
backing(name, items, desired_item, select_default, EqualityComparer<T>.Default, validation_steps);
/// <summary>
/// Returns a SelectorProperty&lt;T&gt; that observes an items source, and a desired item. When either observable ticks, it determines whether or not to assign the selected_item property.
@@ -541,8 +547,8 @@ namespace mbts.ui.shell
/// <param name="desired_item">The observable sequence of a desired item.</param>
/// <param name="select_default">The fallback function to select an item by default.</param>
/// <param name="items_match">The item-matching function used to preserve a selected item when new items arrive.</param>
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, Func<T, T, bool> items_match) =>
backing(name, items, desired_item, select_default, items_match, new List<PropertyValidation<T>>(0));
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IEqualityComparer<T> comparer) =>
backing(name, items, desired_item, select_default, comparer, new List<PropertyValidation<T>>(0));
/// <summary>
/// Returns a SelectorProperty&lt;T&gt; that observes an items source, and a desired item. When either observable ticks, it determines whether or not to assign the selected_item property.
@@ -555,14 +561,24 @@ namespace mbts.ui.shell
/// <param name="select_default">The fallback function to select an item by default.</param>
/// <param name="items_match">The item-matching function used to preserve a selected item when new items arrive.</param>
/// <param name="validation_steps">The validation steps to take when selected_item changes.</param>
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, Func<T, T, bool> items_match, IReadOnlyList<PropertyValidation<T>> validation_steps) {
if (_observable_properties == null) _observable_properties = new List<IDisposable>();
var prop = new SelectorProperty<T>(this, name, select_default, items_match, validation_steps);
_observable_properties.Add(items.OnDispatcher().Subscribe(prop));
_observable_properties.Add(desired_item.OnDispatcher().Subscribe(prop));
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IEqualityComparer<T> comparer, IReadOnlyList<PropertyValidation<T>> validation_steps) {
var prop = new SelectorProperty<T>(this, name, select_default, comparer, validation_steps);
attach(prop, items, desired_item);
return prop;
}
protected SelectorProperty<T, V> backing<T, V>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T, V> item_to_value, Func<V> select_default, IEqualityComparer<V> comparer, IReadOnlyList<PropertyValidation<V>> validation_steps) {
var prop = new SelectorProperty<T, V>(this, name, item_to_value, select_default, comparer, validation_steps);
attach(prop, items, desired_item);
return prop;
}
protected void attach<T, V>(SelectorProperty<T, V> selector_property, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item) {
if (_observable_properties == null) _observable_properties = new List<IDisposable>();
_observable_properties.Add(items.OnDispatcher().Subscribe(selector_property));
_observable_properties.Add(desired_item.OnDispatcher().Subscribe(selector_property));
}
protected void set_dispose(IDisposable disposable) {
if (_dispose != null) throw new InvalidOperationException("Cannot set disposable twice");
_dispose = disposable;
@@ -579,37 +595,44 @@ namespace mbts.ui.shell
OnDisposed?.Invoke(true);
}
protected class SelectorProperty<T> : SelectorProperty<T, T> {
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<T> select_default, IEqualityComparer<T> comparer, IReadOnlyList<PropertyValidation<T>> validation_steps)
: base(owner, prop_name, i => i, select_default, comparer, validation_steps) { }
}
/// <summary>
/// Designed to observe an items source, and a [settings-driven] desired item. When a new desired item is observed, it will evaluate it's current state and determine if it should be assigned to the selected_item.
/// <para/>Notes: If the user has selected an item (ie the selected_item has been assigned through the public setter), the desired item will be ignored unless force_override is true.
/// <para/>If the user has not selected an item, but the current items do not contain the desired item, it will re-evaluate whether or not to select the item when new items arrive.
/// </summary>
protected class SelectorProperty<T> : IObserver<InlineUserProperty<T>>, IObserver<IEnumerable<T>>, IObservable<(T oldval, T newval)> {
protected class SelectorProperty<TItem, TValue> : IObserver<InlineUserProperty<TItem>>, IObserver<IEnumerable<TItem>>, IObservable<(TValue oldval, TValue newval)> {
readonly DisposableViewModelBase _owner;
readonly string _prop_name;
readonly IReadOnlyList<PropertyValidation<T>> _validation_steps;
readonly ObservableCollection<T> _items = new ObservableCollection<T>();
readonly Func<T> _select_default;
readonly Func<T, T, bool> _items_match; // used to maintain selected_item through an items-change
T _selected_item;
InlineUserProperty<T> _desired_item;
readonly IReadOnlyList<PropertyValidation<TValue>> _validation_steps;
readonly ObservableCollection<TItem> _items = new ObservableCollection<TItem>();
readonly Func<TValue> _select_default;
readonly IEqualityComparer<TValue> _value_comparer;
readonly Func<TItem, TValue> _item_to_value;
TValue _selected_item;
InlineUserProperty<TItem> _desired_item = new InlineUserProperty<TItem>();
bool _is_user_selected_item;
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<T> select_default, Func<T, T, bool> items_match, IReadOnlyList<PropertyValidation<T>> validation_steps) {
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<TItem, TValue> item_to_value, Func<TValue> select_default, IEqualityComparer<TValue> value_comparer, IReadOnlyList<PropertyValidation<TValue>> validation_steps) {
_owner = owner;
_prop_name = prop_name;
_item_to_value = item_to_value;
_select_default = select_default;
_items_match = items_match;
_value_comparer = value_comparer ?? EqualityComparer<TValue>.Default;
_validation_steps = validation_steps;
items = new ReadOnlyObservableCollection<T>(_items);
items = new ReadOnlyObservableCollection<TItem>(_items);
}
public event PropertyChange<T> Changing;
public event PropertyChange<T> Changed;
public event PropertyChange<TValue> Changing;
public event PropertyChange<TValue> Changed;
public ReadOnlyObservableCollection<T> items { get; }
public ReadOnlyObservableCollection<TItem> items { get; }
public T selected_item {
public TValue selected_item {
get => _selected_item;
set {
_is_user_selected_item = true;
@@ -617,31 +640,31 @@ namespace mbts.ui.shell
}
}
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
public IDisposable Subscribe(IObserver<(TValue oldval, TValue newval)> observer) {
Changed += pch;
return Disposable.Create(() => Changed -= pch);
void pch(T o, T n) => observer.OnNext((o, n));
void pch(TValue o, TValue n) => observer.OnNext((o, n));
}
public IObservable<T> observe_current(bool start_now = false) {
public IObservable<TValue> observe_current(bool start_now = false) {
var source = this.Select(vals => vals.newval);
if (start_now)
source = source.StartWith(_selected_item);
source = source.StartWith(selected_item);
return source;
}
void IObserver<InlineUserProperty<T>>.OnNext(InlineUserProperty<T> iup) {
void IObserver<InlineUserProperty<TItem>>.OnNext(InlineUserProperty<TItem> iup) {
_desired_item = iup;
_try_auto_select();
}
void IObserver<InlineUserProperty<T>>.OnError(Exception error) { }
void IObserver<InlineUserProperty<T>>.OnCompleted() { }
void IObserver<InlineUserProperty<TItem>>.OnError(Exception error) { }
void IObserver<InlineUserProperty<TItem>>.OnCompleted() { }
void IObserver<IEnumerable<T>>.OnNext(IEnumerable<T> value) {
if (_items_match != null && _is_user_selected_item) {
void IObserver<IEnumerable<TItem>>.OnNext(IEnumerable<TItem> value) {
if (_is_user_selected_item) {
var curr_selected_item = selected_item;
_items.sync_with(value);
if (_try_match_item(curr_selected_item, out T match))
if (_try_match_item(curr_selected_item, out TValue match))
selected_item = match;
else {
_is_user_selected_item = false;
@@ -649,18 +672,13 @@ namespace mbts.ui.shell
}
} else {
_items.sync_with(value);
if (_is_user_selected_item) {
_is_user_selected_item = _items.Contains(_selected_item);
}
if (!_is_user_selected_item) {
_try_auto_select();
}
_try_auto_select();
}
}
void IObserver<IEnumerable<T>>.OnError(Exception error) { }
void IObserver<IEnumerable<T>>.OnCompleted() { }
void IObserver<IEnumerable<TItem>>.OnError(Exception error) { }
void IObserver<IEnumerable<TItem>>.OnCompleted() { }
void _run_validation(T val) {
void _run_validation(TValue val) {
var invalid_steps = _validation_steps.Select(v => v.validate(val)).Where(r => !r.valid);
if (invalid_steps.Count() > 0) {
var error_msg = string.Join("\n", invalid_steps.Where(r => !string.IsNullOrEmpty(r.msg)).Select(r => r.msg));
@@ -670,15 +688,15 @@ namespace mbts.ui.shell
void _try_auto_select() {
if (_is_user_selected_item) {
if (desired_item_valid() && _desired_item.force_override && _try_match_item(_desired_item.value, out T match)) {
if (desired_item_valid() && _desired_item.force_override && _try_match_item(_desired_item.value, out TValue match)) {
_set_selected_item(match);
return;
}
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out T match)) {
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out TValue match)) {
_set_selected_item(match);
return;
}
if (_try_match_item(_select_default(), out T default_match))
if (_try_match_item(_select_default(), out TValue default_match))
_set_selected_item(default_match);
else {
// the _set_selected_item has never been entered, so validation has never ran, force it here
@@ -688,8 +706,8 @@ namespace mbts.ui.shell
bool desired_item_valid() => (_desired_item?.has_value).GetValueOrDefault();
}
void _set_selected_item(T value) {
if (!Equals(value, _selected_item)) {
void _set_selected_item(TValue value) {
if (!_value_comparer.Equals(value, _selected_item)) {
Changing?.Invoke(_selected_item, value);
var old = _selected_item;
_selected_item = value;
@@ -699,10 +717,20 @@ namespace mbts.ui.shell
}
}
bool _try_match_item(T item, out T match) =>
_items_match != null ?
_items.TryGetFirst(i => _items_match(i, item), out match) :
_items.TryGetFirst(i => i.Equals(item), out match);
bool _try_match_item(TValue value, out TValue match) {
foreach (TItem item in _items) {
TValue v = _item_to_value(item);
if (_value_comparer.Equals(v, value)) {
match = v;
return true;
}
}
match = default;
return false;
}
bool _try_match_item(TItem item, out TValue match) =>
_try_match_item(_item_to_value(item), out match);
}
public event Action<bool> OnDisposed;
@@ -15,7 +15,7 @@ namespace mbts.spark {
value = initial_value;
}
event Action<(T oldval, T newval)> _value_set;
public event Action<(T oldval, T newval)> value_set;
public T value { get; private set; }
public string text => _text ?? (_text = _format(value));
@@ -27,14 +27,22 @@ namespace mbts.spark {
}
}
public IDisposable on_next_distinct_as_job(T value, ref bool dirty) {
if (!value.Equals(this.value)) {
dirty = true;
return Disposable.Create(() => OnNext(value));
}
return null;
}
public void OnCompleted() { }
public void OnError(Exception error) { }
public void OnNext(T value) {
if (_value_set != null) {
if (value_set != null) {
T prev = this.value;
this.value = value;
_text = null;
_value_set.Invoke((prev, value));
value_set.Invoke((prev, value));
} else {
this.value = value;
_text = null;
@@ -42,7 +50,7 @@ namespace mbts.spark {
}
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) =>
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => _value_set += cb, cb => _value_set -= cb)
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => value_set += cb, cb => value_set -= cb)
.Subscribe(observer);
}
}
@@ -47,7 +47,7 @@
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<usp:OrderTypeItem OrderType="{Binding order_type}" Metadata="{Binding meta}"/>
<usp:OrderTypeItem OrderType="{Binding order_type}" DisplayName="{Binding display_name}" Metadata="{Binding meta}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
@@ -222,8 +222,6 @@
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@@ -235,11 +233,9 @@
<uag:QuantityMeasureControl Grid.Row="1" Grid.Column="2" QuantityMeasure="{Binding cross_threshold}"/>
<TextBlock Grid.Row="3" VerticalAlignment="Center">Max Chase Ticks</TextBlock>
<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>
<TextBlock Grid.Row="5">Child</TextBlock>
<uag:OrderDetailsPopupControl
Grid.Row="7" Grid.Column="2"
Grid.Row="5" Grid.Column="2"
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding child_order_types}"
SelectedItem="{Binding child_order}"
@@ -33,7 +33,7 @@
Width="15"
Height="10"
/>
<TextBlock
<TextBlock x:Name="text"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="20,0,0,0"
@@ -3,23 +3,49 @@ using bts.spark;
using System.Windows;
using System.Windows.Controls;
namespace mbts.ui.spark
{
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for OrderTypeItem.xaml
/// </summary>
public partial class OrderTypeItem : Control
{
static OrderTypeItem() {
partial class OrderTypeItem : Control {
static OrderTypeItem() =>
DefaultStyleKeyProperty.OverrideMetadata(typeof(OrderTypeItem), new FrameworkPropertyMetadata(typeof(OrderTypeItem)));
}
public static readonly DependencyProperty OrderTypeProperty = DependencyProperty.Register(nameof(OrderType), typeof(CustomOrderDefinition.CustomOneofCase), typeof(OrderTypeItem),
new PropertyMetadata(CustomOrderDefinition.CustomOneofCase.None));
public CustomOrderDefinition.CustomOneofCase OrderType { get => (CustomOrderDefinition.CustomOneofCase)GetValue(OrderTypeProperty); set => SetValue(OrderTypeProperty, value); }
public static readonly DependencyProperty DisplayNameProperty =
WPFHelper.create_dp<string, OrderTypeItem>(nameof(DisplayName), (o, v) => {
o._display_name = v;
o._update_text();
});
public string DisplayName {
get => GetValue(DisplayNameProperty) as string;
set => SetValue(DisplayNameProperty, value);
}
public static readonly DependencyProperty MetadataProperty = DependencyProperty.Register(nameof(Metadata), typeof(OrderMetadata), typeof(OrderTypeItem),
new PropertyMetadata(new OrderMetadata { Color = 0, KeyBinding = string.Empty }));
public OrderMetadata Metadata { get => GetValue(MetadataProperty) as OrderMetadata; set => SetValue(MetadataProperty, value); }
string _display_name;
TextBlock _text;
public override void OnApplyTemplate() {
this.try_get_template_child("text", out _text);
_update_text();
}
void _update_text() {
if (_text != null) {
if (string.IsNullOrEmpty(_display_name)) {
_text.ClearValue(TextBlock.TextProperty);
} else {
_text.SetCurrentValue(TextBlock.TextProperty, _display_name);
}
}
}
}
}
}
@@ -1,18 +0,0 @@
using bts.api;
using mbts.ui.utility;
using System;
using System.Windows.Data;
namespace mbts.ui.converters
{
public class SecurityTypeStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return SecurityDisplay.format_security_type((SecurityType)value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
}
@@ -1,32 +0,0 @@
using bts.api;
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace mbts.ui.converters
{
[ValueConversion(typeof(SecurityType), typeof(Brush))]
public class SecurityTypeForegroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (value is SecurityType) return _convert((SecurityType)value);
//else if (value is SecurityTuple) return _convert(((SecurityTuple)value).security_type);
//else if (value is SecurityExpiration) return _convert(((SecurityExpiration)value).security_type);
else return SystemColors.ControlTextBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
private Brush _convert(SecurityType type) {
switch (type) {
case SecurityType.Option: return (Brush)BTSColors.header_text;
case SecurityType.Future: return new SolidColorBrush(Colors.Gold);
case SecurityType.Spread: return new SolidColorBrush(Colors.SlateBlue);
default: return new SolidColorBrush(Colors.PaleGreen);
}
}
}
}
@@ -26,8 +26,6 @@
<cv:CellPathConverter x:Key="CellPathConverter" />
<cv:CellKeyConverter x:Key="CellKeyConverter" />
<cv:SecurityDisplayTextConverter x:Key="SecurityTextConverter"/>
<cv:SecurityTypeForegroundConverter x:Key="SecurityTypeForegroundConverter" />
<cv:SecurityTypeStringConverter x:Key="SecurityTypeStringConverter" />
<cv:NumericSignBrushConverter x:Key="NumericSignBrushConverter" />
<cv:TickDisplayTextConverter x:Key="TickTextConverter" />
<cv:DoubleTextConverter x:Key="DoubleTextConverter" />
@@ -1,37 +0,0 @@
using bts.api.core;
using bts.api.persistence;
using bts.api.user;
using bts.test;
using mbts.persist;
using mbts.ui.shell;
using System;
using System.Linq;
namespace bts.settings {
public class SettingsManagerTool {
public static void run() {
var sc = new ServiceContext();
var users = sc.locate<UserService>();
var persist = sc.locate<PersistenceService>("settings");
var user_list = users.get_users(new GetUsersRequest());
var user_names = user_list.Users.Select(u => u.Login);
var from = ConsoleEx.prompt("From User", user_names);
var from_persist = new UserUISettings(user_list.Users.First(u => u.Login == from).Id, persist, null);
var workspaces = from_persist.query<WorkspaceDefinition>(WorkspacesModel.WORKSPACE_NAMESPACE, ".*").Result;
var selected_ws = ConsoleEx.prompt("Choose workspace:", workspaces.Select(w => w.key));
var to = ConsoleEx.prompt("To User", user_names);
var name = ConsoleEx.input_prompt("Rename workspace?", selected_ws);
var confirm = ConsoleEx.prompt($"copy workspace '{selected_ws}' from {from} to {to} and name it '{name}'. Confirm?", "Yes", "No");
if (confirm == "Yes") {
var ws_blob = workspaces.First(w => w.key == selected_ws).value;
var to_persist = new UserUISettings(user_list.Users.First(u => u.Login == to).Id, persist, null);
to_persist.set(WorkspacesModel.WORKSPACE_NAMESPACE, name, ws_blob).Wait();
Console.WriteLine("Done");
}
}
}
}
@@ -386,7 +386,7 @@ namespace mbts.spark {
void _tick() {
if (_settings != null) {
ulong unused = 0;
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out DateTime _, out ulong __);
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out ulong __);
bool depth_changed = _vm.md.get_depth(ref _prices_updated, ref _bids, ref _asks);
_mkt_break_lines.refresh();
bool prices_changed =
@@ -78,7 +78,7 @@ namespace mbts.spark {
_dispose = Disposable.Create(
settings_command,
order_properties_vm,
order_properties_vm.observe_account(true).Select(a => a.name).Subscribe(account_positions),
order_properties_vm.observe_account(true).Select(a => a?.name ?? string.Empty).Subscribe(account_positions),
account_positions,
size_calculator = new CalculatorLogic(0, _settings_manager.subscribe_current().Select(s => s.calculator_buttons)),
bus.subscribe(SparkTags.LogActivity).OnDispatcher().Subscribe(status_update),
@@ -275,7 +275,7 @@ namespace mbts.spark {
_open.set(md.open_price);
_settlement.set(md.settlement_price);
ulong unused = 0;
md.get_last_trade(ref unused, out NativePriceSize last, out DateTime time, out ulong volume);
md.get_last_trade(ref unused, out NativePriceSize last, out ulong volume);
if (!double.IsNaN(last.price)) {
_change.set(last.price - md.settlement_price);
} else {
@@ -113,7 +113,7 @@ namespace mbts.spark {
if (!sec_md.md.get_bbo(ref bbo_time, out NativePriceSize bid, out NativePriceSize ask)) return false;
// last is only used in waterfall and last calculations, so if neither of those types are selected
// we should not exit early if last is somehow not avaialble
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out DateTime unused1, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
if (pnl_request.HasFlag(pnl_calc_type.waterfall)) {
// last price is available and withing range of available bid and ask
@@ -12,7 +12,7 @@ namespace mbts.spark.utilities
internal interface ISecurityMDPump
{
IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo { get; }
IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade { get; }
IObservable<(double last, uint last_size, ulong volume)> last_trade { get; }
IObservable<double> bid_price { get; }
IObservable<uint> bid_size { get; }
IObservable<double> ask_price { get; }
@@ -61,7 +61,6 @@ namespace mbts.spark.utilities
private double _bid_price, _ask_price, _last_price;
private uint _bid_size, _ask_size, _last_size;
private ulong _volume;
private DateTime _last_time;
private bool _refresh_bbo(MDConsumerHandle md) {
if (md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
@@ -75,10 +74,9 @@ namespace mbts.spark.utilities
}
private bool _refresh_last(MDConsumerHandle md) {
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
_last_price = ps.price;
_last_size = ps.size;
_last_time = ts;
_volume = v;
return true;
}
@@ -86,17 +84,16 @@ namespace mbts.spark.utilities
}
private (double, uint, double, uint) _select_bbo() { return (_bid_price, _bid_size, _ask_price, _ask_size); }
private (double, uint, DateTime, ulong) _select_last() { return (_last_price, _last_size, _last_time, _volume); }
private (double, uint, ulong) _select_last() { return (_last_price, _last_size, _volume); }
public IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo => _bbo_pump.Select(_ => _select_bbo()).StartWith(_select_bbo());
public IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
public IObservable<(double last, uint last_size, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
public IObservable<double> bid_price => _bbo_pump.Select(_ => _bid_price).DistinctUntilChanged().StartWith(_bid_price);
public IObservable<uint> bid_size => _bbo_pump.Select(_ => _bid_size).DistinctUntilChanged().StartWith(_bid_size);
public IObservable<double> ask_price => _bbo_pump.Select(_ => _ask_price).DistinctUntilChanged().StartWith(_ask_price);
public IObservable<uint> ask_size => _bbo_pump.Select(_ => _ask_size).DistinctUntilChanged().StartWith(_ask_size);
public IObservable<double> last_price => _bbo_pump.Select(_ => _last_price).DistinctUntilChanged().StartWith(_last_price);
public IObservable<uint> last_size => _bbo_pump.Select(_ => _last_size).DistinctUntilChanged().StartWith(_last_size);
public IObservable<DateTime> last_time => _last_pump.Select(_ => _last_time).DistinctUntilChanged().StartWith(_last_time);
public IObservable<ulong> volume => _last_pump.Select(_ => _volume).DistinctUntilChanged().StartWith(_volume);
public IObservable<double> session_low => _root_pump.Select(md => md.session_low).DistinctUntilChanged();
public IObservable<double> session_high => _root_pump.Select(md => md.session_high).DistinctUntilChanged();
@@ -110,6 +110,29 @@ namespace mbts.spark.utilities {
return defs;
}
public Dictionary<OrderTemplateHeader, CustomOrderDefinitionImmutable> default_order_type_templates(SecurityImmutable security, bool is_child = false) {
const int name_ref_seed = 1;
// standard types
var defs = default_order_types(security, is_child)
.Except(new[] { CustomOrderDefinition.CustomOneofCase.Dynamic })
.ToDictionary(ot => new OrderTemplateHeader(new OrderTemplateKey(ot), OrderUtils.order_type_display_name(ot)), ot => new CustomOrderDefinitionImmutable(custom_order(ot)));
// TODO: replace with better naming scheme (right now, the order type ref count 'n' is appended to the order-type name)
var order_type_ref_count = defs.ToDictionary(kv => kv.Key, kv => name_ref_seed);
var dynamic_defs = new List<CustomOrderDefinitionImmutable>();
DynamicOrderHelper.add_dynamic_order_defs(dynamic_defs, ot => custom_order(ot));
foreach (var ddef in dynamic_defs) {
var header = new OrderTemplateHeader(new OrderTemplateKey(ddef.CustomCase, ddef.Dynamic.DynamicOrderType), ddef.Dynamic.DynamicOrderType );
// if (order_type_ref_count.TryGetValue(header, out int count)) {
// order_type_ref_count[header]++;
// header = new OrderTemplateHeader(new OrderTemplateKey(header.key.type, $"{header.key.name}{count}"), $"{header.display_name}{count}");
// } else {
// order_type_ref_count[header] = name_ref_seed;
// }
defs.Add(header, ddef);
}
return defs;
}
public IEnumerable<CustomOrderDefinition.CustomOneofCase> default_order_types(SecurityImmutable? security, bool is_child=false) =>
security.HasValue ? default_order_types(security.Value, is_child) : default_order_types();
@@ -212,7 +235,7 @@ namespace mbts.spark.utilities {
public DynamicOrderDefinition dynamic_order() => new DynamicOrderDefinition
{
Child = custom_order(),
//Child = custom_order(),
};
@@ -7,8 +7,8 @@ using System.Windows.Threading;
namespace mbts.spark {
static class WorkLoop {
public const double default_excessive_cycle_ratio = 1.2;
static readonly DispatcherPriority default_priority;
static readonly TimeSpan default_interval;
public static readonly TimeSpan default_interval;
public static readonly DispatcherPriority default_priority;
static WorkLoop() {
var timer_params = config.Configuration.get<bts.config.LadderKnobs>();
@@ -1,90 +0,0 @@
using bts.api;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.utility
{
public enum DateFormat { Standard, DayMonthAbvDiff2000, DayMonthCodeDiff2000 }
static class SecurityDisplay
{
/// <summary>
/// Returns a shorthand string representation of a security type appropriate for UIs.
/// </summary>
public static string format_security_type(SecurityType type) {
switch (type) {
case SecurityType.Option: return "Opt";
case SecurityType.Future: return "Fut";
case SecurityType.Stock: return "Stk";
case SecurityType.Spread: return "Spd";
default: return type.ToString();
}
}
/// <summary>
/// Returns a concise string representation of a security expiration appropriate for UIs (e.g. es March 22, 2019: es 22 Mar 19).
/// </summary>
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date) { return format_expiration(sec_type, symbol, exp_date, false, true, true, DateFormat.DayMonthAbvDiff2000); }
/// <summary>
/// Returns a concise string representation of a security expiration (using symbol-mapped expiration dates, and single-letter month codes) appropriate for UIs (e.g. es March 22, 2019: [Opt] [es] 22 Mar 19).
/// </summary>
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date, bool show_type, bool show_symbol, bool use_mapped_exp) { return format_expiration(sec_type, symbol, exp_date, show_type, show_symbol, use_mapped_exp, DateFormat.Standard); }
/// <summary>
/// Returns a concise string representation of a security expiration (using symbol-mapped expiration dates, and single-letter month codes) appropriate for UIs (e.g. es March 22, 2019: [Opt] [es] 22 Mar 19, or [Opt] [es] 22 H19).
/// </summary>
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date, bool show_type, bool show_symbol, bool use_mapped_exp, DateFormat date_format) {
if (use_mapped_exp) exp_date = ExpirationFormatter.convert_real_to_mapped(sec_type, symbol, exp_date);
string result = format_date(exp_date);
if (show_symbol) result = (symbol + " " + result);
if (show_type) result = (format_security_type(sec_type) + " " + result);
return result;
}
/// <summary>
/// Returns a concise string representation of a future trade appropriate for UIs.
/// </summary>
public static string format_future_trade(string symbol, DateTime exp_date, int size, double marginal_price) { return "{0} {1} lots @ {2:C}".fmt(format_expiration(SecurityType.Future, symbol, exp_date, false, true, true), size, marginal_price); }
/// <summary>
/// Returns a concise string representation of an option trade appropriate for UIs.
/// </summary>
public static string format_option_trade(string symbol, DateTime exp_date, double strike, bool is_call, int size, double marginal_price) {
return "{0} {1} {2} {3} lots @ {4:C}".fmt(format_expiration(SecurityType.Option, symbol, exp_date, false, true, true), strike, is_call ? "C" : "P", size, marginal_price);
}
/// <summary>
/// Returns a concise string representation of a date (using standard month abbreviations) appropriate for UIs (e.g. March 22, 2019: 22 Mar 19).
/// </summary>
public static string format_date(DateTime date) { return format_date(date.Year, date.Month, date.Day, DateFormat.DayMonthAbvDiff2000); }
/// <summary>
/// Returns a concise string representation of a date (using single-letter month codes) appropriate for UIs (e.g. March 22, 2019: 22 Mar 19, or 22 H19).
/// </summary>
public static string format_date(int year, int month, int day, DateFormat format) {
switch(format) {
case DateFormat.DayMonthAbvDiff2000: return "{0} {1} {2}".fmt(day, get_month_abv(month), year - 2000);
case DateFormat.DayMonthCodeDiff2000: return "{0} {1}{2}".fmt(day, get_month_code(month), year - 2000);
case DateFormat.Standard: goto default;
default: return "{0}/{1}/{2}".fmt(day, month, year);
}
}
/// <summary>
/// Returns the option industry standard month code.
/// </summary>
public static string get_month_code(int month) { _check_month(month); return _month_codes[month - 1]; }
/// <summary>
/// Returns the standard month abbreviation (Jan, Feb, Mar, etc.).
/// </summary>
public static string get_month_abv(int month) { _check_month(month); return _month_abvs[month - 1]; }
#region Private Members
private static void _check_month(int month) { if (month < 1 || month > 12) throw new ArgumentException("There are only twelve months in a year", "month"); }
private static string[] _month_codes = new string[] { "F", "G", "H", "J", "K", "M", "N", "Q", "U", "V", "X", "Z" };
private static string[] _month_abvs = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
#endregion
}
}
+2 -1
View File
@@ -31,7 +31,8 @@ namespace bts {
Mercury,
Testing,
Latency,
DataFlow
DataFlow,
Plugin
// Please keep this list in sync with logging.h/logging.cpp
}
readonly struct Logger {
@@ -113,7 +113,5 @@ namespace mbts.co2
[DllImport("libspark")]
internal static extern void co2_get_zero_and_nan_book(ref NativePriceLevel nps);
[DllImport("libspark")]
internal static extern void co2_get_sample_datetime(ref utils.LLDateTime now, ref utils.LLDateTime utc_now);
}
}
+10 -5
View File
@@ -72,7 +72,12 @@ namespace mbts.co2
return false;
}
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out DateTime timestamp, out ulong total_volume) {
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out ulong total_volume) {
total_volume = _cold->total_volume;
return (_cold->last_trade.load_if_new(ref time, out ps));
}
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out utils.LLDateTime timestamp, out ulong total_volume) {
timestamp = _cold->last_trade_time;
total_volume = _cold->total_volume;
return (_cold->last_trade.load_if_new(ref time, out ps));
@@ -88,15 +93,15 @@ namespace mbts.co2
public ulong total_volume { get { return _cold->total_volume; } }
public double settlement_price { get { return _cold->settlement_price;} }
public DateTime settlement_date { get { return _cold->settlement_date;} }
public utils.LLDate settlement_date { get { return _cold->settlement_date;} }
public double previous_settlement_price { get { return _cold->previous_settlement_price;} }
public DateTime previous_settlement_date { get { return _cold->previous_settlement_date;} }
public utils.LLDate previous_settlement_date { get { return _cold->previous_settlement_date;} }
public double open_price { get { return _cold->open_price;} }
public DateTime open_date { get { return _cold->open_date; } }
public utils.LLDate open_date { get { return _cold->open_date; } }
public double close_price { get { return _cold->close_price;} }
public DateTime close_date { get { return _cold->close_date; } }
public utils.LLDate close_date { get { return _cold->close_date; } }
public double session_high { get { return _cold->session_high;} }
public double session_low { get { return _cold->session_low; } }
public double open_interest { get { return _cold->open_interest; } }
+9 -28
View File
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace bts.test {
public static class ConsoleEx {
@@ -23,34 +21,17 @@ namespace bts.test {
}
public static T prompt<T>(string prompt, params T[] options) {
return ConsoleEx.prompt(prompt, (IEnumerable<T>)options);
}
public static T prompt<T>(string prompt, IEnumerable<T> options) {
WriteLine(prompt, ConsoleColor.Yellow);
for (int x = 0; x < options.Count(); ++x) {
Console.WriteLine(prompt);
for (int x = 1; x <= options.Length; ++x) {
Write($"{x}. ", ConsoleColor.Yellow);
WriteLine(options.ElementAt(x).ToString());
WriteLine(options[x].ToString());
}
int response = 0;
bool success = false;
while(!success) {
var key = Console.ReadKey();
success = Int32.TryParse(key.KeyChar.ToString(), out response);
if (response > options.Count()) success = false;
}
var value = options.ElementAt(response);
Console.WriteLine(" >> " + value.ToString());
Console.WriteLine();
return value;
}
public static string input_prompt(string prompt, string default_result) {
Write(prompt + " (", ConsoleColor.Yellow);
Write(default_result, ConsoleColor.White);
Write(") ", ConsoleColor.Yellow);
var result = Console.ReadLine();
if (string.IsNullOrWhiteSpace(result)) return default_result;
return result;
int response;
do {
Int32.TryParse(Console.ReadKey().ToString(), out response);
if (response > options.Length) response = 0;
} while (response == 0);
return options[response];
}
@@ -43,9 +43,6 @@ namespace bts.test {
if (ue.InnerException is AssertFailture af) {
result.Message = $"Assertion Failure:\n{af.Message}\nLocation:{af._filename}:{af._line}";
}
else if (ue.InnerException != null) {
result.Message = $"Unexpected error: {ue.InnerException}";
}
else {
result.Message = $"Unexpected error: {ue.Message}\n\n{ue.StackTrace}";
}
@@ -27,6 +27,9 @@ namespace bts.utils {
public static IEqualityComparer<T?> CreateNullable<T>(Func<T, T, bool> equals) where T : struct =>
new AnonymousEqualityComparer<T?>(nullable_equals);
public static IEqualityComparer<T> null_check_wrapper<T>(IEqualityComparer<T> comparer) where T : class =>
new AnonymousEqualityComparer<T>((a, b) => NullCheckEquals(a, b, comparer.Equals), comparer.GetHashCode);
public static bool safe_sequence_equals<T>(IEnumerable<T> source, IEnumerable<T> other) =>
NullCheckEquals(source, other, (a, b) => a.SequenceEqual(b));
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace mbts {
@@ -23,14 +24,20 @@ namespace mbts {
return range.Skip(index).First();
}
[DllImport("libspark")]
private static extern void ll_to_parts(UInt64 ll_time, out int year, out int month, out int day, out int hour, out int minute, out int second, out int ms);
public static DateTime lldatetime(this ulong ll) {
// Warning: Do not remove these consts, or try to simplify this method.
// System.DateTime() requires bits 63-64 to be empty in the "DateTime(long ticks)" constructor.
// The only way to set the DateTimeKind is through the "DateTime(long ticks, DateTimeKind kind)" constructor.
// (Yes, it is annoying. Internally, System.DateTime stores the DateTimeKind in bits 63-64 - in the exact format we already have!!!)
const ulong ticks_mask = 0x3FFFFFFFFFFFFFFF;
const int kind_shift = 62;
return new DateTime((long)(ll & ticks_mask), (DateTimeKind)(ll >> kind_shift));
int year, month, day, hour, minute, second, ms;
ll_to_parts(ll, out year, out month, out day, out hour, out minute, out second, out ms);
if (year > 0) {
return new DateTime(year, month, day, hour, minute, second, ms, DateTimeKind.Utc).ToLocalTime();
}
return DateTime.MinValue;
}
public static DateTime lldatetime(this long ll) { return ((ulong)ll).lldatetime(); }
}
}
}
@@ -18,7 +18,6 @@ namespace mbts.utils
}
public static implicit operator DateTime (LLDateTime time) { return time.to_datetime(); }
public static implicit operator LLDateTime (DateTime time) { return new LLDateTime((ulong)time.Ticks); }
public static LLDateTime now() {
return new LLDateTime(BTSNativeMethods.ll_now());
-5
View File
@@ -56,11 +56,6 @@ namespace bts.utils {
if (value > max) return max;
return value;
}
public static long within_range(long min, long max, long value) {
if (value < min) return min;
if (value > max) return max;
return value;
}
public static double within_range(double min, double max, double value) {
if (value < min) return min;
if (value > max) return max;
+13 -27
View File
@@ -112,7 +112,7 @@ namespace mbts.co2.tests
Assert.IsTrue(last.price == 4.2);
Assert.IsTrue(last.size == 101);
Assert.IsTrue(entry.total_volume == 12345);
Assert.IsTrue(compare_date(entry.last_trade_time, DateTime.UtcNow));
Assert.IsTrue(compare_date(entry.last_trade_time, DateTime.Now));
//// Settlement
Assert.AreEqual(entry.settlement_price, 3.3);
Assert.IsTrue(entry.settlement_date == new DateTime(2015, 9, 3));
@@ -210,19 +210,24 @@ namespace mbts.co2.tests
Assert.IsTrue(ask.size == 202);
time = 0;
DateTime trade_date;
ulong total_volume;
NativePriceSize last_trade;
Assert.IsTrue(handle.get_last_trade(ref time, out last_trade, out trade_date, out total_volume));
Assert.IsTrue(handle.get_last_trade(ref time, out NativePriceSize last_trade, out utils.LLDateTime ll_trade_date, out ulong total_volume));
// trade date
DateTime trade_date = ll_trade_date;
Assert.IsTrue(last_trade.price == 5.5 && last_trade.size == 505);
Assert.IsTrue(trade_date.Year == 2015 && trade_date.Month == 9 && trade_date.Day == 22);
Assert.IsTrue(total_volume == 4200);
Assert.IsTrue(handle.settlement_date.Year == 2000 && handle.settlement_date.Day == 9 && handle.settlement_date.Month == 8);
// settlement date
DateTime settlement_dt = handle.settlement_date;
Assert.IsTrue(settlement_dt.Year == 2000 && settlement_dt.Day == 9 && settlement_dt.Month == 8);
Assert.IsTrue(handle.settlement_price == 6.6);
Assert.IsTrue(handle.open_price == 7.7);
Assert.IsTrue(handle.open_date.Year == 2001 && handle.open_date.Month == 1 && handle.open_date.Day == 2);
// open date
DateTime open_dt = handle.open_date;
Assert.IsTrue(open_dt.Year == 2001 && open_dt.Month == 1 && open_dt.Day == 2);
Assert.IsTrue(handle.close_price == 8.8);
Assert.IsTrue(handle.close_date.Year == 2002 && handle.close_date.Month == 3 && handle.close_date.Day == 4);
// close date
DateTime close_dt = handle.close_date;
Assert.IsTrue(close_dt.Year == 2002 && close_dt.Month == 3 && close_dt.Day == 4);
Assert.IsTrue(handle.session_high == 9.9);
Assert.IsTrue(handle.session_low == 10.1);
@@ -251,25 +256,6 @@ namespace mbts.co2.tests
Assert.IsTrue(double.IsNaN(npl.bid.price));
}
[Test]
public void lldatetime_test() {
utils.LLDateTime now = DateTime.MinValue, utc_now = DateTime.MinValue;
Co2NativeTestMethods.co2_get_sample_datetime(ref now, ref utc_now);
DateTime dt_now = now;
DateTime dt_utc_now = utc_now;
Assert.AreEqual(dt_now.ToShortDateString(), DateTime.Now.ToShortDateString());
Assert.AreEqual(dt_utc_now.ToShortDateString(), DateTime.UtcNow.ToShortDateString());
void assert_about_equal(int a, int b) {
Assert.That(Math.Abs(a - b) <= 1);
}
assert_about_equal(dt_now.Hour, DateTime.Now.Hour);
assert_about_equal(dt_now.Minute, DateTime.Now.Minute);
assert_about_equal(dt_now.Second, DateTime.Now.Second);
assert_about_equal(dt_utc_now.Hour, DateTime.UtcNow.Hour);
assert_about_equal(dt_utc_now.Minute, DateTime.UtcNow.Minute);
assert_about_equal(dt_utc_now.Second, DateTime.UtcNow.Second);
}
}
}
@@ -1,20 +0,0 @@
using ManyConsole;
using System.Reflection;
namespace bts {
public class SettinsManagerCommand : ConsoleCommand {
public SettinsManagerCommand() {
IsCommand("SettingsManager", "Copy workspaces around");
}
public override int Run(string[] remainingArguments) {
var asm = Assembly.Load("spark");
var type = asm.GetType("bts.settings.SettingsManagerTool");
var run = type.GetMethod("run", BindingFlags.Static | BindingFlags.Public);
run.Invoke(null, new object[0]);
return 0;
}
}
}
-3
View File
@@ -13,8 +13,5 @@ namespace sparkcmd {
ConsoleCommandDispatcher.DispatchCommand(commands, args, Console.Out);
return;
}
}
}
+2 -1
View File
@@ -8,7 +8,8 @@
<Authors>Blue Trading Systems</Authors>
<Company>Blue Trading Systems</Company>
<Product>Spark</Product>
<Platforms>x64</Platforms>
<Platform>x64</Platform>
<PlatformTarget>x64</PlatformTarget>
<Version>1.0.0</Version>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
+1 -1
View File
@@ -1 +1 @@
set(sources files/Onixs.BTS.lic;files/cert_secure_logon.txt;files/perf_trace/compiled.css;files/perf_trace/index.html;files/perf_trace/jquery-3.3.1.min.js;files/perf_trace/main.js;files/perf_trace/plotly-latest.min.js)
set(sources /home/ppinto/Dropbox/bts/spark/src/data_files/files/Onixs.BTS.lic;/home/ppinto/Dropbox/bts/spark/src/data_files/files/Onixs.BTS.lic.orig;/home/ppinto/Dropbox/bts/spark/src/data_files/files/cert_secure_logon.txt)
+1 -1
View File
@@ -4,7 +4,7 @@ project(data_files)
include(${CMAKE_SOURCE_DIR}/tools/safe_dep_glob.cmake)
# DEPENDENCIES
file (GLOB_RECURSE To_Copy RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} files/*)
file (GLOB_RECURSE To_Copy ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR} files/*)
update_deps_file("${To_Copy}")
# END DEPENDENCIES
Binary file not shown.
@@ -1,63 +0,0 @@
<html>
<head>
<title>BTS Spark Socket To Socket Requote Times</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/perf_trace/compiled.css">
<script src="https://cdn.polyfill.io/v2/polyfill.js?features=es6"></script>
<style type="text/css">
.summary-block {
margin: 2em 1em;
}
.summary-block > ul {
margin: 0em 1em;
display:inline-block;
vertical-align: top;
}
.histogram-div {
width: 550px;
height:350px;
display:inline-block
}
.clear {
clear:both;
}
</style>
</head>
<body>
<div>
<div class="columns is-fullheight">
<div class="column is-narrow is-launcher-sidebar-menu">
<aside class="menu">
<ul class="menu-list">
<li>&nbsp;&nbsp;</li>
</ul>
</aside>
</div>
<div class="column is-main-content">
<div class="columns is-fullheight">
<!--div class="column is-narrow is-sidebar-menu">
</div-->
<div class="column is-main-content">
<!--div class="tabs is-boxed">
<ul>
<li class="is-active"><a>Stats</a></li>
</ul>
</div-->
<div style="margin:2em 0 0 2em;"><!--div class="is-tab-content" is-tab-content is shorter than the screen to accommodate tabs at the top -->
<h1 class="is-size-2">Socket To Socket Requote Times</h1>
<div id="output"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="/perf_trace/jquery-3.3.1.min.js"></script>
<script src="/perf_trace/plotly-latest.min.js"></script>
<script src="/perf_trace/main.js"></script>
</body>
</html>
-2
View File
@@ -1,2 +0,0 @@
/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:"jQuery"+("3.3.1"+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==c.call(e))&&(!(t=i(e))||"function"==typeof(n=f.call(t,"constructor")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),"function"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function C(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",I="\\["+M+"*("+R+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+R+"))|)"+M+"*\\]",W=":("+R+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+I+")*)|.*)\\)|)",$=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),F=new RegExp("^"+M+"*,"+M+"*"),_=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)Line truncated
-164
View File
@@ -1,164 +0,0 @@
$( document ).ready(function (){
let urlParams = new URLSearchParams(window.location.search);
num_rows = urlParams.get('r');
let show_rows = urlParams.get('showrows');
let trace_data_url = "/perf_trace_data";
if(num_rows != null) {
trace_data_url += "/" + num_rows;
}
$.ajax({
url: trace_data_url,
dataType: 'json',
context: document.body,
error: ajax_err,
crossDomain: true
}).done(function(result) {
if(show_rows != null) {
list_rows(show_rows, result);
}
else {
if(result.length > 0){
let summary_info = "<h1 class='is-size-3'><b>Host:</b> " + result[0].host + "</h1>";
$("#output").html(summary_info);
$(result).each(display_session);
}
}
});
});
function list_rows(show_rows, data) {
$.each(data, function(index, value){
if(value.session_name === show_rows){
let summary_info = "<table class='table bts-data-table'>";
summary_info += "<thead><tr><th>Trace Time</th>" +
"<th>Order Key</th>" +
"<th>MD</th>" +
"<th>Spreader</th>" +
"<th>Fix</th>" +
"<th>Total</th></tr></thead><tbody>";
$.each(value.rows, function(key, val) {
summary_info += "<tr>";
console.log(val);
summary_info += "<td>" + val.trace_time + "</td>" +
"<td>" + val.order_key + "</td>" +
"<td>" + val.md + "</td>" +
"<td>" + val.spreader + "</td>" +
"<td>" + val.fix + "</td>" +
"<td>" + val.total + "</td>";
summary_info += "</tr>";
});
summary_info += "</tbody></table>";
$("#output").html(summary_info);
return false;
}
});
}
function ajax_err (jqXHR, textStatus,errorThrown) {
$("#output").html("<h3 class='is-size-3 has-text-danger'>Error loading perf_trace_data</h3>" +
"<p>" + textStatus + "</p>" +
"<pre>" + errorThrown + "</pre>"
);
console.log(textStatus);
console.log(errorThrown);
}
function first_upper (str)
{
let ret_str = str[0].toUpperCase() + str.substring(1, str.length);
return ret_str
}
function generate_histogram(id, data)
{
var trace = {
x: data,
type: 'histogram',
marker: {
color: 'rgb(65,105,170)'
},
};
var plot_data = [trace];
Plotly.newPlot(id, plot_data);
}
function display_session (index, value) {
//console.log(value);
let session_info = "<ul class=''>";
session_info += "<li id='" + value.session_name + "' class='is-size-5'><b>Session:</b> " + value.session_name + "</li>";
session_info += "<li><b>Build Type:</b> " + value.build_type + "</li>";
session_info += "<li><b>Version:</b> " + value.version + "</li>";
if(num_rows != null) {
session_info += "<li><a href='?showrows=" + value.session_name + "&r=" + num_rows + "'><b>Rows:</b> " + value.n_rows + "</a></li>";
}
else {
session_info += "<li><a href='?showrows=" + value.session_name + "'><b>Rows:</b> " + value.n_rows + "</a></li>";
}
$(value.summaries).each(function(i,v){
if(v.value === "total") {
session_info += "<li class='summary-block'><ul>";
session_info += "<li><b>" + first_upper(v.value) + "</b></li>";
session_info += "<li>Min: " + v.min + "</li>";
session_info += "<li>Median: " + v.median + "</li>";
session_info += "<li>Max: " + v.max + "</li>";
session_info += "<li>99%: " + v.ninenty_nine + "</li>";
session_info += "<li>Standard Deviation: " + v.stdev + "</li>";
session_info += "</ul>";
session_info += "<div id='" + value.session_name + "-" + v.value + "' class='histogram-div'></div>"
session_info += "</li>";
return false
}
});
$(value.summaries).each(function(i,v){
if(v.value !== "total") {
session_info += "<li class='summary-block'><ul>";
session_info += "<li><b>" + first_upper(v.value) + "</b></li>";
session_info += "<li>Min: " + v.min + "</li>";
session_info += "<li>Median: " + v.median + "</li>";
session_info += "<li>Max: " + v.max + "</li>";
session_info += "<li>99%: " + v.ninenty_nine + "</li>";
session_info += "<li>Standard Deviation: " + v.stdev + "</li>";
session_info += "</ul>";
session_info += "<div id='" + value.session_name + "-" + v.value + "' class='histogram-div'></div>"
session_info += "</li>";
}
});
session_info += "</ul><hr class='clear'>";
$("#output").append(session_info);
let all_data = {};
$(value.rows).each(function(i, row) {
$.each(row, function(name, v) {
if(all_data[name] === undefined){
all_data[name] = [v];
}
else {
all_data[name].push(v);
}
});
});
//console.log(all_data);
$(value.summaries).each(function(i,v){
generate_histogram(value.session_name + "-" + v.value, all_data[v.value]);
});
}
-7
View File
@@ -1,7 +0,0 @@
/**
* plotly.js v1.41.3
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
* Licensed under the MIT license
*/
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Plotly=t()}}(function(){return function(){return function t(e,r,n){function i(o,s){if(!r[o]){if(!e[o]){var l="function"==typeof require&&require;if(!s&&l)return l(o,!0);if(a)return a(o,!0);var c=new Error("Cannot find module '"+o+"'");throw c.code="MODULE_NOT_FOUND",c}var u=r[o]={exports:{}};e[o][0].call(u.exports,function(t){return i(e[o][1][t]||t)},u,u.exports,t,e,r,n)}return r[o].exports}for(var a="function"==typeof require&&require,o=0;o<n.length;o++)i(n[o]);return i}}()({1:[function(t,e,r){"use strict";var n=t("../src/lib"),i={"X,X div":"direction:ltr;font-family:'Open Sans', verdana, arial, sans-serif;margin:0;padding:0;","X input,X button":"font-family:'Open Sans', verdana, arial, sans-serif;","X input:focus,X button:focus":"outline:none;","X a":"text-decoration:none;","X a:hover":"text-decoration:none;","X .crisp":"shape-rendering:crispEdges;","X .user-select-none":"-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;","X svg":"overflow:hidden;","X svg a":"fill:#447adb;","X svg a:hover":"fill:#3c6dc5;","X .main-svg":"position:absolute;top:0;left:0;pointer-events:none;","X .main-svg .draglayer":"pointer-events:all;","X .cursor-default":"cursor:default;","X .cursor-pointer":"cursor:pointer;","X .cursor-crosshair":"cursor:crosshair;","X .cursor-move":"cursor:move;","X .cursor-col-resize":"cursor:col-resize;","X .cursor-row-resize":"cursor:row-resize;","X .cursor-ns-resize":"cursor:ns-resize;","X .cursor-ew-resize":"cursor:ew-resize;","X .cursor-sw-resize":"cursor:sw-resize;","X .cursor-s-resize":"cursor:s-resize;","X .cursor-se-resize":"cursor:se-resize;","X .cursor-w-resize":"cursor:w-resize;","X .cursor-e-resize":"cursor:e-resize;","X .cursor-nw-resize":"cursor:nw-resize;","X .cursor-n-resize":"cursor:n-resize;","X .cursor-ne-resize":"cursor:ne-resize;","X .cursor-grab":"cursor:-webkit-grab;cursor:grab;","X .modebar":"position:absolute;top:2px;right:2px;z-index:1001;background:rgba(255,255,255,0.7);","X .modebar--hover":"opacity:0;-webkit-transition:opacity 0.3s ease 0s;-moz-transition:opacity 0.3s ease 0s;-ms-transition:opacity 0.3s ease 0s;-o-transition:opacity 0.3s ease 0s;transition:opacity 0.3s ease 0s;","X:hover .modebar--hover":"opacity:1;","X .modebar-group":"float:left;display:inline-block;box-sizing:border-box;margin-left:8px;position:relative;vertical-align:middle;white-space:nowrap;","X .modebar-group:first-child":"margin-left:0px;","X .modebar-btn":"position:relative;font-size:16px;padding:3px 4px;cursor:pointer;line-height:normal;box-sizing:border-box;","X .modebar-btn svg":"position:relative;top:2px;","X .modebar-btn path":"fill:rgba(0,31,95,0.3);","X .modebar-btn.active path,X .modebar-btn:hover path":"fill:rgba(0,22,72,0.5);","X .modebar-btn.modebar-btn--logo":"padding:3px 1px;","X .modebar-btn.modebar-btn--logo path":"fill:#447adb !important;","X [data-title]:before,X [data-title]:after":"position:absolute;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);-ms-transform:translate3d(0, 0, 0);-o-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);display:none;opacity:0;z-index:1001;pointer-events:none;top:110%;right:50%;","X [data-title]:hover:before,X [data-title]:hover:after":"display:block;opacity:1;","X [data-title]:before":"content:'';position:absolute;background:transparent;border:6px solid transparent;z-index:1002;margin-top:-12px;border-bottom-color:#69738a;margin-right:-6px;","X [data-title]:after":"content:attr(data-title);background:#69738a;color:white;padding:8px 10px;font-size:12px;line-height:12px;white-space:nowrap;margin-right:-18px;border-radius:2px;","X .select-outline":"fill:none;stroke-width:1;shape-rendering:crispEdges;","X .select-outline-1":"stroke:white;","X .select-outline-2":"stroke:black;stroke-dasharray:2px 2px;",Y:"font-family:'Open Sans';position:fixed;top:50px;right:20px;z-index:10000;font-size:10pt;max-width:180px;","Y p":"margin:0;","Y .notifier-note":"min-width:180px;max-width:250px;border:1px solid #fff;z-index:3000;margin:0;background-color:#8c97af;background-color:rgba(140,151,175,0.9);color:#fff;padding:10px;overflow-wrap:break-word;word-wrap:break-word;-ms-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;","Y .notifier-close":"color:#fff;opacity:0.8;float:right;padding:0 5px;background:none;border:none;font-size:20px;font-weight:bold;line-height:20px;","Y .notifier-close:hover":"color:#444;text-decoration:none;cursor:pointer;"};for(var a in i){var o=a.replace(/^,/," ,").replace(/X/g,".js-plotly-plot .plotly").replace(/Y/g,".plotly-notifier");n.addStyleRule(o,i[a])}},{"../src/lib":693}],2:[function(t,e,r){"use strict";e.exports={undo:{width:857.1,height:1e3,path:"m857 350q0-87-34-166t-91-137-137-92-166-34q-96 0Line truncated
+1 -1
View File
@@ -1 +1 @@
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cpp_config.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/expiration_display_offset.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cpp_config.proto;config/protos/dynamic_orders.proto;config/protos/expiration_display_offset.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/IPollableActor.cpp;mercury/broker/Broker.cpp;mercury/broker/BrokerProxy.cpp;mercury/broker/ILocalBroker.cpp;mercury/broker/IRemoteBroker.cpp;mercury/common/mercury_common.cpp;mercury/events/TimerEvent.cpp;mercury/executor/Executor.cpp;mercury/topics/Topic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.Line truncated
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/dynamic_orders.proto;config/protos/environment.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/Actor.cpp;mercury/broker/AsyncEventBroker.cpp;mercury/broker/CoreEventBroker.cpp;mercury/broker/IEventBroker.cpp;mercury/events/TimerEvent.cpp;mercury/mercury_utils/Executor.cpp;mercury/mercury_utils/IPollableActor.cpp;mercury/mercury_utils/mercury_common.cpp;mercury/synopsis/SynopsisBuilder.cpp;mercury/topics/ITopic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/DynamicOrderRegistry.cpp;ordermanLine truncated
-1
View File
@@ -103,7 +103,6 @@ else ()
boost_chrono
boost_date_time
boost_atomic
SQLiteCpp
sqlite3
curl
uuid
@@ -1,34 +1,40 @@
#include "lib/api/services/AdminService.server.pb.h"
#include "lib/api/service_helpers/AdminServiceUtils.h"
#include "lib/md/get_symbols.h"
#include "lib/config/protos/cme_reference_data.pb.h"
#include "lib/config/protos/jetfix.pb.h"
#include "lib/config/config.h"
#include <sstream>
namespace bts{
namespace admin{
////////////////////////////////////////////
// connection accessors ////////////////////
////////////////////////////////////////////
uint32_t AdminServiceUtils::find_max_connection_id (const bts::api::admin::AdminData& data){
uint32_t AdminServiceUtils::find_max_connection_id (const AdminData& data){
uint32_t rv = 0;
for(const auto &conn : data.connections())
if (conn.id() > rv)
rv = conn.id();
return rv;
}
const bts::api::admin::ExchangeConnection* AdminServiceUtils::find_connection(const bts::api::admin::AdminData& data,
const std::string& connection_name){
const ExchangeConnection* AdminServiceUtils::find_connection(
const AdminData& data,
const std::string& connection_name){
for(const auto& connection : data.connections())
if(connection.name()==connection_name)
return &connection;
return nullptr;
}
bool AdminServiceUtils::has_exchange(const bts::api::admin::ExchangeConnection& conn,
bts::api::Venue exchange){
bool AdminServiceUtils::has_exchange(const ExchangeConnection& conn,
api::Venue exchange){
bool rv = false;
switch(exchange)
{
case api::Venue::VENUE_GLBX:
rv = conn.has_cme_connection() &&
(conn.cme_connection().has_cgw_connection() || conn.cme_connection().has_msgw_connection());
(conn.cme_connection().has_cgw_connection() ||
conn.cme_connection().has_msgw_connection());
break;
case api::Venue::VENUE_UNSET:
case api::Venue::VENUE_SIM:
@@ -870,6 +876,89 @@ void AdminServiceUtils::validate_user_exchange_data (const bts::api::admin::BTSU
}
}
}
void AdminServiceUtils::get_md_entitlement_report(const AdminData& admin_data,
std::vector<MDEntitlementReportUnit>& entitlements){
for (const auto& user : admin_data.users()){
const CMEUserData* cme_data=AdminServiceUtils::get_user_cme_data(user,
admin_data);
if(cme_data!=nullptr){
for (const auto& cme_mic_data : cme_data->md_permissions()){
MDEntitlementReportUnit rv=get_cme_md_entitlement_unit(user.name(),
cme_mic_data);
entitlements.push_back(rv);
}
}
}
}
MDEntitlementReportUnit AdminServiceUtils::get_cme_md_entitlement_unit(
const std::string& user,
const CMEMicData& cme_mic_data){
MDEntitlementReportUnit rv;
rv.set_user(user);
rv.set_exchange("GLBX");
switch(cme_mic_data.mic())
{
case api::CMEMics::CME:
rv.set_mic("CME");
break;
case api::CMEMics::NYMEX:
rv.set_mic("NYMEX");
break;
case api::CMEMics::CBT:
rv.set_mic("CBT");
break;
case api::CMEMics::COMEX:
rv.set_mic("COMEX");
break;
case api::CMEMics::MGE:
rv.set_mic("MGE");
break;
case api::CMEMics::DME:
rv.set_mic("DME");
break;
case api::CMEMics::NYMSW:
rv.set_mic("NYMSW");
break;
case api::CMEMics::FXS:
rv.set_mic("FXS");
break;
case api::CMEMics::UNSET:
case api::CMEMics::CMEMics_INT_MIN_SENTINEL_DO_NOT_USE_:
case api::CMEMics::CMEMics_INT_MAX_SENTINEL_DO_NOT_USE_:
rv.set_mic("");
break;
}
rv.set_enabled(cme_mic_data.enabled());
std::ostringstream key;
key << rv.user() << rv.exchange() << rv.mic();
rv.set_record_id(key.str());
return rv;
}
void AdminServiceUtils::get_user_symbol_permissions(const AdminData& data,
const BTSUser& user,
std::vector<UserSymbolMDPermissionUnit>& rv){
std::map<api::CMEMics, bool> mic_perm_map;
auto exchange = api::Venue::VENUE_GLBX;
const CMEUserData* cme_data=get_user_cme_data(user,data);
if(cme_data!=nullptr)
for(const auto& mic_data : cme_data->md_permissions())
if(mic_data.enabled())
mic_perm_map[mic_data.mic()]=true;
const auto& cme_symb_mics = config::get<config::CmeSymbolMics>().cme_mic();
for(auto it=cme_symb_mics.begin();it!=cme_symb_mics.end();it++){
const std::string& symbol=it->first;
api::CMEMics mic=it->second;
UserSymbolMDPermissionUnit u;
std::ostringstream key;
key << exchange << user.name() << symbol;
u.set_record_id(key.str());
u.set_user(user.name());
u.set_exchange(exchange);
u.set_symbol(symbol);
u.set_enabled(mic_perm_map.find(mic)!=mic_perm_map.end());
rv.push_back(u);
}
}
////////////////////////////////////////////
// user mutators ///////////////////////////
////////////////////////////////////////////
+199 -145
View File
@@ -4,12 +4,13 @@
#include "lib/api/services/AdminService.server.pb.h"
#include "lib/api/services/OrderService.server.pb.h"
#include "lib/domain_model/Security.h"
#include "lib/config/protos/jetfix.pb.h"
#include "lib/config/config.h"
namespace bts{
namespace admin{
using namespace bts::api::admin;
using namespace bts::api::orderman;
class AdminServiceUtils{
public:
////////////////////////////////////////////
@@ -17,233 +18,286 @@ public:
////////////////////////////////////////////
// finds the max id out of all the existing connections
// (todo: deleted connections)
static uint32_t find_max_connection_id (const bts::api::admin::AdminData& data);
static uint32_t find_max_connection_id (const AdminData& data);
// finds a connection by name and returns a mutable pointer to it
static const bts::api::admin::ExchangeConnection* find_connection(const bts::api::admin::AdminData& data,
const std::string& connection_name);
static const ExchangeConnection* find_connection(const AdminData& data,
const std::string& connection_name);
// finds the presence of an exchange in a connection
static bool has_exchange(const bts::api::admin::ExchangeConnection& conn,
static bool has_exchange(const ExchangeConnection& conn,
bts::api::Venue exchange);
// finds the default connections for an exchange
// in a given account
static const bts::api::admin::ExchangeConnection* find_default_account_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
bts::api::Venue exchange);
static const bts::api::admin::ExchangeConnection* resolve_cme_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
const bts::api::Security& sec);
static const bts::api::admin::ExchangeConnection* resolve_sim_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
const bts::api::Security& sec);
static const bts::api::admin::ExchangeConnection* resolve_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
const bts::api::Security& sec);
static const ExchangeConnection* find_default_account_connection(
const AdminData& data,
const BTSAccount& account,
bts::api::Venue exchange);
static const ExchangeConnection* resolve_cme_connection(
const AdminData& data,
const BTSAccount& account,
const api::Security& sec);
static const ExchangeConnection* resolve_sim_connection(
const AdminData& data,
const BTSAccount& account,
const api::Security& sec);
static const ExchangeConnection* resolve_connection(
const AdminData& data,
const BTSAccount& account,
const bts::api::Security& sec);
////////////////////////////////////////////
// connection mutators /////////////////////
////////////////////////////////////////////
// adds a new connection (does not check for name uniqueness)
static bts::api::admin::ExchangeConnection* add_connection(bts::api::admin::AdminData& data,
const bts::api::admin::ExchangeConnection& new_connection);
static ExchangeConnection* add_connection(AdminData& data,
const ExchangeConnection& new_connection);
// reads the connections from config and fills in the
// admin data (with names only)
static void fill_connections_from_config(bts::api::admin::AdminData& admin_data);
static void fill_connections_from_config(AdminData& admin_data);
////////////////////////////////////////////
// account accessors ///////////////////////
////////////////////////////////////////////
// finds the account from the name and returns
// a mutable pointer to the account
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, const std::string& acct_name, bool include_deleted=false);
static BTSAccount* find_account (AdminData& data,
const std::string& acct_name,
bool include_deleted=false);
// same as above for const pointer
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::AdminData& data, const std::string& acct_name, bool include_deleted=false);
static const BTSAccount* find_account (const AdminData& data,
const std::string& acct_name,
bool include_deleted=false);
// finds the account from the id and returns
// a mutable pointer to the account
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static BTSAccount* find_account (AdminData& data,
uint32_t id,
bool include_deleted=false);
// like above but returns a const pointer
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static const BTSAccount* find_account (const AdminData& data,
uint32_t id,
bool include_deleted=false);
// this function is an indirection layer for account access
// so deletions are dealt in a more deliberate manner
static std::vector<const bts::api::admin::BTSAccount*> accounts (const bts::api::admin::AdminData& data, bool include_deleted);
static std::vector<bts::api::admin::BTSAccount*> accounts_mutable (bts::api::admin::AdminData& data, bool include_deleted);
static std::vector<const BTSAccount*> accounts (const AdminData& data,
bool include_deleted);
static std::vector<BTSAccount*> accounts_mutable (AdminData& data,
bool include_deleted);
// finds the max id amongts all the existing accounts
static uint32_t find_max_acct_id (const bts::api::admin::AdminData& data);
static uint32_t find_max_acct_id (const AdminData& data);
// gets the account data for cme (and goes up the hierarchy
// if needed)
static const bts::api::admin::CMEAccountData* get_account_cme_data(const bts::api::admin::BTSAccount& account,
const bts::api::admin::AdminData& data);
static const bts::api::admin::SIMAccountData* get_account_sim_data(const bts::api::admin::BTSAccount& account,
const bts::api::admin::AdminData& data);
static const CMEAccountData* get_account_cme_data(const BTSAccount& account,
const AdminData& data);
static const SIMAccountData* get_account_sim_data(const BTSAccount& account,
const AdminData& data);
// returns true if an account has a connection
bool static account_has_connection(const bts::api::admin::BTSAccount& account, const std::string& connection_name);
bool static account_has_connection(const BTSAccount& account,
const std::string& connection_name);
// finds the external/clearing account associated
// with an account
static std::string find_account_exchange_account (const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
api::Venue exchange,
bts::api::admin::AdminServiceOperationResult& out_result);
static std::string find_account_exchange_account (const AdminData& data,
const BTSAccount& account,
api::Venue exchange,
AdminServiceOperationResult& out_result);
// returns a map of the accounts vs their 'is_active'
static std::map<uint32_t,bool> accounts_map(const bts::api::admin::AdminData& admin_data);
static std::map<uint32_t,bool> accounts_map(const AdminData& admin_data);
// validates that the update to the account is valid
static void validate_account_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSAccount& updated_account,
bts::api::admin::AdminServiceOperationResult& result);
static void validate_account_update (const AdminData& admin_data,
const BTSAccount& updated_account,
AdminServiceOperationResult& result);
// validates that the account exchange changes are valid
// (ex > 12 characters for accounts at CME)
static void validate_account_exchange_data (const bts::api::admin::BTSAccount& account,
bts::api::admin::AdminServiceOperationResult& out_result);
static bts::api::orderman::RoutingRecord get_routing_record(const bts::api::admin::AdminData& data,
const std::string& account_name,
const std::string& user_name,
const bts::api::Security& sec,
bts::api::admin::AdminServiceOperationResult& out_result);
static bts::api::orderman::RoutingRecord get_routing_record(const bts::api::admin::AdminData& data,
uint32_t account_id,
uint32_t user_id,
const bts::api::Security& sec,
bts::api::admin::AdminServiceOperationResult& out_result);
static void validate_account_exchange_data (const BTSAccount& account,
AdminServiceOperationResult& out_result);
static RoutingRecord get_routing_record(
const AdminData& data,
const std::string& account_name,
const std::string& user_name,
const bts::api::Security& sec,
AdminServiceOperationResult& out_result);
static RoutingRecord get_routing_record(const AdminData& data,
uint32_t account_id,
uint32_t user_id,
const bts::api::Security& sec,
AdminServiceOperationResult& out_result);
////////////////////////////////////////////
// account mutators ////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSAccount* create_account(bts::api::admin::AdminData& data,
uint32_t parent_account_id,
const std::string& account_name,
const std::string& description,
bool is_active,
bts::api::admin::AdminServiceCreateAccountResult& result);
static BTSAccount* create_account(AdminData& data,
uint32_t parent_account_id,
const std::string& account_name,
const std::string& description,
bool is_active,
AdminServiceCreateAccountResult& result);
// writes over the account data completely
static void update_account(bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& updated_account,
bts::api::admin::AdminServiceOperationResult& result);
static void delete_account (bts::api::admin::AdminData& admin_data,
const bts::api::admin::IDAPIArgument& id,
bts::api::admin::AdminServiceOperationResult& result);
static void set_account_exchange_data(bts::api::admin::BTSAccount* account,
const bts::api::admin::ExchangeAccountData& exchange_data);
static void update_account(AdminData& data,
const BTSAccount& updated_account,
AdminServiceOperationResult& result);
static void delete_account (AdminData& admin_data,
const IDAPIArgument& id,
AdminServiceOperationResult& result);
static void set_account_exchange_data(BTSAccount* account,
const ExchangeAccountData& exchange_data);
// this is not a generally useful function but since
// connection are in config, this cleans up the account's
// connections and syncs it with the list in AdminData
static void sync_account_connections(const bts::api::admin::AdminData& data,
bts::api::admin::BTSAccount& account);
static void sync_account_connections(const AdminData& data,
BTSAccount& account);
////////////////////////////////////////////
// group accessors /////////////////////////
////////////////////////////////////////////
// given an id, finds the mutable pointer to a group
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, uint32_t id);
static BTSUserGroup* find_group (AdminData& data, uint32_t id);
// given an id, finds the const pointer to a group
static const bts::api::admin::BTSUserGroup* const find_group (const bts::api::admin::AdminData& data, uint32_t id);
static const BTSUserGroup* const find_group (const AdminData& data,
uint32_t id);
// given a name, finds the mutable pointer to a group
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, const std::string& group_name);
static BTSUserGroup* find_group (AdminData& data,
const std::string& group_name);
// finds the max id out of all the groups
static uint32_t find_max_group_id (const bts::api::admin::AdminData& data);
static uint32_t find_max_group_id (const AdminData& data);
// travels up the group tree until it finds a populated cme data
static const bts::api::admin::CMEUserData* get_group_cme_data(const bts::api::admin::BTSUserGroup& group,
const bts::api::admin::AdminData& data);
static const bts::api::admin::SIMUserData* get_group_sim_data(const bts::api::admin::BTSUserGroup& group,
const bts::api::admin::AdminData& data);
static const bts::api::admin::UserAccountPermissions* const get_group_user_permissions (const bts::api::admin::AdminData& admin_data,
uint32_t group_id);
static const CMEUserData* get_group_cme_data(const BTSUserGroup& group,
const AdminData& data);
static const SIMUserData* get_group_sim_data(const BTSUserGroup& group,
const AdminData& data);
static const UserAccountPermissions* const get_group_user_permissions (
const bts::api::admin::AdminData& admin_data,
uint32_t group_id);
////////////////////////////////////////////
// group mutators/ /////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSUserGroup* create_group(bts::api::admin::AdminData& data,
uint32_t parent_group_id,
const std::string& group_name,
bts::api::admin::AdminServiceOperationResult& result);
static BTSUserGroup* create_group(AdminData& data,
uint32_t parent_group_id,
const std::string& group_name,
AdminServiceOperationResult& result);
////////////////////////////////////////////
// user accessors //////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSUser* find_user (bts::api::admin::AdminData& data, const std::string& user_name, bool include_deleted=false);
static const bts::api::admin::BTSUser* find_user (const bts::api::admin::AdminData& data, const std::string& user_name, bool include_deleted=false);
static bts::api::admin::BTSUser* find_user (bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static const bts::api::admin::BTSUser* const find_user (const bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static std::vector<const bts::api::admin::BTSUser*> users (const bts::api::admin::AdminData& data, bool include_deleted);
static std::vector<bts::api::admin::BTSUser*> users_mutable (bts::api::admin::AdminData& data, bool include_deleted);
static uint32_t find_max_user_id (const bts::api::admin::AdminData& data);
static const bts::api::admin::CMEUserData* get_user_cme_data(const bts::api::admin::BTSUser& user,
const bts::api::admin::AdminData& data);
static const bts::api::admin::SIMUserData* get_user_sim_data(const bts::api::admin::BTSUser& user,
const bts::api::admin::AdminData& data);
static BTSUser* find_user (AdminData& data,
const std::string& user_name,
bool include_deleted=false);
static const BTSUser* find_user (const AdminData& data,
const std::string& user_name,
bool include_deleted=false);
static BTSUser* find_user (AdminData& data,
uint32_t id,
bool include_deleted=false);
static const BTSUser* const find_user (const AdminData& data,
uint32_t id,
bool include_deleted=false);
static std::vector<const BTSUser*> users (const AdminData& data,
bool include_deleted);
static std::vector<BTSUser*> users_mutable (AdminData& data,
bool include_deleted);
static uint32_t find_max_user_id (const AdminData& data);
static const CMEUserData* get_user_cme_data(const BTSUser& user,
const AdminData& data);
static const SIMUserData* get_user_sim_data(const BTSUser& user,
const AdminData& data);
// finds the "exchange user" (ex: "operator_id" at CME or "authorized_trader"
// at ICE) for a user
static std::string find_user_exchange_id (const bts::api::admin::AdminData& data,
const bts::api::admin::BTSUser& user,
api::Venue exchange,
bts::api::admin::AdminServiceOperationResult& out_result);
static std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>
find_user_account_matches (const bts::api::admin::AdminData& admin_data,
const std::string& connection, const std::string& exchange_account,
static std::string find_user_exchange_id (
const AdminData& data,
const BTSUser& user,
api::Venue exchange,
AdminServiceOperationResult& out_result);
static std::pair<const BTSAccount*, const BTSUser*>
find_user_account_matches (const AdminData& admin_data,
const std::string& connection,
const std::string& exchange_account,
const std::string& exchange_user,
api::Venue exchange);
// for a given user finds the account permissions (if permissions are
// derived from the group, it traverses the group hierarcy to find the
// correct permissions.
static const bts::api::admin::UserAccountPermissions* get_user_permissions (const bts::api::admin::AdminData& admin_data, uint32_t user_id);
static const UserAccountPermissions* get_user_permissions (
const AdminData& admin_data,
uint32_t user_id);
// for a given user, fills in the associated_accounts ref arg
// with the accounts the user has permission to trade in
static void find_user_trading_accounts (const bts::api::admin::AdminData& admin_data,
uint32_t user_id,
std::vector<const api::admin::BTSAccount*>& associated_accounts);
static void find_user_trading_accounts (
const AdminData& admin_data,
uint32_t user_id,
std::vector<const BTSAccount*>& associated_accounts);
// validates that changes in user data satisfy all the
// constraints
static void validate_user_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& result);
static void validate_user_update (const AdminData& admin_data,
const BTSUser& updated_user,
AdminServiceOperationResult& result);
// vaidates the exchange part of user data updates
static void validate_user_exchange_data (const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& out_result);
static void validate_user_exchange_data (
const BTSUser& updated_user,
AdminServiceOperationResult& out_result);
static void get_md_entitlement_report(const AdminData& admin_data,
std::vector<MDEntitlementReportUnit>& entitlements);
// Gets a reporting unit out of CMEMicData
static MDEntitlementReportUnit get_cme_md_entitlement_unit(
const std::string& user,
const CMEMicData& cme_mic_data);
static void get_user_symbol_permissions(
const AdminData& data,
const BTSUser& user,
std::vector<UserSymbolMDPermissionUnit>& res);
////////////////////////////////////////////
// user mutators ///////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSUser* create_user (bts::api::admin::AdminData& data,
uint32_t parent_group_id,
const std::string& name,
const std::string& password,
bool is_active,
const bts::api::admin::LicenseData& license_data,
const bts::api::admin::LicenseEntitlements& license_entitlements,
bts::api::admin::AdminServiceCreateEntityResult& result);
static bts::api::admin::BTSUser* update_user(bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& result);
static void delete_user (bts::api::admin::AdminData& admin_data,
const bts::api::admin::IDAPIArgument& id,
bts::api::admin::AdminServiceOperationResult& result);
static void set_user_exchange_data(bts::api::admin::BTSUser* user,
const bts::api::admin::ExchangeUserData& exchange_user_data);
static void set_user_md_entitlement_data(bts::api::admin::BTSUser* user,
const bts::api::admin::ExchangeUserMarketDataEntitlementData& exchange_user_md_entitelemnt_data);
static void clear_user_accounts (bts::api::admin::BTSUser* user);
static void set_user_accounts (bts::api::admin::BTSUser* user,
const bts::api::admin::UserAccountPermissions& user_account_permissions);
static BTSUser* create_user (AdminData& data,
uint32_t parent_group_id,
const std::string& name,
const std::string& password,
bool is_active,
const LicenseData& license_data,
const LicenseEntitlements& license_entitlements,
AdminServiceCreateEntityResult& result);
static BTSUser* update_user(AdminData& admin_data,
const BTSUser& updated_user,
AdminServiceOperationResult& result);
static void delete_user (AdminData& admin_data,
const IDAPIArgument& id,
AdminServiceOperationResult& result);
static void set_user_exchange_data(
BTSUser* user,
const ExchangeUserData& exchange_user_data);
static void set_user_md_entitlement_data(BTSUser* user,
const ExchangeUserMarketDataEntitlementData&);
static void clear_user_accounts (BTSUser* user);
static void set_user_accounts (BTSUser* user,
const UserAccountPermissions& user_account_permissions);
////////////////////////////////////////////
//risk limits //////////////////////////////
////////////////////////////////////////////
// sorting function used by sort_limits to
// sort SecurityScope's
static bool _sort_security_scopes (const bts::api::admin::SecurityScope& a, const bts::api::admin::SecurityScope& b);
static bool _sort_security_scopes (const SecurityScope& a,
const SecurityScope& b);
// sorting function used by sort_limits to
// sort ProductScope's
static bool _sort_product_scopes (const bts::api::admin::ProductScope& a, const bts::api::admin::ProductScope&);
static bool _sort_product_scopes (const ProductScope& a,
const ProductScope&);
// this sorts the rules such that the most
// specific ones are at the top. this makes it
// easier to match rules with securities/products
static void sort_limits (bts::api::admin::BTSAccount& account);
static void sort_limits (BTSAccount& account);
// creates a copy of AdminData with sorted rules
static bts::api::admin::AdminData sort_limits (const bts::api::admin::AdminData& admin_data);
static AdminData sort_limits (const AdminData& admin_data);
// find the clip size for a security, account
static const uint32_t find_account_security_clip_size(const bts::api::admin::BTSAccount& account,
const api::Security& security);
static const uint32_t find_account_security_clip_size(
const BTSAccount& account,
const api::Security& security);
// find the position limit for an account, security
static const bts::api::admin::AccountSecurityPositionLimitUnit* find_account_security_position_limit(const bts::api::admin::BTSAccount& account,
static const AccountSecurityPositionLimitUnit*
find_account_security_position_limit(const BTSAccount& account,
const api::Security& security);
// find the position limit for an account, product
static const bts::api::admin::AccountProductPositionLimitUnit* find_account_product_position_limit(const bts::api::admin::BTSAccount& account,
static const AccountProductPositionLimitUnit*
find_account_product_position_limit(const BTSAccount& account,
const api::Product& product);
static bool match_security_scope (const bts::api::admin::SecurityScope& scope,
const bts::api::Security& security);
static bool match_product_scope (const bts::api::admin::ProductScope& scope,
const bts::api::Product& product);
static bool match_product(const api::Security& security, const api::Product& product);
static bool _match_limit_rule_symbol (const std::string& symbol, const std::string& limit_symbol);
static bool match_security_scope (const SecurityScope& scope,
const api::Security& security);
static bool match_product_scope (const ProductScope& scope,
const api::Product& product);
static bool match_product(const api::Security& security,
const api::Product& product);
static bool _match_limit_rule_symbol (const std::string& symbol,
const std::string& limit_symbol);
static api::SecurityType security_type(const api::Security& security);
////////////////////////////////////////////
// misc//////// ////////////////////////////
+62
View File
@@ -182,6 +182,17 @@ message AccountExchangeConnections{
/***************************Exchange Data********************************/
/************************************************************************/
message CMEMicData{
api.CMEMics mic=10;
bool enabled=20;
// there are other things here
}
message ICEMicData{
api.CMEMics mic=10;
bool enabled=20;
}
message ExchangeUserMarketDataEntitlementData{
CMEUserMarketDataEntitlementData cme_data = 10;
ICEUserMarketDataEntitlementData ice_data = 20;
@@ -276,6 +287,8 @@ message CMEUserData{
string smp_instruction = 70;
string max_order_rate_per_connection = 80;
string location = 90;
// add suff here
repeated CMEMicData md_permissions = 1000;
}
message SIMUserData {
@@ -331,6 +344,48 @@ message ICEUserData{
message ICEUserMarketDataEntitlementData{
}
///////////////////////////////////////////////////////////
// Order Auxiliary Service ////////////////////////////////
message OrdersSummaryUnit{
string account = 10;
string user = 20;
uint32 total_orders = 30;
uint32 total_contracts = 40;
}
message OrdersSummary{
repeated OrdersSummaryUnit units = 10;
}
message OrderSummaryRequest{
}
// top level orders that have account
// and user that are present here, will
// be cancelled. wild cards are not
// supported.
message OrderCancelRequest{
repeated string accounts = 10;
repeated string users = 20;
}
///////////////////////////////////////////////////////////
// Reporting //////////////////////////////////////////////
message MDEntitlementReportUnit{
string record_id = 1 [(bts.api.key)=true];
string user = 10;
string exchange = 20;
string mic = 30;
bool enabled = 40;
}
////////////////////////////////////////////////////////////
// Misc ///////////////////////////////////////////////////
message UserSymbolMDPermissionUnit{
string record_id = 1 [(bts.api.key)=true];
string user=10;
api.Venue exchange=20;
string symbol=30;
bool enabled=40;
}
/************************************************************************/
/************************************************************************/
/************************************************************************/
@@ -385,4 +440,11 @@ service AdminService {
// subscription
rpc admin_data(bts.api.VoidMessage) returns (stream AdminData);
rpc get_admin_data(bts.api.VoidMessage) returns (AdminData);
// orders
rpc get_order_summary(bts.api.VoidMessage) returns (OrdersSummary);
rpc cancel_orders(OrderCancelRequest) returns (bts.api.VoidMessage);
// reports
rpc md_entitlement_data(bts.api.VoidMessage) returns (stream MDEntitlementReportUnit);
// misc
rpc md_permissions_data(bts.api.VoidMessage) returns (stream UserSymbolMDPermissionUnit);
}
@@ -0,0 +1,17 @@
syntax="proto3";
package bts.api.md.auxiliary;
option csharp_namespace="bts.api.md.auxiliary";
import "lib/api/apioptions.proto";
import "lib/api/apicore.proto";
message VolumeAtPriceLevel{
int32 record_id = 1 [(bts.api.key)=true];
uint32 security_id = 20;
double price = 30;
uint32 volume = 40;
}
service MarketDataAuxiliaryService{
option (bts.api.service_description)="Provides non-core supplementary market data";
rpc volume_at_price(bts.api.VoidMessage) returns (stream VolumeAtPriceLevel);
}
+79 -12
View File
@@ -6,6 +6,7 @@ import "lib/api/apioptions.proto";
import "lib/domain_model/Security.proto";
import "google/protobuf/timestamp.proto";
import "lib/sparkproto/SparkProtos.proto";
import "lib/api/apicore.proto";
service OrderService {
option (bts.api.service_description)="Implements order management";
@@ -15,9 +16,12 @@ service OrderService {
rpc cancel_order(Cancel) returns (Response);
rpc update_order(Update) returns (Response);
rpc crack_order(Crack) returns (Response);
rpc get_registered_dynamic_order_types(bts.api.VoidMessage) returns (RegisteredDynamicOrderTypes);
// streams
rpc orders (OrdersSub) returns (stream OrderRecord);
rpc fills (FillsSub) returns (stream Fill);
}
@@ -109,15 +113,6 @@ message TickOrderDefinition {
message LeanOrderDefinition {
spark.QuantityMeasure cross_threshold = 1;
uint32 max_chase_ticks = 2;
/*deprecated*/ bool detach_on_toward = 4;
enum OnToward
{
NO_CHANGE = 0; //continue to lean on initial inside market
CANCEL = 1; //cancel algo and order
DETACH = 2; //cancel algo but leave order working
REPRICE = 3; //lean on new inside market
}
OnToward trade_toward_behavior = 5;
CustomOrderDefinition child = 3;
}
message JoinOrderDefinition {
@@ -148,8 +143,7 @@ message CoverOrderDefinition {
}
message DynamicOrderDefinition {
string dynamic_order_type = 1;
map<string,string> parameters = 2;
CustomOrderDefinition child = 3;
map<string, DynamicOrderParam> order_params = 2;
}
// End custom order definitions
@@ -268,7 +262,7 @@ message TopOrderState {}
message TriggerOrderState {}
message CoverOrderState {}
message DynamicOrderState {
map<string,string> state = 2;
map<string,string> state = 1;
}
enum OrderStatus {
@@ -474,3 +468,76 @@ message TriggerExitCondition{
uint32 timeout_seconds=20; //seconds
bool conditional_cancel=30;
}
// Dynamic Orders
enum DynamicOrderPrimitiveDescriptor {
DYNAMIC_ORDER_PRIMITIVE_INT = 0;
DYNAMIC_ORDER_PRIMITIVE_UINT = 1;
DYNAMIC_ORDER_PRIMITIVE_DOUBLE = 2;
DYNAMIC_ORDER_PRIMITIVE_STRING = 3;
DYNAMIC_ORDER_PRIMITIVE_BOOL = 4;
DYNAMIC_ORDER_PRIMITIVE_ORDER_DEF = 5;
}
message DynamicOrderTypeDescriptor {
oneof descriptor {
DynamicOrderPrimitiveDescriptor primitive = 2;
DynamicOrderArrayDescriptor array = 3;
DynamicOrderStructDescriptor structure = 4;
DynamicOrderEnumeratedDescriptor enumerated = 5;
}
}
message DynamicOrderArrayDescriptor {
DynamicOrderTypeDescriptor element_type = 1;
}
message DynamicOrderParamDescriptor {
string param_name = 1;
DynamicOrderTypeDescriptor param_type = 2;
}
message DynamicOrderStructDescriptor {
repeated DynamicOrderParamDescriptor field = 1;
}
message DynamicOrderEnumeratedDescriptor {
repeated string element = 1;
}
message DynamicOrderDescriptor {
string dynamic_order_type = 1;
repeated DynamicOrderParamDescriptor param_desc = 3;
}
message RegisteredDynamicOrderTypes {
repeated DynamicOrderDescriptor dynamic_order_desc = 1;
}
message DynamicOrderParam {
oneof value {
uint32 as_int32 = 1;
uint32 as_uint32 = 2;
double as_double = 3;
string as_string = 4;
bool as_bool = 5;
CustomOrderDefinition as_order_def = 6;
DynamicOrderArray as_array = 7;
DynamicOrderStruct as_struct = 8;
DynamicOrderEnumerated as_enumerated = 9;
}
}
message DynamicOrderArray {
repeated DynamicOrderParam element = 1;
}
message DynamicOrderStruct {
map<string,DynamicOrderParam> field = 1;
}
message DynamicOrderEnumerated {
string enum_value = 1;
}
+1 -1
View File
@@ -234,7 +234,7 @@ bool ConfigPropertyEvaluator::get_value(const std::string& property, Value* out_
tokenizer<char_separator<char> >::iterator iter = tokens.begin (), end = tokens.end ();
// The first token is the key name
const proto::Message* key = _config.try_get_message_or_default(*iter);
const proto::Message* key = _config.try_get_message(*iter);
if (!key) return false;
// 2) Drill down using reflection to find the named property
-13
View File
@@ -616,19 +616,6 @@ const proto::Message* ConfigurationState::try_get_message(const std::string& pro
return nullptr;
}
const proto::Message* ConfigurationState::try_get_message_or_default(const std::string& property_name) {
const auto pmsg = try_get_message(property_name);
if (pmsg) {
return pmsg;
}
// If we can't find a value we should return a default instance
const auto* descriptor = get_descriptor_by_name(property_name);
if (descriptor) {
return proto::MessageFactory::generated_factory()->GetPrototype(descriptor);
}
return nullptr;
}
const proto::Message& ConfigurationState::get_message(const proto::Descriptor* property_desc)
{
if (!is_valid_key_descriptor(property_desc))
-1
View File
@@ -59,7 +59,6 @@ namespace internal {
const proto::Message& get_message(const proto::Descriptor* property_desc);
const proto::Message* try_get_message(const std::string& property_name);
const proto::Message* try_get_message_or_default(const std::string& property_name);
bool is_initialized() { return _is_initialized; }
+10 -1
View File
@@ -76,7 +76,16 @@ extern "C" BTS_EXPORT const char* get_buffer(const char* key_name, int& out_leng
extern "C" BTS_EXPORT const proto::Message* get_named(const char* key_name)
{
return config_state.try_get_message_or_default(key_name);
const auto* pmessage = config_state.try_get_message(key_name);
if (pmessage) {
return pmessage;
}
// If we can't find a value we should return a default instance
const auto* descriptor = config_state.get_descriptor_by_name(key_name);
if (descriptor) {
return proto::MessageFactory::generated_factory()->GetPrototype(descriptor);
}
return nullptr;
}
BTS_EXPORT std::string get_macro_string(const char* name) { return config_state.get_macro_string(name); }
-20
View File
@@ -26,26 +26,6 @@ SymbolList {
}
}
Symbols {
rule: "DeploymentType.type == 'DEMO' and System.platform == 'windows'"
value {
sim {
future: @SymbolList.symbol
spread: @SymbolList.symbol
}
}
}
Symbols {
rule: "DeploymentType.type == 'PROD' and System.platform == 'windows'"
value {
glbx {
future: @SymbolList.symbol
spread: @SymbolList.symbol
}
}
}
Symbols {
value {
glbx {
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+12 -12
View File
@@ -2,17 +2,17 @@
DynamicOrderList {
value {
# dynamic_orders
# {
# type_name: 'DynamicOrder1'
# parameter_keys: 'param1'
# parameter_keys: 'param2'
# }
# dynamic_orders
# {
# type_name: 'DynamicOrder2'
# parameter_keys: 'param3'
# parameter_keys: 'param4'
# }
dynamic_orders
{
type_name: 'DynamicOrder1'
parameter_keys: 'param1'
parameter_keys: 'param2'
}
dynamic_orders
{
type_name: 'DynamicOrder2'
parameter_keys: 'param3'
parameter_keys: 'param4'
}
}
}
@@ -1,194 +0,0 @@
ExpirationDisplayOffset
{
value
{
entries
{
security_type: "OPTION"
security_name: "lo"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "CL"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ob"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "RB"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "oh"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "HO"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "wbs"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "WBS"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "so"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "SI"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "og"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "GC"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "hxe"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "HG"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozs"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozw"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "osd"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZS"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozm"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZM"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozl"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZL"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozc"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZC"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozn"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZN"
addition_count: 0
addition_type: MonthMoveToStart
}
}
}
-34
View File
@@ -1,34 +0,0 @@
OrdermanCfg {
rule: "DeploymentType.type == 'dev'"
value {
executor {
thread_name: "oman_orders"
poll: false
hosted_actor: "MDSource"
hosted_actor: "OrderManager"
hosted_actor: "ExecutionGateway"
}
executor {
thread_name: "oman_slow"
poll: false
hosted_actor: "*"
}
}
}
OrdermanCfg {
value {
executor {
thread_name: "oman_orders"
poll: true
hosted_actor: "MDSource"
hosted_actor: "OrderManager"
hosted_actor: "ExecutionGateway"
}
executor {
thread_name: "oman_slow"
poll: false
hosted_actor: "*"
}
}
}
-7
View File
@@ -1,7 +0,0 @@
Threads {
value {
thread_group {name_rx: "mdp3feed" core: 0}
thread_group {name_rx: "oman_orders" core: 1}
thread_group {name_rx: ".*" exclude:true core:0 core:1}
}
}
+1 -1
View File
@@ -75,7 +75,7 @@ message CMEOptions
// Defines amount of time Feed Engine keeps cycling before going to sleep when no useful activity can be done
optional uint32 spin_time = 4 [default = 1];
optional uint32 channels_per_thread = 5 [default = 3];
optional string thread_group = 10 [default=""]; // if present this will be used to retrieve affinity settings from Threads config key
repeated uint32 affinity = 10;
optional uint32 udp_socket_buffer_size = 11 [default = 33554432]; //32mb
}
enum BookType {
@@ -0,0 +1,11 @@
syntax='proto2';
package bts.config;
import "lib/domain_model/Security.proto";
message CppConfig {
map<string, double> cpp_entry = 1;
}
message CmeSymbolMics {
map<string, bts.api.CMEMics> cme_mic = 1;
}
-6
View File
@@ -1,6 +0,0 @@
syntax='proto2';
package bts.config;
message CppConfig {
map<string, double> cpp_entry = 1;
}
+8
View File
@@ -0,0 +1,8 @@
syntax='proto2';
package bts.config;
message Deployment {
// Acceptable values:
// DEV_CHAPEL_HILL, DEV_CHICAGO, DEMO_GT, QA, CUSTOMER
optional string type = 1 [default="DEV_CHAPEL_HILL"];
}
@@ -1,24 +0,0 @@
syntax='proto2';
package bts.config;
message ExpirationOffsetType
{
enum type
{
Month=0;
MonthMoveToStart=1;
}
}
message ExpirationDisplayOffsetEntry
{
required string security_type = 1;
required string security_name = 2;
required int32 addition_count = 3;
required ExpirationOffsetType.type addition_type = 4;
}
message ExpirationDisplayOffset
{
repeated ExpirationDisplayOffsetEntry entries = 1;
}
-11
View File
@@ -1,11 +0,0 @@
syntax='proto2';
package bts.config;
message OrdermanCfg {
message Executor {
required string thread_name = 1;
optional bool poll = 2 [ default = false];
repeated string hosted_actor = 3;
}
repeated Executor executor = 1;
}
-13
View File
@@ -1,13 +0,0 @@
syntax='proto2';
package bts.config;
message ThreadGroupCfg {
required string name_rx = 1 [default = "*"];
optional bool exclude = 2 [default = false];
repeated uint32 core = 3;
}
message Threads {
repeated ThreadGroupCfg thread_group = 1;
}
+4
View File
@@ -26,4 +26,8 @@ message OrdersSoftCleanup{
message ToastNotifications {
optional bool enabled = 1 [default = false];
}
message VolumeAtPrice{
optional bool enabled = 1 [default = true];
}
+16
View File
@@ -40,6 +40,22 @@ enum Currency {
CURRENCY_RMB = 14;
}
enum CMEMics {
UNSET = 0;
CME = 1;
NYMEX = 2;
CBT = 3;
COMEX = 4;
MGE = 5;
DME = 6;
NYMSW = 7;
FXS = 8;
}
enum ICEMics{
ICE_FUTURES_CANADA=0;
}
enum Side {
SIDE_UNDEFINED = 0;
SIDE_BUY = 49;
+1 -1
View File
@@ -11,7 +11,7 @@
#include "lib/jetfix/codec/IFIXMsg.h"
#include "lib/jetfix/common/InMsgBuffer.h"
#include "lib/utils/meta_programming.h"
#include "lib/orderman/orderman_utils/PerfTrace.h"
#include "lib/orderman/orderman_utils/TickToTradeCorID.h"
namespace bts {
namespace jetfix {
+1 -1
View File
@@ -6,7 +6,7 @@
#include <vector>
#include "lib/utils/bts_assert.h"
#include "lib/jetfix/codec/MessageTypes.h"
#include "lib/orderman/orderman_utils/PerfTrace.h"
#include "lib/orderman/orderman_utils/TickToTradeCorID.h"
namespace bts {
namespace jetfix {
+3 -4
View File
@@ -7,8 +7,7 @@
#include "lib/utils/bts_assert.h"
#include "lib/os/os.h"
#include "lib/tracing/bts_trace.h"
#include "lib/orderman/orderman_utils/PerfTrace.h"
#include "lib/utils/thread_manager.h"
#include "lib/orderman/orderman_utils/TickToTradeCorID.h"
#include <fstream>
@@ -113,8 +112,8 @@ AsyncReader::AsyncReader (IConnection &connection,
void AsyncReader::start ()
{
auto thread_name = fmt::format ("jf_ar_{}", me->connection_name);
me->reader_thread = threading::make_thread (thread_name,[this] () {
me->reader_thread = std::thread ([this] () {
os::set_thread_name(me->connection_name+"_asyncr");
dispatch();
});
}
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#include <array>
#include "lib/orderman/orderman_utils/PerfTrace.h"
#include "lib/orderman/orderman_utils/TickToTradeCorID.h"
namespace bts {
namespace jetfix {
Loaded 100 of 283 files, more files were not shown because too many files have changed in this diff. Show more