Merge branch 'master' of bitbucket.org:bluetradesys/spark into simplify_md_sdk
This commit is contained in:
commit
e22649c19d
69 files changed
+2026
-560
No files matched your search
@@ -0,0 +1 @@
|
||||
set(sources /home/ppinto/Dropbox/bts/spark/doc/user/build.sh;/home/ppinto/Dropbox/bts/spark/doc/user/mkdocs.yml;bts-help-theme/404.html;bts-help-theme/base.html;bts-help-theme/content.html;bts-help-theme/css/base.css;bts-help-theme/css/bts.css;bts-help-theme/css/font-awesome.min.css;bts-help-theme/css/highlight.css;bts-help-theme/css/local.css;bts-help-theme/fonts/fontawesome-webfont.eot;bts-help-theme/fonts/glyphicons-halflings-regular.eot;bts-help-theme/img/favicon.ico;bts-help-theme/js/base.js;bts-help-theme/js/bootstrap-3.0.3.min.js;bts-help-theme/js/highlight.pack.js;bts-help-theme/js/jquery-1.10.2.min.js;bts-help-theme/keyboard-modal.html;bts-help-theme/main.html;bts-help-theme/nav-sub.html;bts-help-theme/nav.html;bts-help-theme/search-modal.html;bts-help-theme/toc.html;docs/Help.md;docs/Launcher.md;docs/Logging-In-to-the-System.md;docs/Market.md;docs/My-Windows.md;docs/Settings.md;docs/Spreader.md;docs/Trading.md;docs/images/image1.png;docs/images/image10.png;docs/images/image11.png;docs/images/image12.png;docs/images/image13.png;docs/images/image14.png;docs/images/image15.png;docs/images/image16.png;docs/images/image17.png;docs/images/image18.png;docs/images/image19.png;docs/images/image2.png;docs/images/image20.png;docs/images/image21.png;docs/images/image22.png;docs/images/image23.png;docs/images/image24.png;docs/images/image25.png;docs/images/image26.png;docs/images/image27.png;docs/images/image28.png;docs/images/image29.png;docs/images/image3.png;docs/images/image30.png;docs/images/image31.png;docs/images/image32.png;docs/images/image33.png;docs/images/image34.png;docs/images/image35.png;docs/images/image36.png;docs/images/image37.png;docs/images/image38.png;docs/images/image39.png;docs/images/image4.png;docs/images/image40.png;docs/images/image41.png;docs/images/image42.png;docs/images/image43.png;docs/images/image44.png;docs/images/image45.png;docs/images/image46.png;docs/images/image47.png;docs/images/image48.png;docs/images/image49.png;docs/images/image5.png;docs/images/image50.png;docs/images/image51.png;docs/images/image52.png;docs/images/image53.png;docs/images/image54.png;docs/images/image55.png;docs/images/image56.png;docs/images/image57.png;docs/images/image58.png;docs/images/image59.png;docs/images/image6.png;docs/images/image60.png;docs/images/image61.png;docs/images/image62.png;docs/images/image63.png;docs/images/image64.png;docs/images/image65.png;docs/images/image66.png;docs/images/image67.png;docs/images/image68.png;docs/images/image69.png;docs/images/image7.png;docs/images/image70.png;docs/images/image71.png;docs/images/image72.png;docs/images/image73.png;docs/images/image74.png;docs/images/image76.png;docs/images/image8.png;docs/images/image9.png;docs/index.md;docs/release_notes.md)
|
||||
@@ -16,6 +16,7 @@ set(DOC_GLOBS
|
||||
favicon.ico
|
||||
)
|
||||
file (GLOB_RECURSE All_Deps RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${DOC_GLOBS})
|
||||
set (All_Deps ${All_Deps} ${CMAKE_CURRENT_SOURCE_DIR}/build.sh ${CMAKE_CURRENT_SOURCE_DIR}/mkdocs.yml)
|
||||
update_deps_file("${All_Deps}")
|
||||
# END DEPENDENCIES
|
||||
|
||||
|
||||
+10
-1
@@ -1,2 +1,11 @@
|
||||
#!/bin/bash
|
||||
python -m mkdocs build -d $1
|
||||
tmpfile=$(mktemp /tmp/quiet_build_log.XXXX)
|
||||
python -m mkdocs build -d $1 >$tmpfile 2>&1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
rm $tmpfile
|
||||
exit 0
|
||||
else
|
||||
cat $tmpfile
|
||||
exit 1
|
||||
fi
|
||||
+1
-1
Submodule docker/linux updated: aedfd79e02...8ee9692597.
@@ -1,14 +1,14 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>BTS Spark Socket To Socket Requote Times</title>
|
||||
<title>BTS Spark Socket To Socket Requote and Hedge 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;
|
||||
padding: 1em 1em;
|
||||
}
|
||||
.summary-block > ul {
|
||||
margin: 0em 1em;
|
||||
@@ -23,6 +23,16 @@
|
||||
.clear {
|
||||
clear:both;
|
||||
}
|
||||
.session-table tr {
|
||||
padding-top: 1em;
|
||||
}
|
||||
.session-table th {
|
||||
background-color: #4169AA;
|
||||
color:#fff;
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
border-left: 1px solid #f6f6f6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -47,7 +57,7 @@
|
||||
</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>
|
||||
<h1 class="is-size-2">Socket To Socket Latencies</h1>
|
||||
<div id="output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,9 @@ $( document ).ready(function (){
|
||||
let urlParams = new URLSearchParams(window.location.search);
|
||||
num_rows = urlParams.get('r');
|
||||
let show_rows = urlParams.get('showrows');
|
||||
let rows_of = urlParams.get('rowsof');
|
||||
|
||||
//let trace_data_url = "./perf_trace_data";
|
||||
let trace_data_url = "/perf_trace_data";
|
||||
if(num_rows != null) {
|
||||
trace_data_url += "/" + num_rows;
|
||||
@@ -15,14 +17,46 @@ $( document ).ready(function (){
|
||||
error: ajax_err,
|
||||
crossDomain: true
|
||||
}).done(function(result) {
|
||||
|
||||
if(show_rows != null) {
|
||||
list_rows(show_rows, result);
|
||||
if(rows_of === "quot") {
|
||||
list_rows(show_rows, rows_of, result.requotes);
|
||||
}
|
||||
else {
|
||||
list_rows(show_rows, rows_of, result.hedges);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
if(result.length > 0){
|
||||
let summary_info = "<h1 class='is-size-3'><b>Host:</b> " + result[0].host + "</h1>";
|
||||
if((result.requotes.length + result.hedges.length) > 0) {
|
||||
let useful_result = (result.requotes.length > 0 ? result.requotes : result.hedges);
|
||||
let less_useful_result = (result.requotes.length === 0 ? result.requotes : result.hedges);
|
||||
|
||||
let summary_info = "<h1 class='is-size-3'><b>Host:</b> " + useful_result[0].host + "</h1><br>";
|
||||
|
||||
$("#output").html(summary_info);
|
||||
$(result).each(display_session);
|
||||
|
||||
let whole_result = result.requotes.concat(result.hedges);
|
||||
let unique_sessions = whole_result.filter(function(value, index, self){
|
||||
return self.find(function(elm){
|
||||
return elm.session_name === value.session_name;
|
||||
});
|
||||
});
|
||||
|
||||
$(unique_sessions).each(function (index, sess_val){
|
||||
let r = result.requotes.find(function(elm){
|
||||
return elm.session_name === sess_val.session_name;
|
||||
});
|
||||
|
||||
let h = result.hedges.find(function(elm){
|
||||
return elm.session_name === sess_val.session_name;
|
||||
});
|
||||
|
||||
display_session(r, h);
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,29 +64,30 @@ $( document ).ready(function (){
|
||||
|
||||
});
|
||||
|
||||
function list_rows(show_rows, data) {
|
||||
function list_rows(show_rows, rows_of, 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>";
|
||||
|
||||
summary_info += "<thead><tr><th>Trace Time</th>"
|
||||
$.each(value.rows[0], function(key, unval){
|
||||
if(key !== "trace_time" && key !== "total")
|
||||
{
|
||||
summary_info +="<th>" + format_title(key) + "</th>";
|
||||
}
|
||||
});
|
||||
summary_info += "<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 += "<td>" + val.trace_time + "</td>";
|
||||
$.each(val, function(key, uval){
|
||||
if(key !== "trace_time" && key !== "total")
|
||||
{
|
||||
summary_info += "<td>" + uval + "</td>";
|
||||
}
|
||||
});
|
||||
summary_info += "<td>" + val.total + "</td>";
|
||||
summary_info += "</tr>";
|
||||
});
|
||||
summary_info += "</tbody></table>";
|
||||
@@ -77,7 +112,26 @@ function ajax_err (jqXHR, textStatus,errorThrown) {
|
||||
function first_upper (str)
|
||||
{
|
||||
let ret_str = str[0].toUpperCase() + str.substring(1, str.length);
|
||||
return ret_str
|
||||
return ret_str;
|
||||
}
|
||||
|
||||
function format_title (str)
|
||||
{
|
||||
let ret_str = "";
|
||||
|
||||
for(let i=0; i < str.length; i++) {
|
||||
if(i === 0 || str[i-1] === "_") {
|
||||
ret_str += str[i].toUpperCase();
|
||||
}
|
||||
else if(str[i] === "_") {
|
||||
ret_str += " ";
|
||||
}
|
||||
else {
|
||||
ret_str += str[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ret_str;
|
||||
}
|
||||
|
||||
function generate_histogram(id, data)
|
||||
@@ -95,70 +149,143 @@ function generate_histogram(id, data)
|
||||
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>";
|
||||
function write_summary (histo_id, v)
|
||||
{
|
||||
session_info = "<ul>";
|
||||
session_info += "<li><b>" + format_title(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='" + histo_id + "' class='histogram-div'></div>"
|
||||
|
||||
|
||||
return session_info;
|
||||
}
|
||||
|
||||
function display_session (quot_val, hed_val) {
|
||||
let safe_quot_val = (quot_val != undefined) ? quot_val : {
|
||||
session_name: hed_val.session_name,
|
||||
build_type: hed_val.build_type,
|
||||
version: hed_val.version,
|
||||
n_rows: 0,
|
||||
total: 0,
|
||||
summaries: []
|
||||
};
|
||||
let safe_hed_val = (hed_val != undefined) ? hed_val : {
|
||||
session_name: quot_val.session_name,
|
||||
build_type: quot_val.build_type,
|
||||
version: quot_val.version,
|
||||
n_rows: 0,
|
||||
total: 0,
|
||||
summaries: []
|
||||
};
|
||||
|
||||
let session_info = "<table class='session-table'>";
|
||||
session_info += "<tr><td colspan='2' id='" + safe_quot_val.session_name + "' class='is-size-5'><b>Session:</b> " + safe_quot_val.session_name + "<br>";
|
||||
session_info += "<b>Build Type:</b> " + safe_quot_val.build_type + "<br>";
|
||||
session_info += "<b>Version:</b> " + safe_quot_val.version + "<br><br></td></tr>";
|
||||
|
||||
//column headers
|
||||
session_info += "<tr><th>Requotes</th><th>Hedges</th></tr>"
|
||||
|
||||
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>";
|
||||
}
|
||||
session_info += "<tr><td ><a href='?showrows=" + safe_quot_val.session_name + "&rowsof=quot" + "&r=" + num_rows + "'><b>Rows:</b> " + safe_quot_val.n_rows + "</a></td>";
|
||||
session_info += "<td><a href='?showrows=" + safe_hed_val.session_name + "&rowsof=hed" + "&r=" + num_rows + "'><b>Rows:</b> " + safe_hed_val.n_rows + "</a></td></tr>";
|
||||
}
|
||||
else {
|
||||
session_info += "<tr><td><a href='?showrows=" + safe_quot_val.session_name + "&rowsof=quot" + "'><b>Rows:</b> " + safe_quot_val.n_rows + "</a></td>";
|
||||
session_info += "<td><a href='?showrows=" + safe_hed_val.session_name + "&rowsof=hed" + "'><b>Rows:</b> " + safe_hed_val.n_rows + "</a></td></tr>";
|
||||
}
|
||||
|
||||
$(value.summaries).each(function(i,v){
|
||||
session_info += "<tr><td class='summary-block'>";
|
||||
$(safe_quot_val.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
|
||||
session_info += write_summary(safe_quot_val.session_name + "-quot-" + v.value, v);
|
||||
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 += "</td>";
|
||||
session_info += "<td class='summary-block'>";
|
||||
|
||||
$(safe_hed_val.summaries).each(function(i,v){
|
||||
if(v.value === "total") {
|
||||
session_info += write_summary(safe_hed_val.session_name + "-hed-" + v.value, v);
|
||||
return false
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
session_info += "</ul><hr class='clear'>";
|
||||
session_info += "</td></tr>";
|
||||
|
||||
let loop_val = 0;
|
||||
|
||||
if(safe_quot_val.summaries.length >= safe_hed_val.summaries.length ) {
|
||||
loop_val = safe_quot_val.summaries.length;
|
||||
}
|
||||
else {
|
||||
loop_val = safe_hed_val.summaries.length;
|
||||
}
|
||||
|
||||
/*
|
||||
for(let i = 0; i < loop_val; i++) {
|
||||
session_info += "<tr><td class='summary-block'>";
|
||||
if (safe_quot_val.summaries[i] !== undefined && safe_quot_val.summaries[i].value !== "total") {
|
||||
session_info += write_summary(safe_quot_val.session_name + "-quot-" + safe_quot_val.summaries[i].value, safe_quot_val.summaries[i]);
|
||||
}
|
||||
session_info += "</td><td class='summary-block'>";
|
||||
if (safe_hed_val.summaries[i] !== undefined && safe_hed_val.summaries[i].value !== "total") {
|
||||
session_info += write_summary(safe_hed_val.session_name + "-hed-" + safe_hed_val.summaries[i].value, safe_hed_val.summaries[i]);
|
||||
}
|
||||
session_info += "</td></tr>";
|
||||
}
|
||||
*/
|
||||
|
||||
session_info += "</table><hr class='clear'>";
|
||||
$("#output").append(session_info);
|
||||
|
||||
let all_data = {};
|
||||
let quot_val_data = {};
|
||||
|
||||
$(value.rows).each(function(i, row) {
|
||||
$(safe_quot_val.rows).each(function(i, row) {
|
||||
$.each(row, function(name, v) {
|
||||
if(all_data[name] === undefined){
|
||||
all_data[name] = [v];
|
||||
if(quot_val_data[name] === undefined){
|
||||
quot_val_data[name] = [v];
|
||||
}
|
||||
else {
|
||||
all_data[name].push(v);
|
||||
quot_val_data[name].push(v);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//console.log(all_data);
|
||||
let hed_val_data = {};
|
||||
|
||||
$(value.summaries).each(function(i,v){
|
||||
generate_histogram(value.session_name + "-" + v.value, all_data[v.value]);
|
||||
$(safe_hed_val.rows).each(function(i, row) {
|
||||
$.each(row, function(name, v) {
|
||||
if(hed_val_data[name] === undefined){
|
||||
hed_val_data[name] = [v];
|
||||
}
|
||||
else {
|
||||
hed_val_data[name].push(v);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if(safe_quot_val.summaries.length > 0){
|
||||
generate_histogram(safe_quot_val.session_name + "-quot-total", quot_val_data["total"]);
|
||||
}
|
||||
/*
|
||||
$(safe_quot_val.summaries).each(function(i,v){
|
||||
generate_histogram(safe_quot_val.session_name + "-quot-" + v.value, quot_val_data[v.value]);
|
||||
});
|
||||
*/
|
||||
if(safe_hed_val.summaries.length > 0){
|
||||
generate_histogram(safe_hed_val.session_name + "-hed-total", hed_val_data["total"]);
|
||||
}
|
||||
/*
|
||||
$(safe_hed_val.summaries).each(function(i,v){
|
||||
generate_histogram(safe_hed_val.session_name + "-hed-" + v.value, hed_val_data[v.value]);
|
||||
});
|
||||
*/
|
||||
}
|
||||
@@ -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/edge.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/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.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;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.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;os/os.cpp;os/tests/os_tests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/datetime.cpp;utils/download.cpp;utils/file_utils.cpp;utils/init_spark_lib.cpp;utils/is_unittest_environment.cpp;utils/stats.cpp;utils/thread_manager.cpp)
|
||||
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/edge.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/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/mercury_cfg.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/MDPeriodicDumper.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/MDSupplementarySource.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/DynamiLine truncated
|
||||
@@ -4,7 +4,10 @@
|
||||
#include "lib/config/protos/cme_reference_data.pb.h"
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/config/protos/system.pb.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
namespace bts{
|
||||
namespace admin{
|
||||
@@ -83,8 +86,7 @@ AdminServiceUtils::resolve_cme_connection(const bts::api::admin::AdminData& data
|
||||
const bts::api::admin::ExchangeConnection*
|
||||
AdminServiceUtils::resolve_sim_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::Security& sec){
|
||||
bts_assert(sec.exchange() == api::Venue::VENUE_SIM);
|
||||
const bts::api::Security& ){
|
||||
if(account.has_connections())
|
||||
for (const std::string& conn_name : account.connections().exchange_connection_names()){
|
||||
const bts::api::admin::ExchangeConnection* conn = find_connection(data, conn_name);
|
||||
@@ -100,24 +102,30 @@ AdminServiceUtils::resolve_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::Security& sec){
|
||||
const bts::api::admin::ExchangeConnection* rv = nullptr;
|
||||
switch(sec.exchange()){
|
||||
case api::Venue::VENUE_GLBX:
|
||||
rv = resolve_cme_connection(data, account, sec);
|
||||
break;
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_SIM:
|
||||
case api::Venue::VENUE_GLBX: {
|
||||
auto deployment_type =
|
||||
boost::to_lower_copy(config::get<config::DeploymentType>().type());
|
||||
rv = resolve_cme_connection(data, account, sec);
|
||||
if (rv == nullptr && (deployment_type == "dev" ||
|
||||
deployment_type == "demo"))
|
||||
rv = resolve_sim_connection(data, account, sec);
|
||||
break;
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::VENUE_ICE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_SIM:
|
||||
rv = resolve_sim_connection(data, account, sec);
|
||||
break;
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::VENUE_ICE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
rv = nullptr;
|
||||
break;
|
||||
rv = nullptr;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////
|
||||
// connection mutators /////////////////////
|
||||
////////////////////////////////////////////
|
||||
|
||||
@@ -204,7 +204,7 @@ message OrderState {
|
||||
CoverOrderState cover = 22;
|
||||
OffsetOrderState offset = 24;
|
||||
|
||||
DynamicOrderState dynamic = 1000;
|
||||
DynamicOrderState dynamic = 255; // do not use anything bigger than 255, or things will break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ message LimitOrderState {NativeOrderState native_state = 1;}
|
||||
message StopOrderState {NativeOrderState native_state = 1;}
|
||||
message StopLimitOrderState {NativeOrderState native_state = 1;}
|
||||
message IcebergOrderState {}
|
||||
message SpreaderOrderState {SpreaderChildKind child_kind = 1;}
|
||||
message SpreaderOrderState {}
|
||||
message TimeBoxOrderState {}
|
||||
message TickOrderState {}
|
||||
message LeanOrderState {}
|
||||
@@ -276,9 +276,7 @@ message TopOrderState {}
|
||||
message TriggerOrderState {}
|
||||
message CoverOrderState {}
|
||||
message OffsetOrderState {}
|
||||
message DynamicOrderState {
|
||||
map<string,string> state = 1;
|
||||
}
|
||||
message DynamicOrderState {}
|
||||
|
||||
enum OrderStatus {
|
||||
|
||||
@@ -403,12 +401,6 @@ enum ExecType
|
||||
EXEC_TYPE_TRADE_CANCEL = 72 ;
|
||||
}
|
||||
|
||||
enum SpreaderChildKind {
|
||||
SPREADER_CHILD_KIND_UNDEFINED = 0;
|
||||
SPREADER_CHILD_KIND_SPREADER_HEDGING = 1;
|
||||
SPREADER_CHILD_KIND_SPREADER_QUOTING = 2;
|
||||
}
|
||||
|
||||
enum OrderError
|
||||
{
|
||||
ORDER_ERROR_UNDEFINED = 0;
|
||||
|
||||
@@ -8,4 +8,5 @@ message OrdermanCfg {
|
||||
repeated string hosted_actor = 3;
|
||||
}
|
||||
repeated Executor executor = 1;
|
||||
optional uint32 default_iceberg_pause_secs = 2 [default = 0];
|
||||
}
|
||||
@@ -163,6 +163,7 @@ void AsyncReader::dispatch ()
|
||||
|
||||
for (auto &msg : framed_msgs) {
|
||||
msg.set_trace(trace);
|
||||
LOG(Latency, Diag, "perf_event AsyncReader.on_fix");
|
||||
tracepoint(bts_trace, trace_order, (char *)"AsyncReader.on_fix", 0,
|
||||
msg.get_seq_num(), 0);
|
||||
me->sink.in_msg_raw (msg);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#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>
|
||||
@@ -84,6 +83,7 @@ int SocketConnection::read(char *to_buffer, size_t read_count) {
|
||||
|
||||
bts_assert(_fd >= 0);
|
||||
auto result = ::read(_fd, to_buffer, read_count);
|
||||
LOG(Latency, Diag, "perf_event after_socket_read");
|
||||
if (_log && result > 0) {
|
||||
_in_log.write(to_buffer, result);
|
||||
_in_log.flush();
|
||||
@@ -123,18 +123,20 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size,
|
||||
trace.md_sn, s2s.microseconds());
|
||||
}
|
||||
|
||||
LOG(Latency, Diag, "perf_event before_socket_write");
|
||||
auto result = ::writev(_fd, iv, (int)vec_size);
|
||||
|
||||
if (trace.md.to_uint64()) {
|
||||
LOG(Latency, Info,
|
||||
"perf_event:tick_to_order s2s_us:{} fix_socket_r:{} md:{} "
|
||||
"perf_event:tick_to_order s2s_us:{} do_work_begin:{} 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:{} "
|
||||
"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(),
|
||||
s2s.microseconds(), trace_cpy.do_work_begin.to_uint64(),
|
||||
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(),
|
||||
@@ -145,19 +147,20 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size,
|
||||
|
||||
if (trace.fix_socket_r.to_uint64()) {
|
||||
LOG(Latency, Info,
|
||||
"perf_event:fill_to_order s2s_us:{} fix_socket_r:{} md:{} md_src:{} "
|
||||
"perf_event:fill_to_order s2s_us:{} do_work_begin:{} 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:{} "
|
||||
"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(),
|
||||
s2s.microseconds(), trace_cpy.do_work_begin.to_uint64(),
|
||||
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,
|
||||
trace.send_fix_buffer.to_uint64());
|
||||
trace_cpy.fix_socket_w.to_uint64(), trace_cpy.md_sn, trace_cpy.order_key,
|
||||
trace_cpy.send_fix_buffer.to_uint64());
|
||||
_perf_log.log(trace_cpy);
|
||||
}
|
||||
|
||||
|
||||
@@ -394,6 +394,7 @@ void CoreGateway::sync_reader_disconnected(EventData const &) {
|
||||
}
|
||||
|
||||
void CoreGateway::sync_in_msg_raw(EventData const &ev) {
|
||||
LOG(Latency, Diag, "perf_event sync_in_msg_raw");
|
||||
switch (me->state) {
|
||||
case State::OFF:
|
||||
case State::PAUSED:
|
||||
@@ -412,6 +413,7 @@ void CoreGateway::sync_in_msg_raw(EventData const &ev) {
|
||||
}
|
||||
|
||||
void CoreGateway::sync_in_msg_sequenced(EventData const &ev) {
|
||||
LOG(Latency, Diag, "perf_event sync_in_msg_sequenced");
|
||||
switch (me->state) {
|
||||
case State::OFF:
|
||||
case State::PAUSED:
|
||||
|
||||
@@ -83,8 +83,10 @@ private:
|
||||
|
||||
void dispatch (InMsgBuffer const&in_msg) override
|
||||
{
|
||||
LOG(Latency, Diag, "perf_event JetFIXGateway::before_parse");
|
||||
msg.read (in_msg.data (),in_msg.size ());
|
||||
msg.set_trace(in_msg.trace());
|
||||
LOG(Latency, Diag, "perf_event JetFIXGateway::after_parse");
|
||||
handler (msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -467,6 +467,7 @@ void Session::on_hb(InMsgBuffer const &msg) {
|
||||
}
|
||||
|
||||
void Session::on_app(InMsgBuffer const &msg) {
|
||||
LOG(Latency, Diag, "perf_event on_app");
|
||||
switch (me->state) {
|
||||
case State::WLOGON:
|
||||
terminate_session(
|
||||
|
||||
@@ -54,6 +54,15 @@ struct LoggerHandle {
|
||||
Logger *logger;
|
||||
};
|
||||
|
||||
struct CharPtrWrapper
|
||||
{const char* ptr;};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream&s,CharPtrWrapper const&ptr)
|
||||
{
|
||||
s << ptr.ptr;
|
||||
return s;
|
||||
}
|
||||
|
||||
extern thread_local LoggerHandle _thread_logger;
|
||||
void configure_logging(LoggingConfig const&cfg);
|
||||
void configure_logging(bts::config::Logging const&cfg,bts::config::ThreadGroupCfg const&);
|
||||
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
// Private default constructor allows friend classes to store this class in a concurrent_queue
|
||||
MDProducerHandle();
|
||||
friend class tbb::concurrent_queue < MDProducerHandle > ;
|
||||
friend class SecurityIDRecorderState;
|
||||
friend struct SecurityIDRecorderState;
|
||||
friend struct bts::co2::Work;
|
||||
|
||||
HotEntry& hdata() const {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lib/mercury/topics/ITopic.h"
|
||||
#include "lib/utils/Puid.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
@@ -30,13 +31,15 @@ struct Broker::LocalSubFilter {
|
||||
struct Broker::StreamRec {
|
||||
StreamRec(Broker &owner, IRemoteBroker &src, StreamID sid,
|
||||
TopicPtr const &topic)
|
||||
: owner(owner), local(false), src(&src), sid(sid), topic(topic),
|
||||
local_subs(), external_subs(), sub_id(),
|
||||
: owner(owner), local(false), src(&src), sid(sid),
|
||||
topic_str(intern_topic_str(topic)), topic(topic), local_subs(),
|
||||
external_subs(), sub_id(),
|
||||
synopsis_builder(topic->make_synopsis_builder()),
|
||||
topic_tag(topic->to_str()) {}
|
||||
|
||||
StreamRec(Broker &owner, StreamID sid, TopicPtr const &topic)
|
||||
: owner(owner), local(true), src(), sid(sid), topic(topic), local_subs(),
|
||||
: owner(owner), local(true), src(), sid(sid),
|
||||
topic_str(intern_topic_str(topic)), topic(topic), local_subs(),
|
||||
external_subs(), sub_id(),
|
||||
synopsis_builder(topic->make_synopsis_builder()),
|
||||
topic_tag(topic->to_str()) {}
|
||||
@@ -56,10 +59,21 @@ struct Broker::StreamRec {
|
||||
IRemoteBroker *neighbour;
|
||||
};
|
||||
|
||||
char *intern_topic_str(TopicPtr const &topic) {
|
||||
// this C string is used to make it possible to log topic names
|
||||
// assynchronously, without copying strings around. we leak
|
||||
// topic names, which isn't great, but performance oblige.
|
||||
auto ts = topic->to_str();
|
||||
auto result = new char[ts.size() + 1];
|
||||
memcpy(result, ts.c_str(), ts.size() + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
Broker &owner;
|
||||
const bool local;
|
||||
IRemoteBroker *const src;
|
||||
const StreamID sid;
|
||||
const char *topic_str;
|
||||
const TopicPtr topic;
|
||||
|
||||
std::vector<LocalSubRec> local_subs;
|
||||
@@ -337,15 +351,26 @@ void Broker::notify(BrokerID sender, StreamID sid, SubID ex_subid,
|
||||
Notification const &payload) {
|
||||
NoReenter nr(me->inside);
|
||||
#else
|
||||
void Broker::notify(BrokerID , StreamID sid, SubID ex_subid,
|
||||
void Broker::notify(BrokerID, StreamID sid, SubID ex_subid,
|
||||
Notification const &payload) {
|
||||
#endif
|
||||
auto &srec = me->streams[sid];
|
||||
bts_assert_d(srec);
|
||||
bts_assert_d((srec->is_local() && sender == id()) ||
|
||||
(!srec->is_local() && srec->src->id() == sender));
|
||||
if (srec->is_local() || srec->sub_id == ex_subid)
|
||||
|
||||
if (srec->is_local() || srec->sub_id == ex_subid) {
|
||||
|
||||
LOG(Latency, Diag, "Started handling event {} on broker {}",
|
||||
log::CharPtrWrapper{srec->topic_str}, me->my_id.value());
|
||||
auto start = Timer::now();
|
||||
srec->notify(payload);
|
||||
auto stop = Timer::now();
|
||||
|
||||
LOG(Latency, Diag, "Finished handling event {} on broker {}. Time: {}us",
|
||||
log::CharPtrWrapper{srec->topic_str}, me->my_id.value(),
|
||||
us_diff(stop, start));
|
||||
}
|
||||
}
|
||||
|
||||
void Broker::subscribe(BrokerID sender, SubID ex_subid, StreamID sid) {
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace mercury {
|
||||
|
||||
BrokerProxy::BrokerProxy(ILocalBroker &real_broker)
|
||||
: _real_broker(real_broker), _id(real_broker.id()),
|
||||
_cycles(0),
|
||||
_outgoing(config::get<config::Mercury>().queue_size()),
|
||||
_incoming(config::get<config::Mercury>().queue_size()),
|
||||
_action_pool() {}
|
||||
|
||||
@@ -59,7 +59,7 @@ class BrokerProxy : public ILocalBroker {
|
||||
void local_unsubscribe(LocalSubID) override;
|
||||
// ILocalBroker
|
||||
|
||||
void drain() { _outgoing.drain();}
|
||||
void drain() { _outgoing.drain(); }
|
||||
void schedule_action(std::function<void()> const &action);
|
||||
|
||||
// these are just for performance, we want to allow for
|
||||
@@ -80,6 +80,7 @@ class BrokerProxy : public ILocalBroker {
|
||||
}
|
||||
|
||||
void do_work() {
|
||||
_cycles++;
|
||||
_outgoing.consume_all([this](BrokerMsg *m) {
|
||||
switch (m->msg_type) {
|
||||
case BrokerMsgType::ADD_NEIGHBOUR:
|
||||
@@ -101,6 +102,8 @@ class BrokerProxy : public ILocalBroker {
|
||||
_real_broker.unsubscribe(m->broker_id, m->sub_id, m->stream_id);
|
||||
break;
|
||||
case BrokerMsgType::NOTIFY:
|
||||
LOG(Latency, Diag, "Notify broker {}. Cycles: {}", _id.value(),
|
||||
_cycles);
|
||||
_real_broker.notify(m->broker_id, m->stream_id, m->sub_id,
|
||||
m->notification);
|
||||
break;
|
||||
@@ -111,9 +114,16 @@ class BrokerProxy : public ILocalBroker {
|
||||
case BrokerMsgType::LOCAL_UNSUBSCRIBE:
|
||||
_real_broker.local_unsubscribe(m->local_sub_id);
|
||||
break;
|
||||
case BrokerMsgType::EXECUTE_ACTION:
|
||||
case BrokerMsgType::EXECUTE_ACTION: {
|
||||
auto start = Timer::now();
|
||||
LOG(Latency, Diag, "Executing lambda on broker {}", _id.value());
|
||||
m->action();
|
||||
auto stop = Timer::now();
|
||||
LOG(Latency, Diag,
|
||||
"Finished executing lambda on broker {}. Took: {}us",
|
||||
_id.value(), us_diff(stop, start));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
bts_assert(false);
|
||||
break;
|
||||
@@ -126,6 +136,7 @@ class BrokerProxy : public ILocalBroker {
|
||||
private:
|
||||
ILocalBroker &_real_broker;
|
||||
const BrokerID _id;
|
||||
uint64_t _cycles;
|
||||
utils::GrowableSPSCQueue<BrokerMsg *> _outgoing;
|
||||
utils::GrowableSPSCQueue<BrokerMsg *> _incoming;
|
||||
boost::object_pool<BrokerMsg> _action_pool;
|
||||
|
||||
@@ -14,7 +14,7 @@ using TopicFilter = std::function<bool(const ITopic&)> ;
|
||||
|
||||
using StreamID = utils::ValueWrapper<struct StreamIDTag,uint32_t>;
|
||||
using SubID = utils::ValueWrapper<struct SubIDTag,uint32_t>;
|
||||
using Notification = FatWrapper<80>;
|
||||
using Notification = FatWrapper<112>;
|
||||
using LocalSubID = utils::ValueWrapper<struct LocalSubIDTag,uint32_t>;
|
||||
using BrokerID = utils::ValueWrapper<struct BrokerIDTag,uint32_t>;
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
#include "ExecutionGateway.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/utils/TimeStamp.h"
|
||||
#include "lib/jetfix/codec/MessageDefinitions.h"
|
||||
#include "lib/jetfix/common/OutFIX.h"
|
||||
#include "lib/jetfix/gateway/JetFIXGateway.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/events/CancelRejectEvent.h"
|
||||
#include "lib/orderman/events/GatewayStatusChangeEvent.h"
|
||||
#include "lib/orderman/events/NewExecutionReportEvent.h"
|
||||
#include "lib/orderman/events/NewSecuritiesEvent.h"
|
||||
#include "lib/orderman/orderman_utils/fix_order_codec.h"
|
||||
#include "lib/tracing/bts_trace.h"
|
||||
#include "lib/jetfix/common/OutFIX.h"
|
||||
#include "lib/utils/TimeStamp.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
|
||||
#include <boost/pool/object_pool.hpp>
|
||||
|
||||
@@ -18,17 +19,16 @@ namespace orderman {
|
||||
|
||||
using namespace jetfix;
|
||||
|
||||
|
||||
using JFGw =
|
||||
JetFIXGateway<fix::ExecutionReportMsg, fix::BusinessMessageRejectMsg,
|
||||
fix::RejectMsg, fix::CancelRejectMsg>;
|
||||
|
||||
struct ExecutionGateway::PImpl {
|
||||
PImpl(config::JetFIX::Connection const &cfg,PerfTraceLog &log)
|
||||
: gw(cfg,log), exe_report_pool(), state(State::WAITING_FOR_SECURITIES),
|
||||
PImpl(config::JetFIX::Connection const &cfg, PerfTraceLog &log)
|
||||
: gw(cfg, log), exe_report_pool(), state(State::WAITING_FOR_SECURITIES),
|
||||
securities(), securities_by_descriptor(), exe_report_stream(),
|
||||
gw_status_change_stream(), cancel_reject_stream(), gw_name(cfg.name()),
|
||||
cfg(cfg) {}
|
||||
cfg(cfg) {}
|
||||
|
||||
JFGw gw;
|
||||
boost::object_pool<ExecutionReport> exe_report_pool;
|
||||
@@ -43,8 +43,9 @@ struct ExecutionGateway::PImpl {
|
||||
config::JetFIX::Connection cfg;
|
||||
};
|
||||
|
||||
ExecutionGateway::ExecutionGateway(config::JetFIX::Connection const &cfg,PerfTraceLog &log)
|
||||
: me(new PImpl(cfg,log)) {}
|
||||
ExecutionGateway::ExecutionGateway(config::JetFIX::Connection const &cfg,
|
||||
PerfTraceLog &log)
|
||||
: me(new PImpl(cfg, log)) {}
|
||||
ExecutionGateway::~ExecutionGateway() {}
|
||||
|
||||
void ExecutionGateway::init() {
|
||||
@@ -77,6 +78,7 @@ void ExecutionGateway::on_securities(
|
||||
|
||||
// subscribe to gateway events
|
||||
me->gw.on<fix::ExecutionReportMsg>() = [this](auto const &msg) {
|
||||
LOG(Latency, Diag, "perf_event ExecutionGateway::after_parse");
|
||||
this->on_exe_report(msg);
|
||||
};
|
||||
me->gw.on<fix::CancelRejectMsg>() = [this](auto const &msg) {
|
||||
@@ -114,10 +116,13 @@ void ExecutionGateway::on_securities(
|
||||
|
||||
void ExecutionGateway::on_exe_report(
|
||||
const jetfix::fix::ExecutionReportMsg &msg) {
|
||||
auto start = Timer::now();
|
||||
OrderKey ok;
|
||||
SecurityKey sk;
|
||||
decode_clorid(msg.get<fix::ClOrdID>(), &ok, &sk);
|
||||
|
||||
LOG(Latency, Info, "Started handling of execution report for order {}",
|
||||
ok.value());
|
||||
auto sec = me->securities[sk.value()];
|
||||
|
||||
if (!sec)
|
||||
@@ -190,7 +195,7 @@ void ExecutionGateway::on_exe_report(
|
||||
data->exec_type = api::orderman::ExecType(msg.get<fix::ExecType>());
|
||||
data->msg_seq_num = msg.get<fix::MsgSeqNum>();
|
||||
tracepoint(bts_trace, trace_order,
|
||||
(char *)"ExecutionGateway.on_exe_report", 0, 0,0);
|
||||
(char *)"ExecutionGateway.on_exe_report", 0, 0, 0);
|
||||
|
||||
// copy data from fix msg to our structure
|
||||
if (msg.has<fix::Account>())
|
||||
@@ -239,14 +244,14 @@ void ExecutionGateway::on_exe_report(
|
||||
data->last_shares = msg.has<fix::LastShares>()
|
||||
? Quantity(msg.get<fix::LastShares>())
|
||||
: Quantity(0);
|
||||
auto last_px_sec = data->leg_security? data->leg_security:sec;
|
||||
auto last_px_sec = data->leg_security ? data->leg_security : sec;
|
||||
data->last_price = msg.has<fix::LastPx>()
|
||||
? securities::decode_exchange_price(
|
||||
*last_px_sec, Price(msg.get<fix::LastPx>()))
|
||||
: Price(0);
|
||||
data->avg_price = msg.has<fix::AvgPx>()
|
||||
? securities::decode_exchange_price(
|
||||
*last_px_sec, Price(msg.get<fix::AvgPx>()))
|
||||
*last_px_sec, Price(msg.get<fix::AvgPx>()))
|
||||
: Price(0);
|
||||
if (msg.has<fix::ExecID>())
|
||||
str_to(msg.get<fix::ExecID>(), &data->exchange_fill_id);
|
||||
@@ -255,7 +260,10 @@ void ExecutionGateway::on_exe_report(
|
||||
data->msg = text_msg;
|
||||
auto trace = msg.trace();
|
||||
trace.exe_gw = utils::TimeStamp::now();
|
||||
publish(me->exe_report_stream, data,trace);
|
||||
publish(me->exe_report_stream, data, trace);
|
||||
LOG(Latency, Info,
|
||||
"Finished handling of execution report for order {}. {}ns",
|
||||
ok.value(), ns_diff(Timer::now(), start));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,11 +314,13 @@ void ExecutionGateway::on_outgoing_fix(
|
||||
mercury::Update<OutFIXMsgEvent> const &msg) {
|
||||
if (msg.events)
|
||||
for (auto const &ev : *(msg.events)) {
|
||||
LOG(Latency, Info, "on_outgoing_fix sn: {} ok: {}", ev.trace.md_sn,
|
||||
ev.trace.order_key);
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_outgoing_fix", 0,
|
||||
ev.trace.md_sn, 0);
|
||||
auto trace = ev.trace;
|
||||
trace.exe_gw = utils::TimeStamp::now();
|
||||
me->gw.send(trace,ev.msg);
|
||||
me->gw.send(trace, ev.msg);
|
||||
me->gw.dispatch_events();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,9 +76,11 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
|
||||
private:
|
||||
void on_poll() override {
|
||||
Book book;
|
||||
PerfTrace trace;
|
||||
|
||||
auto start = Timer::now();
|
||||
PerfTrace trace;
|
||||
auto start = utils::TimeStamp::now();
|
||||
trace.do_work_begin = start;
|
||||
|
||||
for (auto &h : _handles) {
|
||||
auto &handle = h.handle;
|
||||
if (handle.get_book(h.last, std::tuple_size<BookSide>(),
|
||||
@@ -93,8 +95,8 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
|
||||
publish(_book_update, book, trace);
|
||||
}
|
||||
}
|
||||
auto stop = Timer::now();
|
||||
_loop_timer->observe(ns_diff(stop, start));
|
||||
auto stop = utils::TimeStamp::now();
|
||||
_loop_timer->observe((start-stop).nanoseconds());
|
||||
}
|
||||
|
||||
struct HandleRecord {
|
||||
|
||||
@@ -29,7 +29,7 @@ struct OrderStore::PImpl {
|
||||
|
||||
State state;
|
||||
const GatewayName gw_name;
|
||||
std::unordered_map<OrderKey, google::protobuf::Timestamp> known_orders;
|
||||
std::unordered_map<OrderKey, api::orderman::OrderState> known_orders;
|
||||
std::unique_ptr<persistence::IStore> store;
|
||||
mercury::Stream<StoredOrderEvent> order_stream;
|
||||
mercury::Actor::SubHandle stored_sec_sub;
|
||||
@@ -93,7 +93,7 @@ void OrderStore::init() {
|
||||
} else {
|
||||
if (!_order_cutoff(rec))
|
||||
stored_batch.emplace_back(rec);
|
||||
me->known_orders[ok] = rec.state().created();
|
||||
me->known_orders[ok] = rec.state();
|
||||
}
|
||||
} else
|
||||
LOG(OrderMan, Error,
|
||||
@@ -122,19 +122,22 @@ void OrderStore::on_order_state_update(
|
||||
order.set_key(ev.key.value());
|
||||
order.set_parent_key(ev.parent_key.value());
|
||||
*order.mutable_def() = *ev.definition;
|
||||
*order.mutable_state() = ev.state;
|
||||
*order.mutable_state() = ev.rebuild_state();
|
||||
*order.mutable_state()->mutable_last_change() = utils::pb::pb_now();
|
||||
|
||||
auto it = me->known_orders.find(ev.key);
|
||||
if (it == me->known_orders.end()) {
|
||||
// new order
|
||||
auto now = utils::pb::pb_now();
|
||||
me->known_orders[ev.key] = now;
|
||||
*order.mutable_state()->mutable_created() = now;
|
||||
me->known_orders[ev.key] = order.state();
|
||||
me->store->insert(orders_ns, std::to_string(order.key()),
|
||||
utils::pb::to_string(order));
|
||||
} else {
|
||||
*order.mutable_state()->mutable_created() = it->second;
|
||||
// existing order
|
||||
auto &existing_state = it->second;
|
||||
existing_state.MergeFrom(order.state());
|
||||
*order.mutable_state() = existing_state;
|
||||
me->store->update(orders_ns, std::to_string(order.key()),
|
||||
utils::pb::to_string(order));
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ ServiceBridge::create_order(api::orderman::Create const &c) {
|
||||
me->order_factory.create(null_order_key(), c.new_order());
|
||||
me->known_orders.insert(order.key());
|
||||
publish(me->activate_order_pub, order, Price(c.price()),
|
||||
Quantity(c.quantity()));
|
||||
Quantity(c.quantity()), PerfTrace());
|
||||
r.set_order_key(order.key().value());
|
||||
r.set_error_code(api::orderman::ORDER_ERROR_OK);
|
||||
} else
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "lib/orderman/order_factory/OrderFactory.h"
|
||||
#include "lib/orderman/orders/Order.h"
|
||||
#include "lib/orderman/securities/ISecurityDB.h"
|
||||
#include "lib/utils/inplace_function.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace bts {
|
||||
@@ -40,18 +42,24 @@ struct OrderManager::OrderInfo {
|
||||
};
|
||||
|
||||
struct OrderManager::PImpl {
|
||||
PImpl(Actor &owner, DynamicOrderRegistry const &b)
|
||||
: state(State::WAIT_ADMIN), services_data(owner, b) {}
|
||||
PImpl(OrderManager &owner, DynamicOrderRegistry const &b)
|
||||
: state(State::WAIT_ADMIN), services_data(owner, b) {
|
||||
pending_order_events.reserve(1000);
|
||||
}
|
||||
|
||||
State state;
|
||||
std::unordered_map<OrderKey, OrderInfo> orders;
|
||||
|
||||
std::vector<PendingOrderEvent> pending_order_events;
|
||||
|
||||
mercury::Actor::SubHandle stored_order_sub;
|
||||
mercury::Actor::SubHandle stored_fills_sub;
|
||||
OrderServicesData services_data;
|
||||
mercury::Stream<OrderManagerReadyEvent> pub_ready;
|
||||
};
|
||||
|
||||
OrderManager::OrderManager(DynamicOrderRegistry const&b) : me(new PImpl(*this,b)) {}
|
||||
OrderManager::OrderManager(DynamicOrderRegistry const &b)
|
||||
: me(new PImpl(*this, b)) {}
|
||||
OrderManager::~OrderManager() {}
|
||||
|
||||
void OrderManager::init() {
|
||||
@@ -193,66 +201,82 @@ void OrderManager::on_execution_report(
|
||||
}
|
||||
}
|
||||
|
||||
void OrderManager::queue_order_event(PendingOrderEvent const &event_handler) {
|
||||
me->pending_order_events.push_back(event_handler);
|
||||
}
|
||||
|
||||
void OrderManager::on_activate_order(
|
||||
const mercury::Update<ActivateOrderEvent> &m) {
|
||||
if (m.events)
|
||||
for (auto const &ev : *m.events) {
|
||||
auto order = ev.order;
|
||||
auto k = order->key();
|
||||
bts_assert(me->orders.find(k) == me->orders.end());
|
||||
OrderInfo oi{*order, me->services_data};
|
||||
auto serv_ptr = oi.order_services.get();
|
||||
me->orders[k] = std::move(oi);
|
||||
order->on_activate(ev.price, ev.quantity, *serv_ptr, ev.trace);
|
||||
}
|
||||
for (auto const &ev : *m.events)
|
||||
queue_order_event(ev);
|
||||
}
|
||||
|
||||
void OrderManager::handle_order_event(ActivateOrderEvent const &ev) {
|
||||
auto order = ev.order;
|
||||
auto k = order->key();
|
||||
bts_assert(me->orders.find(k) == me->orders.end());
|
||||
OrderInfo oi{*order, me->services_data};
|
||||
auto serv_ptr = oi.order_services.get();
|
||||
me->orders[k] = std::move(oi);
|
||||
order->on_activate(ev.price, ev.quantity, *serv_ptr, ev.trace);
|
||||
}
|
||||
|
||||
void OrderManager::on_update_order(const mercury::Update<UpdateOrderEvent> &m) {
|
||||
if (m.events)
|
||||
for (auto const &ev : *m.events) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_update(ev.price, ev.quantity, ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received an update request for an unknown order {}. "
|
||||
"This should not happen and likely indicates a serious bug. ",
|
||||
ev.key().value());
|
||||
}
|
||||
}
|
||||
for (auto const &ev : *m.events)
|
||||
queue_order_event(ev);
|
||||
}
|
||||
|
||||
void OrderManager::handle_order_event(UpdateOrderEvent const &ev) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_update(ev.price, ev.quantity, ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received an update request for an unknown order {}. "
|
||||
"This should not happen and likely indicates a serious bug. ",
|
||||
ev.key().value());
|
||||
}
|
||||
}
|
||||
|
||||
void OrderManager::on_cancel_order(const mercury::Update<CancelOrderEvent> &m) {
|
||||
if (m.events)
|
||||
for (auto const &ev : *m.events) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_cancel(ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received a cancel request for an unknown order {}. "
|
||||
"This should not happen and likely indicates a serious bug. ",
|
||||
ev.key().value());
|
||||
}
|
||||
}
|
||||
for (auto const &ev : *m.events)
|
||||
queue_order_event(ev);
|
||||
}
|
||||
|
||||
void OrderManager::handle_order_event(CancelOrderEvent const &ev) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_cancel(ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received a cancel request for an unknown order {}. "
|
||||
"This should not happen and likely indicates a serious bug. ",
|
||||
ev.key().value());
|
||||
}
|
||||
}
|
||||
|
||||
void OrderManager::on_crack_order(const mercury::Update<CrackOrderEvent> &m) {
|
||||
if (m.events)
|
||||
for (auto const &ev : *m.events) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_crack(ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received a crack request for an unknown order {}. "
|
||||
"This should not happen and likely indicates a serious bug. ",
|
||||
ev.key().value());
|
||||
}
|
||||
}
|
||||
for (auto const &ev : *m.events)
|
||||
queue_order_event(ev);
|
||||
}
|
||||
|
||||
void OrderManager::handle_order_event(CrackOrderEvent const &ev) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_crack(ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received a crack request for an unknown order {}. "
|
||||
"This should not happen and likely indicates a serious bug. ",
|
||||
ev.key().value());
|
||||
}
|
||||
}
|
||||
|
||||
void OrderManager::on_gateway_state(
|
||||
@@ -277,6 +301,13 @@ void OrderManager::on_timer(const mercury::Update<mercury::TimerEvent> &m) {
|
||||
if (m.events)
|
||||
for (auto ev : *m.events)
|
||||
me->services_data.last_timer_ev = ev;
|
||||
|
||||
for (auto &osd : me->services_data.sessions) {
|
||||
if (fix_buffer_pool_size > osd->free_buffers.size()) {
|
||||
auto need = fix_buffer_pool_size - osd->free_buffers.size();
|
||||
publish(me->services_data.create_fix_req_pub, need, osd->cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<jetfix::OutFIXPtr> &
|
||||
@@ -339,6 +370,7 @@ void OrderManager::init_order_services() {
|
||||
|
||||
// FIX output
|
||||
s->out_fix_pub = make_stream<OutFIXMsgEvent>(gw_name);
|
||||
reload_fix_buffer(*s);
|
||||
}
|
||||
|
||||
// Order creation and maintenance
|
||||
@@ -360,7 +392,6 @@ void OrderManager::init_order_services() {
|
||||
[this](auto const &ev) { this->on_new_fix_buffer(ev); });
|
||||
|
||||
// Outputs
|
||||
me->services_data.order_state_pub = make_stream<OrderStateUpdateEvent>();
|
||||
me->services_data.activate_order_pub = make_stream<ActivateOrderEvent>();
|
||||
me->services_data.update_order_pub = make_stream<UpdateOrderEvent>();
|
||||
me->services_data.cancel_order_pub = make_stream<CancelOrderEvent>();
|
||||
@@ -371,7 +402,8 @@ void OrderManager::init_order_services() {
|
||||
me->services_data.create_fix_req_pub =
|
||||
make_stream<CreateFIXBufferRequestEvent>();
|
||||
me->services_data.md_request_pub = make_stream<MDRequestEvent>();
|
||||
me->services_data.settlement_request_pub= make_stream<SettlementRequestEvent>();
|
||||
me->services_data.settlement_request_pub =
|
||||
make_stream<SettlementRequestEvent>();
|
||||
me->services_data.report_order_state_pub =
|
||||
make_stream<OrderStateUpdateEvent>();
|
||||
me->pub_ready = make_stream<OrderManagerReadyEvent>();
|
||||
@@ -390,12 +422,43 @@ void OrderManager::init_order_services() {
|
||||
me->services_data.md_subs =
|
||||
std::make_unique<ContentSubscription<BookUpdateEvent>>(*this, on_md_sub);
|
||||
me->services_data.settlement_subs =
|
||||
std::make_unique<ContentSubscription<SettlementUpdateEvent>>(*this,on_settlement_sub);
|
||||
std::make_unique<ContentSubscription<SettlementUpdateEvent>>(
|
||||
*this, on_settlement_sub);
|
||||
me->services_data.time_subs =
|
||||
std::make_unique<ContentSubscription<TimerEvent, NoKey>>(*this);
|
||||
me->services_data.order_creation_subs =
|
||||
std::make_unique<ContentSubscription<CreateOrderReplyEvent>>(*this);
|
||||
}
|
||||
|
||||
void OrderManager::on_poll() {
|
||||
if (me->state == State::READY) {
|
||||
for (size_t i = 0; i < me->pending_order_events.size(); i++)
|
||||
me->pending_order_events[i](*this);
|
||||
me->pending_order_events.clear();
|
||||
for (auto &osd : me->services_data.sessions) {
|
||||
auto &fix_stream = osd->current_buffer->first_stream();
|
||||
if (fix_stream.n_msgs()) {
|
||||
fix_stream.close();
|
||||
publish(osd->out_fix_pub, osd->current_buffer, osd->current_traces);
|
||||
osd->current_traces.clear();
|
||||
reload_fix_buffer(*osd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OrderManager::reload_fix_buffer(SessionServicesData &dt) {
|
||||
if (dt.free_buffers.size()) {
|
||||
dt.current_buffer = dt.free_buffers.back();
|
||||
dt.free_buffers.pop_back();
|
||||
} else {
|
||||
LOG(OrderMan, Warn,
|
||||
"Ran out of fix buffers in {}. Will allocate directly. "
|
||||
"This will have an impact on performance",
|
||||
dt.cfg.name());
|
||||
dt.current_buffer = std::make_shared<jetfix::OutFIX>(dt.cfg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -3,6 +3,13 @@
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/jetfix/common/OutFIXPtr.h"
|
||||
#include "lib/mercury/actors/Actor.h"
|
||||
#include "lib/mercury/actors/IPollableActor.h"
|
||||
#include "lib/utils/inplace_function.h"
|
||||
#include "lib/orderman/events/ActivateOrderEvent.h"
|
||||
#include "lib/orderman/events/UpdateOrderEvent.h"
|
||||
#include "lib/orderman/events/CancelOrderEvent.h"
|
||||
#include "lib/orderman/events/CrackOrderEvent.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
// fwd
|
||||
@@ -22,6 +29,7 @@ class StoredFillEvent;
|
||||
class CreateFIXBufferReplyEvent;
|
||||
class GatewayStatusChangeEvent;
|
||||
class NewAdminDataEvent;
|
||||
struct SessionServicesData;
|
||||
class DynamicOrderRegistry;
|
||||
}
|
||||
}
|
||||
@@ -50,13 +58,16 @@ namespace orderman {
|
||||
// - crack
|
||||
// - update
|
||||
|
||||
class OrderManager : public mercury::Actor {
|
||||
class OrderManager : public mercury::Actor,
|
||||
public mercury::IPollableActor
|
||||
{
|
||||
public:
|
||||
OrderManager(DynamicOrderRegistry const&dyn_order_builder);
|
||||
~OrderManager();
|
||||
void init() override;
|
||||
|
||||
private:
|
||||
friend class OrderServices;
|
||||
void on_securities(const mercury::Update<NewSecuritiesEvent> &);
|
||||
void on_fill_recovery(const mercury::Update<StoredFillEvent> &);
|
||||
void on_order_recovery(const mercury::Update<StoredOrderEvent> &);
|
||||
@@ -71,6 +82,26 @@ class OrderManager : public mercury::Actor {
|
||||
void on_admin_data(const mercury::Update<NewAdminDataEvent> &);
|
||||
|
||||
void init_order_services();
|
||||
|
||||
void on_poll() override;
|
||||
|
||||
using PendingOrderEvent = stdext::inplace_function<
|
||||
void(OrderManager &),
|
||||
std::max({128ul, sizeof(ActivateOrderEvent), sizeof(UpdateOrderEvent),
|
||||
sizeof(CancelOrderEvent), sizeof(CrackOrderEvent)})>;
|
||||
|
||||
template <class EV>
|
||||
void queue_order_event(EV const&ev) {
|
||||
queue_order_event(PendingOrderEvent( [ev] (auto &om) {
|
||||
om.handle_order_event(ev);
|
||||
}));
|
||||
}
|
||||
void queue_order_event(PendingOrderEvent const&ev);
|
||||
void handle_order_event(ActivateOrderEvent const &);
|
||||
void handle_order_event(UpdateOrderEvent const &);
|
||||
void handle_order_event(CancelOrderEvent const &);
|
||||
void handle_order_event(CrackOrderEvent const&);
|
||||
void reload_fix_buffer(SessionServicesData &dt);
|
||||
|
||||
std::vector<jetfix::OutFIXPtr> &free_buffers(std::string const&);
|
||||
enum class State;
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/jetfix/common/OutFIX.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/actors/order_manager/OrderManager.h"
|
||||
#include "lib/orderman/actors/order_manager/OrderServicesData.h"
|
||||
#include "lib/orderman/governor/Governor.h"
|
||||
#include "lib/orderman/orderman_utils/EventStream.h"
|
||||
#include "lib/orderman/orders/Order.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
@@ -15,69 +17,44 @@ namespace orderman {
|
||||
class SessionServices {
|
||||
|
||||
public:
|
||||
SessionServices(SessionServicesData &session_data, OrderServicesData &data)
|
||||
SessionServices(SessionServicesData &session_data)
|
||||
: exe_reports(*session_data.exe_report_subs),
|
||||
cancel_rejects(*session_data.cancel_reject_subs),
|
||||
gateway_status(*session_data.gateway_status_subs),
|
||||
_session_data(&session_data), _data(&data) {}
|
||||
_session_data(&session_data) {}
|
||||
|
||||
std::string const &session_name() const { return _session_data->session; }
|
||||
|
||||
config::JetFIX::Connection const &session_cfg() const {
|
||||
return _session_data->cfg;
|
||||
}
|
||||
|
||||
jetfix::OutFIXPtr get_fix_buffer() {
|
||||
jetfix::OutFIXPtr result;
|
||||
if (_session_data->free_buffers.size()) {
|
||||
result = _session_data->free_buffers.back();
|
||||
_session_data->free_buffers.pop_back();
|
||||
} else {
|
||||
LOG(OrderMan, Warn,
|
||||
"Ran out of fix buffers in {}. Will allocate directly. "
|
||||
"This will have an impact on performance",
|
||||
_session_data->cfg.name());
|
||||
result = std::make_shared<jetfix::OutFIX>(_session_data->cfg);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void refill_fix_buffer_pool()
|
||||
{
|
||||
if (fix_buffer_pool_size > _session_data->free_buffers.size()) {
|
||||
auto need = fix_buffer_pool_size - _session_data->free_buffers.size();
|
||||
_data->owner.publish(_data->create_fix_req_pub, need,
|
||||
_session_data->cfg);
|
||||
}
|
||||
void queue_fix(jetfix::MessageTypes mt, jetfix::FIXFragment const&f,PerfTrace const&trace) {
|
||||
auto &stream = _session_data->current_buffer->first_stream();
|
||||
stream.new_msg(mt).append(f);
|
||||
_session_data->current_traces.push_back(trace);
|
||||
}
|
||||
|
||||
bool is_gateway_connected() const { return _session_data->gw_connected; }
|
||||
|
||||
void send_fix_buffer(jetfix::OutFIXPtr const &fix, PerfTrace &trace) {
|
||||
trace.send_fix_buffer = utils::TimeStamp::now();
|
||||
_data->owner.publish(_session_data->out_fix_pub, trace, fix);
|
||||
}
|
||||
Governor &governor() { return _session_data->governor; }
|
||||
|
||||
EventStream<NewExecutionReportEvent> exe_reports;
|
||||
EventStream<CancelRejectEvent> cancel_rejects;
|
||||
EventStream<GatewayStatusChangeEvent, mercury::NoKey> gateway_status;
|
||||
Governor &governor() { return _session_data->governor; }
|
||||
|
||||
private:
|
||||
SessionServicesData *_session_data;
|
||||
OrderServicesData *_data;
|
||||
};
|
||||
|
||||
class OrderServices {
|
||||
public:
|
||||
OrderServices(Order &owner, OrderServicesData &data)
|
||||
: book_updates(*data.md_subs),
|
||||
settlement_updates(*data.settlement_subs),
|
||||
child_updates(*data.child_order_subs),
|
||||
time_change(*data.time_subs),
|
||||
: book_updates(*data.md_subs), settlement_updates(*data.settlement_subs),
|
||||
child_updates(*data.child_order_subs), time_change(*data.time_subs),
|
||||
order_creations(*data.order_creation_subs), _owner(owner), _data(data),
|
||||
_sessions() {
|
||||
for (auto &sd : data.sessions)
|
||||
_sessions.push_back(std::make_unique<SessionServices>(*sd, data));
|
||||
_sessions.push_back(std::make_unique<SessionServices>(*sd));
|
||||
}
|
||||
|
||||
EventStream<BookUpdateEvent> book_updates;
|
||||
@@ -119,7 +96,7 @@ class OrderServices {
|
||||
bts_assert(false);
|
||||
}
|
||||
|
||||
void schedule_action(std::function<void()> const&action) {
|
||||
void schedule_action(std::function<void()> const &action) {
|
||||
_data.owner.schedule_action(action);
|
||||
}
|
||||
|
||||
@@ -136,29 +113,33 @@ class OrderServices {
|
||||
}
|
||||
|
||||
friend class ChildOrder;
|
||||
|
||||
template <class OP> void queue_order_op(const OP &op) {
|
||||
_data.owner.queue_order_event(op);
|
||||
}
|
||||
void send_activate(Order &o, Price p, Quantity q, PerfTrace const &trace) {
|
||||
_data.owner.publish(_data.activate_order_pub, o, p, q, trace);
|
||||
queue_order_op(ActivateOrderEvent{o, p, q, trace});
|
||||
}
|
||||
void send_activate(Order &o, Price p, Quantity q) {
|
||||
_data.owner.publish(_data.activate_order_pub, o, p, q, PerfTrace());
|
||||
queue_order_op(ActivateOrderEvent{o, p, q, PerfTrace()});
|
||||
}
|
||||
void send_update(OrderKey k, Price p, Quantity q, PerfTrace const &trace) {
|
||||
_data.owner.publish(_data.update_order_pub, k, p, q, trace);
|
||||
queue_order_op(UpdateOrderEvent{k, p, q, trace});
|
||||
}
|
||||
void send_update(OrderKey k, Price p, Quantity q) {
|
||||
_data.owner.publish(_data.update_order_pub, k, p, q, PerfTrace());
|
||||
queue_order_op(UpdateOrderEvent{k, p, q, PerfTrace()});
|
||||
}
|
||||
void send_crack(OrderKey k, PerfTrace const &trace) {
|
||||
_data.owner.publish(_data.crack_order_pub, k, trace);
|
||||
queue_order_op(CrackOrderEvent{k, trace});
|
||||
}
|
||||
void send_crack(OrderKey k) {
|
||||
_data.owner.publish(_data.crack_order_pub, k, PerfTrace());
|
||||
queue_order_op(CrackOrderEvent{k, PerfTrace()});
|
||||
}
|
||||
void send_cancel(OrderKey k, PerfTrace const &trace) {
|
||||
_data.owner.publish(_data.cancel_order_pub, k, trace);
|
||||
queue_order_op(CancelOrderEvent{k, trace});
|
||||
}
|
||||
void send_cancel(OrderKey k) {
|
||||
_data.owner.publish(_data.cancel_order_pub, k, PerfTrace());
|
||||
queue_order_op(CancelOrderEvent{k, PerfTrace()});
|
||||
}
|
||||
|
||||
Order &_owner;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
OrderServicesData::OrderServicesData(mercury::Actor &owner,DynamicOrderRegistry const&b)
|
||||
OrderServicesData::OrderServicesData(OrderManager &owner,DynamicOrderRegistry const&b)
|
||||
: owner(owner), order_router(), order_factory(sec_db, order_router,b),
|
||||
last_timer_ev(
|
||||
Timer::now(),
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
class OrderManager;
|
||||
|
||||
struct ParentKey {
|
||||
OrderKey operator()(const OrderStateUpdateEvent &ev) {
|
||||
@@ -49,7 +50,9 @@ struct SessionServicesData {
|
||||
cfg(cfg),
|
||||
governor(cfg.max_order_msgs_per_window(),
|
||||
cfg.window_duration_msecs())
|
||||
{}
|
||||
{
|
||||
current_traces.reserve(1000);
|
||||
}
|
||||
|
||||
std::string session;
|
||||
std::vector<jetfix::OutFIXPtr> free_buffers;
|
||||
@@ -65,13 +68,14 @@ struct SessionServicesData {
|
||||
gateway_status_subs;
|
||||
|
||||
Governor governor;
|
||||
jetfix::OutFIXPtr current_buffer;
|
||||
std::vector<PerfTrace> current_traces;
|
||||
};
|
||||
|
||||
class OrderServicesData {
|
||||
public:
|
||||
OrderServicesData(mercury::Actor &owner,DynamicOrderRegistry const&b);
|
||||
|
||||
mercury::Actor &owner;
|
||||
public:
|
||||
OrderServicesData(OrderManager &owner,DynamicOrderRegistry const&b);
|
||||
OrderManager &owner;
|
||||
securities::MapSecurityDB sec_db;
|
||||
OrderRouter order_router;
|
||||
Limiter limiter;
|
||||
@@ -89,7 +93,6 @@ class OrderServicesData {
|
||||
std::unique_ptr<mercury::ContentSubscription<CreateOrderReplyEvent>>
|
||||
order_creation_subs;
|
||||
|
||||
mercury::Stream<OrderStateUpdateEvent> order_state_pub;
|
||||
mercury::Stream<ActivateOrderEvent> activate_order_pub;
|
||||
mercury::Stream<UpdateOrderEvent> update_order_pub;
|
||||
mercury::Stream<CancelOrderEvent> cancel_order_pub;
|
||||
|
||||
@@ -16,13 +16,147 @@ class OrderStateUpdateEvent : public mercury::Event<OrderStateUpdateEvent> {
|
||||
api::orderman::OrderDefinition const &def,
|
||||
api::orderman::OrderState const &state,
|
||||
PerfTrace const &trace = PerfTrace())
|
||||
: key(key), parent_key(parent_key), definition(&def), state(state),
|
||||
trace(trace) {}
|
||||
: key(key), parent_key(parent_key), trace(trace), definition(&def) {
|
||||
|
||||
status = state.status();
|
||||
price = state.price();
|
||||
quantity = state.quantity();
|
||||
filled_quantity = state.filled_quantity();
|
||||
last_price = state.last_price();
|
||||
avg_price = state.avg_price();
|
||||
last_msg = state.last_msg();
|
||||
custom = state.custom_case();
|
||||
|
||||
auto native_state = get_native_state(state);
|
||||
if (native_state) {
|
||||
exchange_order_id = native_state->exchange_order_id();
|
||||
last_msg_seq_num = native_state->last_msg_seq_num();
|
||||
sub_error_code = native_state->sub_error_code();
|
||||
native_status = native_state->native_status();
|
||||
routing_record = native_state->routing_record();
|
||||
native_type = native_state->native_type();
|
||||
orderman::str_to(native_state->last_transact_time(),
|
||||
&last_transact_time);
|
||||
}
|
||||
}
|
||||
OrderKey key;
|
||||
OrderKey parent_key;
|
||||
api::orderman::OrderDefinition const *definition;
|
||||
api::orderman::OrderState state;
|
||||
|
||||
// common state
|
||||
api::orderman::OrderStatus status;
|
||||
double price;
|
||||
uint32_t quantity;
|
||||
uint32_t filled_quantity;
|
||||
double last_price;
|
||||
double avg_price;
|
||||
std::string last_msg;
|
||||
|
||||
PerfTrace trace;
|
||||
api::orderman::OrderState::CustomCase custom;
|
||||
|
||||
// native order state
|
||||
std::string exchange_order_id;
|
||||
uint64_t last_msg_seq_num;
|
||||
api::orderman::NativeOrderState::SubError sub_error_code;
|
||||
api::orderman::NativeOrderStatus native_status;
|
||||
api::orderman::RoutingRecord routing_record;
|
||||
api::orderman::NativeOrderType native_type;
|
||||
mercury::TimeStampStr last_transact_time;
|
||||
|
||||
api::orderman::OrderDefinition const *definition;
|
||||
|
||||
api::orderman::OrderState rebuild_state() const {
|
||||
api::orderman::OrderState result;
|
||||
result.set_status(status);
|
||||
result.set_price(price);
|
||||
result.set_quantity(quantity);
|
||||
result.set_filled_quantity(filled_quantity);
|
||||
result.set_last_price(last_price);
|
||||
result.set_avg_price(avg_price);
|
||||
result.set_last_msg(last_msg);
|
||||
|
||||
switch (custom) {
|
||||
case api::orderman::OrderState::kMarket:
|
||||
rebuild_native_state(result.mutable_market()->mutable_native_state());
|
||||
break;
|
||||
case api::orderman::OrderState::kLimit:
|
||||
rebuild_native_state(result.mutable_limit()->mutable_native_state());
|
||||
break;
|
||||
case api::orderman::OrderState::kStop:
|
||||
rebuild_native_state(result.mutable_stop()->mutable_native_state());
|
||||
break;
|
||||
case api::orderman::OrderState::kStopLimit:
|
||||
rebuild_native_state(result.mutable_stop_limit()->mutable_native_state());
|
||||
break;
|
||||
case api::orderman::OrderState::kIceberg:
|
||||
result.mutable_iceberg();
|
||||
break;
|
||||
case api::orderman::OrderState::kSpreader:
|
||||
result.mutable_spreader();
|
||||
break;
|
||||
case api::orderman::OrderState::kTimeBox:
|
||||
result.mutable_time_box();
|
||||
break;
|
||||
case api::orderman::OrderState::kTick:
|
||||
result.mutable_tick();
|
||||
break;
|
||||
case api::orderman::OrderState::kLean:
|
||||
result.mutable_lean();
|
||||
break;
|
||||
case api::orderman::OrderState::kJoin:
|
||||
result.mutable_join();
|
||||
break;
|
||||
case api::orderman::OrderState::kTop:
|
||||
result.mutable_top();
|
||||
break;
|
||||
case api::orderman::OrderState::kTrigger:
|
||||
result.mutable_trigger();
|
||||
break;
|
||||
case api::orderman::OrderState::kCover:
|
||||
result.mutable_cover();
|
||||
break;
|
||||
case api::orderman::OrderState::kOffset:
|
||||
result.mutable_offset();
|
||||
break;
|
||||
case api::orderman::OrderState::kDynamic:
|
||||
result.mutable_dynamic();
|
||||
break;
|
||||
case api::orderman::OrderState::CUSTOM_NOT_SET:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
void rebuild_native_state(api::orderman::NativeOrderState *st) const
|
||||
{
|
||||
st->set_exchange_order_id(exchange_order_id);
|
||||
st->set_last_msg_seq_num(last_msg_seq_num);
|
||||
st->set_sub_error_code(sub_error_code);
|
||||
st->set_native_status(native_status);
|
||||
*st->mutable_routing_record() = routing_record;
|
||||
st->set_native_type(native_type);
|
||||
st->set_last_transact_time(to_str(last_transact_time));
|
||||
}
|
||||
|
||||
|
||||
api::orderman::NativeOrderState const *
|
||||
get_native_state(api::orderman::OrderState const &st) {
|
||||
switch (st.custom_case()) {
|
||||
case api::orderman::OrderState::kMarket:
|
||||
return &st.market().native_state();
|
||||
case api::orderman::OrderState::kLimit:
|
||||
return &st.limit().native_state();
|
||||
case api::orderman::OrderState::kStop:
|
||||
return &st.stop().native_state();
|
||||
case api::orderman::OrderState::kStopLimit:
|
||||
return &st.stop_limit().native_state();
|
||||
default:
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
|
||||
@@ -21,12 +21,12 @@ public:
|
||||
// missed.
|
||||
using SynopsisPolicy = mercury::NoSynopsis;
|
||||
|
||||
OutFIXMsgEvent (PerfTrace trace, jetfix::OutFIXPtr const&fix) :
|
||||
trace(trace), msg(fix)
|
||||
OutFIXMsgEvent (jetfix::OutFIXPtr const&fix,std::vector<PerfTrace> const&traces) :
|
||||
msg(fix),trace(traces[0])
|
||||
{}
|
||||
|
||||
jetfix::OutFIXPtr msg;
|
||||
PerfTrace trace;
|
||||
jetfix::OutFIXPtr msg;
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -7,6 +7,7 @@ namespace bts {
|
||||
|
||||
class PerfTrace {
|
||||
public:
|
||||
utils::TimeStamp do_work_begin;
|
||||
utils::TimeStamp fix_socket_r;
|
||||
utils::TimeStamp md ;
|
||||
utils::TimeStamp md_src ;
|
||||
|
||||
@@ -13,89 +13,115 @@
|
||||
#include <SQLiteCpp/SQLiteCpp.h>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <tbb/concurrent_queue.h>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
|
||||
namespace bts {
|
||||
|
||||
auto insert = "insert into trace ("
|
||||
"version,"
|
||||
"host,"
|
||||
"build_type,"
|
||||
"session_start,"
|
||||
"trace_time,"
|
||||
"fix_socket_r,"
|
||||
"md,"
|
||||
"md_src,"
|
||||
"spreader_on_book,"
|
||||
"spreader_on_child_order_update,"
|
||||
"order_update,"
|
||||
"exe_gw,"
|
||||
"fix_socket_w,"
|
||||
"spreader_modify_order,"
|
||||
"send_fix_buffer,"
|
||||
"order_key,"
|
||||
"md_sn"
|
||||
") values ("
|
||||
":version,"
|
||||
":host,"
|
||||
":build_type,"
|
||||
":session_start,"
|
||||
":trace_time,"
|
||||
":fix_socket_r,"
|
||||
":md,"
|
||||
":md_src,"
|
||||
":spreader_on_book,"
|
||||
":spreader_on_child_order_update,"
|
||||
":order_update,"
|
||||
":exe_gw,"
|
||||
":fix_socket_w,"
|
||||
":spreader_modify_order,"
|
||||
":send_fix_buffer,"
|
||||
":order_key,"
|
||||
":md_sn"
|
||||
")";
|
||||
auto current_schema_version = 3;
|
||||
|
||||
auto create = "create table trace ("
|
||||
"version TEXT, "
|
||||
"host TEXT, "
|
||||
"build_type TEXT, "
|
||||
"session_start TEXT,"
|
||||
"trace_time TEXT,"
|
||||
"fix_socket_r INTEGER,"
|
||||
"md INTEGER,"
|
||||
"md_src INTEGER,"
|
||||
"spreader_on_book INTEGER,"
|
||||
"spreader_on_child_order_update INTEGER,"
|
||||
"order_update INTEGER,"
|
||||
"exe_gw INTEGER,"
|
||||
"fix_socket_w INTEGER,"
|
||||
"spreader_modify_order INTEGER,"
|
||||
"send_fix_buffer INTEGER,"
|
||||
"order_key INTEGER,"
|
||||
"md_sn INTEGER );";
|
||||
auto insert_trace = "insert into trace ("
|
||||
"version,"
|
||||
"host,"
|
||||
"build_type,"
|
||||
"session_start,"
|
||||
"trace_time,"
|
||||
"do_work_begin,"
|
||||
"fix_socket_r,"
|
||||
"md,"
|
||||
"md_src,"
|
||||
"spreader_on_book,"
|
||||
"spreader_on_child_order_update,"
|
||||
"order_update,"
|
||||
"exe_gw,"
|
||||
"fix_socket_w,"
|
||||
"spreader_modify_order,"
|
||||
"send_fix_buffer,"
|
||||
"order_key,"
|
||||
"md_sn"
|
||||
") values ("
|
||||
":version,"
|
||||
":host,"
|
||||
":build_type,"
|
||||
":session_start,"
|
||||
":trace_time,"
|
||||
":do_work_begin,"
|
||||
":fix_socket_r,"
|
||||
":md,"
|
||||
":md_src,"
|
||||
":spreader_on_book,"
|
||||
":spreader_on_child_order_update,"
|
||||
":order_update,"
|
||||
":exe_gw,"
|
||||
":fix_socket_w,"
|
||||
":spreader_modify_order,"
|
||||
":send_fix_buffer,"
|
||||
":order_key,"
|
||||
":md_sn"
|
||||
")";
|
||||
|
||||
auto view = "create view requote_trace as select "
|
||||
"version, "
|
||||
"host, "
|
||||
"build_type, "
|
||||
"session_start,"
|
||||
"trace_time,"
|
||||
"order_key,"
|
||||
"(fix_socket_w-md) / 1000.0 total,"
|
||||
"(spreader_on_book - md) / 1000.0 md,"
|
||||
"(send_fix_buffer-spreader_on_book)/1000.0 spreader,"
|
||||
"(fix_socket_w-send_fix_buffer)/1000.0 fix "
|
||||
"from "
|
||||
"trace "
|
||||
"where md<>0 and (md_src-md)<1000000";
|
||||
auto create_trace_table = "drop table if exists trace;create table trace ("
|
||||
"version TEXT, "
|
||||
"host TEXT, "
|
||||
"build_type TEXT, "
|
||||
"session_start TEXT,"
|
||||
"trace_time TEXT,"
|
||||
"do_work_begin INTEGER,"
|
||||
"fix_socket_r INTEGER,"
|
||||
"md INTEGER,"
|
||||
"md_src INTEGER,"
|
||||
"spreader_on_book INTEGER,"
|
||||
"spreader_on_child_order_update INTEGER,"
|
||||
"order_update INTEGER,"
|
||||
"exe_gw INTEGER,"
|
||||
"fix_socket_w INTEGER,"
|
||||
"spreader_modify_order INTEGER,"
|
||||
"send_fix_buffer INTEGER,"
|
||||
"order_key INTEGER,"
|
||||
"md_sn INTEGER );";
|
||||
|
||||
auto create_schema_version_table =
|
||||
"create table schema_version(version INTEGER); insert into "
|
||||
"schema_version(version) values(0);";
|
||||
|
||||
auto query_schema_version = "select version from schema_version limit 1";
|
||||
auto delete_version_record = "delete from schema_version;";
|
||||
auto update_version = "insert into schema_version(version) values(:version);";
|
||||
|
||||
auto requote_trace_view = "drop view if exists requote_trace; "
|
||||
"create view requote_trace as select "
|
||||
"version, "
|
||||
"host, "
|
||||
"build_type, "
|
||||
"session_start,"
|
||||
"trace_time,"
|
||||
"order_key,"
|
||||
"(fix_socket_w-md) / 1000.0 total,"
|
||||
"0 md,"
|
||||
"0 spreader,"
|
||||
"0 fix "
|
||||
"from "
|
||||
"trace "
|
||||
"where md<>0 and (md_src-md)<1000000";
|
||||
|
||||
auto hedge_trace_view =
|
||||
"drop view if exists hedge_trace; "
|
||||
"CREATE VIEW hedge_trace as "
|
||||
"select version, host, build_type, session_start,trace_time,order_key, "
|
||||
"(fix_socket_w-fix_socket_r) / 1000.0 total, "
|
||||
"0 fix_in, "
|
||||
"0 spreader, "
|
||||
"0 fix_out "
|
||||
"from trace where fix_socket_r<>0 ";
|
||||
|
||||
auto requote_query =
|
||||
"select * from requote_trace order by trace_time desc limit ?";
|
||||
|
||||
auto hedge_query = "select * from hedge_trace order by trace_time desc limit ?";
|
||||
|
||||
struct PerfTraceLog::PImpl {
|
||||
PImpl(std::string const &loc)
|
||||
: db(loc, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE),
|
||||
@@ -103,6 +129,7 @@ struct PerfTraceLog::PImpl {
|
||||
SQLite::Database db;
|
||||
std::unique_ptr<SQLite::Statement> insert_statement;
|
||||
std::unique_ptr<SQLite::Statement> requote_query_statement;
|
||||
std::unique_ptr<SQLite::Statement> hedge_query_statement;
|
||||
tbb::concurrent_queue<PerfTrace> pending_traces;
|
||||
std::string session_start;
|
||||
std::mutex lock;
|
||||
@@ -112,16 +139,29 @@ PerfTraceLog::PerfTraceLog() : me() {
|
||||
auto loc = init_storage_location();
|
||||
try {
|
||||
me = std::make_unique<PImpl>(loc);
|
||||
if (!me->db.tableExists("trace")) {
|
||||
if (!me->db.tableExists("schema_version")) {
|
||||
LOG(persist, Warn, "{} database does not exist yet. Creating it ",
|
||||
std::string(me->db.getFilename()));
|
||||
me->db.exec(create);
|
||||
me->db.exec(view);
|
||||
me->db.exec(create_schema_version_table);
|
||||
}
|
||||
|
||||
if (schema_out_of_date()) {
|
||||
me->db.exec(create_trace_table);
|
||||
me->db.exec(requote_trace_view);
|
||||
me->db.exec(hedge_trace_view);
|
||||
|
||||
SQLite::Statement(me->db, delete_version_record).exec();
|
||||
SQLite::Statement update_version_statement(me->db, update_version);
|
||||
update_version_statement.bind(":version", current_schema_version);
|
||||
update_version_statement.exec();
|
||||
}
|
||||
|
||||
me->insert_statement =
|
||||
std::make_unique<SQLite::Statement>(me->db, insert);
|
||||
std::make_unique<SQLite::Statement>(me->db, insert_trace);
|
||||
me->requote_query_statement =
|
||||
std::make_unique<SQLite::Statement>(me->db, requote_query);
|
||||
me->hedge_query_statement =
|
||||
std::make_unique<SQLite::Statement>(me->db, hedge_query);
|
||||
me->session_start = datetime::FIX_timestamp(datetime::local_now());
|
||||
} catch (SQLite::Exception const &e) {
|
||||
auto msg = fmt::format("Unable to create {}. Error: {}", loc,
|
||||
@@ -178,6 +218,8 @@ void PerfTraceLog::store(std::vector<PerfTrace> const &traces) {
|
||||
datetime::FIX_timestamp(
|
||||
datetime::timestamp_to_ptime(t.fix_socket_r)));
|
||||
|
||||
me->insert_statement->bind(":do_work_begin",
|
||||
(long long)t.do_work_begin.to_uint64());
|
||||
me->insert_statement->bind(":fix_socket_r",
|
||||
(long long)t.fix_socket_r.to_uint64());
|
||||
me->insert_statement->bind(":md", (long long)t.md.to_uint64());
|
||||
@@ -210,6 +252,24 @@ void PerfTraceLog::store(std::vector<PerfTrace> const &traces) {
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfTraceLog::schema_out_of_date() {
|
||||
try {
|
||||
SQLite::Statement query_schema_version_statement(me->db,
|
||||
query_schema_version);
|
||||
|
||||
while (query_schema_version_statement.executeStep()) {
|
||||
int version = query_schema_version_statement.getColumn("version");
|
||||
return version != current_schema_version;
|
||||
}
|
||||
} catch (SQLite::Exception const &e) {
|
||||
auto msg = fmt::format("Unable to query schema version in {}. Error: {}",
|
||||
std::string(me->db.getFilename()),
|
||||
std::string(e.getErrorStr()));
|
||||
bts_assert_msg(false, msg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string encode_string(SQLite::Column const &c) {
|
||||
return fmt::format("\"{}\"", std::string(c));
|
||||
}
|
||||
@@ -219,7 +279,7 @@ std::string encode_number(SQLite::Column const &c) {
|
||||
}
|
||||
|
||||
std::vector<std::map<std::string, std::string>>
|
||||
PerfTraceLog::get_latest_traces(size_t n) {
|
||||
PerfTraceLog::get_latest_requote_traces(size_t n) {
|
||||
std::vector<std::map<std::string, std::string>> result;
|
||||
|
||||
std::lock_guard<std::mutex> l(me->lock);
|
||||
@@ -252,7 +312,7 @@ PerfTraceLog::get_latest_traces(size_t n) {
|
||||
}
|
||||
me->requote_query_statement->reset();
|
||||
} catch (SQLite::Exception const &e) {
|
||||
auto msg = fmt::format("Unable to query {}. Error: {}",
|
||||
auto msg = fmt::format("Unable to quote_traces {}. Error: {}",
|
||||
std::string(me->db.getFilename()),
|
||||
std::string(e.getErrorStr()));
|
||||
bts_assert_msg(false, msg);
|
||||
@@ -260,6 +320,47 @@ PerfTraceLog::get_latest_traces(size_t n) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::map<std::string, std::string>>
|
||||
PerfTraceLog::get_latest_hedge_traces(size_t n) {
|
||||
std::vector<std::map<std::string, std::string>> result;
|
||||
|
||||
std::lock_guard<std::mutex> l(me->lock);
|
||||
try {
|
||||
me->hedge_query_statement->bind(1, (long long)n);
|
||||
|
||||
while (me->hedge_query_statement->executeStep()) {
|
||||
auto &row = result.emplace_back();
|
||||
row["version"] =
|
||||
encode_string(me->hedge_query_statement->getColumn("version"));
|
||||
row["host"] =
|
||||
encode_string(me->hedge_query_statement->getColumn("host"));
|
||||
row["build_type"] =
|
||||
encode_string(me->hedge_query_statement->getColumn("build_type"));
|
||||
row["session_start"] = encode_string(
|
||||
me->hedge_query_statement->getColumn("session_start"));
|
||||
row["trace_time"] =
|
||||
encode_string(me->hedge_query_statement->getColumn("trace_time"));
|
||||
|
||||
row["order_key"] =
|
||||
encode_number(me->hedge_query_statement->getColumn("order_key"));
|
||||
row["total"] =
|
||||
encode_number(me->hedge_query_statement->getColumn("total"));
|
||||
row["fix_in"] =
|
||||
encode_number(me->hedge_query_statement->getColumn("fix_in"));
|
||||
row["spreader"] =
|
||||
encode_number(me->hedge_query_statement->getColumn("spreader"));
|
||||
row["fix_out"] =
|
||||
encode_number(me->hedge_query_statement->getColumn("fix_out"));
|
||||
}
|
||||
me->hedge_query_statement->reset();
|
||||
} catch (SQLite::Exception const &e) {
|
||||
auto msg = fmt::format("Unable to query hedge_traces. Error: {}",
|
||||
std::string(e.getErrorStr()));
|
||||
bts_assert_msg(false, msg);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace perf_stat {
|
||||
|
||||
using Row = std::map<std::string, std::string>;
|
||||
@@ -286,8 +387,8 @@ struct Session {
|
||||
|
||||
} // namespace perf_stat
|
||||
|
||||
std::map<std::string, perf_stat::Session>
|
||||
structure_traces(std::vector<std::map<std::string, std::string>> "es) {
|
||||
std::map<std::string, perf_stat::Session> structure_quote_traces(
|
||||
std::vector<std::map<std::string, std::string>> "es) {
|
||||
|
||||
std::map<std::string, perf_stat::Session> result;
|
||||
|
||||
@@ -322,32 +423,63 @@ structure_traces(std::vector<std::map<std::string, std::string>> "es) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void print_summary(std::ostream &ss, perf_stat::Summary const &s,bool last) {
|
||||
std::map<std::string, perf_stat::Session> structure_hedge_traces(
|
||||
std::vector<std::map<std::string, std::string>> "es) {
|
||||
|
||||
std::map<std::string, perf_stat::Session> result;
|
||||
|
||||
for (auto &q : quotes) {
|
||||
auto &session = result[q["session_start"]];
|
||||
if (session.start.empty()) {
|
||||
session.start = q["session_start"];
|
||||
session.host = q["host"];
|
||||
session.version = q["version"];
|
||||
session.build_type = q["build_type"];
|
||||
}
|
||||
for (auto st : {"total", "fix_in", "spreader", "fix_out"}) {
|
||||
auto &summary = session.summaries[st];
|
||||
if (summary.name.empty())
|
||||
summary.name = st;
|
||||
summary.values.push_back(std::stod(q[st]));
|
||||
}
|
||||
session.rows.push_back(q);
|
||||
session.n_rows++;
|
||||
}
|
||||
|
||||
for (auto &session_kvp : result)
|
||||
for (auto &stat_kvp : session_kvp.second.summaries) {
|
||||
auto &summary = stat_kvp.second;
|
||||
summary.min = stats::min(summary.values);
|
||||
summary.max = stats::max(summary.values);
|
||||
summary.median = stats::percentile(summary.values, 0.5);
|
||||
summary.ninenty_nine = stats::percentile(summary.values, 0.99);
|
||||
summary.stddev = stats::stdev(summary.values);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void print_summary(std::ostream &ss, perf_stat::Summary const &s, bool last) {
|
||||
ss << " { "
|
||||
<< "\"value\":"
|
||||
<< " \"" << s.name << "\""
|
||||
<< ", \"min\":" << s.min
|
||||
<< ", \"max\":" << s.max
|
||||
<< ", \"median\":" << s.median
|
||||
<< ", \"ninenty_nine\":" << s.ninenty_nine
|
||||
<< ", \"min\":" << s.min << ", \"max\":" << s.max
|
||||
<< ", \"median\":" << s.median << ", \"ninenty_nine\":" << s.ninenty_nine
|
||||
<< ", \"stdev\":" << s.stddev;
|
||||
if (!last)
|
||||
ss << " },\n";
|
||||
else
|
||||
ss << " }\n";
|
||||
|
||||
}
|
||||
|
||||
void print_row(std::ostream &ss, perf_stat::Row const &r,bool last) {
|
||||
void print_row(std::ostream &ss, perf_stat::Row const &r, bool last) {
|
||||
ss << " { ";
|
||||
size_t i = 0;
|
||||
for (auto const &kvp : r)
|
||||
if (kvp.first != "version" &&
|
||||
kvp.first != "host" &&
|
||||
kvp.first != "build_type" &&
|
||||
kvp.first != "session_start") {
|
||||
if (kvp.first != "version" && kvp.first != "host" &&
|
||||
kvp.first != "build_type" && kvp.first != "session_start") {
|
||||
ss << "\"" << kvp.first << "\":" << kvp.second;
|
||||
if (++i != r.size()-4)
|
||||
if (++i != r.size() - 4)
|
||||
ss << ",";
|
||||
}
|
||||
if (!last)
|
||||
@@ -356,7 +488,7 @@ void print_row(std::ostream &ss, perf_stat::Row const &r,bool last) {
|
||||
ss << " }\n";
|
||||
}
|
||||
|
||||
void print_session(std::ostream &ss, perf_stat::Session const &s,bool last) {
|
||||
void print_session(std::ostream &ss, perf_stat::Session const &s, bool last) {
|
||||
ss << "{\n"
|
||||
<< " \"session_name\": " << s.start << ",\n"
|
||||
<< " \"host\": " << s.host << ",\n"
|
||||
@@ -365,15 +497,15 @@ void print_session(std::ostream &ss, perf_stat::Session const &s,bool last) {
|
||||
<< " \"n_rows\": " << s.n_rows << ",\n";
|
||||
|
||||
ss << " \"summaries\":\n [\n";
|
||||
size_t i = 0;
|
||||
size_t i = 0;
|
||||
for (auto &summaries_kvp : s.summaries)
|
||||
print_summary(ss, summaries_kvp.second,++i == s.summaries.size());
|
||||
print_summary(ss, summaries_kvp.second, ++i == s.summaries.size());
|
||||
ss << " ],\n";
|
||||
|
||||
ss << " \"rows\":\n [\n";
|
||||
i = 0;
|
||||
for (auto &r : s.rows)
|
||||
print_row(ss, r,++i == s.rows.size());
|
||||
print_row(ss, r, ++i == s.rows.size());
|
||||
ss << " ]\n";
|
||||
if (!last)
|
||||
ss << "},\n";
|
||||
@@ -382,14 +514,28 @@ void print_session(std::ostream &ss, perf_stat::Session const &s,bool last) {
|
||||
}
|
||||
|
||||
void PerfTraceLog::print_latest_traces(std::ostream &ss, size_t n) {
|
||||
auto rows = get_latest_traces(n);
|
||||
auto structured = structure_traces(rows);
|
||||
|
||||
ss << "[\n";
|
||||
size_t i = 0;
|
||||
for (auto &session_kvp : boost::adaptors::reverse(structured))
|
||||
print_session(ss, session_kvp.second, ++i == structured.size());
|
||||
ss << "]\n";
|
||||
{
|
||||
auto rows = get_latest_requote_traces(n);
|
||||
auto structured = structure_quote_traces(rows);
|
||||
|
||||
ss << "{\n\"requotes\": [\n";
|
||||
size_t i = 0;
|
||||
for (auto &session_kvp : boost::adaptors::reverse(structured))
|
||||
print_session(ss, session_kvp.second, ++i == structured.size());
|
||||
ss << "],\n";
|
||||
}
|
||||
|
||||
{
|
||||
auto rows = get_latest_hedge_traces(n);
|
||||
auto structured = structure_hedge_traces(rows);
|
||||
|
||||
ss << "\"hedges\": [\n";
|
||||
|
||||
size_t i = 0;
|
||||
for (auto &session_kvp : boost::adaptors::reverse(structured))
|
||||
print_session(ss, session_kvp.second, ++i == structured.size());
|
||||
ss << "]\n}\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace bts
|
||||
@@ -17,7 +17,9 @@ class PerfTraceLog {
|
||||
int persist_traces();
|
||||
|
||||
// return the N last traces
|
||||
std::vector<std::map<std::string, std::string>> get_latest_traces(size_t n=0);
|
||||
std::vector<std::map<std::string, std::string>> get_latest_requote_traces(size_t n=0);
|
||||
std::vector<std::map<std::string, std::string>> get_latest_hedge_traces(size_t n=0);
|
||||
|
||||
void print_latest_traces(std::ostream &,size_t n = 0);
|
||||
|
||||
private:
|
||||
@@ -25,6 +27,7 @@ class PerfTraceLog {
|
||||
std::unique_ptr<PImpl> me;
|
||||
|
||||
std::string init_storage_location();
|
||||
bool schema_out_of_date();
|
||||
void store(std::vector<PerfTrace> const &);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#include "IcebergOrder.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/mercury/events/TimerEvent.h"
|
||||
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/config/protos/orderman_cfg.pb.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace bts {
|
||||
@@ -16,8 +21,13 @@ struct IcebergOrder::ActiveChild {
|
||||
void clear() { state = api::orderman::OrderState(); }
|
||||
};
|
||||
|
||||
enum class IcebergOrder::WorkingSubStatus { WORKING, PAUSED };
|
||||
|
||||
struct IcebergOrder::PImpl {
|
||||
PImpl() : services(nullptr), child() {}
|
||||
PImpl()
|
||||
: services(nullptr), child(),
|
||||
working_sub_status(WorkingSubStatus::PAUSED),
|
||||
start_of_pause(Timer::now()) {}
|
||||
|
||||
OrderServices *services;
|
||||
api::orderman::OrderDefinition def;
|
||||
@@ -25,6 +35,9 @@ struct IcebergOrder::PImpl {
|
||||
OrderBuilder child_builder;
|
||||
ActiveChild child;
|
||||
Quantity show_quantity;
|
||||
WorkingSubStatus working_sub_status;
|
||||
TimeStamp start_of_pause;
|
||||
uint32_t pause_between_orders;
|
||||
};
|
||||
|
||||
IcebergOrder::IcebergOrder() : me(new PImpl()) {}
|
||||
@@ -42,6 +55,8 @@ void IcebergOrder::on_init_new(api::orderman::OrderDefinition const &def,
|
||||
|
||||
auto const &iceberg_def = def.custom_def().iceberg();
|
||||
me->show_quantity = Quantity(iceberg_def.show_quantity());
|
||||
me->pause_between_orders =
|
||||
config::get<config::OrdermanCfg>().default_iceberg_pause_secs();
|
||||
|
||||
auto child_def = def;
|
||||
*child_def.mutable_custom_def() = iceberg_def.child();
|
||||
@@ -89,7 +104,7 @@ void IcebergOrder::on_init_recovered(api::orderman::OrderRecord const &rec,
|
||||
}
|
||||
|
||||
void IcebergOrder::on_activate(Price p, Quantity q, OrderServices &services,
|
||||
PerfTrace const&) {
|
||||
PerfTrace const &) {
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
me->child_builder.activate(services);
|
||||
@@ -98,9 +113,13 @@ void IcebergOrder::on_activate(Price p, Quantity q, OrderServices &services,
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
me->state.set_price(p.value());
|
||||
me->state.set_quantity(q.value());
|
||||
if (me->pause_between_orders)
|
||||
services.time_change.sub(
|
||||
[this](auto const &time) { this->on_time(time); });
|
||||
services.child_updates.sub(
|
||||
key(), [this](auto const &os) { this->on_child_order_update(os); });
|
||||
transition(ORDER_STATUS_WORKING);
|
||||
me->working_sub_status = WorkingSubStatus::WORKING;
|
||||
send_next_child_order();
|
||||
break;
|
||||
|
||||
@@ -126,7 +145,7 @@ void IcebergOrder::on_activate(Price p, Quantity q, OrderServices &services,
|
||||
report_state();
|
||||
}
|
||||
|
||||
void IcebergOrder::on_update(Price p, Quantity q, PerfTrace const&) {
|
||||
void IcebergOrder::on_update(Price p, Quantity q, PerfTrace const &) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
@@ -152,9 +171,9 @@ void IcebergOrder::on_update(Price p, Quantity q, PerfTrace const&) {
|
||||
report_state();
|
||||
}
|
||||
|
||||
void IcebergOrder::on_crack(PerfTrace const&) {}
|
||||
void IcebergOrder::on_crack(PerfTrace const &) {}
|
||||
|
||||
void IcebergOrder::on_cancel(PerfTrace const&) {
|
||||
void IcebergOrder::on_cancel(PerfTrace const &) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
LOG(OrderMan, Info, "Canceling Iceberg Order {}", key().value());
|
||||
@@ -243,9 +262,9 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
if (ev.key == me->child.order.key()) {
|
||||
me->child.state = ev.state;
|
||||
me->child.state = ev.rebuild_state();
|
||||
|
||||
switch (ev.state.status()) {
|
||||
switch (ev.status) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
@@ -253,14 +272,18 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) {
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_COMPLETED: {
|
||||
api::orderman::OrderState merged_state;
|
||||
merge_states(me->state, me->child.state, &merged_state);
|
||||
me->state = merged_state;
|
||||
me->child.clear();
|
||||
if (me->state.quantity() > me->state.filled_quantity())
|
||||
api::orderman::OrderState merged_state;
|
||||
merge_states(me->state, me->child.state, &merged_state);
|
||||
me->state = merged_state;
|
||||
me->child.clear();
|
||||
if (me->state.quantity() > me->state.filled_quantity()) {
|
||||
if (me->pause_between_orders) {
|
||||
me->working_sub_status = WorkingSubStatus::PAUSED;
|
||||
me->start_of_pause = Timer::now();
|
||||
} else
|
||||
send_next_child_order();
|
||||
else
|
||||
transition(ORDER_STATUS_COMPLETED);
|
||||
} else
|
||||
transition(ORDER_STATUS_COMPLETED);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -268,8 +291,7 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) {
|
||||
LOG(OrderMan, Info,
|
||||
"Unexpected cancel of child {} in Iceberg Order {}. Canceling "
|
||||
"parent",
|
||||
ev.key.value(),
|
||||
key().value());
|
||||
ev.key.value(), key().value());
|
||||
transition(ORDER_STATUS_CANCELED);
|
||||
break;
|
||||
|
||||
@@ -292,7 +314,7 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) {
|
||||
"Iceberg order {} received update for non active child order {}."
|
||||
"update state = {}",
|
||||
key().value(), me->child.order.key().value(),
|
||||
utils::pb::to_string(ev.state));
|
||||
utils::pb::to_string(ev.rebuild_state()));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -312,5 +334,16 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) {
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void IcebergOrder::on_time(mercury::TimerEvent const &t) {
|
||||
bts_assert(me->pause_between_orders);
|
||||
if (sec_diff(t.ts, me->start_of_pause) >= me->pause_between_orders &&
|
||||
me->state.status() == ORDER_STATUS_WORKING &&
|
||||
me->working_sub_status == WorkingSubStatus::PAUSED) {
|
||||
me->working_sub_status = WorkingSubStatus::WORKING;
|
||||
send_next_child_order();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "lib/api/services/OrderService.server.pb.h"
|
||||
|
||||
namespace bts {
|
||||
namespace mercury {class TimerEvent;}
|
||||
namespace orderman {
|
||||
|
||||
class OrderStateUpdateEvent;
|
||||
@@ -35,7 +36,9 @@ private:
|
||||
void on_child_order_update(OrderStateUpdateEvent const&);
|
||||
void transition(api::orderman::OrderStatus new_state,std::string const&msg);
|
||||
void transition(api::orderman::OrderStatus new_state);
|
||||
void on_time (mercury::TimerEvent const&);
|
||||
|
||||
enum class WorkingSubStatus;
|
||||
struct ActiveChild;
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "lib/orderman/securities/ISecurityDB.h"
|
||||
#include "lib/tracing/bts_trace.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
|
||||
#include "lib/orderman/actors/order_manager/OrderServices.h"
|
||||
|
||||
@@ -29,7 +30,7 @@ struct NativeOrder::PImpl {
|
||||
PImpl()
|
||||
: services(nullptr), session_services(), sec(nullptr),
|
||||
previous_position_contribution(0), definition(), state(),
|
||||
price_encoding_precision(7) {}
|
||||
price_encoding_precision(7),have_exchange_order_id(false) {}
|
||||
|
||||
OrderServices *services;
|
||||
SessionServices *session_services;
|
||||
@@ -40,7 +41,8 @@ struct NativeOrder::PImpl {
|
||||
OrderDefinition definition;
|
||||
OrderState state;
|
||||
int price_encoding_precision;
|
||||
|
||||
bool have_exchange_order_id;
|
||||
|
||||
jetfix::FIXFragment update_encoding;
|
||||
jetfix::FIXFragment::Bookmark<jetfix::fix::Price> update_price_bm;
|
||||
jetfix::FIXFragment::Bookmark<jetfix::fix::OrderQty> update_quantity_bm;
|
||||
@@ -273,10 +275,13 @@ NativeOrder::~NativeOrder() {}
|
||||
void NativeOrder::on_activate(Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services,
|
||||
PerfTrace const &t) {
|
||||
LOG(Latency,Info, "on_activate start {}", key().value());
|
||||
|
||||
auto trace = t;
|
||||
trace.order_key = key().value();
|
||||
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_activate", 0, trace.md_sn, 0);
|
||||
trace.order_update = utils::TimeStamp::now();
|
||||
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_activate", 0, trace.md_sn, key().value());
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
|
||||
@@ -384,23 +389,18 @@ void NativeOrder::on_activate(Price p, Quantity q,
|
||||
auto const &ts = services.get_time_str();
|
||||
me->create_transact_time_bm = encoding.overwrite(
|
||||
me->create_transact_time_bm, &ts.value()[0], ts.value().size());
|
||||
auto buffer = me->session_services->get_fix_buffer();
|
||||
auto &stream = buffer->fix[0];
|
||||
auto &f = stream.new_msg(jetfix::MessageTypes::NewOrderSingle);
|
||||
f.append(me->create_encoding);
|
||||
stream.close();
|
||||
|
||||
// Send it
|
||||
me->session_services->send_fix_buffer(buffer, trace);
|
||||
|
||||
// post send book keeping
|
||||
trace.send_fix_buffer = utils::TimeStamp::now();
|
||||
me->session_services->queue_fix(jetfix::MessageTypes::NewOrderSingle,
|
||||
me->create_encoding, trace);
|
||||
me->session_services->governor().record_sent();
|
||||
me->session_services->refill_fix_buffer_pool();
|
||||
me->state.set_status(ORDER_STATUS_PENDING_WORKING);
|
||||
|
||||
LOG(Latency,Diag, "on_activate done fix {} t: {}us", key().value(),
|
||||
(utils::TimeStamp::now() - trace.order_update).microseconds());
|
||||
LOG(OrderMan, Info, "Sent new order with key {} to gateway",
|
||||
key().value());
|
||||
break;
|
||||
// early return so we skip the expensive report_state() call
|
||||
return;
|
||||
}
|
||||
|
||||
// all cases below are for orders recovered from disk
|
||||
@@ -526,32 +526,20 @@ void NativeOrder::on_update(Price p, Quantity q, PerfTrace const &t) {
|
||||
me->update_quantity_bm =
|
||||
encoding.overwrite(me->update_quantity_bm, q.value(), quantity_sz());
|
||||
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_update.half_way", 0,
|
||||
trace.md_sn, trace.order_key);
|
||||
|
||||
auto const &ts = me->services->get_time_str();
|
||||
me->update_transact_time_bm = encoding.overwrite(
|
||||
me->update_transact_time_bm, &ts.value()[0], ts.value().size());
|
||||
auto buffer = me->session_services->get_fix_buffer();
|
||||
auto &stream = buffer->fix[0];
|
||||
auto &f = stream.new_msg(jetfix::MessageTypes::CancelReplace);
|
||||
f.append(me->update_encoding);
|
||||
stream.close();
|
||||
|
||||
// send it
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_update.before_send_fix", 0,
|
||||
trace.md_sn, trace.order_key);
|
||||
me->session_services->send_fix_buffer(buffer, trace);
|
||||
me->session_services->queue_fix(jetfix::MessageTypes::CancelReplace,
|
||||
me->update_encoding, trace);
|
||||
|
||||
me->session_services->governor().record_sent();
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_update.end", 0,
|
||||
trace.md_sn, trace.order_key);
|
||||
// post send book keeping
|
||||
|
||||
// these are slow and we need to return out of this handler so
|
||||
// that we can process the fix
|
||||
me->services->schedule_action([this]() {
|
||||
me->session_services->refill_fix_buffer_pool();
|
||||
if (me->state.last_msg().size())
|
||||
me->state.set_last_msg("");
|
||||
report_state();
|
||||
});
|
||||
update_working_position();
|
||||
if (me->state.last_msg().size())
|
||||
me->state.set_last_msg("");
|
||||
|
||||
// early return so we skip report_state (for speed)
|
||||
return;
|
||||
@@ -585,16 +573,10 @@ void NativeOrder::on_cancel(PerfTrace const &trace) {
|
||||
auto const &ts = me->services->get_time_str();
|
||||
me->cancel_transact_time_bm = encoding.overwrite(
|
||||
me->cancel_transact_time_bm, &ts.value()[0], ts.value().size());
|
||||
auto buffer = me->session_services->get_fix_buffer();
|
||||
auto &stream = buffer->fix[0];
|
||||
auto &f = stream.new_msg(jetfix::MessageTypes::Cancel);
|
||||
f.append(me->cancel_encoding);
|
||||
stream.close();
|
||||
auto trace_cpy = trace;
|
||||
me->session_services->send_fix_buffer(buffer, trace_cpy);
|
||||
|
||||
// post send book keeping
|
||||
me->session_services->refill_fix_buffer_pool();
|
||||
me->session_services->queue_fix(jetfix::MessageTypes::Cancel,
|
||||
me->cancel_encoding, trace);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -689,7 +671,8 @@ void NativeOrder::on_exe_report(const NewExecutionReportEvent &er) {
|
||||
|
||||
native_state.set_native_status(er.data->order_status);
|
||||
native_state.set_native_type(er.data->order_type);
|
||||
if (native_state.exchange_order_id().empty()) {
|
||||
bool got_first_exchange_order_id = !me->have_exchange_order_id;
|
||||
if (got_first_exchange_order_id) {
|
||||
auto ts = to_trim_str(er.data->exchange_order_id.value());
|
||||
native_state.set_exchange_order_id(std::string(ts.first, ts.second));
|
||||
add_exchange_order_id_to_fix();
|
||||
@@ -732,6 +715,15 @@ void NativeOrder::on_exe_report(const NewExecutionReportEvent &er) {
|
||||
break;
|
||||
}
|
||||
report_state(er.trace);
|
||||
|
||||
// we only need the exhange order id and the routing record
|
||||
// reported once, since they are both immutable, so we clear them
|
||||
// after their first report to make subsquent state updates faster
|
||||
if (got_first_exchange_order_id) {
|
||||
me->have_exchange_order_id = true;
|
||||
native_state.clear_exchange_order_id();
|
||||
native_state.mutable_routing_record()->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeOrder::on_cancel_reject(const orderman::CancelRejectEvent &cr) {
|
||||
@@ -802,7 +794,7 @@ void NativeOrder::on_gateway_status(const GatewayStatusChangeEvent &ev) {
|
||||
report_state();
|
||||
}
|
||||
|
||||
void NativeOrder::report_state(PerfTrace const &trace) {
|
||||
void NativeOrder::update_working_position() {
|
||||
if (me->sec) {
|
||||
auto current_position = position_contribution();
|
||||
auto previous_position = me->previous_position_contribution;
|
||||
@@ -823,7 +815,10 @@ void NativeOrder::report_state(PerfTrace const &trace) {
|
||||
"Order {} ignored for purposes of limit enforcing "
|
||||
"because it references unknown security {} ",
|
||||
key().value(), me->definition.security_key());
|
||||
}
|
||||
|
||||
void NativeOrder::report_state(PerfTrace const &trace) {
|
||||
update_working_position();
|
||||
me->services->report_state(me->state, trace);
|
||||
}
|
||||
|
||||
@@ -1038,7 +1033,7 @@ void NativeOrder::transition(api::orderman::OrderStatus new_status) {
|
||||
else
|
||||
LOG(OrderMan, Diag, "Transitioning order {} from {} to {}", key().value(),
|
||||
from, to);
|
||||
|
||||
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ private:
|
||||
void transition_to_error(api::orderman::NativeOrderState::SubError sub_error,
|
||||
std::string const&msg);
|
||||
|
||||
void update_working_position();
|
||||
bool has_exchange_order_id() ;
|
||||
Quantity position_contribution();
|
||||
bool is_old_exe_report( api::orderman::NativeOrderState &, const NewExecutionReportEvent &) const;
|
||||
|
||||
@@ -320,11 +320,11 @@ void TimeBoxOrder::on_time_change() {
|
||||
|
||||
void TimeBoxOrder::on_child_order_update(OrderStateUpdateEvent const&ev)
|
||||
{
|
||||
me->child_state = ev.state;
|
||||
me->child_state = ev.rebuild_state();
|
||||
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
switch (ev.state.status()) {
|
||||
switch (ev.status) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
|
||||
@@ -232,22 +232,23 @@ void TriggerOrder::_on_book_update(const BookUpdateEvent& b_event){
|
||||
}
|
||||
void TriggerOrder::_on_child_order_update(const OrderStateUpdateEvent& o_ev){
|
||||
if(o_ev.key==me->child_order.key()){
|
||||
me->child_state=o_ev.state;
|
||||
auto ev_state = o_ev.rebuild_state();
|
||||
me->child_state=ev_state;
|
||||
switch (_state){
|
||||
case State::START:
|
||||
case State::WAITING_FOR_TRIGGER:
|
||||
bts_assert(false);
|
||||
break;
|
||||
case State::WAITING_FOR_FIRST_ACK:
|
||||
if(SpreaderUtils::order_acknowledged(o_ev.state.status())){
|
||||
if(SpreaderUtils::order_in_terminal_state(o_ev.state.status()))
|
||||
if(SpreaderUtils::order_acknowledged(o_ev.status)){
|
||||
if(SpreaderUtils::order_in_terminal_state(o_ev.status))
|
||||
_switch_state(State::END);
|
||||
else
|
||||
_switch_state(State::STEADY);
|
||||
}
|
||||
break;
|
||||
case State::STEADY:
|
||||
if(SpreaderUtils::order_in_terminal_state(o_ev.state.status()))
|
||||
if(SpreaderUtils::order_in_terminal_state(ev_state.status()))
|
||||
_switch_state(State::END);
|
||||
break;
|
||||
case State::END:
|
||||
|
||||
@@ -343,15 +343,15 @@ void BookAlgo::on_child_order_update(const OrderStateUpdateEvent& ev)
|
||||
if(me->fake_detached_child)
|
||||
return;
|
||||
if(ev.key != me->child.key())
|
||||
me->hedges_state[ev.key] = ev.state;
|
||||
me->hedges_state[ev.key] = ev.rebuild_state();
|
||||
else
|
||||
{
|
||||
api::orderman::OrderState orig_state = child_state();
|
||||
me->child_state = ev.state;
|
||||
me->child_state = ev.rebuild_state();
|
||||
switch (this_state().status())
|
||||
{
|
||||
case ORDER_STATUS_WORKING:
|
||||
switch (ev.state.status())
|
||||
switch (ev.status)
|
||||
{
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
break;
|
||||
|
||||
@@ -52,10 +52,10 @@ bool CoverOrder::setup_hedge(const api::orderman::OrderDefinition& this_def, con
|
||||
|
||||
void CoverOrder::send_hedge_if_new_fills(const api::orderman::OrderState& orig_state, const OrderStateUpdateEvent& new_state)
|
||||
{
|
||||
uint32_t qty = new_state.state.filled_quantity() - orig_state.filled_quantity();
|
||||
uint32_t qty = new_state.filled_quantity - orig_state.filled_quantity();
|
||||
if(qty > 0)
|
||||
{
|
||||
double prx = new_state.state.last_price();
|
||||
double prx = new_state.last_price;
|
||||
if(definition().side() == api::SIDE_BUY) //if this is a buy, I'm going to sell my hedge, nticks higher than the fill price
|
||||
prx = prx + tick_size() * me->hedge_ticks;
|
||||
else
|
||||
|
||||
@@ -121,11 +121,11 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){
|
||||
if (!_active) return;
|
||||
SecurityKey sec_key = SecurityKey(ord_ev.definition->security_key());
|
||||
OrderKey order_key = ord_ev.key;
|
||||
bts::api::orderman::OrderStatus status = ord_ev.state.status();
|
||||
bts::api::orderman::OrderStatus status = ord_ev.status;
|
||||
|
||||
Quantity filled_qty = Quantity (ord_ev.state.filled_quantity());
|
||||
Price last_price = Price(ord_ev.state.last_price()),
|
||||
order_price=Price(ord_ev.state.price());
|
||||
Quantity filled_qty = Quantity (ord_ev.filled_quantity);
|
||||
Price last_price = Price(ord_ev.last_price),
|
||||
order_price=Price(ord_ev.price);
|
||||
if (!SpreaderUtils::order_acknowledged(status)){
|
||||
LOG(OrderMan, Diag, "SpreaderOrder::_on_child_order_update, unack'ed "
|
||||
"callback for key:{} sec_key:{} order_key:{} "
|
||||
@@ -146,7 +146,7 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){
|
||||
key(), sec_key,
|
||||
static_cast<int>(_state_worker->state()), order_key, status,
|
||||
filled_qty, order_price, last_price,
|
||||
ord_ev.state.last_msg(), static_cast<int>(order_error));
|
||||
ord_ev.last_msg, static_cast<int>(order_error));
|
||||
leg_data.order_update_message().on_order_update(ord_ev);
|
||||
if (order_error == ChildOrderError::NONE){
|
||||
if (leg_data.order_update_message().last_update_filled_quantity().value() > 0)
|
||||
@@ -170,7 +170,7 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){
|
||||
key(), sec_key,
|
||||
static_cast<int>(_state_worker->state()), order_key, status,
|
||||
filled_qty, order_price, last_price,
|
||||
ord_ev.state.last_msg (), static_cast<int>(order_error));
|
||||
ord_ev.last_msg, static_cast<int>(order_error));
|
||||
hedger->order_state().on_order_update(ord_ev);
|
||||
if (order_error == ChildOrderError::NONE)
|
||||
_state_worker->on_hedger_order_update (*hedger);
|
||||
@@ -182,10 +182,12 @@ void SpreaderOrder::_on_child_order_update(const OrderStateUpdateEvent& ord_ev){
|
||||
"key:{} sec_key:{} order_key:{} status:{} "
|
||||
"filled_qty:{} last_price:{} msg:{}",
|
||||
key(), sec_key, order_key, status, filled_qty,
|
||||
last_price, ord_ev.state.last_msg ());
|
||||
last_price, ord_ev.last_msg);
|
||||
}
|
||||
_send_check_termination(true);
|
||||
_report_state();
|
||||
LOG(Latency,Diag, "_on_child_order_update k:{} t:{}us", key().value(),
|
||||
(utils::TimeStamp::now() - trace.spreader_on_child_order_update).microseconds());
|
||||
}
|
||||
// State Transformations ////////////////////
|
||||
/////////////////////////////////////////////
|
||||
|
||||
@@ -209,7 +209,7 @@ private:
|
||||
|
||||
static ChildOrderError _get_order_error (const OrderStateUpdateEvent& ord_ev,
|
||||
bool expecting_cancel){
|
||||
bts::api::orderman::OrderStatus order_status = ord_ev.state.status();
|
||||
bts::api::orderman::OrderStatus order_status = ord_ev.status;
|
||||
if (SpreaderUtils::order_in_error_state(order_status))
|
||||
return ChildOrderError::ORDER_STATE_ERROR;
|
||||
if (SpreaderUtils::SpreaderUtils::order_in_cancelled_state(order_status)){
|
||||
@@ -218,12 +218,12 @@ private:
|
||||
// i. cancels with messages are always an error state
|
||||
// ii. when we get a cancel when not expecting thats also
|
||||
// an error state
|
||||
if(ord_ev.state.last_msg().length() > 0 || !expecting_cancel)
|
||||
if(ord_ev.last_msg.length() > 0 || !expecting_cancel)
|
||||
return ChildOrderError::UNEXPECTED_CANCEL_ERROR;
|
||||
}
|
||||
// this is an inelegant way to detect modify errors
|
||||
if (!SpreaderUtils::order_in_terminal_state(order_status) &&
|
||||
ord_ev.state.last_msg().length() > 0)
|
||||
ord_ev.last_msg.length() > 0)
|
||||
return ChildOrderError::MODIFY_ERROR;
|
||||
return ChildOrderError::NONE;
|
||||
}
|
||||
|
||||
@@ -113,11 +113,11 @@ public:
|
||||
// last filled price
|
||||
void on_order_update(const bts::orderman::OrderStateUpdateEvent& e){
|
||||
bts_assert(!_is_live || e.key == order_key());
|
||||
bts_assert(e.state.filled_quantity() >= _filled_quantity.value());
|
||||
_status = e.state.status();
|
||||
_last_filled_quantity = Quantity(e.state.filled_quantity() - _filled_quantity.value());
|
||||
_last_filled_price = Price(e.state.last_price());
|
||||
_last_reported_order_price=Price(e.state.price());
|
||||
bts_assert(e.filled_quantity >= _filled_quantity.value());
|
||||
_status = e.status;
|
||||
_last_filled_quantity = Quantity(e.filled_quantity - _filled_quantity.value());
|
||||
_last_filled_price = Price(e.last_price);
|
||||
_last_reported_order_price=Price(e.price);
|
||||
SpreaderUtils::compute_average_price(_filled_price,
|
||||
_filled_quantity,
|
||||
_last_filled_price,
|
||||
|
||||
@@ -72,9 +72,9 @@ public:
|
||||
// this function checks for the order status (above) or
|
||||
// for the message size (todo:this is a temporary fix)
|
||||
static bool order_in_error_state(const bts::orderman::OrderStateUpdateEvent& ord_ev){
|
||||
bts::api::orderman::OrderStatus order_status = ord_ev.state.status();
|
||||
bts::api::orderman::OrderStatus order_status = ord_ev.status;
|
||||
return order_in_error_state(order_status) ||
|
||||
(!order_in_terminal_state (order_status) && ord_ev.state.last_msg().length() > 0);
|
||||
(!order_in_terminal_state (order_status) && ord_ev.last_msg.length() > 0);
|
||||
}
|
||||
// checks for the 4 states that are designated error states
|
||||
static bool order_in_terminal_state(bts::api::orderman::OrderStatus order_status){
|
||||
|
||||
@@ -103,7 +103,6 @@ void on_order_update (SpreaderChildOrderState& order,
|
||||
order_state.set_filled_quantity (filled_quantity.value());
|
||||
bts::api::orderman::OrderDefinition order_def;
|
||||
OrderStateUpdateEvent e (OrderKey(),OrderKey(),order_def, order_state);
|
||||
e.state = order_state;
|
||||
order.on_order_update(e);
|
||||
}
|
||||
/**********************************************************************/
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import pandas as pd
|
||||
import sqlite3
|
||||
import dateutil
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
log_path = "%s/sparkdata/data/logging/log" % str(Path.home())
|
||||
raw_data = None
|
||||
|
||||
def load():
|
||||
global raw_data
|
||||
global requotes
|
||||
global hedges
|
||||
|
||||
raw_data = pd.read_csv(log_path,sep='|',names=['time','ts','ss','ll','tid','tn','pid','loc','dt','msg'],
|
||||
usecols=lambda x: x in ['time','ts','tn','msg'],
|
||||
parse_dates=True)
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
log_path = sys.argv[1]
|
||||
|
||||
load()
|
||||
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import pandas as pd
|
||||
import sqlite3
|
||||
import dateutil
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# dt = dateutil.parser.parse('2018-10-23 16:35:01.566000')
|
||||
# requotes = requotes[requotes.session_start == dt]
|
||||
#samples = requotes.resample('2S',on='trace_time').mean()
|
||||
#samples.plot()
|
||||
#plotable = requotes[(requotes.total < 1000) & (requotes.trace_time > '2018-11-06')][-200:].set_index('trace_time')
|
||||
|
||||
requotes = None
|
||||
hedges = None
|
||||
db_path = "file:%s/sparkdata/data/databases/perf_trace/perf_trace.sqlite?mode=ro" % str(Path.home())
|
||||
raw_data = None
|
||||
|
||||
def load():
|
||||
global raw_data
|
||||
global requotes
|
||||
global hedges
|
||||
|
||||
c = sqlite3.connect(db_path,uri = True)
|
||||
raw_data = pd.read_sql_query("select * from trace;", c)
|
||||
c.close()
|
||||
|
||||
requotes = raw_data[(raw_data.md>0) ]
|
||||
requotes = requotes.assign (total = (requotes.fix_socket_w - requotes.md) / 1000)
|
||||
requotes = requotes.assign (md = (requotes.spreader_on_book - requotes.md) / 1000)
|
||||
requotes = requotes.assign (spreader = (requotes.order_update - requotes.spreader_on_book) / 1000)
|
||||
requotes = requotes.assign (native_order = (requotes.exe_gw - requotes.spreader_on_book) / 1000)
|
||||
requotes = requotes.assign (fix = (requotes.fix_socket_w - requotes.exe_gw) / 1000)
|
||||
requotes = requotes.assign (session_start = requotes.session_start.map(dateutil.parser.parse))
|
||||
requotes = requotes.assign (trace_time = requotes.trace_time.map(dateutil.parser.parse))
|
||||
|
||||
|
||||
requotes = requotes.drop(['fix_socket_w','spreader_modify_order','send_fix_buffer',
|
||||
'order_update','exe_gw','fix_socket_r','md_src','host', 'do_work_begin',
|
||||
'order_key','version',
|
||||
'build_type', 'spreader_on_book',
|
||||
'spreader_on_child_order_update','md_sn'],axis=1)
|
||||
|
||||
hedges = raw_data[(raw_data.spreader_on_child_order_update>0)]
|
||||
hedges = hedges.assign (total = (hedges.fix_socket_w - hedges.fix_socket_r) / 1000)
|
||||
hedges = hedges.assign (fix_in = (hedges.spreader_on_child_order_update - hedges.fix_socket_r) / 1000)
|
||||
hedges = hedges.assign (spreader = (hedges.order_update - hedges.spreader_on_child_order_update)/ 1000)
|
||||
hedges = hedges.assign (native_order = (hedges.exe_gw - hedges.order_update)/ 1000)
|
||||
hedges = hedges.assign (fix_out = (hedges.fix_socket_w - hedges.exe_gw)/ 1000)
|
||||
|
||||
hedges = hedges.assign (in_native_order = (hedges.send_fix_buffer - hedges.order_update)/ 1000)
|
||||
hedges = hedges.drop(['fix_socket_w','spreader_modify_order','send_fix_buffer',
|
||||
'order_update','exe_gw','fix_socket_r','md_src','host','do_work_begin',
|
||||
'order_key','version',
|
||||
'build_type', 'spreader_on_book',
|
||||
'spreader_on_child_order_update','md_sn'],axis=1)
|
||||
summary()
|
||||
requotes
|
||||
|
||||
def plot(n):
|
||||
plt.clf()
|
||||
p = requotes[-n:][['trace_time','total']]
|
||||
q = p.set_index('trace_time')
|
||||
plt.plot(q)
|
||||
|
||||
|
||||
def summary():
|
||||
grouped = requotes.groupby(requotes['session_start'])
|
||||
counts = grouped.count()['total']
|
||||
medians = grouped.median()
|
||||
medians['count'] = counts
|
||||
print ("\n\nRequotes")
|
||||
print (medians)
|
||||
|
||||
grouped = hedges.groupby(hedges['session_start'])
|
||||
counts = grouped.count()['total']
|
||||
medians = grouped.median()
|
||||
medians['count'] = counts
|
||||
print ("\n\nHedges")
|
||||
print (medians)
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
db_path = sys.argv[1]
|
||||
|
||||
load()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
if [ $# -ne 2 ];
|
||||
then
|
||||
echo
|
||||
echo " Syntax: quick_stats.sh tick_to_order|fill_to_order"
|
||||
echo " Syntax: quick_stats.sh log_file tick_to_order|fill_to_order"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -22,6 +22,6 @@ sleep $TRACE_DURATION
|
||||
lttng stop
|
||||
lttng destroy
|
||||
mkdir -p trace_data
|
||||
babeltrace ~/lttng-traces/* > trace_data/raw_trace.txt
|
||||
babeltrace --clock-seconds ~/lttng-traces/* > trace_data/raw_trace.txt
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "lib/plugin/SparkServices.h"
|
||||
#include "lib/utils/thread_manager.h"
|
||||
#include "lib/utils/type_name.h"
|
||||
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
namespace bts {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/domain_model/SecurityKey.h"
|
||||
#include "orderman_utils/orderman_utils.h"
|
||||
|
||||
namespace bts {
|
||||
namespace api {
|
||||
namespace orderman {
|
||||
class OrderDefinition;
|
||||
}
|
||||
} // namespace api
|
||||
namespace orderman2 {
|
||||
|
||||
class OrderState;
|
||||
|
||||
class IOrderManagerObserver {
|
||||
public:
|
||||
void subscribe_book(SecurityKey, void *sub);
|
||||
void request_new_fill_buffers(config::JetFIX::Connection const &,
|
||||
size_t n_buffers, void *sub);
|
||||
void request_new_orders(api::orderman::OrderDefinition const &,
|
||||
OrderKey parent_key, size_t n_orders, void *sub);
|
||||
void send_fix(size_t gw_idx, jetfix::OutFIXPtr const &);
|
||||
};
|
||||
|
||||
} // namespace orderman2
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "OrderManager2.h"
|
||||
#include "IOrderManagerObserver.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman2 {
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "orderman_utils/orderman_utils.h"
|
||||
#include "orderman_utils/Book.h"
|
||||
#include "lib/jetfix/common/OutFIXPtr.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace bts {
|
||||
namespace api { class Security;}
|
||||
namespace orderman2 {
|
||||
|
||||
class Order;
|
||||
class IOrderManagerObserver;
|
||||
class ExecutionReport;
|
||||
|
||||
class OrderManager {
|
||||
OrderManager();
|
||||
|
||||
void init(IOrderManagerObserver &observer);
|
||||
|
||||
void on_activate(Order &, Price , Quantity);
|
||||
void on_update(Order&, Price , Quantity);
|
||||
void on_cancel(Order&);
|
||||
void on_book_update(Book const&b,void*sub);
|
||||
void on_execution_report(ExecutionReport &);
|
||||
|
||||
void on_securities(std::vector<api::Security const*> const&);
|
||||
void on_new_fill_buffers(std::vector<jetfix::OutFIXPtr> const&,void*sub);
|
||||
void on_new_orders(std::vector<Order*> const&,void*sub);
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/config/protos/MarketData.pb.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
|
||||
|
||||
namespace bts {
|
||||
namespace orderman2 {
|
||||
|
||||
using BookSide = std::array<md::PriceSize,5> ;
|
||||
|
||||
class Book {
|
||||
public:
|
||||
Book () :
|
||||
_security_key(),
|
||||
_book()
|
||||
{}
|
||||
|
||||
Book (SecurityKey key) :
|
||||
_security_key(key),
|
||||
_book()
|
||||
{}
|
||||
|
||||
Book (SecurityKey key,
|
||||
BookSide const&bid,
|
||||
BookSide const&ask) :
|
||||
_security_key(key),
|
||||
_book {bid,ask}
|
||||
{}
|
||||
|
||||
Book (Book const&rhs)
|
||||
: _security_key(rhs._security_key),
|
||||
_book(rhs._book)
|
||||
{}
|
||||
|
||||
Book &operator=(Book const &rhs)
|
||||
{
|
||||
_security_key = rhs._security_key;
|
||||
_book = rhs._book;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SecurityKey security_key() const {return _security_key;} ;
|
||||
|
||||
BookSide const &bid () const {return _book[0];}
|
||||
BookSide const &ask () const {return _book[1];}
|
||||
BookSide &bid () {return _book[0];}
|
||||
BookSide &ask () {return _book[1];}
|
||||
|
||||
size_t n_levels() const {return std::tuple_size<BookSide>();}
|
||||
|
||||
BookSide const& side(api::Side bs) const
|
||||
{
|
||||
bts_assert_d(bs != api::SIDE_UNDEFINED);
|
||||
return _book[bs - api::SIDE_BUY];
|
||||
}
|
||||
|
||||
BookSide & side(api::Side bs)
|
||||
{
|
||||
bts_assert_d(bs != api::SIDE_UNDEFINED);
|
||||
return _book[bs - api::SIDE_BUY];
|
||||
}
|
||||
|
||||
private:
|
||||
friend class MDSource;
|
||||
SecurityKey _security_key;
|
||||
std::array<BookSide,2> _book;
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/utils/ValueWrapper.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman2 {
|
||||
using Price = utils::ValueWrapper<struct PriceTag,double>;
|
||||
using Quantity = utils::ValueWrapper<struct QuantityTag,uint32_t>;
|
||||
using OrderKey = utils::ValueWrapper<struct OrderKeyTag, uint32_t>;
|
||||
}}
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/persistence/persistence_utils.h"
|
||||
#include "lib/utils/Sqlite_utils.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
#include "lib/utils/bts_no_copy.h"
|
||||
#include "lib/utils/defer.h"
|
||||
#include "lib/utils/file_utils.h"
|
||||
#include "lib/persistence/persistence_utils.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <sqlite/sqlite3.h>
|
||||
@@ -15,10 +16,9 @@
|
||||
namespace bts {
|
||||
namespace persistence {
|
||||
|
||||
|
||||
struct SqliteStore::PImpl {
|
||||
PImpl(std::string const &store_root, std::string const &db_name)
|
||||
: db(db_name), db_path(persistence::storage_location(db,store_root)),
|
||||
: db(db_name), db_path(persistence::storage_location(db, store_root)),
|
||||
conn(nullptr, sqlite3_close), insert(nullptr, sqlite3_finalize),
|
||||
remove(nullptr, sqlite3_finalize),
|
||||
remove_all(nullptr, sqlite3_finalize),
|
||||
@@ -156,7 +156,22 @@ void SqliteStore::remove(std::string const &ns,
|
||||
SQLITE_CHK(sqlite3_bind_text(me->remove.get(), 2, k.c_str(), k.size(),
|
||||
SQLITE_TRANSIENT),
|
||||
me->conn);
|
||||
bts_assert(sqlite3_step(me->remove.get()) == SQLITE_DONE);
|
||||
auto r = sqlite3_step(me->remove.get());
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Could not delete row in store. Will retry once. error_code: {} "
|
||||
"ns:{}, k: {}",
|
||||
r, ns, k);
|
||||
sleep_for(2s);
|
||||
r = sqlite3_step(me->remove.get());
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Failed a second time to delete row. Bailing out. error_code: "
|
||||
"{}",
|
||||
r);
|
||||
bts_assert(r == SQLITE_DONE);
|
||||
}
|
||||
}
|
||||
SQLITE_CHK(sqlite3_reset(me->remove.get()), me->conn);
|
||||
}
|
||||
}
|
||||
@@ -166,7 +181,22 @@ void SqliteStore::remove_all(std::string const &ns) {
|
||||
SQLITE_CHK(sqlite3_bind_text(me->remove_all.get(), 1, ns.c_str(), ns.size(),
|
||||
SQLITE_TRANSIENT),
|
||||
me->conn);
|
||||
bts_assert(sqlite3_step(me->remove_all.get()) == SQLITE_DONE);
|
||||
auto r = sqlite3_step(me->remove_all.get());
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Could not delete all rows in store. Will retry once. error_code: {} "
|
||||
"ns:{}",
|
||||
r, ns);
|
||||
sleep_for(2s);
|
||||
r = sqlite3_step(me->remove_all.get());
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Failed a second time to delete all rows. Bailing out. error_code: "
|
||||
"{}",
|
||||
r);
|
||||
bts_assert(r == SQLITE_DONE);
|
||||
}
|
||||
}
|
||||
SQLITE_CHK(sqlite3_reset(me->remove_all.get()), me->conn);
|
||||
}
|
||||
|
||||
@@ -182,7 +212,20 @@ void SqliteStore::insert(std::string const &ns, std::string const &k,
|
||||
SQLITE_TRANSIENT),
|
||||
me->conn);
|
||||
auto r = sqlite3_step(me->insert.get());
|
||||
bts_assert(r == SQLITE_DONE);
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Could not insert row in store. Will retry once. error_code: {} ns: "
|
||||
"{}, k: {}, v: {}",
|
||||
r, ns, k, v);
|
||||
sleep_for(2s);
|
||||
r = sqlite3_step(me->insert.get());
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Failed a second time to insert row. Bailing out. error_code: {}",
|
||||
r);
|
||||
bts_assert(r == SQLITE_DONE);
|
||||
}
|
||||
}
|
||||
SQLITE_CHK(sqlite3_reset(me->insert.get()), me->conn);
|
||||
}
|
||||
|
||||
@@ -198,7 +241,20 @@ void SqliteStore::update(std::string const &ns, std::string const &k,
|
||||
SQLITE_TRANSIENT),
|
||||
me->conn);
|
||||
auto r = sqlite3_step(me->update.get());
|
||||
bts_assert(r == SQLITE_DONE);
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Could not update row in store. Will retry once. error_code: {} ns: "
|
||||
"{}, k: {}, v: {}",
|
||||
r, ns, k, v);
|
||||
sleep_for(2s);
|
||||
r = sqlite3_step(me->update.get());
|
||||
if (r != SQLITE_DONE) {
|
||||
LOG(persist, Error,
|
||||
"Failed a second time to update row. Bailing out. error_code: {}",
|
||||
r);
|
||||
bts_assert(r == SQLITE_DONE);
|
||||
}
|
||||
}
|
||||
SQLITE_CHK(sqlite3_reset(me->update.get()), me->conn);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ inline bool equal(google::protobuf::Timestamp const &t1, google::protobuf::Times
|
||||
return t1.seconds() == t2.seconds() && t1.nanos() == t2.nanos();
|
||||
}
|
||||
|
||||
inline double to_double_time(google::protobuf::Timestamp const &t1)
|
||||
{return t1.seconds() + t1.nanos()/1e9;}
|
||||
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Boost Software License - Version 1.0 - August 17th, 2003
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
namespace stdext {
|
||||
|
||||
namespace inplace_function_detail {
|
||||
|
||||
static constexpr size_t InplaceFunctionDefaultCapacity = 32;
|
||||
|
||||
#if defined(__GLIBCXX__) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61458
|
||||
template<size_t Cap>
|
||||
union aligned_storage_helper {
|
||||
struct double1 { double a; };
|
||||
struct double4 { double a[4]; };
|
||||
template<class T> using maybe = std::conditional_t<(Cap >= sizeof(T)), T, char>;
|
||||
char real_data[Cap];
|
||||
maybe<int> a;
|
||||
maybe<long> b;
|
||||
maybe<long long> c;
|
||||
maybe<void*> d;
|
||||
maybe<void(*)()> e;
|
||||
maybe<double1> f;
|
||||
maybe<double4> g;
|
||||
maybe<long double> h;
|
||||
};
|
||||
|
||||
template<size_t Cap, size_t Align = std::alignment_of<aligned_storage_helper<Cap>>::value>
|
||||
struct aligned_storage {
|
||||
using type = std::aligned_storage_t<Cap, Align>;
|
||||
};
|
||||
|
||||
template<size_t Cap, size_t Align = std::alignment_of<aligned_storage_helper<Cap>>::value>
|
||||
using aligned_storage_t = typename aligned_storage<Cap, Align>::type;
|
||||
#else
|
||||
using std::aligned_storage;
|
||||
using std::aligned_storage_t;
|
||||
#endif
|
||||
|
||||
template<typename T> struct wrapper
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args> struct vtable
|
||||
{
|
||||
using storage_ptr_t = void*;
|
||||
|
||||
using invoke_ptr_t = R(*)(storage_ptr_t, Args&&...);
|
||||
using process_ptr_t = void(*)(storage_ptr_t, storage_ptr_t);
|
||||
using destructor_ptr_t = void(*)(storage_ptr_t);
|
||||
|
||||
const invoke_ptr_t invoke_ptr;
|
||||
const process_ptr_t copy_ptr;
|
||||
const process_ptr_t relocate_ptr;
|
||||
const destructor_ptr_t destructor_ptr;
|
||||
|
||||
explicit constexpr vtable() noexcept :
|
||||
invoke_ptr{ [](storage_ptr_t, Args&&...) -> R
|
||||
{ throw std::bad_function_call(); }
|
||||
},
|
||||
copy_ptr{ [](storage_ptr_t, storage_ptr_t) noexcept -> void {} },
|
||||
relocate_ptr{ [](storage_ptr_t, storage_ptr_t) noexcept -> void {} },
|
||||
destructor_ptr{ [](storage_ptr_t) noexcept -> void {} }
|
||||
{}
|
||||
|
||||
template<typename C> explicit constexpr vtable(wrapper<C>) noexcept :
|
||||
invoke_ptr{ [](storage_ptr_t storage_ptr, Args&&... args)
|
||||
noexcept(noexcept(std::declval<C>()(args...))) -> R
|
||||
{ return (*static_cast<C*>(storage_ptr))(
|
||||
std::forward<Args>(args)...
|
||||
); }
|
||||
},
|
||||
copy_ptr{ [](storage_ptr_t dst_ptr, storage_ptr_t src_ptr)
|
||||
noexcept(std::is_nothrow_copy_constructible<C>::value) -> void
|
||||
{ ::new (dst_ptr) C{ (*static_cast<C*>(src_ptr)) }; }
|
||||
},
|
||||
relocate_ptr{ [](storage_ptr_t dst_ptr, storage_ptr_t src_ptr)
|
||||
noexcept(std::is_nothrow_move_constructible<C>::value) -> void
|
||||
{
|
||||
::new (dst_ptr) C{ std::move(*static_cast<C*>(src_ptr)) };
|
||||
static_cast<C*>(src_ptr)->~C();
|
||||
}
|
||||
},
|
||||
destructor_ptr{ [](storage_ptr_t src_ptr)
|
||||
noexcept -> void
|
||||
{ static_cast<C*>(src_ptr)->~C(); }
|
||||
}
|
||||
{}
|
||||
|
||||
vtable(const vtable&) = delete;
|
||||
vtable(vtable&&) = delete;
|
||||
|
||||
vtable& operator= (const vtable&) = delete;
|
||||
vtable& operator= (vtable&&) = delete;
|
||||
|
||||
~vtable() = default;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
#if __cplusplus >= 201703L
|
||||
inline constexpr
|
||||
#endif
|
||||
vtable<R, Args...> empty_vtable{};
|
||||
|
||||
template<size_t DstCap, size_t DstAlign, size_t SrcCap, size_t SrcAlign>
|
||||
struct is_valid_inplace_dst : std::true_type
|
||||
{
|
||||
static_assert(DstCap >= SrcCap,
|
||||
"Can't squeeze larger inplace_function into a smaller one"
|
||||
);
|
||||
|
||||
static_assert(DstAlign % SrcAlign == 0,
|
||||
"Incompatible inplace_function alignments"
|
||||
);
|
||||
};
|
||||
|
||||
} // namespace inplace_function_detail
|
||||
|
||||
template<
|
||||
typename Signature,
|
||||
size_t Capacity = inplace_function_detail::InplaceFunctionDefaultCapacity,
|
||||
size_t Alignment = std::alignment_of<inplace_function_detail::aligned_storage_t<Capacity>>::value
|
||||
>
|
||||
class inplace_function; // unspecified
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename... Args,
|
||||
size_t Capacity,
|
||||
size_t Alignment
|
||||
>
|
||||
class inplace_function<R(Args...), Capacity, Alignment>
|
||||
{
|
||||
public:
|
||||
using capacity = std::integral_constant<size_t, Capacity>;
|
||||
using alignment = std::integral_constant<size_t, Alignment>;
|
||||
|
||||
using storage_t = inplace_function_detail::aligned_storage_t<Capacity, Alignment>;
|
||||
using vtable_t = inplace_function_detail::vtable<R, Args...>;
|
||||
using vtable_ptr_t = const vtable_t*;
|
||||
|
||||
template <typename, size_t, size_t> friend class inplace_function;
|
||||
|
||||
inplace_function() noexcept :
|
||||
vtable_ptr_{std::addressof(inplace_function_detail::empty_vtable<R, Args...>)}
|
||||
{}
|
||||
|
||||
template<
|
||||
typename T,
|
||||
typename C = std::decay_t<T>,
|
||||
typename = std::enable_if_t<
|
||||
!(std::is_same<C, inplace_function>::value
|
||||
|| std::is_convertible<C, inplace_function>::value)
|
||||
>
|
||||
>
|
||||
inplace_function(T&& closure)
|
||||
{
|
||||
#if __cplusplus >= 201703L
|
||||
static_assert(std::is_invocable_r<R, C, Args...>::value,
|
||||
"inplace_function cannot be constructed from non-callable type"
|
||||
);
|
||||
#endif
|
||||
static_assert(std::is_copy_constructible<C>::value,
|
||||
"inplace_function cannot be constructed from non-copyable type"
|
||||
);
|
||||
|
||||
static_assert(sizeof(C) <= Capacity,
|
||||
"inplace_function cannot be constructed from object with this (large) size"
|
||||
);
|
||||
|
||||
static_assert(Alignment % std::alignment_of<C>::value == 0,
|
||||
"inplace_function cannot be constructed from object with this (large) alignment"
|
||||
);
|
||||
|
||||
static const vtable_t vt{inplace_function_detail::wrapper<C>{}};
|
||||
vtable_ptr_ = std::addressof(vt);
|
||||
|
||||
::new (std::addressof(storage_)) C{std::forward<T>(closure)};
|
||||
}
|
||||
|
||||
inplace_function(std::nullptr_t) noexcept :
|
||||
vtable_ptr_{std::addressof(inplace_function_detail::empty_vtable<R, Args...>)}
|
||||
{}
|
||||
|
||||
inplace_function(const inplace_function& other) :
|
||||
vtable_ptr_{other.vtable_ptr_}
|
||||
{
|
||||
vtable_ptr_->copy_ptr(
|
||||
std::addressof(storage_),
|
||||
std::addressof(other.storage_)
|
||||
);
|
||||
}
|
||||
|
||||
inplace_function(inplace_function&& other) :
|
||||
vtable_ptr_{std::exchange(other.vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable<R, Args...>))}
|
||||
{
|
||||
vtable_ptr_->relocate_ptr(
|
||||
std::addressof(storage_),
|
||||
std::addressof(other.storage_)
|
||||
);
|
||||
}
|
||||
|
||||
inplace_function& operator= (std::nullptr_t) noexcept
|
||||
{
|
||||
vtable_ptr_->destructor_ptr(std::addressof(storage_));
|
||||
vtable_ptr_ = std::addressof(inplace_function_detail::empty_vtable<R, Args...>);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inplace_function& operator= (const inplace_function& other)
|
||||
{
|
||||
if(this != std::addressof(other))
|
||||
{
|
||||
vtable_ptr_->destructor_ptr(std::addressof(storage_));
|
||||
|
||||
vtable_ptr_ = other.vtable_ptr_;
|
||||
vtable_ptr_->copy_ptr(
|
||||
std::addressof(storage_),
|
||||
std::addressof(other.storage_)
|
||||
);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inplace_function& operator= (inplace_function&& other)
|
||||
{
|
||||
if(this != std::addressof(other))
|
||||
{
|
||||
vtable_ptr_->destructor_ptr(std::addressof(storage_));
|
||||
|
||||
vtable_ptr_ = std::exchange(other.vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable<R, Args...>));
|
||||
vtable_ptr_->relocate_ptr(
|
||||
std::addressof(storage_),
|
||||
std::addressof(other.storage_)
|
||||
);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~inplace_function()
|
||||
{
|
||||
vtable_ptr_->destructor_ptr(std::addressof(storage_));
|
||||
}
|
||||
|
||||
R operator() (Args... args) const
|
||||
{
|
||||
return vtable_ptr_->invoke_ptr(
|
||||
std::addressof(storage_),
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
constexpr bool operator== (std::nullptr_t) const noexcept
|
||||
{
|
||||
return !operator bool();
|
||||
}
|
||||
|
||||
constexpr bool operator!= (std::nullptr_t) const noexcept
|
||||
{
|
||||
return operator bool();
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const noexcept
|
||||
{
|
||||
return vtable_ptr_ != std::addressof(inplace_function_detail::empty_vtable<R, Args...>);
|
||||
}
|
||||
|
||||
template<size_t Cap, size_t Align>
|
||||
operator inplace_function<R(Args...), Cap, Align>() const&
|
||||
{
|
||||
static_assert(inplace_function_detail::is_valid_inplace_dst<
|
||||
Cap, Align, Capacity, Alignment
|
||||
>::value, "conversion not allowed");
|
||||
|
||||
return {vtable_ptr_, vtable_ptr_->copy_ptr, std::addressof(storage_)};
|
||||
}
|
||||
|
||||
template<size_t Cap, size_t Align>
|
||||
operator inplace_function<R(Args...), Cap, Align>() &&
|
||||
{
|
||||
static_assert(inplace_function_detail::is_valid_inplace_dst<
|
||||
Cap, Align, Capacity, Alignment
|
||||
>::value, "conversion not allowed");
|
||||
|
||||
auto vtable_ptr = std::exchange(vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable<R, Args...>));
|
||||
|
||||
return {vtable_ptr, vtable_ptr->relocate_ptr, std::addressof(storage_)};
|
||||
}
|
||||
|
||||
void swap(inplace_function& other)
|
||||
{
|
||||
if (this == std::addressof(other)) return;
|
||||
|
||||
storage_t tmp;
|
||||
vtable_ptr_->relocate_ptr(
|
||||
std::addressof(tmp),
|
||||
std::addressof(storage_)
|
||||
);
|
||||
|
||||
other.vtable_ptr_->relocate_ptr(
|
||||
std::addressof(storage_),
|
||||
std::addressof(other.storage_)
|
||||
);
|
||||
|
||||
vtable_ptr_->relocate_ptr(
|
||||
std::addressof(other.storage_),
|
||||
std::addressof(tmp)
|
||||
);
|
||||
|
||||
std::swap(vtable_ptr_, other.vtable_ptr_);
|
||||
}
|
||||
|
||||
friend void swap(inplace_function& lhs, inplace_function& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
vtable_ptr_t vtable_ptr_;
|
||||
mutable storage_t storage_;
|
||||
|
||||
inplace_function(
|
||||
vtable_ptr_t vtable_ptr,
|
||||
typename vtable_t::process_ptr_t process_ptr,
|
||||
typename vtable_t::storage_ptr_t storage_ptr
|
||||
) : vtable_ptr_{vtable_ptr}
|
||||
{
|
||||
process_ptr(std::addressof(storage_), storage_ptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace stdext
|
||||
@@ -264,9 +264,9 @@ void DynamicIcebergOrder::on_child_order_update(
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
if (ev.key == me->child.order.key()) {
|
||||
me->child.state = ev.state;
|
||||
me->child.state = ev.rebuild_state();
|
||||
|
||||
switch (ev.state.status()) {
|
||||
switch (me->child.state.status()) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
@@ -312,7 +312,7 @@ void DynamicIcebergOrder::on_child_order_update(
|
||||
"DynamicIceberg order {} received update for non active child "
|
||||
"order{} . update state = {} ",
|
||||
key().value(), me->child.order.key().value(),
|
||||
utils::pb::to_string(ev.state));
|
||||
utils::pb::to_string(ev.rebuild_state()));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
set(sources bts_trace.cpp;cmds/AutoCert.cpp;cmds/Benchmark.cpp;cmds/CmdRegistry.cpp;cmds/ConfigCheck.cpp;cmds/Help.cpp;cmds/Md.cpp;cmds/QuickTest.cpp;cmds/Run.cpp;cmds/RunSim.cpp;cmds/Span.cpp;cmds/Test.cpp;cmds/TestCeloxica.cpp;cmds/Web.cpp;dspark/mirage/quick_queue/quick_queue.cpp;exchange_sim/ExchangeSim.cpp;exchange_sim/ExchangeSimApplication.cpp;exchange_sim/book/Book.cpp;exchange_sim/book/ExchangeSim.proto;exchange_sim/book/Order.cpp;exchange_sim/book/OrderMatcher.cpp;exchange_sim/book/book_transform.cpp;exchange_sim/tests/test_book_transform.cpp;http/ApiGateway.cpp;http/WebServer.cpp;main.cpp;md/platforms/celoxica/CXListener.cpp;md/platforms/celoxica/CXMain.cpp;md/platforms/celoxica/tests/cx_tests.cpp;md/platforms/mdp3_onixs/MDP3Listener.cpp;md/platforms/mdp3_onixs/MDP3Main.cpp;md/platforms/mdp3_onixs/tests/mdp3_tests.cpp;md/run_md.cpp;position/IMarginObserver.cpp;position/IPositionObserver.cpp;position/MarginServiceCore.cpp;position/PositionServiceCore.cpp;position/PositionServiceServer.cpp;position/tests/PositionTests.cpp;support/ErrorReportService.cpp;support/ShellLatencyServer.cpp;user/AdminServiceServer.cpp;user/UserServiceServer.cpp;user/tests/admin_service_tests.cpp)
|
||||
set(sources bts_trace.cpp;cmds/AutoCert.cpp;cmds/Benchmark.cpp;cmds/CmdRegistry.cpp;cmds/ConfigCheck.cpp;cmds/Help.cpp;cmds/Md.cpp;cmds/PrintHedgeOrders.cpp;cmds/QuickTest.cpp;cmds/Run.cpp;cmds/RunSim.cpp;cmds/Span.cpp;cmds/Test.cpp;cmds/TestCeloxica.cpp;cmds/Web.cpp;dspark/mirage/quick_queue/quick_queue.cpp;exchange_sim/ExchangeSim.cpp;exchange_sim/ExchangeSimApplication.cpp;exchange_sim/book/Book.cpp;exchange_sim/book/ExchangeSim.proto;exchange_sim/book/Order.cpp;exchange_sim/book/OrderMatcher.cpp;exchange_sim/book/book_transform.cpp;exchange_sim/tests/test_book_transform.cpp;http/ApiGateway.cpp;http/WebServer.cpp;main.cpp;md/ChannelVolume.cpp;md/MarketDataAuxiliaryServiceServer.cpp;md/VolumeAtPriceState.cpp;md/platforms/celoxica/CXListener.cpp;md/platforms/celoxica/CXMain.cpp;md/platforms/celoxica/tests/cx_tests.cpp;md/platforms/mdp3_onixs/MDP3Listener.cpp;md/platforms/mdp3_onixs/MDP3Main.cpp;md/platforms/mdp3_onixs/tests/mdp3_tests.cpp;md/run_md.cpp;position/IMarginObserver.cpp;position/IPositionObserver.cpp;position/MarginServiceCore.cpp;position/PositionServiceCore.cpp;position/PositionServiceServer.cpp;position/tests/PositionTests.cpp;support/ErrorReportService.cpp;support/ShellLatencyServer.cpp;user/AdminServiceServer.cpp;user/UserServiceServer.cpp;user/tests/admin_service_tests.cpp)
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "lib/mercury/actors/Actor.h"
|
||||
#include "lib/mercury/common/FatWrapper.h"
|
||||
#include "lib/mercury/executor/Executor.h"
|
||||
#include "lib/orderman/events/OrderStateUpdateEvent.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/utils/Puid.h"
|
||||
@@ -30,12 +31,87 @@
|
||||
#include <moodycamel/concurrentqueue.h>
|
||||
#include <moodycamel/readerwriterqueue.h>
|
||||
#include <mutex>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <tbb/concurrent_queue.h>
|
||||
|
||||
namespace bts {
|
||||
namespace cmd {
|
||||
|
||||
using namespace orderman;
|
||||
|
||||
api::orderman::NativeOrderState const *
|
||||
get_native_state(api::orderman::OrderState const &st) {
|
||||
switch (st.custom_case()) {
|
||||
case api::orderman::OrderState::kMarket:
|
||||
return &st.market().native_state();
|
||||
case api::orderman::OrderState::kLimit:
|
||||
return &st.limit().native_state();
|
||||
case api::orderman::OrderState::kStop:
|
||||
return &st.stop().native_state();
|
||||
case api::orderman::OrderState::kStopLimit:
|
||||
return &st.stop_limit().native_state();
|
||||
default:
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
class QuickOrderStateUpdateEvent {
|
||||
public:
|
||||
QuickOrderStateUpdateEvent(OrderKey key, OrderKey parent_key,
|
||||
api::orderman::OrderDefinition const &def,
|
||||
api::orderman::OrderState const &state,
|
||||
PerfTrace const &trace = PerfTrace())
|
||||
: key(key), parent_key(parent_key), trace(trace), definition(&def) {
|
||||
|
||||
status = state.status();
|
||||
price = state.price();
|
||||
quantity = state.quantity();
|
||||
filled_quantity = state.quantity();
|
||||
last_price = state.last_price();
|
||||
avg_price = state.avg_price();
|
||||
last_msg = state.last_msg();
|
||||
custom = state.custom_case();
|
||||
|
||||
auto native_state = get_native_state(state);
|
||||
if (native_state) {
|
||||
exchange_order_id = native_state->exchange_order_id();
|
||||
last_msg_seq_num = native_state->last_msg_seq_num();
|
||||
sub_error_code = native_state->sub_error_code();
|
||||
native_status = native_state->native_status();
|
||||
routing_record = native_state->routing_record();
|
||||
native_type = native_state->native_type();
|
||||
orderman::str_to(native_state->last_transact_time(),&last_transact_time);
|
||||
}
|
||||
}
|
||||
|
||||
OrderKey key;
|
||||
OrderKey parent_key;
|
||||
|
||||
// common state
|
||||
api::orderman::OrderStatus status;
|
||||
double price;
|
||||
uint32_t quantity;
|
||||
uint32_t filled_quantity;
|
||||
double last_price;
|
||||
double avg_price;
|
||||
std::string last_msg;
|
||||
|
||||
PerfTrace trace;
|
||||
api::orderman::OrderState::CustomCase custom;
|
||||
|
||||
// native order state
|
||||
std::string exchange_order_id;
|
||||
uint64_t last_msg_seq_num;
|
||||
api::orderman::NativeOrderState::SubError sub_error_code;
|
||||
api::orderman::NativeOrderStatus native_status;
|
||||
api::orderman::RoutingRecord routing_record;
|
||||
api::orderman::NativeOrderType native_type;
|
||||
mercury::TimeStampStr last_transact_time;
|
||||
|
||||
api::orderman::OrderDefinition const *definition;
|
||||
};
|
||||
|
||||
auto sec_str = " id: 3\n"
|
||||
" symbol: \"ES\"\n"
|
||||
" exchange: VENUE_GLBX\n"
|
||||
@@ -77,37 +153,59 @@ auto order_str = " order_key: 189285\n"
|
||||
" cti_code: CTI_CTI1\n"
|
||||
" order_status: OS_UNACKNOWLEDGED\n";
|
||||
|
||||
auto order_state_str = " status: ORDER_STATUS_COMPLETED\n"
|
||||
" price: 65.56\n"
|
||||
" quantity: 5\n"
|
||||
" filled_quantity: 5\n"
|
||||
" last_price: 65.56\n"
|
||||
" avg_price: 65.56\n"
|
||||
auto order_state_str = " status: ORDER_STATUS_WORKING\n"
|
||||
" price: 73.42\n"
|
||||
" quantity: 25\n"
|
||||
" last_msg: \"\"\n"
|
||||
" last_change {\n"
|
||||
" seconds: 1532982945\n"
|
||||
" nanos: 378466000\n"
|
||||
" seconds: 1541621138\n"
|
||||
" nanos: 899901000\n"
|
||||
" }\n"
|
||||
" limit {\n"
|
||||
" native_state {\n"
|
||||
" exchange_order_id: \"12345678901234567\"\n"
|
||||
" native_status: NATIVE_ORDER_STATUS_FILLED\n"
|
||||
" last_msg_seq_num: 868\n"
|
||||
" native_status: NATIVE_ORDER_STATUS_REPLACED\n"
|
||||
" last_msg_seq_num: 31869\n"
|
||||
" routing_record {\n"
|
||||
" session: \"sim\"\n"
|
||||
" account: \"ca_ACC A\"\n"
|
||||
" account: \"ACC A\"\n"
|
||||
" operator_id: \"op_id_bts\"\n"
|
||||
" cti_code: CTI_CODE_CTI_CODE1\n"
|
||||
" customer_or_firm: CUSTOMER_OR_FIRM_FIRM\n"
|
||||
" location: \"us,nc\"\n"
|
||||
" }\n"
|
||||
" native_type: NATIVE_ORDER_TYPE_LIMIT\n"
|
||||
" last_transact_time: \"20181107-20:00:46.000\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" created {\n"
|
||||
" seconds: 1532962902\n"
|
||||
" nanos: 989007000\n"
|
||||
" seconds: 1541619812\n"
|
||||
" nanos: 895210000\n"
|
||||
" }\n";
|
||||
|
||||
auto clean_os =
|
||||
" status: ORDER_STATUS_WORKING\n"
|
||||
" price: 73.42\n"
|
||||
" quantity: 25\n"
|
||||
" last_msg: \"\"\n"
|
||||
" limit {\n"
|
||||
" native_state {\n"
|
||||
//" exchange_order_id: \"12345678901234567\"\n"
|
||||
" native_status: NATIVE_ORDER_STATUS_REPLACED\n"
|
||||
" last_msg_seq_num: 31869\n"
|
||||
// " routing_record {\n"
|
||||
// " session: \"sim\"\n"
|
||||
// " account: \"ACC A\"\n"
|
||||
// " operator_id: \"op_id_bts\"\n"
|
||||
// " cti_code: CTI_CODE_CTI_CODE1\n"
|
||||
// " customer_or_firm: CUSTOMER_OR_FIRM_FIRM\n"
|
||||
// " location: \"us,nc\"\n"
|
||||
// " }\n"
|
||||
" native_type: NATIVE_ORDER_TYPE_LIMIT\n"
|
||||
" last_transact_time: \"20181107-20:00:46.000\"\n"
|
||||
" }\n"
|
||||
" }\n";
|
||||
|
||||
static void gen_id(benchmark::State &state) {
|
||||
std::string scope = "benchmark";
|
||||
|
||||
@@ -160,16 +258,29 @@ static void copy_perf_trace(benchmark::State &state) {
|
||||
}
|
||||
BENCHMARK(copy_perf_trace);
|
||||
|
||||
// static void serialize_order(benchmark::State &state) {
|
||||
// auto order_state =
|
||||
// utils::pb::from_string<api::orderman::OrderState>(order_state_str);
|
||||
// auto
|
||||
// auto order_state_cpy = order_state;
|
||||
// for (auto _ : state) {
|
||||
// order_state_cpy = order_state;
|
||||
// }
|
||||
// }
|
||||
// BENCHMARK(copy_order);
|
||||
static void init_with_clean_os(benchmark::State &state) {
|
||||
api::orderman::OrderDefinition def;
|
||||
auto order_state =
|
||||
utils::pb::from_string<api::orderman::OrderState>(clean_os);
|
||||
PerfTrace trace;
|
||||
OrderKey k(1);
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(
|
||||
QuickOrderStateUpdateEvent(k, k, def, order_state, trace));
|
||||
}
|
||||
BENCHMARK(init_with_clean_os);
|
||||
|
||||
static void init_with_old_order_update(benchmark::State &state) {
|
||||
api::orderman::OrderDefinition def;
|
||||
auto order_state =
|
||||
utils::pb::from_string<api::orderman::OrderState>(order_state_str);
|
||||
PerfTrace trace;
|
||||
OrderKey k(1);
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(
|
||||
orderman::OrderStateUpdateEvent(k, k, def, order_state, trace));
|
||||
}
|
||||
BENCHMARK(init_with_old_order_update);
|
||||
|
||||
static void serialize_update(benchmark::State &state) {
|
||||
api::orderman::Update update;
|
||||
@@ -446,7 +557,6 @@ static void tbb_concurrent_queue(benchmark::State &state) {
|
||||
}
|
||||
BENCHMARK(tbb_concurrent_queue);
|
||||
|
||||
|
||||
static void boost_spsc(benchmark::State &state) {
|
||||
boost::lockfree::spsc_queue<int> q(10000);
|
||||
|
||||
@@ -652,7 +762,7 @@ static void moodycamel_concurrent_queue(benchmark::State &state) {
|
||||
using Q = moodycamel::ConcurrentQueue<int>;
|
||||
Q queue(8);
|
||||
int i = 0;
|
||||
|
||||
|
||||
for (auto _ : state) {
|
||||
queue.enqueue(++i); // NOLINT
|
||||
benchmark::DoNotOptimize(queue.try_dequeue(i));
|
||||
@@ -672,6 +782,59 @@ static void moodycamel_spsc_queue(benchmark::State &state) {
|
||||
}
|
||||
BENCHMARK(moodycamel_spsc_queue);
|
||||
|
||||
struct MyBase {
|
||||
virtual int inc(int &x) = 0;
|
||||
};
|
||||
struct MyDerived : MyBase {
|
||||
int inc(int &x) override { return x += 1; };
|
||||
};
|
||||
|
||||
struct MyDirect {
|
||||
int inc(int &x) { return x += 1; };
|
||||
};
|
||||
|
||||
static void derived_call(benchmark::State &state) {
|
||||
int x = 0;
|
||||
MyDerived d;
|
||||
MyBase &b = d;
|
||||
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(b.inc(x));
|
||||
}
|
||||
}
|
||||
BENCHMARK(derived_call);
|
||||
|
||||
static void direct_call(benchmark::State &state) {
|
||||
int x = 0;
|
||||
MyDerived b;
|
||||
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(b.inc(x));
|
||||
}
|
||||
}
|
||||
BENCHMARK(direct_call);
|
||||
|
||||
static void get_time_of_day(benchmark::State &state) {
|
||||
std::string result(strlen("20121204-14:44:02.999"), ' ');
|
||||
struct timeval tv;
|
||||
for (auto _ : state) {
|
||||
gettimeofday(&tv, nullptr);
|
||||
auto tm = localtime(&tv.tv_sec);
|
||||
sprintf(&result[0], "%d%02d%02d-%02d:%02d:%02d.%03d", tm->tm_year,
|
||||
tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 0);
|
||||
}
|
||||
}
|
||||
BENCHMARK(get_time_of_day);
|
||||
|
||||
static void fix_time_stamp(benchmark::State &state) {
|
||||
std::string r(128, 32);
|
||||
auto now = datetime::now();
|
||||
for (auto _ : state) {
|
||||
datetime::FIX_timestamp(now, &r);
|
||||
}
|
||||
}
|
||||
BENCHMARK(fix_time_stamp);
|
||||
|
||||
std::string Benchmark::help() {
|
||||
return "Run micro-benchmarks. Use --benchmark_filter=regex to run only "
|
||||
"specific benchmarks.";
|
||||
|
||||
@@ -1,36 +1,58 @@
|
||||
#include "server/sparkd/cmds/PrintHedgeOrders.h"
|
||||
#include "lib/persistence/SqliteStore.h"
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/persistence/SqliteStore.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
|
||||
namespace bts {
|
||||
namespace cmd {
|
||||
|
||||
int PrintHedgeOrders::execute(std::vector<std::string> const &) {
|
||||
persistence::SqliteStore store("orders");
|
||||
auto all = store.retrieve_all()["orders"];
|
||||
persistence::SqliteStore order_store("orders");
|
||||
auto all_orders = order_store.retrieve_all()["orders"];
|
||||
|
||||
std::cout << "order_key,time_to_completed" << "\n";
|
||||
api::orderman::OrderRecord rec;
|
||||
for (auto const &kvp : all)
|
||||
if (utils::pb::from_string<api::orderman::OrderRecord>(kvp.second, &rec)) {
|
||||
auto &def = rec.def();
|
||||
auto &state = rec.state();
|
||||
if (rec.parent_key() &&
|
||||
def.custom_def().has_limit() &&
|
||||
def.sub_type() == api::orderman::OrderSubType::ORDER_SUB_TYPE_HEDGING_LEG) {
|
||||
auto created = state.created().seconds()* 1e9 + state.created().nanos();
|
||||
auto updated = state.last_change().seconds()* 1e9 + state.last_change().nanos();
|
||||
std::cout << kvp.first << "," << (updated-created) / 1000 / 1000 / 1000 << "\n";
|
||||
std::map<uint32_t, std::pair<std::string, double>> fill_times;
|
||||
persistence::SqliteStore fill_store("fills");
|
||||
auto all_fills = fill_store.retrieve_all()["fills"];
|
||||
for (auto const &kvp : all_fills) {
|
||||
api::orderman::Fill fill_rec;
|
||||
if (utils::pb::from_string<api::orderman::Fill>(kvp.second, &fill_rec)) {
|
||||
auto ts = utils::pb::to_double_time(fill_rec.timestamp());
|
||||
auto &p = fill_times[fill_rec.order_key()];
|
||||
auto &min_time = p.second;
|
||||
if (min_time < ts) {
|
||||
p.first = kvp.first;
|
||||
min_time = ts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "order_key,time_to_first_fill,fill_id"
|
||||
<< "\n";
|
||||
api::orderman::OrderRecord rec;
|
||||
for (auto const &kvp : all_orders)
|
||||
if (utils::pb::from_string<api::orderman::OrderRecord>(kvp.second,
|
||||
&rec)) {
|
||||
auto &def = rec.def();
|
||||
auto &state = rec.state();
|
||||
if (rec.parent_key() && def.custom_def().has_limit() &&
|
||||
def.sub_type() ==
|
||||
api::orderman::OrderSubType::ORDER_SUB_TYPE_HEDGING_LEG) {
|
||||
auto create_ts = utils::pb::to_double_time(state.created());
|
||||
auto &first_fill = fill_times[rec.key()];
|
||||
auto delta = first_fill.second - create_ts;
|
||||
if (first_fill.first.size())
|
||||
std::cout << kvp.first << "," << delta << ","
|
||||
<< first_fill.first << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string PrintHedgeOrders::help(){
|
||||
return
|
||||
"Print out order ids for all hedge orders"
|
||||
"which were completed at least one second being created";
|
||||
std::string PrintHedgeOrders::help() {
|
||||
return "Print out order ids for all hedge orders"
|
||||
"which were completed at least one second being created";
|
||||
}
|
||||
|
||||
}}
|
||||
} // namespace cmd
|
||||
} // namespace bts
|
||||
@@ -1,61 +1,36 @@
|
||||
#include "QuickTest.h"
|
||||
#include "ICmd.h"
|
||||
|
||||
#include "lib/api/services/OrderService.server.pb.h"
|
||||
#include "lib/mercury/actors/PingPong.h"
|
||||
#include "lib/mercury/broker/BrokerProxy.h"
|
||||
#include "lib/mercury/common/mercury_common.h"
|
||||
#include "lib/mercury/executor/Executor.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/utils/thread_manager.h"
|
||||
#include "lib/orderman/events/OrderStateUpdateEvent.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace bts {
|
||||
namespace cmd {
|
||||
|
||||
void test_ping_pong_mercury2()
|
||||
{
|
||||
using namespace mercury;
|
||||
|
||||
Executor ex1;
|
||||
Executor ex2;
|
||||
|
||||
ex1.init_neighbours(std::vector<Executor*> {&ex2});
|
||||
ex2.init_neighbours(std::vector<Executor*> {&ex1});
|
||||
|
||||
ex1.spawn<Ping>();
|
||||
//ex1.spawn<Pong>();
|
||||
ex2.spawn<Pong>();
|
||||
|
||||
auto t = std::thread([&ex2]() {
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(1, &cpuset);
|
||||
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
|
||||
|
||||
while (true)
|
||||
ex2.do_work();
|
||||
});
|
||||
|
||||
bts::sleep_for(2s);
|
||||
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(0, &cpuset);
|
||||
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
|
||||
|
||||
while (true) {
|
||||
ex1.do_work();
|
||||
bts::sleep_for(100ms);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using namespace bts::mercury;
|
||||
using namespace bts::orderman;
|
||||
|
||||
int QuickTest::execute(std::vector<std::string> const &) {
|
||||
test_ping_pong_mercury2();
|
||||
sleep_for(10s);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
auto t = utils::TimeStamp::now();
|
||||
LOG(OrderMan,Info,"Now: {}", (utils::TimeStamp::now() - t).nanoseconds());
|
||||
}
|
||||
sleep_for(10s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string QuickTest::help() {
|
||||
return "This is a place holder to make it easy to quickly write discardable "
|
||||
"test code";
|
||||
"test code";
|
||||
}
|
||||
} // namespace cmd
|
||||
} // namespace bts
|
||||
@@ -1 +1 @@
|
||||
set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/cssstyle/scripts/run_tests.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs)
|
||||
set(sources ../../externals/linux/include/google/protobuf/descriptor.proto;../../externals/linux/include/google/protobuf/timestamp.proto;../lib/api/apicore.proto;../lib/api/apigateway.proto;../lib/api/apioptions.proto;../lib/api/services/AdminService.proto;../lib/api/services/ApiUnitTestService.proto;../lib/api/services/ErrorReportService.proto;../lib/api/services/HelloService.proto;../lib/api/services/MarketDataAuxiliaryService.proto;../lib/api/services/MarketDataRelay.proto;../lib/api/services/OrderService.proto;../lib/api/services/OutOfProcessURLListener.proto;../lib/api/services/PersistenceService.proto;../lib/api/services/PositionService.proto;../lib/api/services/ShellDiagnosticService.proto;../lib/api/services/ShellLatencyService.proto;../lib/api/services/SyntheticSecurityService.proto;../lib/api/services/UserService.proto;../lib/domain_model/Security.proto;../lib/md/protos/co2.proto;../lib/sparkproto/SparkProtos.proto;api/build.sh;api/node_modules/cssstyle/scripts/run_tests.sh;api/node_modules/exit/test/fixtures/create-files.sh;api/node_modules/protobufjs/cli/node_modules/acorn-jsx/node_modules/acorn/bin/update_authors.sh;api/node_modules/watch/release.sh;api/quiet_build.sh;api/src/DynamicService.ts;api/src/ServiceContext.ts;api/src/bts_assert.ts;ui/src/Access.fs;ui/src/Accounts/ClipLimits.fs;ui/src/Accounts/ProductLimits.fs;ui/src/Accounts/SecurityLimits.fs;ui/src/Accounts/State.fs;ui/src/Accounts/Types.fs;ui/src/Accounts/View.fs;ui/src/App.fs;ui/src/Cmd.fs;ui/src/Controls/Button.fs;ui/src/Controls/DataGrid.fs;ui/src/Controls/Fields.fs;ui/src/Controls/Modal.fs;ui/src/Controls/ReactGrid.fs;ui/src/Controls/Table.fs;ui/src/Controls/nbsp.fs;ui/src/Global.fs;ui/src/Imports.fs;ui/src/Lens.fs;ui/src/Login/Login.fs;ui/src/Nav.fs;ui/src/State.fs;ui/src/Types.fs;ui/src/Users/State.fs;ui/src/Users/Types.fs;ui/src/Users/View.fs;ui/src/Util/EnumUtils.fs;ui/src/Util/JSMap.fs)
|
||||
Regular → Executable
+4
-4
@@ -1,11 +1,11 @@
|
||||
#!/bin/bash
|
||||
sed 's/[ \t]*|/|/g' sparkdata/data/logging/log >clean
|
||||
grep '|' ~/sparkdata/data/logging/log | sed 's/[ \t]*|/|/g' > clean_db
|
||||
rm log_db
|
||||
sqlite3 log_db <<EOF
|
||||
create table log(ts,ss,level,tid,tname,pid,loc,msg);
|
||||
create table log(dt,ts,ss,level,tid,tname,pid,loc,dtype,msg);
|
||||
.separator |
|
||||
.import $1 log
|
||||
.import clean_db log
|
||||
EOF
|
||||
|
||||
sqlite3 log_db "select ts,tname, msg from log order by ts" > log.csv
|
||||
|
||||
|
||||
Regular → Executable
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
tac ~/.bts/data/logging/log | grep "Sparkd launched" -m 1 -B 999999 | tac | sort -n -t '|' -k 2,5 | sed 's/[ \t]*|/|/g' | column -t -s'|'
|
||||
grep Latency ~/sparkdata/data/logging/log | sort -n -t '|' -k 2,5
|
||||
|
||||
Reference in new issue
Block a user