Compare commits

..
62 Commits
Author SHA1 Message Date
Pedro Pinto dcf116fe82 Updated release notes. 2018-10-11 18:28:10 +00:00
Pedro Pinto 9c571cc16d Moved externals pointer 2018-10-11 17:53:00 +00:00
Pedro Pinto aa8e32ee43 Updated external subrepos 2018-10-11 17:43:39 +00:00
Michael Harding 4d0a793ecc SPARK-1773: rows in table 2018-10-11 11:44:30 -04:00
Michael Harding 659bf6b208 SPARK-1773: update paths 2018-10-11 09:36:19 -04:00
Pedro Pinto 33312a4bf8 Fixed up build with respect to the perf_trace web page. 2018-10-11 12:46:12 +00:00
Pedro Pinto 929a93b1f7 Updated docker 2018-10-11 12:11:00 +00:00
Pedro Pinto f49e41c5c0 Fixed a few bugs in perf state json generation. 2018-10-11 12:11:00 +00:00
Michael Harding 87f99d42bf SPARK-1773: Add Histogram and rows 2018-10-10 16:13:29 -04:00
Michael Harding e4f5531855 Add perf_trace page 2018-10-09 17:43:42 -04:00
Pedro Pinto d62bde8158 Added placeholder for perf trace web page. 2018-10-09 20:28:56 +00:00
Pedro Pinto 53ea5ddf81 Merged 2018-10-09 19:27:54 +00:00
Pedro Pinto 9e0b95a1ad SPARK-1772, Serving perf traces via json 2018-10-09 17:43:18 +00:00
Pedro Pinto 5325c372ba Added a few docs 2018-10-08 19:08:49 +00:00
Pedro Pinto 50abbd6aea Added a few more benchmarks. 2018-10-08 14:11:26 +00:00
Pedro Pinto f324504df1 Added locking to perf trace log. 2018-10-08 14:10:56 +00:00
Pedro Pinto 931d5dad01 SPARK-1771, Logging perf metrics in a DB 2018-10-05 20:08:45 -04:00
Pedro Pinto ef094b891a SPARK-1771, Logging perf metrics in a DB 2018-10-05 23:05:27 +00:00
Pedro Pinto d25d91038d clang format. 2018-10-05 15:37:44 +00:00
Pedro Pinto 700f1d97fd Renamed TickToOrderCorID.h to PerfTrace.h 2018-10-05 15:37:09 +00:00
Michael Harding 5b1cf890e8 Merged in spark1538-risk-admin-cloning (pull request #79)
SPARK-1538: Spark Admin - Cloning

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2018-10-04 19:30:19 +00:00
Michael Harding c254248886 SPARK-1538: Clones incoming 2018-10-04 15:00:33 -04:00
Pedro Pinto 5aaa5a3360 Ran clang-format 2018-10-04 10:13:29 -04:00
Pedro Pinto 54d31c345a Logged non-routable orders at Error level. 2018-10-03 19:23:09 +00:00
Pedro Pinto ae3e721f62 Changed MDP3 producer to honor new thread configuration. 2018-10-03 15:45:29 +00:00
Pedro Pinto 0833dce43d Added some tools to quickly analyze latency stats. 2018-10-03 14:53:36 +00:00
Pedro Pinto 47b2e917c1 Tweaked threading defaults. 2018-10-02 16:30:56 +00:00
Pedro Pinto c2864d1715 Improved performance. 2018-10-02 16:24:00 +00:00
Pedro Pinto 2769de6f7e Added central control of threading. 2018-10-02 16:24:00 +00:00
Pedro Pinto ef3b39361a Cleaning up mercury. 2018-10-02 16:24:00 +00:00
Pedro Pinto fa2a2e2107 Rewrite of mercury for better performance. 2018-10-02 16:24:00 +00:00
Pedro Pinto 3005dfdc0f Perf analysys script tweak. 2018-10-02 16:22:04 +00:00
Pedro Pinto 4fd8d9dc5b Fixed typo in comment. 2018-10-02 16:22:04 +00:00
Pedro Pinto c948b981cf More performance tracing work. 2018-10-02 16:22:04 +00:00
Pedro Pinto 8e51b05941 More tweaks to improve performance tracing. 2018-10-02 16:22:04 +00:00
Pedro Pinto 75568e6c75 Made thread allocation configurable for order management. 2018-10-02 16:22:04 +00:00
Pedro Pinto 6e3c880ea2 Changed mercury to assume direct broker connections.
This is needed to reduce latency as we (optionally) move the execution
gateway to its on thread.
2018-10-02 16:20:00 +00:00
Pedro Pinto ded957a0ef SPARK-1686, Towards better server side performance. 2018-10-02 16:20:00 +00:00
Eric Harding 05741ceab0 SPARK-1742 test can fail when time moves foward 2018-10-01 14:56:35 -04:00
John Colvin 9e3b3879d0 Merged in lldatetime (pull request #75)
SPARK-1726 change DateTime.cpp to match c# format

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2018-09-25 15:32:54 +00:00
Kevin Darby a1b189fcb1 repenting my sins against the proto gods 2018-09-21 12:46:42 -04:00
Michael Harding 7a48e5dd5c SPARK-1725: not too many characters 2018-09-21 11:26:09 -04:00
John Colvin 2842aea933 lldatetime - TimeAndSales rows show local time 2018-09-20 15:35:48 -04:00
John Colvin f97d156020 in datetime.cpp, ptime_to_ll should use KindUnspecified by default 2018-09-20 15:13:20 -04:00
Eric Harding d8922be0ad Add udp.py to tools 2018-09-20 14:35:43 -04:00
John Colvin 5634ada367 cautionary comment in lldatetime(this ulong) extension 2018-09-20 13:43:56 -04:00
John Colvin 94d249edbd use ticks_per_day instead of (micros_per_day * ticks_per_micro) 2018-09-20 13:21:06 -04:00
John Colvin 1c29ac0ec5 missed a couple changes in last commit 2018-09-20 13:18:02 -04:00
John Colvin e7e280bad8 lldatetime pr edits, add test_lldatetime() to Co2Tests 2018-09-20 13:10:48 -04:00
Eric Harding 7ca11c3eee SPARK-1718 Fix trailing comma after deleted users. 2018-09-20 10:27:52 -04:00
Eric Harding caf6ac029c Fix ancient config bug where you can't reference a non-overloaded key in a rule or macro. 2018-09-20 10:27:52 -04:00
Eric Harding 4c0fa81963 Remove unused environment.proto 2018-09-20 10:27:52 -04:00
Kevin Darby 720c1595e0 Merged in more_lean (pull request #76)
made the 'toward' behavior for lean an enum
2018-09-19 22:14:31 +00:00
Kevin Darby bedd0051a9 made the 'toward' behavior on lean an enum 2018-09-19 16:36:25 -04:00
Jake Norbut 09bed1a713 SPARK-1728 - Symbol list is now restrictued according to DeploymentType for the gui; when DEMO, only sim; when PROD, not sim; will require upkeep as exchanges are added 2018-09-19 15:26:25 -05:00
John Colvin ebb53c5035 LLDateTime conversion pr edits 2018-09-19 14:20:33 -04:00
Eric Harding 243b82a6d7 Primitive settingsmanager 2018-09-19 13:31:45 -04:00
Taha Afzal bd4f840d27 Setting last_price to avg_price for SOD records 2018-09-19 12:17:22 -04:00
John Colvin de893d2175 SPARK-1726 change DateTime.cpp to match c# format 2018-09-19 11:49:38 -04:00
Taha Afzal 33658f13f6 SPARK-1722 orders cleanup weekend bug 2018-09-18 13:28:20 -04:00
Kevin Darby 469ee033b2 added a 'detach on toward' boolean to Lean, reasonable in it's own right, but so K. Loftus can race us against Chalupa. 2018-09-15 15:29:12 -04:00
Eric Harding 451fb67195 Fix market_segment_id in shared memory dumper. (uint8_t and std::cout disagree) 2018-09-11 12:44:52 -04:00
281 changed files with 6923 additions and 7798 deletions

No files matched your search

+1
View File
@@ -25,3 +25,4 @@ 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/
+1 -3
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} -DNDEBUG -O3")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -DNDEBUG -O3")
add_subdirectory(src/server/sparkd)
add_subdirectory(src/lib)
add_subdirectory(src/web)
@@ -54,8 +54,6 @@ 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
@@ -0,0 +1,301 @@
<?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
@@ -0,0 +1,55 @@
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
+5
View File
@@ -1,3 +1,8 @@
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.
+55 -59
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", "{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}"
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", "{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{9AD1A867-93A9-301D-BF77-0113E18E9E39}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
ProjectSection(ProjectDependencies) = postProject
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C} = {69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3} = {8530E0E8-3768-37EC-B1E1-8248C5A92FE3}
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
{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
{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
{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,30 +93,26 @@ 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|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
{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
{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
@@ -137,22 +133,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
{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
{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
{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,9 +5,11 @@ 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;
@@ -16,6 +18,7 @@ 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 {
@@ -75,29 +78,16 @@ 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),
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;
})
_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)
);
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;
@@ -139,52 +129,27 @@ namespace mbts.spark {
public void raise_invalidated() => invalidated?.Invoke();
/// <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>();
public void refresh() {
bool dirty = false;
if (md.md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
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);
_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);
}
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);
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
_last_price.set(ps.price);
_last_size.on_next_distinct(ps.size, ref dirty);
_volume.on_next_distinct(v, ref dirty);
}
_settlement.set(md.md.settlement_price);
_session_low.set(md.md.session_low);
_session_high.set(md.md.session_high);
_day_change.set(last_price - settlement);
if (dirty)
invalidated?.Invoke();
}
public bool Equals(Row other) =>
@@ -3,13 +3,10 @@ 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;
@@ -17,7 +14,7 @@ using static mbts.ui.controls.DIYGrid;
using static mbts.ui.spark.MarketViewView;
namespace mbts.spark {
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD>, IPrepareUpdateForDispatcher {
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
@@ -115,7 +112,8 @@ 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()
securities_connectable.Connect(),
WorkLoop.Start("MarketView", _refresh)
);
}
@@ -161,25 +159,6 @@ 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); }
@@ -188,4 +167,4 @@ namespace mbts.spark {
foreach (var r in _row_vms) r.refresh();
}
}
}
}
@@ -14,18 +14,16 @@ 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 _resources;
IDisposable _subscriptions;
public MarketViewWindow(MarketViewWindowFactory factory, DispatcherUpdateMaster dispatcher_update_master, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
public MarketViewWindow(MarketViewWindowFactory factory, 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();
@@ -59,14 +57,12 @@ 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))
};
_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));
_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())));
}
public override void Dispose() {
Disposable.dispose(ref _resources);
Disposable.dispose(ref _subscriptions);
_vm.Dispose();
Commands.OfType<IDisposable>().DisposeAll();
}
@@ -12,7 +12,6 @@ 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;
@@ -26,7 +25,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, _dispatcher_update_master, _bus, _orders_model, state);
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _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 = trade.Time.lldatetime();
time = ((ulong)trade.Time).lldatetime().ToLocalTime();
price = trade.Mantissa * Math.Pow(10, trade.Exponent);
size = trade.Size;
aggressor_side = trade.AggressorSide;
@@ -1,7 +1,6 @@
using bts;
using bts.api;
using bts.api.orderman;
using bts.utils;
using mbts.ui;
using mbts.ui.shell;
using System;
@@ -12,60 +11,6 @@ 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;
@@ -94,7 +39,7 @@ namespace mbts.spark {
class OrderPropertiesEditorVM : DisposableViewModelBase {
readonly OrdersModel _model;
readonly Property<SecurityImmutable> _security;
readonly SelectorProperty<AccountTuple, AccountTuple?> _accounts;
readonly SelectorProperty<AccountTuple> _accounts;
readonly SelectorProperty<TimeInForce> _time_in_force;
readonly SelectorProperty<IOrderTypeVM> _order_type;
IDisposable _order_type_param_errors_sub;
@@ -113,21 +58,14 @@ namespace mbts.spark {
nameof(selected_account),
model.factory.subscribe_account_tuples(),
order_properties.Select(ops => ops.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());
() => accounts?.FirstOrDefault() ?? default,
val => (!string.IsNullOrWhiteSpace(val.name) && accounts.Contains(val), "Please select an account"));
_order_type = backing(
nameof(selected_order_type),
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))),
security_source.Select(s => model.factory.default_order_type_defs(s).Select(create_order_type_vm)),
order_properties.Select(get_order_type_vm_prop),
get_default_order_type_vm,
EqualityComparer.null_check_wrapper(OrderTypeVMExtensions.key_comparer));
(a, b) => a.order_type == b.order_type);
_order_type.Changed += on_selected_order_type_changed;
_time_in_force = backing(
nameof(selected_time_in_force),
@@ -139,22 +77,19 @@ 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, string id, string display_name) {
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable cd) {
IOrderTypeVM vm = null;
if(cd.CustomCase == CustomOrderDefinition.CustomOneofCase.Dynamic)
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source, cd.Dynamic.DynamicOrderType);
vm = OrderTypeVMFactory.create(cd.CustomCase, model, security_md_source, cd.Dynamic.DynamicOrderType);
else
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source);
vm = OrderTypeVMFactory.create(cd.CustomCase, 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.value.CustomCase.ToString(),
OrderUtils.order_type_display_name(p.order_type_def.value.CustomCase)),
p.order_type_def.force_override);
return new InlineUserProperty<IOrderTypeVM>(create_order_type_vm(p.order_type_def.value), p.order_type_def.force_override);
}
IOrderTypeVM get_default_order_type_vm() {
var ot = model.factory.default_order_type(security);
@@ -179,13 +114,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(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlineCoverOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
var hedgetype = CustomOneofCase.Limit;
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
hedge_ticks = new InlineUserProperty<int>(1, false);
}
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<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<int> hedge_ticks;
@@ -42,25 +42,25 @@ namespace mbts.spark
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
InlineCoverOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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, string id, string display_name)
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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)
new InlineCoverOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
{ }
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineCoverOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
IObservable<InlineCoverOrderProperties> inline_properties) : base(model)
{
_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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
{
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
_select_hedge_order(p.selected_hedge_order_type.value);
}
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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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.key.type :
_inline_props.selected_child_order_type.value :
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.key.type :
_inline_props.selected_hedge_order_type.value :
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(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlineDynamicOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
}
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> 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<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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, string id, string display_name)
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type)
: this(model, security_md_source, dyn_type, security_md_source.Select(smd =>
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)
new InlineDynamicOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
{ }
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type,
IObservable<InlineDynamicOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
IObservable<InlineDynamicOrderProperties> inline_properties) : base(model)
{
_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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
_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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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.key.type :
_inline_props.selected_child_order_type.value :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -208,4 +208,4 @@ namespace mbts.spark
}
}
}
}
}
@@ -1,13 +1,11 @@
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; }
@@ -23,12 +21,4 @@ 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(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
public InlineIcebergOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
show_quantity = new InlineUserProperty<double>(1, true);
}
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
public readonly InlineUserProperty<double> show_quantity;
}
class IcebergOrderVM : OrderTypeVMBase<IcebergOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable {
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
InlineIcebergOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
public IcebergOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
public IcebergOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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) { }
new InlineIcebergOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public IcebergOrderVM(OrdersModel model,
IObservable<SecurityMD> security_md_source,
IObservable<InlineIcebergOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
IObservable<InlineIcebergOrderProperties> inline_properties)
: base(model) {
_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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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.key.type :
_inline_props.selected_child_order_type.value :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -17,19 +17,19 @@ namespace mbts.spark
{
class InlineJoinOrderProperties
{
public InlineJoinOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlineJoinOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
var hedgetype = CustomOneofCase.Lean;
if(!child_order_types.Any(t => t.key.type == hedgetype))
if(!child_order_types.Contains(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<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(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<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<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<uint> tick_offset_on_deploy;
@@ -55,13 +55,13 @@ namespace mbts.spark
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
InlineJoinOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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, string id, string display_name)
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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) { }
new InlineJoinOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineJoinOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
IObservable<InlineJoinOrderProperties> inline_properties) : base(model)
{
_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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
{
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
_select_hedge_order(p.selected_hedge_order_type.value);
}
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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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.key.type :
_inline_props.selected_child_order_type.value :
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.key.type :
_inline_props.selected_hedge_order_type.value :
model.factory.default_order_type(_security.Value, true);
_select_hedge_order(ot);
}
@@ -17,41 +17,44 @@ namespace mbts.spark
{
class InlineLeanOrderProperties
{
public InlineLeanOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlineLeanOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
cross_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1}, false);
max_chase_ticks = new InlineUserProperty<uint>(10, false);
max_chase_ticks = new InlineUserProperty<uint>(2, false);
trade_toward_behavior = new InlineUserProperty<LeanOrderDefinition.Types.OnToward>(LeanOrderDefinition.Types.OnToward.Cancel, false);
}
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> 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<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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; } = 10;
public uint max_chase_ticks { get; set; } = 2;
public LeanOrderDefinition.Types.OnToward trade_toward_behavior { get; set; } = LeanOrderDefinition.Types.OnToward.Cancel;
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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) { }
new InlineLeanOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineLeanOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
IObservable<InlineLeanOrderProperties> inline_properties) : base(model)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -65,7 +68,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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
if (p.cross_threshold.force_override)
{
@@ -77,6 +80,11 @@ 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();
})
@@ -94,17 +102,20 @@ 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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _child_order_choices;
}
}
@@ -150,7 +161,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.key.type :
_inline_props.selected_child_order_type.value :
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, "Limit", OrderUtils.order_type_display_name(CustomOrderDefinition.CustomOneofCase.Limit)) { }
internal LimitOrderVM(OrdersModel model) : base(model) { }
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, "Market", OrderUtils.order_type_display_name(CustomOrderDefinition.CustomOneofCase.Market)) { }
internal MarketOrderVM(OrdersModel model) : base(model) { }
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, 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 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 create(CustomOneofCase order_type, string id, string display_name, OrdersModel model,
public static IOrderTypeVM create(CustomOneofCase order_type, 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, 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);
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);
default: throw new NotImplementedException();
}
}
@@ -51,17 +51,12 @@ namespace mbts.spark {
protected readonly OrdersModel model;
protected OrderFactory factory => model.factory;
protected OrderTypeVMBase(OrdersModel model, string id, string display_name) {
this.model = model;
this.id = id;
this.display_name = display_name;
}
protected OrderTypeVMBase(OrdersModel model) => this.model = model;
public abstract CustomOneofCase order_type { get; }
public abstract string type_name { get; }
public bool is_bts_type => display_name.StartsWith("BTS");
public string id { get; }
public string display_name { get; }
public string display_name => OrderUtils.order_type_display_name(order_type);
public OrderMetadata meta => factory.get_metadata(order_type);
public virtual bool has_editable_properties => !meta.NoProps;
public virtual bool editable_properties_open { get; set; }
@@ -81,7 +76,7 @@ namespace mbts.spark {
}
private abstract class OrderTypeVMBase<T> : OrderTypeVMBase where T : Google.Protobuf.IMessage, new() {
protected OrderTypeVMBase(OrdersModel model, string id, string display_name) : base(model, id, display_name) { }
protected OrderTypeVMBase(OrdersModel model) : base(model) { }
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, string id, string display_name)
public SpreaderOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
: 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, string id, string display_name)
: base(model, id, display_name) {
IObservable<InlineUserProperty<SpreaderOrderDefinitionImmutable>> order_template_source)
: base(model) {
_template = backing(nameof(template), new SpreaderOrderDefinitionImmutable?());
_strategy_editor_wrapper = new StrategyEditorWrapper(this);
_dispose = Disposable.Create(
@@ -29,11 +29,10 @@ namespace mbts.spark {
InlineStopLimitOrderProperties _inline_props;
IDisposable _dispose;
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<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<ContractSpecificationImmutable> spec_source, IObservable<InlineStopLimitOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
internal StopLimitOrderVM(OrdersModel model, IObservable<ContractSpecificationImmutable> spec_source, IObservable<InlineStopLimitOrderProperties> inline_properties) : base(model) {
_stop_price = new UserProperty<double>(backing(nameof(stop_price), double.NaN));
_dispose = Disposable.Create(
spec_source.OnDispatcher().Subscribe(s => {
@@ -6,7 +6,8 @@ namespace mbts.spark {
private class StopOrderVM : OrderTypeVMBase<StopOrderDefinition> {
double _stop_price = 0;
internal StopOrderVM(OrdersModel model, string id, string display_name) : base(model, id, display_name) { }
internal StopOrderVM(OrdersModel model) : base(model) { }
public double stop_price {
get => _stop_price;
@@ -17,11 +17,11 @@ namespace mbts.spark
{
class InlineTickOrderProperties
{
public InlineTickOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlineTickOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
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<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> 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<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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, string id, string display_name)
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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) { }
new InlineTickOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTickOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
IObservable<InlineTickOrderProperties> inline_properties) : base(model)
{
_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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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.key.type :
_inline_props.selected_child_order_type.value :
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(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
public InlineTimeBoxOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
start = new InlineUserProperty<DateTime>(DateTime.Now, true);
stop = new InlineUserProperty<DateTime>(DateTime.Now.AddMinutes(5), true);
}
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> 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<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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, string id, string display_name)
public TimeBoxOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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) { }
new InlineTimeBoxOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public TimeBoxOrderVM(OrdersModel model,
IObservable<SecurityMD> security_md_source,
IObservable<InlineTimeBoxOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
IObservable<InlineTimeBoxOrderProperties> inline_properties)
: base(model) {
_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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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.key.type :
_inline_props.selected_child_order_type.value :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -17,17 +17,17 @@ namespace mbts.spark
{
class InlineTopOrderProperties
{
public InlineTopOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlineTopOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
var hedgetype = CustomOneofCase.Lean;
if(!child_order_types.Any(ct => ct.key.type == hedgetype))
if(!child_order_types.Contains(hedgetype))
hedgetype = CustomOneofCase.Limit;
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(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<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<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<uint> watch_level_tick_offset;
@@ -53,13 +53,13 @@ namespace mbts.spark
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
InlineTopOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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, string id, string display_name)
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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)
new InlineTopOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
{ }
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTopOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
IObservable<InlineTopOrderProperties> inline_properties) : base(model)
{
_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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
{
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
_select_hedge_order(p.selected_hedge_order_type.value);
}
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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, 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.key.type :
_inline_props.selected_child_order_type.value :
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.key.type :
_inline_props.selected_hedge_order_type.value :
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<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> 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(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
public InlineTriggerOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> 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<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
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);
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,20 +47,19 @@ namespace mbts.spark {
readonly UserProperty<bool> _use_fixed_price, _is_timeout_checked, _is_priceout_checked;
SecurityMD? _security_md;
SecurityImmutable? _security => _security_md.security();
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _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, string id, string display_name)
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
: this(model, security_md_source, security_md_source.Select(smd =>
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) { }
new InlineTriggerOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineTriggerOrderProperties> inline_properties, string id, string display_name)
: base(model, id, display_name) {
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineTriggerOrderProperties> inline_properties) : base(model) {
_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);
@@ -89,7 +88,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.key.type);
_select_child_order(p.selected_child_order_type.value);
}
// trigger price
_trigger_price_type.on_inline_prop(p.trigger_price_type);
@@ -136,7 +135,7 @@ namespace mbts.spark {
public ICollection<IOrderTypeVM> child_order_types {
get {
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
return _child_order_choices;
}
}
@@ -211,13 +210,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 ulong v);
_security_md.Value.md.get_last_trade(ref _last_trade_ref, out co2.NativePriceSize ps, out DateTime ts, 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.key.type :
_inline_props.selected_child_order_type.value :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
@@ -1,99 +0,0 @@
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);
}
}
@@ -0,0 +1,156 @@
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); }
}
}
+57 -85
View File
@@ -156,13 +156,15 @@ namespace mbts.ui.shell
public string name => _propname;
public void set(T value) {
if (!Equals(value, _value))
_apply_new_value(value);
if (!Equals(value, _value)) {
Changing?.Invoke(_value, value);
var old = _value;
_value = value;
Changed?.Invoke(old, value);
_owner.RaisePropertyChanged(_propname);
}
}
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);
@@ -180,14 +182,6 @@ 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> {
@@ -535,7 +529,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, EqualityComparer<T>.Default, validation_steps);
backing(name, items, desired_item, select_default, null, 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.
@@ -547,8 +541,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, IEqualityComparer<T> comparer) =>
backing(name, items, desired_item, select_default, comparer, 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, Func<T, T, bool> items_match) =>
backing(name, items, desired_item, select_default, items_match, 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.
@@ -561,22 +555,12 @@ 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, 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) {
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>();
_observable_properties.Add(items.OnDispatcher().Subscribe(selector_property));
_observable_properties.Add(desired_item.OnDispatcher().Subscribe(selector_property));
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));
return prop;
}
protected void set_dispose(IDisposable disposable) {
@@ -595,44 +579,37 @@ 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<TItem, TValue> : IObserver<InlineUserProperty<TItem>>, IObserver<IEnumerable<TItem>>, IObservable<(TValue oldval, TValue newval)> {
protected class SelectorProperty<T> : IObserver<InlineUserProperty<T>>, IObserver<IEnumerable<T>>, IObservable<(T oldval, T newval)> {
readonly DisposableViewModelBase _owner;
readonly string _prop_name;
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>();
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;
bool _is_user_selected_item;
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) {
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<T> select_default, Func<T, T, bool> items_match, IReadOnlyList<PropertyValidation<T>> validation_steps) {
_owner = owner;
_prop_name = prop_name;
_item_to_value = item_to_value;
_select_default = select_default;
_value_comparer = value_comparer ?? EqualityComparer<TValue>.Default;
_items_match = items_match;
_validation_steps = validation_steps;
items = new ReadOnlyObservableCollection<TItem>(_items);
items = new ReadOnlyObservableCollection<T>(_items);
}
public event PropertyChange<TValue> Changing;
public event PropertyChange<TValue> Changed;
public event PropertyChange<T> Changing;
public event PropertyChange<T> Changed;
public ReadOnlyObservableCollection<TItem> items { get; }
public ReadOnlyObservableCollection<T> items { get; }
public TValue selected_item {
public T selected_item {
get => _selected_item;
set {
_is_user_selected_item = true;
@@ -640,31 +617,31 @@ namespace mbts.ui.shell
}
}
public IDisposable Subscribe(IObserver<(TValue oldval, TValue newval)> observer) {
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
Changed += pch;
return Disposable.Create(() => Changed -= pch);
void pch(TValue o, TValue n) => observer.OnNext((o, n));
void pch(T o, T n) => observer.OnNext((o, n));
}
public IObservable<TValue> observe_current(bool start_now = false) {
public IObservable<T> 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<TItem>>.OnNext(InlineUserProperty<TItem> iup) {
void IObserver<InlineUserProperty<T>>.OnNext(InlineUserProperty<T> iup) {
_desired_item = iup;
_try_auto_select();
}
void IObserver<InlineUserProperty<TItem>>.OnError(Exception error) { }
void IObserver<InlineUserProperty<TItem>>.OnCompleted() { }
void IObserver<InlineUserProperty<T>>.OnError(Exception error) { }
void IObserver<InlineUserProperty<T>>.OnCompleted() { }
void IObserver<IEnumerable<TItem>>.OnNext(IEnumerable<TItem> value) {
if (_is_user_selected_item) {
void IObserver<IEnumerable<T>>.OnNext(IEnumerable<T> value) {
if (_items_match != null && _is_user_selected_item) {
var curr_selected_item = selected_item;
_items.sync_with(value);
if (_try_match_item(curr_selected_item, out TValue match))
if (_try_match_item(curr_selected_item, out T match))
selected_item = match;
else {
_is_user_selected_item = false;
@@ -672,13 +649,18 @@ namespace mbts.ui.shell
}
} else {
_items.sync_with(value);
_try_auto_select();
if (_is_user_selected_item) {
_is_user_selected_item = _items.Contains(_selected_item);
}
if (!_is_user_selected_item) {
_try_auto_select();
}
}
}
void IObserver<IEnumerable<TItem>>.OnError(Exception error) { }
void IObserver<IEnumerable<TItem>>.OnCompleted() { }
void IObserver<IEnumerable<T>>.OnError(Exception error) { }
void IObserver<IEnumerable<T>>.OnCompleted() { }
void _run_validation(TValue val) {
void _run_validation(T 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));
@@ -688,15 +670,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 TValue match)) {
if (desired_item_valid() && _desired_item.force_override && _try_match_item(_desired_item.value, out T match)) {
_set_selected_item(match);
return;
}
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out TValue match)) {
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out T match)) {
_set_selected_item(match);
return;
}
if (_try_match_item(_select_default(), out TValue default_match))
if (_try_match_item(_select_default(), out T default_match))
_set_selected_item(default_match);
else {
// the _set_selected_item has never been entered, so validation has never ran, force it here
@@ -706,8 +688,8 @@ namespace mbts.ui.shell
bool desired_item_valid() => (_desired_item?.has_value).GetValueOrDefault();
}
void _set_selected_item(TValue value) {
if (!_value_comparer.Equals(value, _selected_item)) {
void _set_selected_item(T value) {
if (!Equals(value, _selected_item)) {
Changing?.Invoke(_selected_item, value);
var old = _selected_item;
_selected_item = value;
@@ -717,20 +699,10 @@ namespace mbts.ui.shell
}
}
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);
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);
}
public event Action<bool> OnDisposed;
@@ -15,7 +15,7 @@ namespace mbts.spark {
value = initial_value;
}
public event Action<(T oldval, T newval)> value_set;
event Action<(T oldval, T newval)> _value_set;
public T value { get; private set; }
public string text => _text ?? (_text = _format(value));
@@ -27,22 +27,14 @@ 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;
@@ -50,7 +42,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}" DisplayName="{Binding display_name}" Metadata="{Binding meta}"/>
<usp:OrderTypeItem OrderType="{Binding order_type}" Metadata="{Binding meta}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
@@ -222,6 +222,8 @@
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@@ -233,9 +235,11 @@
<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">Child</TextBlock>
<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>
<uag:OrderDetailsPopupControl
Grid.Row="5" Grid.Column="2"
Grid.Row="7" 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 x:Name="text"
<TextBlock
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="20,0,0,0"
@@ -3,49 +3,23 @@ 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>
partial class OrderTypeItem : Control {
static OrderTypeItem() =>
public 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);
}
}
}
}
}
}
@@ -0,0 +1,18 @@
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();
}
}
}
@@ -0,0 +1,32 @@
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,6 +26,8 @@
<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" />
@@ -0,0 +1,37 @@
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 ulong __);
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out DateTime _, 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 ?? string.Empty).Subscribe(account_positions),
order_properties_vm.observe_account(true).Select(a => a.name).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 ulong volume);
md.get_last_trade(ref unused, out NativePriceSize last, out DateTime time, 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 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 DateTime unused1, 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, ulong volume)> last_trade { get; }
IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade { get; }
IObservable<double> bid_price { get; }
IObservable<uint> bid_size { get; }
IObservable<double> ask_price { get; }
@@ -61,6 +61,7 @@ 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)) {
@@ -74,9 +75,10 @@ namespace mbts.spark.utilities
}
private bool _refresh_last(MDConsumerHandle md) {
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
_last_price = ps.price;
_last_size = ps.size;
_last_time = ts;
_volume = v;
return true;
}
@@ -84,16 +86,17 @@ namespace mbts.spark.utilities
}
private (double, uint, double, uint) _select_bbo() { return (_bid_price, _bid_size, _ask_price, _ask_size); }
private (double, uint, ulong) _select_last() { return (_last_price, _last_size, _volume); }
private (double, uint, DateTime, ulong) _select_last() { return (_last_price, _last_size, _last_time, _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, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
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> 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,29 +110,6 @@ 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();
@@ -235,7 +212,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;
public static readonly TimeSpan default_interval;
public static readonly DispatcherPriority default_priority;
static readonly DispatcherPriority default_priority;
static readonly TimeSpan default_interval;
static WorkLoop() {
var timer_params = config.Configuration.get<bts.config.LadderKnobs>();
@@ -0,0 +1,90 @@
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
}
}
+1 -2
View File
@@ -31,8 +31,7 @@ namespace bts {
Mercury,
Testing,
Latency,
DataFlow,
Plugin
DataFlow
// Please keep this list in sync with logging.h/logging.cpp
}
readonly struct Logger {
@@ -113,5 +113,7 @@ 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);
}
}
+5 -10
View File
@@ -72,12 +72,7 @@ namespace mbts.co2
return false;
}
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) {
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out DateTime 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));
@@ -93,15 +88,15 @@ namespace mbts.co2
public ulong total_volume { get { return _cold->total_volume; } }
public double settlement_price { get { return _cold->settlement_price;} }
public utils.LLDate settlement_date { get { return _cold->settlement_date;} }
public DateTime settlement_date { get { return _cold->settlement_date;} }
public double previous_settlement_price { get { return _cold->previous_settlement_price;} }
public utils.LLDate previous_settlement_date { get { return _cold->previous_settlement_date;} }
public DateTime previous_settlement_date { get { return _cold->previous_settlement_date;} }
public double open_price { get { return _cold->open_price;} }
public utils.LLDate open_date { get { return _cold->open_date; } }
public DateTime open_date { get { return _cold->open_date; } }
public double close_price { get { return _cold->close_price;} }
public utils.LLDate close_date { get { return _cold->close_date; } }
public DateTime 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; } }
+28 -9
View File
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace bts.test {
public static class ConsoleEx {
@@ -21,17 +23,34 @@ namespace bts.test {
}
public static T prompt<T>(string prompt, params T[] options) {
Console.WriteLine(prompt);
for (int x = 1; x <= options.Length; ++x) {
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) {
Write($"{x}. ", ConsoleColor.Yellow);
WriteLine(options[x].ToString());
WriteLine(options.ElementAt(x).ToString());
}
int response;
do {
Int32.TryParse(Console.ReadKey().ToString(), out response);
if (response > options.Length) response = 0;
} while (response == 0);
return options[response];
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;
}
@@ -43,6 +43,9 @@ 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,9 +27,6 @@ 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,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace mbts {
@@ -24,20 +23,14 @@ 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) {
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;
// 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));
}
public static DateTime lldatetime(this long ll) { return ((ulong)ll).lldatetime(); }
}
}
}
@@ -18,6 +18,7 @@ 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,6 +56,11 @@ 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;
+27 -13
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.Now));
Assert.IsTrue(compare_date(entry.last_trade_time, DateTime.UtcNow));
//// Settlement
Assert.AreEqual(entry.settlement_price, 3.3);
Assert.IsTrue(entry.settlement_date == new DateTime(2015, 9, 3));
@@ -210,24 +210,19 @@ namespace mbts.co2.tests
Assert.IsTrue(ask.size == 202);
time = 0;
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;
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(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);
// 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_date.Year == 2000 && handle.settlement_date.Day == 9 && handle.settlement_date.Month == 8);
Assert.IsTrue(handle.settlement_price == 6.6);
Assert.IsTrue(handle.open_price == 7.7);
// 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.open_date.Year == 2001 && handle.open_date.Month == 1 && handle.open_date.Day == 2);
Assert.IsTrue(handle.close_price == 8.8);
// 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.close_date.Year == 2002 && handle.close_date.Month == 3 && handle.close_date.Day == 4);
Assert.IsTrue(handle.session_high == 9.9);
Assert.IsTrue(handle.session_low == 10.1);
@@ -256,6 +251,25 @@ 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);
}
}
}
@@ -0,0 +1,20 @@
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,5 +13,8 @@ namespace sparkcmd {
ConsoleCommandDispatcher.DispatchCommand(commands, args, Console.Out);
return;
}
}
}
+1 -2
View File
@@ -8,8 +8,7 @@
<Authors>Blue Trading Systems</Authors>
<Company>Blue Trading Systems</Company>
<Product>Spark</Product>
<Platform>x64</Platform>
<PlatformTarget>x64</PlatformTarget>
<Platforms>x64</Platforms>
<Version>1.0.0</Version>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
+1 -1
View File
@@ -1 +1 @@
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)
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)
+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 ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR} files/*)
file (GLOB_RECURSE To_Copy RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} files/*)
update_deps_file("${To_Copy}")
# END DEPENDENCIES
Binary file not shown.
@@ -0,0 +1,63 @@
<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
@@ -0,0 +1,2 @@
/*! 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
@@ -0,0 +1,164 @@
$( 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
@@ -0,0 +1,7 @@
/**
* 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/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
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
+1
View File
@@ -103,6 +103,7 @@ else ()
boost_chrono
boost_date_time
boost_atomic
SQLiteCpp
sqlite3
curl
uuid
@@ -1,40 +1,34 @@
#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 AdminData& data){
uint32_t AdminServiceUtils::find_max_connection_id (const bts::api::admin::AdminData& data){
uint32_t rv = 0;
for(const auto &conn : data.connections())
if (conn.id() > rv)
rv = conn.id();
return rv;
}
const ExchangeConnection* AdminServiceUtils::find_connection(
const AdminData& data,
const std::string& connection_name){
const bts::api::admin::ExchangeConnection* AdminServiceUtils::find_connection(const bts::api::admin::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 ExchangeConnection& conn,
api::Venue exchange){
bool AdminServiceUtils::has_exchange(const bts::api::admin::ExchangeConnection& conn,
bts::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:
@@ -876,89 +870,6 @@ 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 ///////////////////////////
////////////////////////////////////////////
+145 -199
View File
@@ -4,13 +4,12 @@
#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:
////////////////////////////////////////////
@@ -18,286 +17,233 @@ public:
////////////////////////////////////////////
// finds the max id out of all the existing connections
// (todo: deleted connections)
static uint32_t find_max_connection_id (const AdminData& data);
static uint32_t find_max_connection_id (const bts::api::admin::AdminData& data);
// finds a connection by name and returns a mutable pointer to it
static const ExchangeConnection* find_connection(const AdminData& data,
const std::string& connection_name);
static const bts::api::admin::ExchangeConnection* find_connection(const bts::api::admin::AdminData& data,
const std::string& connection_name);
// finds the presence of an exchange in a connection
static bool has_exchange(const ExchangeConnection& conn,
static bool has_exchange(const bts::api::admin::ExchangeConnection& conn,
bts::api::Venue exchange);
// finds the default connections for an exchange
// in a given account
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);
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);
////////////////////////////////////////////
// connection mutators /////////////////////
////////////////////////////////////////////
// adds a new connection (does not check for name uniqueness)
static ExchangeConnection* add_connection(AdminData& data,
const ExchangeConnection& new_connection);
static bts::api::admin::ExchangeConnection* add_connection(bts::api::admin::AdminData& data,
const bts::api::admin::ExchangeConnection& new_connection);
// reads the connections from config and fills in the
// admin data (with names only)
static void fill_connections_from_config(AdminData& admin_data);
static void fill_connections_from_config(bts::api::admin::AdminData& admin_data);
////////////////////////////////////////////
// account accessors ///////////////////////
////////////////////////////////////////////
// finds the account from the name and returns
// a mutable pointer to the account
static BTSAccount* find_account (AdminData& data,
const std::string& acct_name,
bool include_deleted=false);
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, const std::string& acct_name, bool include_deleted=false);
// same as above for const pointer
static const BTSAccount* find_account (const AdminData& data,
const std::string& acct_name,
bool include_deleted=false);
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::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 BTSAccount* find_account (AdminData& data,
uint32_t id,
bool include_deleted=false);
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
// like above but returns a const pointer
static const BTSAccount* find_account (const AdminData& data,
uint32_t id,
bool include_deleted=false);
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::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 BTSAccount*> accounts (const AdminData& data,
bool include_deleted);
static std::vector<BTSAccount*> accounts_mutable (AdminData& data,
bool include_deleted);
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);
// finds the max id amongts all the existing accounts
static uint32_t find_max_acct_id (const AdminData& data);
static uint32_t find_max_acct_id (const bts::api::admin::AdminData& data);
// gets the account data for cme (and goes up the hierarchy
// if needed)
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);
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);
// returns true if an account has a connection
bool static account_has_connection(const BTSAccount& account,
const std::string& connection_name);
bool static account_has_connection(const bts::api::admin::BTSAccount& account, const std::string& connection_name);
// finds the external/clearing account associated
// with an account
static std::string find_account_exchange_account (const AdminData& data,
const BTSAccount& account,
api::Venue exchange,
AdminServiceOperationResult& out_result);
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);
// returns a map of the accounts vs their 'is_active'
static std::map<uint32_t,bool> accounts_map(const AdminData& admin_data);
static std::map<uint32_t,bool> accounts_map(const bts::api::admin::AdminData& admin_data);
// validates that the update to the account is valid
static void validate_account_update (const AdminData& admin_data,
const BTSAccount& updated_account,
AdminServiceOperationResult& result);
static void validate_account_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSAccount& updated_account,
bts::api::admin::AdminServiceOperationResult& result);
// validates that the account exchange changes are valid
// (ex > 12 characters for accounts at CME)
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);
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);
////////////////////////////////////////////
// account mutators ////////////////////////
////////////////////////////////////////////
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);
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);
// writes over the account data completely
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);
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);
// 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 AdminData& data,
BTSAccount& account);
static void sync_account_connections(const bts::api::admin::AdminData& data,
bts::api::admin::BTSAccount& account);
////////////////////////////////////////////
// group accessors /////////////////////////
////////////////////////////////////////////
// given an id, finds the mutable pointer to a group
static BTSUserGroup* find_group (AdminData& data, uint32_t id);
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, uint32_t id);
// given an id, finds the const pointer to a group
static const BTSUserGroup* const find_group (const AdminData& data,
uint32_t id);
static const bts::api::admin::BTSUserGroup* const find_group (const bts::api::admin::AdminData& data, uint32_t id);
// given a name, finds the mutable pointer to a group
static BTSUserGroup* find_group (AdminData& data,
const std::string& group_name);
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, const std::string& group_name);
// finds the max id out of all the groups
static uint32_t find_max_group_id (const AdminData& data);
static uint32_t find_max_group_id (const bts::api::admin::AdminData& data);
// travels up the group tree until it finds a populated cme data
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);
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);
////////////////////////////////////////////
// group mutators/ /////////////////////////
////////////////////////////////////////////
static BTSUserGroup* create_group(AdminData& data,
uint32_t parent_group_id,
const std::string& group_name,
AdminServiceOperationResult& result);
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);
////////////////////////////////////////////
// user accessors //////////////////////////
////////////////////////////////////////////
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);
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);
// 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 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,
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,
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 UserAccountPermissions* get_user_permissions (
const AdminData& admin_data,
uint32_t user_id);
static const bts::api::admin::UserAccountPermissions* get_user_permissions (const bts::api::admin::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 AdminData& admin_data,
uint32_t user_id,
std::vector<const BTSAccount*>& associated_accounts);
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);
// validates that changes in user data satisfy all the
// constraints
static void validate_user_update (const AdminData& admin_data,
const BTSUser& updated_user,
AdminServiceOperationResult& result);
static void validate_user_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& result);
// vaidates the exchange part of user data updates
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);
static void validate_user_exchange_data (const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& out_result);
////////////////////////////////////////////
// user mutators ///////////////////////////
////////////////////////////////////////////
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);
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);
////////////////////////////////////////////
//risk limits //////////////////////////////
////////////////////////////////////////////
// sorting function used by sort_limits to
// sort SecurityScope's
static bool _sort_security_scopes (const SecurityScope& a,
const SecurityScope& b);
static bool _sort_security_scopes (const bts::api::admin::SecurityScope& a, const bts::api::admin::SecurityScope& b);
// sorting function used by sort_limits to
// sort ProductScope's
static bool _sort_product_scopes (const ProductScope& a,
const ProductScope&);
static bool _sort_product_scopes (const bts::api::admin::ProductScope& a, const bts::api::admin::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 (BTSAccount& account);
static void sort_limits (bts::api::admin::BTSAccount& account);
// creates a copy of AdminData with sorted rules
static AdminData sort_limits (const AdminData& admin_data);
static bts::api::admin::AdminData sort_limits (const bts::api::admin::AdminData& admin_data);
// find the clip size for a security, account
static const uint32_t find_account_security_clip_size(
const BTSAccount& account,
const api::Security& security);
static const uint32_t find_account_security_clip_size(const bts::api::admin::BTSAccount& account,
const api::Security& security);
// find the position limit for an account, security
static const AccountSecurityPositionLimitUnit*
find_account_security_position_limit(const BTSAccount& account,
static const bts::api::admin::AccountSecurityPositionLimitUnit* find_account_security_position_limit(const bts::api::admin::BTSAccount& account,
const api::Security& security);
// find the position limit for an account, product
static const AccountProductPositionLimitUnit*
find_account_product_position_limit(const BTSAccount& account,
static const bts::api::admin::AccountProductPositionLimitUnit* find_account_product_position_limit(const bts::api::admin::BTSAccount& account,
const api::Product& product);
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 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 api::SecurityType security_type(const api::Security& security);
////////////////////////////////////////////
// misc//////// ////////////////////////////
-62
View File
@@ -182,17 +182,6 @@ 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;
@@ -287,8 +276,6 @@ 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 {
@@ -344,48 +331,6 @@ 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;
}
/************************************************************************/
/************************************************************************/
/************************************************************************/
@@ -440,11 +385,4 @@ 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);
}
@@ -1,17 +0,0 @@
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);
}
+12 -79
View File
@@ -6,7 +6,6 @@ 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";
@@ -16,12 +15,9 @@ 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);
}
@@ -113,6 +109,15 @@ 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 {
@@ -143,7 +148,8 @@ message CoverOrderDefinition {
}
message DynamicOrderDefinition {
string dynamic_order_type = 1;
map<string, DynamicOrderParam> order_params = 2;
map<string,string> parameters = 2;
CustomOrderDefinition child = 3;
}
// End custom order definitions
@@ -262,7 +268,7 @@ message TopOrderState {}
message TriggerOrderState {}
message CoverOrderState {}
message DynamicOrderState {
map<string,string> state = 1;
map<string,string> state = 2;
}
enum OrderStatus {
@@ -468,76 +474,3 @@ 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(*iter);
const proto::Message* key = _config.try_get_message_or_default(*iter);
if (!key) return false;
// 2) Drill down using reflection to find the named property
+13
View File
@@ -616,6 +616,19 @@ 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,6 +59,7 @@ 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; }
+1 -10
View File
@@ -76,16 +76,7 @@ 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)
{
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;
return config_state.try_get_message_or_default(key_name);
}
BTS_EXPORT std::string get_macro_string(const char* name) { return config_state.get_macro_string(name); }
+20
View File
@@ -26,6 +26,26 @@ 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'
# }
}
}
@@ -0,0 +1,194 @@
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
@@ -0,0 +1,34 @@
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
@@ -0,0 +1,7 @@
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];
repeated uint32 affinity = 10;
optional string thread_group = 10 [default=""]; // if present this will be used to retrieve affinity settings from Threads config key
optional uint32 udp_socket_buffer_size = 11 [default = 33554432]; //32mb
}
enum BookType {
@@ -1,11 +0,0 @@
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
@@ -0,0 +1,6 @@
syntax='proto2';
package bts.config;
message CppConfig {
map<string, double> cpp_entry = 1;
}
-8
View File
@@ -1,8 +0,0 @@
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"];
}
@@ -0,0 +1,24 @@
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
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,13 @@
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,8 +26,4 @@ message OrdersSoftCleanup{
message ToastNotifications {
optional bool enabled = 1 [default = false];
}
message VolumeAtPrice{
optional bool enabled = 1 [default = true];
}
-16
View File
@@ -40,22 +40,6 @@ 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/TickToTradeCorID.h"
#include "lib/orderman/orderman_utils/PerfTrace.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/TickToTradeCorID.h"
#include "lib/orderman/orderman_utils/PerfTrace.h"
namespace bts {
namespace jetfix {
+4 -3
View File
@@ -7,7 +7,8 @@
#include "lib/utils/bts_assert.h"
#include "lib/os/os.h"
#include "lib/tracing/bts_trace.h"
#include "lib/orderman/orderman_utils/TickToTradeCorID.h"
#include "lib/orderman/orderman_utils/PerfTrace.h"
#include "lib/utils/thread_manager.h"
#include <fstream>
@@ -112,8 +113,8 @@ AsyncReader::AsyncReader (IConnection &connection,
void AsyncReader::start ()
{
me->reader_thread = std::thread ([this] () {
os::set_thread_name(me->connection_name+"_asyncr");
auto thread_name = fmt::format ("jf_ar_{}", me->connection_name);
me->reader_thread = threading::make_thread (thread_name,[this] () {
dispatch();
});
}
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#include <array>
#include "lib/orderman/orderman_utils/TickToTradeCorID.h"
#include "lib/orderman/orderman_utils/PerfTrace.h"
namespace bts {
namespace jetfix {
+34 -37
View File
@@ -1,11 +1,12 @@
#include "SocketConnection.h"
#include "lib/jetfix/store/session_name.h"
#include "lib/logging/logging.h"
#include "lib/metrics/metrics.h"
#include "lib/orderman/orderman_utils/PerfTraceLog.h"
#include "lib/tracing/bts_trace.h"
#include "lib/utils/TimeStamp.h"
#include "lib/utils/bts_assert.h"
#include "lib/utils/helper_macros.h"
#include "lib/orderman/orderman_utils/PerfTraceLog.h"
#include <arpa/inet.h>
#include <fstream>
@@ -19,29 +20,15 @@ namespace bts {
namespace jetfix {
SocketConnection::SocketConnection(bts::config::JetFIX::Connection const &cfg,
metrics::MetricsContainer &stats)
PerfTraceLog &perf_log)
: _fd(-1), _cfg(cfg), _log(cfg.log_fix_stream()), _in_log(), _out_log(),
_stats(stats), _tick_to_order(), _fill_to_order() {
_perf_log(perf_log) {
if (_log) {
_in_log.open(std::string("/tmp/fix_raw_read_log_") + session_name(cfg),
std::ios_base::app);
_out_log.open(std::string("/tmp/fix_raw_write_log_") + session_name(cfg),
std::ios_base::app);
}
std::vector<metrics::Label> labels;
labels.push_back({"connection", cfg.name()});
std::array<double, 30> buckets;
auto i = 1;
for (auto &b : buckets)
b = (i *= 2);
_tick_to_order = std::make_shared<metrics::HistogramMetric<30>>(
"spark_tick_to_order_ns", buckets, labels);
_fill_to_order = std::make_shared<metrics::HistogramMetric<30>>(
"spark_fill_to_order_ns", buckets, labels);
_stats.publish(_tick_to_order);
_stats.publish(_fill_to_order);
}
SocketConnection::~SocketConnection() {
@@ -122,46 +109,56 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size,
auto trace_cpy = trace;
trace_cpy.fix_socket_w = utils::TimeStamp::now();
tracepoint(bts_trace, trace_order, (char *)"SocketConnection.pre_write", 0,
trace.md_sn, 0);
utils::TimeStamp::Interval s2s;
if (trace.md.to_uint64()) {
s2s = (trace_cpy.fix_socket_w - trace_cpy.md);
tracepoint(bts_trace, trace_order,
(char *)"SocketConnection.tick_to_order.pre_write", 0,
trace.md_sn, s2s.microseconds());
} else {
s2s = (trace_cpy.fix_socket_w - trace_cpy.fix_socket_r);
tracepoint(bts_trace, trace_order,
(char *)"SocketConnection.fill_to_order.pre_write", 0,
trace.md_sn, s2s.microseconds());
}
auto result = ::writev(_fd, iv, (int)vec_size);
if (trace.md.to_uint64()) {
auto s2s = (trace_cpy.fix_socket_w - trace_cpy.md);
LOG(Latency, Info,
"perf_event:tick_to_order s2s_us:{} fix_socket_r:{} md:{} "
"md_src:{} spreader_on_book:{} spreader_modify_order:{} "
"spreader_on_child_order_update:{} "
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{}",
"spreader_on_child_order_update:{} "
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{} "
"send_fix_buffer:{}",
s2s.microseconds(), trace_cpy.fix_socket_r.to_uint64(),
trace_cpy.md.to_uint64(), trace_cpy.md_src.to_uint64(),
trace_cpy.spreader_on_book.to_uint64(),
trace_cpy.spreader_modify_order.to_uint64(),
trace_cpy.spreader_on_child_order_update.to_uint64(),
trace_cpy.order_update.to_uint64(),
trace_cpy.exe_gw.to_uint64(), trace_cpy.fix_socket_w.to_uint64(),
trace_cpy.md_sn,
trace_cpy.order_key);
_tick_to_order->observe(s2s.nanoseconds());
trace_cpy.spreader_on_child_order_update.to_uint64(),
trace_cpy.order_update.to_uint64(), trace_cpy.exe_gw.to_uint64(),
trace_cpy.fix_socket_w.to_uint64(), trace_cpy.md_sn,
trace_cpy.order_key, trace.send_fix_buffer.to_uint64());
_perf_log.log(trace_cpy);
}
if (trace.fix_socket_r.to_uint64()) {
auto s2s = (trace_cpy.fix_socket_w - trace_cpy.fix_socket_r);
LOG(Latency, Info,
"perf_event:fill_to_order s2s_us:{} fix_socket_r:{} md:{} md_src:{} "
"spreader_on_book:{} spreader_modify_order:{} "
"spreader_on_child_order_update:{} "
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{}",
"spreader_on_child_order_update:{} "
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{} "
"send_fix_buffer:{} ",
s2s.microseconds(), trace_cpy.fix_socket_r.to_uint64(),
trace_cpy.md.to_uint64(), trace_cpy.md_src.to_uint64(),
trace_cpy.spreader_on_book.to_uint64(),
trace_cpy.spreader_modify_order.to_uint64(),
trace_cpy.spreader_on_child_order_update.to_uint64(),
trace_cpy.order_update.to_uint64(),
trace_cpy.exe_gw.to_uint64(), trace_cpy.fix_socket_w.to_uint64(),
trace_cpy.md_sn,
trace.order_key);
_fill_to_order->observe(s2s.nanoseconds());
trace_cpy.spreader_on_child_order_update.to_uint64(),
trace_cpy.order_update.to_uint64(), trace_cpy.exe_gw.to_uint64(),
trace_cpy.fix_socket_w.to_uint64(), trace_cpy.md_sn, trace.order_key,
trace.send_fix_buffer.to_uint64());
_perf_log.log(trace_cpy);
}
tracepoint(bts_trace, trace_order, (char *)"SocketConnection.post_write", 0,
+3 -5
View File
@@ -7,14 +7,14 @@
#include "lib/metrics/metrics.h"
namespace bts {
namespace metrics {class MetricsContainer;}
class PerfTraceLog;
namespace jetfix {
class SocketConnection : public IConnection
{
public:
SocketConnection(bts::config::JetFIX::Connection const &cfgl,metrics::MetricsContainer &stats);
SocketConnection(bts::config::JetFIX::Connection const &cfgl,PerfTraceLog &log);
~SocketConnection();
bool connect () override;
void shutdown () override;
@@ -27,9 +27,7 @@ private:
bool _log;
std::ofstream _in_log;
std::ofstream _out_log;
metrics::MetricsContainer &_stats;
std::shared_ptr<metrics::HistogramMetric<30>> _tick_to_order;
std::shared_ptr<metrics::HistogramMetric<30>> _fill_to_order;
PerfTraceLog &_perf_log;
};
}}
Loaded 100 of 281 files, more files were not shown because too many files have changed in this diff. Show more