Compare commits

...
Author SHA1 Message Date
Kevin Darby a397d7b18e Revert "Revert "Merge branch 'ilink3_gateway' of bitbucket.org:bluetradesys/spark into ilink3_shard""
This reverts commit c1df312f88.
2020-04-29 17:20:57 -04:00
Kevin Darby 9e1d6a2fe7 Merge branch 'ilink3_gateway' of bitbucket.org:bluetradesys/spark into ilink3_shard 2020-04-29 17:16:12 -04:00
Kevin Darby 8722b70518 update comment 2020-04-28 18:26:32 -04:00
Eric Harding 80d7e34bf1 Fixes for updated sbe codegen 2020-04-28 18:16:45 -04:00
Kevin Darby bca760cec9 this should suffice for at least not-erroneously triggering Execrpt recovery 2020-04-28 17:47:06 -04:00
Kevin Darby 5f1e58df68 disabling recovery from execrpt for now; seems like we might have to move this code 2020-04-28 17:19:42 -04:00
Kevin Darby c1df312f88 Revert "Merge branch 'ilink3_gateway' of bitbucket.org:bluetradesys/spark into ilink3_shard"
This reverts commit 8473311a52, reversing
changes made to 0a83143cf3.
2020-04-28 16:47:12 -04:00
Kevin Darby 8473311a52 Merge branch 'ilink3_gateway' of bitbucket.org:bluetradesys/spark into ilink3_shard 2020-04-28 16:36:36 -04:00
Kevin Darby 0a83143cf3 sharding seems to be working 2020-04-28 16:32:36 -04:00
Eric Harding 8ab69c919b Improve cme provided error message 2020-04-27 16:56:32 -04:00
Eric Harding 99531bcfa0 Update ilink3 generated templates 2020-04-27 16:50:54 -04:00
Eric Harding 6bd516d4f2 cleanup 2020-04-27 11:26:42 -04:00
Eric Harding 1a1d771e1b addition ilink3 tests 2020-04-25 13:18:58 -04:00
Kevin Darby 13b15f257b Merge branch 'ilink3_gateway' of bitbucket.org:bluetradesys/spark into ilink3_shard 2020-04-24 12:37:24 -04:00
Kevin Darby 109de67a06 got gateway working, I don't like the static registration though 2020-04-24 12:36:11 -04:00
Eric Harding 050fcf7c6e Passing simple log in test 2020-04-24 12:31:30 -04:00
Kevin Darby e7b6bf40d9 it builds, ship it 2020-04-23 17:57:13 -04:00
Kevin Darby 3193bc6467 gotta move branches 2020-04-20 18:01:10 -04:00
Kevin Darby f534ef3e39 GatewayProxy 2020-04-20 18:01:02 -04:00
Kevin Darby bbd9693718 beginnings of load balancing the OrderServer 2020-04-20 18:00:55 -04:00
Eric Harding aadeae3201 update cmake, avoid web build on wsl 2020-04-17 22:38:53 -04:00
Eric Harding b72e8aed02 ilink3 test code 2020-04-17 20:30:11 -05:00
Eric Harding 0820cc3e9a Fix a very subtle bug in serializer 2020-04-17 13:15:12 -05:00
Eric Harding b1ba9a1315 update ilink code gen readme 2020-04-16 14:03:53 -05:00
Eric Harding 39ce4323a1 Add CME cert command line tool 2020-04-13 16:18:59 -05:00
Eric Harding d9fcd290d9 source files don't need to be executable 2020-04-13 09:53:28 -05:00
Eric Harding 05939b02c5 save 2020-04-12 15:11:46 -05:00
Eric Harding aa91638fe4 ilink3 receive buffer handler + tests 2020-04-10 10:55:53 -05:00
Eric Harding 065fc54f73 IL3Reactor 2020-04-07 14:05:31 -05:00
Eric Harding 95fb13f58b Fix some build issues 2020-04-01 15:21:04 -05:00
Eric Harding 4eb2931cb8 Additional ilink3 refactoring 2020-03-28 21:08:47 -05:00
Eric Harding 5326015a48 Testcase for framer 2020-03-27 13:46:29 -05:00
Eric Harding fcbe319470 Split out functional pieces for easier testing 2020-03-27 09:14:30 -05:00
Eric Harding 5ad21c88b2 Add tests and refactor includes for faster build 2020-03-25 21:15:19 -05:00
Eric Harding 3a9c1d557b Split Retransmit of old vs new session logic 2020-03-09 16:29:15 -05:00
Eric Harding 6fb5b83249 Only send Negotiate if the session is new 2020-02-28 15:33:27 -06:00
Eric Harding 95830fafdf send_cancel 2020-02-27 14:48:56 -06:00
Eric Harding d68b03bb91 send_cancel_replace 2020-02-26 17:56:50 -06:00
Eric Harding e7062ce01e send_order call for link3 2020-02-26 17:36:18 -06:00
Pedro Pinto 932738f98e Merge branch 'master' into ilink3_gateway 2020-02-20 08:39:47 -05:00
Pedro Pinto 1426b00e83 Added fake iLink3 gateway 2020-02-19 16:21:06 -05:00
Pedro Pinto e724409b58 Added jetfix support for string_view 2020-02-19 10:55:56 -05:00
Pedro Pinto 9cf828e9a4 Implemented iLink3 order 2020-02-18 15:37:06 -05:00
Eric Harding 41408fb609 ILink3ExecutionGateway placeholder 2020-02-14 16:07:44 -06:00
Eric Harding 4c21e32838 ILink3GW core gateway 2020-02-14 16:06:58 -06:00
Eric Harding 385f3ea402 add unix_nano_now() to datetime.h 2020-02-14 16:05:00 -06:00
Eric Harding 8d6d8cab18 Update SecureLogon for ilink3 2020-02-14 16:05:00 -06:00
Eric Harding 01615f824a Generated ilink3 messages 2020-02-14 16:05:00 -06:00
Pedro Pinto c6779ddc90 Reactore GLBX native order for iLink3. 2020-02-13 15:26:33 -05:00
Pedro Pinto 46eff65435 Changed IExecutionGateway to support non FIX gateways. 2020-02-12 10:11:53 -05:00
Eric Harding cb0dfa50b3 Fix dockerfile 2020-02-11 15:02:41 -05:00
Eric Harding 2429e6019c Merge branch 'master' of bitbucket.org:bluetradesys/spark into prod 2020-02-11 14:16:14 -05:00
Eric Harding e0bb48b0c7 Merged in client_sdk (pull request #397)
Client sdk
2020-02-11 18:31:09 +00:00
Eric Harding a38b0dbc79 Merge branch 'master' of bitbucket.org:bluetradesys/spark into client_sdk 2020-02-11 13:29:43 -05:00
Eric Harding 73065ab48a client sdk sample 2020-02-11 13:29:09 -05:00
Eric Harding bd07c96504 Merged in mdsource_crash (pull request #389)
Fix for assert when algo subs to security w/o MD
2020-02-11 17:11:07 +00:00
Eric Harding dc4033875a Fixes from code review feedback 2020-02-11 11:43:04 -05:00
Eric Harding 130794c538 Merge fixup 2020-02-11 11:22:02 -05:00
Eric Harding b1743f0b1c Uninitialized heap, ffs 2020-02-10 18:58:21 -05:00
Eric Harding 33492c9131 Fixes for _WIN32 2020-02-10 18:27:41 -05:00
Eric Harding d434778a82 MarketDataService 2020-02-10 17:06:13 -06:00
Eric Harding 4c6cc9b3e0 Merge branch 'client_sdk' of bitbucket.org:bluetradesys/spark into client_sdk 2020-02-10 12:32:18 -06:00
Eric Harding 6aaeddb7e9 update vscode for linux on linux development 2020-02-10 12:32:10 -06:00
Eric Harding 1685a13994 Add linux on linux build task (vscode) 2020-02-10 13:24:56 -05:00
Eric Harding 54633dd6db note correct config value for local sparkd 2020-02-10 13:21:03 -05:00
Eric Harding 510f163e5b Add to_string methods for Product for new md api 2020-02-10 12:50:05 -05:00
Eric Harding ee4779da73 MarketDataService 2020-02-09 22:39:01 -05:00
Eric Harding 28e98259f6 Add client sdk example 2020-02-07 22:20:42 -05:00
Eric Harding 82bc402216 Update client examples 2020-02-05 14:58:46 -05:00
Eric Harding ff70e9694b Set spark version from jenkins environment when available 2020-02-05 10:02:17 -05:00
Jake Norbut 525d0eda30 fix typo in notes 2020-01-30 07:39:22 -06:00
Jake Norbut e9e85b44c9 updating release notes 2020-01-30 07:37:51 -06:00
John Colvin 2654b2e446 SP-283 Ladder does not display 6c spreads correctly 2020-01-29 12:43:01 -06:00
Eric Harding be45938b51 Fix for assert when algo subs to security w/o MD 2020-01-22 14:08:26 -05:00
Eric Harding 663f9ecc52 Merge branch 'master' of bitbucket.org:bluetradesys/spark into client_sdk 2020-01-16 17:23:42 -05:00
Eric Harding a6edbbe7b5 Fix spark sdk build 2020-01-14 17:13:07 -05:00
Eric Harding 51276d161c Revert "Add diagnostic logs to SharedMemory open/close"
This reverts commit 3fa699b4c9 because of
log spam
2020-01-13 11:39:51 -05:00
Eric Harding 3fa699b4c9 Add diagnostic logs to SharedMemory open/close 2020-01-13 11:13:15 -05:00
Eric Harding c9396bd6af Stabilize spark_vm_shell.sh ssk keys 2020-01-13 11:13:00 -05:00
Kevin Darby b80f96fa5e Merged in ice_excel (pull request #388)
fix RTD crash for ice

Approved-by: Jake Norbut <jake.norbut@bluetradesys.com>
2020-01-10 22:39:27 +00:00
Kevin Darby b7dea6817c fix RTD crash for ice 2020-01-10 14:43:06 -05:00
Pedro Pinto f4dc550f1a Fixed slowness in FIX log parsing.
This slowness was actually causing us to take too long to complete the
FIX connection logon process, resulting in a timeout and failure to
establish the session. It took almost 1ms per log line, with
logs commonly having 20K lines. k
2020-01-10 08:35:33 -05:00
Pedro Pinto bc978ed065 Merge branch 'master' of bitbucket.org:bluetradesys/spark 2020-01-10 08:30:17 -05:00
Eric Harding 202c5faffd update devcontainer to allow 2g shm 2020-01-09 10:40:47 -05:00
Pedro Pinto 65d55a7618 Added a parser of historical MD to facilitate analysis. 2020-01-02 13:57:54 -05:00
Pedro Pinto 57c3ec34c2 Fixed clang build. 2020-01-02 13:55:49 -05:00
Eric Harding c6cd5fcf93 services.md 2019-12-15 22:09:20 -05:00
Eric Harding 177b96b453 manual updates 2019-12-13 17:46:22 -05:00
Eric Harding 292f66a774 Add package id for nuget 2019-12-13 17:46:03 -05:00
Eric Harding 8c837f9f64 Expound on service fundamentals / ServiceContext 2019-12-03 13:16:41 -05:00
Eric Harding 85f97ae552 Combine rpc/streams into services.md 2019-12-01 21:50:17 -05:00
Eric Harding 7ca0d10eb0 client/overview.md 2019-11-29 11:49:24 -05:00
Eric Harding ca8aed1f2b client pages outline 2019-11-22 18:49:58 -05:00
Eric Harding b32d63fcda Update api site template 2019-11-20 12:39:59 -05:00
Eric Harding 54d9d5e2f3 Add google analytics 2019-11-19 16:38:30 -05:00
267 changed files with 148508 additions and 812 deletions

No files matched your search

+1
View File
@@ -34,3 +34,4 @@ trace_data/
/doc/user/public/*
.ionide/*
/.ignore
/build
+8 -3
View File
@@ -5,7 +5,9 @@
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
"${workspaceRoot}",
"${workspaceFolder}/src",
"${workspaceRoot}/externals/linux/include"
],
"defines": [],
"intelliSenseMode": "clang-x64",
@@ -13,13 +15,16 @@
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
"${workspaceRoot}",
"${workspaceFolder}/src",
"${workspaceRoot}/externals/linux/include"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"cStandard": "c11",
"cppStandard": "c++17"
"cppStandard": "c++17",
"compileCommands": "${workspaceFolder}/build/ninja_debug/compile_commands.json"
},
{
"name": "Windows",
+30 -2
View File
@@ -1,13 +1,40 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Spark Local",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/build/ninja_debug/server/sparkd",
"args": [
// "cmecert",
"test",
"-a",
"[ilink3]"
],
"stopAtEntry": false,
"cwd": "${workspaceRoot}/build/ninja_debug/server/",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
{
"name": "SparkVM Launch",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
"args": [
"run"
"run"
//"test",
//"-a",
//"[ilink3]"
],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/server/",
@@ -44,7 +71,8 @@
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
"/home/bts/spark/": "${workspaceRoot}",
"/home/bts/spark_host/": "${workspaceRoot}"
}
},
{
+19 -10
View File
@@ -14,24 +14,21 @@
"focus": false,
"panel": "shared"
},
"group": {
"kind": "build",
"isDefault": true
}
"group": "build"
},
{
"label": "server_build",
"label": "server_build",
"type": "shell",
"command": ".\\tools\\buildsparkd.cmd",
"problemMatcher": {
"base": "$gcc",
"problemMatcher": {
"base": "$gcc",
"owner": "cpp",
"fileLocation": [
"relative",
"${workspaceFolder}"
"${workspaceFolder}"
],
"pattern": {
"regexp": "(.?)(home)(.?)(bts)(.?)(spark)(.?)(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)",
"regexp": "(.?)(home)(.?)(bts)(.?)(spark)(.?)(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)",
"file": 8,
"line": 9,
"column": 10,
@@ -49,6 +46,18 @@
"kind": "build",
"isDefault": true
}
}
},
{
"label": "linux build (Debug)",
"type": "shell",
"command": "cd build/ninja_debug; time ninja",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
}
]
}
+1 -1
View File
@@ -1,6 +1,6 @@
+++
title="Client API"
template="client.html"
redirect_to = "client/getting-started/overview/"
sort_by="weight"
+++
@@ -1,6 +1,5 @@
+++
title="Getting Started"
template="client.html"
sort_by="weight"
weight = 1
+++
@@ -1,9 +1,25 @@
+++
title = "Install Prerequisites"
template="client.html"
weight = 1
weight = 10
+++
## Coming Soon
# C#/.NET
We target [.NET Standard 2.0](https://docs.microsoft.com/en-us/dotnet/standard/net-standard) so you can use .NET Framework 4.6.1+ or .NET Core 2.0+. Simply add a reference to the [Spark Nuget package](https://nuget.org) to get started.
```
dotnet new console -lang c#
dotnet add package spark_sdk
dotnet build
```
# C++
The easiest way to get started with C++ is to use the Spark Server SDK to develop your application. Follow the instructions to [download and install the Spark Server SDK](/server/getting-started/install) and open the client_sdk sample project. If you want to run your C++ Client SDK application on Windows [contact us](mailto://api@bluetradesys.com) to get the required headers and binaries.
# JavaScript
We use JavaScript internally with the Spark Client API over a websocket connection but the documentation and packaging isn't ready yet. If this is something you're interested in get in touch with us at [api@bluetradesys.com](mailto:api@bluetradesys.com).
* Install .net core
@@ -0,0 +1,31 @@
+++
title = "Overview"
weight = 1
+++
The Spark Client SDK is a high level command and control API which can be used to build scripts or integrate Spark into your existing ecosystem. The API is divided into several independent **"services"** responsible for different aspects of the system. A Service can define both [remote procedure call (RPC)](/client/getting-started/services#rpc) and incremental [streaming](/client/getting-started/services#streams) data.
The [Spark Desktop](https://www.bluetradingsystems.com/bts-spark/) is built on top of this API so you can be assured that it is complete and well tested.
Spark uses [Google Protocol Buffers](https://developers.google.com/protocol-buffers/) as an interface definition language similar to [GRPC](https://grpc.io) but backed by our custom high-performance TCP protocol. We currently support C#/.NET and C++ <!--and Javascript--> but the architecture is designed for easy extension so contact us about your specific business needs.
## Orders
Use the [OrderService](/client/services/orderservice) to send and manage orders including native exchange orders, spreader orders, and custom Algo orders created using the [Spark Server SDK](https://api.bluetradesys.com/server/).
## Spreader
Use the [SyntheticSecurityService](/client/services/syntheticsecurityservice) to create and manage synthetic spreads. Once created these spreads show up in the security and market data feeds just like exchange listed spreads.
## Position
Use the [PositionService](/client/services/positionservice) to get your position and P&L reports or add fills manually to keep the Spark system up to date with an external system.
## Administration
Use the [AdminService](/client/services/adminservice) to manage users and control limits.
## Market Data
For .NET subscribe to market data though the high level MarketDataClient interface. From C++ or JavaScript use the MarketDataRelay service directly.
@@ -0,0 +1,127 @@
+++
title = "Services"
weight = 20
+++
The Spark Client SDK uses [Google Protocol Buffers](https://developers.google.com/protocol-buffers/) to define the interface for each service in a language independent manner. Services have both functions which return a single result and streams of data which return values continuously while subscribed. This page describes the mapping from the Protocol Buffer definition to the concrete definition in each supported language.
# ServiceContext
To connect your client to the Spark Server you need to get or create a `ServiceContext` instance. A `ServiceContext` represents a connection to the Spark Server and a background thread for handling messages on that connection. Generally there should be a single `ServiceContext` per process. All of the methods on the `ServiceContext` are safe thread safe.
Construct a ServiceContext by calling the default constructor. The ServiceContext will find the Spark Server by loading the server configuration over an HTTP connection. To determine the URL it will search the following locations and use the first one that is present.
* A command line argument `-configserver <url>`
* An environment variable `BTSCONFIG`
* `%APPDATA%/bts/conf/spark.conf` (Windows)
* /sparkdata/conf/spark.conf (Linux)
* $HOME/sparkdata/conf/spark.conf (Linux)
If your application is running on a system with the BTS Client installed this will probably work without any further configuration. If you plan to run your client application on a separate machine we recommend setting the `BTSCONFIG` environment variable.
<div class="info">
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
If you are using the Spark Server SDK to run a local copy of the Spark server set <p><strong>BTSCONFIG = http://localhost:9000/config/</strong></p>
</div>
To get a proxy for a given service call ServiceContext.locate&lt;T>("qualifier") where T is the type of the service and "qualifier" is an optional qualifier used to disambiguate between 2 instances of the same service. The locate call cannot fail but it may return a disconnected proxy. When you make a call on the proxy you should check the call result to see if the method call succeeded.
# RPC
Here is the OrderService reduced to a single method definition. A RPC method always takes exactly 1 argument and returns 1 value. In this example the `create_order` call takes a `Create` instance and returns a `Response`.
```C
service OrderService {
rpc create_order(Create) returns (Response);
...
}
```
The `Create` and `Response` types are also defined as protocol buffer messages. Each field can either be a primitive type another message or a list or map.
```C
message Create {
OrderDefinition new_order = 1;
double price = 2;
uint32 quantity = 3;
}
message Response {
uint32 order_key = 1;
OrderError error_code = 2;
string msg = 3;
}
```
Each RPC call generates both synchronous (blocking) and asynchronous variants. In C# the asynchronous calls have the `_async` suffix and return a `Task`. In C++ the call is overloaded to either return a value synchronously or accept a callback function to be called on the ServiceContext thread when the call completes. <!-- In Javascript only async methods returning a Promise are generated because it never makes sense to make a blocking call in the browser. -->
To call the resulting service locate a proxy using the [ServiceContext](#servicecontext) and then call `cancel_order` or `cancel_order_async`. If you are calling the Spark API from a GUI application you should always prefer the `_async` version of the calls.
### C# example
```c#
var ctx = new ServiceContext();
var orders = ctx.locate<OrderService>();
var response =
await orders.create_order_async(
new Create { price = 2.25, quantity = 42 });
if (response.success) {
Console.WriteLine($"success: {response.value}");
}
else {
Console.WriteLine($"Error: {response.error_message}");
}
```
### C++ example
```cpp
auto ctx = ServiceContext{};
auto orders = ctx.locate<OrderService>();
Create c;
c.set_price(2.25);
c.set_quantity(42);
// Instead of providing an _async method C++ uses overloading.
// To make a syncronous call simply omit the callback
orders.create_order(c, [=](const Result<Response>& response) {
if(response.success()) {
std::cout << "success.";
}
else {
std::cout << "error: " << response.error_message();
}
});
```
# Streams
Streams allow you to subscribe to live updating data. Each stream represents a changing collection of protocol buffer objects. Similar to a database row each item has an `id` which uniquely identifies it within the collection. Updates from the Spark server can add, remove or replace entries in the collection. Since only the changed items are sent over the wire the stream can remain responsive even when it represents a large collection.
Streams are implemented using the language bindings for [ReativeX](http://reactivex.io/) which provide utility functions to drill down to the specific data your application needs. In C# we provide both mutable and immutable versions of the generated data types (C++ users can rely on `const`).
When defined in a proto file streams use the `stream` keyword on the result type.
```C
service OrderService {
...
rpc fills (FillsSub) returns (stream Fill);
}
```
### C# example
```c#
var sc = new ServiceContext();
var orders = sc.locate<OrderService>();
var fills_observable = orders.subscribei_fills();
var unsub = fills_observable.Subscribe(update => {
Console.WriteLine(
"Added {0} items, Removed {1} items, Updated {2} items. Total items {3}",
update.added.Count(),
update.removed.Count(),
update.changes.Count(),
update.all.Count());
});
Thread.Sleep(TimeSpan.FromMinutes(5));
unsub.Dispose();
```
### C++ Example
```cpp
```
+6
View File
@@ -0,0 +1,6 @@
+++
title="Samples"
sort_by="weight"
weight = 30
+++
@@ -0,0 +1,3 @@
+++
title = "AdminService"
+++
@@ -0,0 +1,3 @@
+++
title = "OrderService"
+++
@@ -0,0 +1,3 @@
+++
title = "PositionService"
+++
@@ -0,0 +1,3 @@
+++
title = "SyntheticService"
+++
@@ -0,0 +1,6 @@
+++
title="Services"
#sort_by="weight"
weight = 10
+++
@@ -0,0 +1,3 @@
+++
title = "Market Data"
+++
-1
View File
@@ -1,6 +1,5 @@
+++
title="Algo API"
template="documentation.html"
redirect_to = "server/getting-started/overview/"
sort_by="weight"
+++
@@ -1,6 +1,5 @@
+++
title="Getting Started"
template="documentation.html"
sort_by="weight"
weight = 1
+++
@@ -71,12 +71,12 @@ The first step is to start the spark_sdk Docker container with the examples dire
Windows Command Prompt:
{% clipable() %}
docker run --rm -it -v %CD%:/examples -u bts -w /examples --shm-size 1024m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
docker run --rm -it -v %CD%:/examples -u bts -w /examples --shm-size 2048m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
{% end %}
**Powershell** / Linux / Mac:
{% clipable() %}
docker run --rm -it -v ${PWD}:/examples -u bts -w /examples --shm-size 1024m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
docker run --rm -it -v ${PWD}:/examples -u bts -w /examples --shm-size 2048m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
{% end %}
### Attach
@@ -5,7 +5,7 @@ weight = 2
## Request Access 🔑
To start using the Server SDK you will need to request access though our sales department. Please email <a href="mailto:info@bluetradesys.com">info@bluetradesys.com</a> or call <a href="tel:919-913-0850">(919) 913-0850</a> and we will provide download credentials.
To start using the Server SDK you will need to request access though our sales department. Please email <a href="mailto:api@bluetradesys.com">api@bluetradesys.com</a> or call <a href="tel:919-913-0850">(919) 913-0850</a> and we will provide download credentials.
## Download
-1
View File
@@ -1,6 +1,5 @@
+++
title="Reference"
template="documentation.html"
sort_by="weight"
weight = 2
+++
+6
View File
@@ -6,3 +6,9 @@ weight = 40
## I need to make a call that might take a few seconds. What is the best way to do this?
Create a background thread in [do_before_launch](/server/ref/initialization#before-launch) or [do_launch](/server/ref/initialization#launch-launch-attached) to do the work. Use [on_timer](/server/ref/subscriptions#timer) to poll until the result is available.
## I don't see the header files in the .zip file. Where are they?
The SDK headers are baked into the docker image along with the build tools. Once you've loaded the image with `docker load < spark_sdk.img` you can run this command to copy them out to your local file system `docker run --rm -it -v $PWD:/out spark_sdk /bin/tar -cvf /out/headers.tar /sdk/include` This will copy the headers to the current directory in headers.tar. We still recommend doing the actual build inside the docker environment but having a copy of the headers can be useful for setting up your development environment.
File renamed without changes.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

-1
View File
@@ -1,6 +1,5 @@
+++
title="Samples"
template="documentation.html"
sort_by="weight"
weight = 3
+++
-31
View File
@@ -1,31 +0,0 @@
{% extends "index.html" %}
{% block extra_nav_class %}{% endblock extra_nav_class %}
{% block extra_content_class %}content--reversed{% endblock extra_content_class %}
{% block content %}
{% set section = get_section(path="client/_index.md") %}
<div class="documentation">
<aside class="documentation__sidebar">
<ul>
{% for p in section.subsections %}
{% set subsection = get_section(path=p) %}
<li>
<span class="documentation__sidebar__title">{{ subsection.title }}</span>
<ul>
{% for page in subsection.pages %}
<li class="{% if current_path == page.path %}active{% endif %}">
<a href="{{page.permalink}}">{{page.title}}</a>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</aside>
<div class="documentation__content">
{% block doc_content %}
{% endblock doc_content %}
</div>
</div>
{% endblock content %}
-36
View File
@@ -1,36 +0,0 @@
{% extends "index.html" %}
{% block extra_nav_class %}{% endblock extra_nav_class %}
{% block extra_content_class %}content--reversed{% endblock extra_content_class %}
{% block content %}
{%if page.extra.section %}
{% set section = get_section(path="{{page.extra.section}}/_index.md") %}
{% else %}
{% set section = get_section(path="server/_index.md") %}
{% endif %}
<div class="documentation">
<aside class="documentation__sidebar">
<ul>
{% for p in section.subsections %}
{% set subsection = get_section(path=p) %}
<li>
<span class="documentation__sidebar__title">{{ subsection.title }}</span>
<ul>
{% for page in subsection.pages %}
<li class="{% if current_path == page.path %}active{% endif %}">
<a href="{{page.permalink}}">{{page.title}}</a>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</aside>
<div class="documentation__content">
{% block doc_content %}
{% endblock doc_content %}
{% block next_link %} {% endblock next_link %}
</div>
</div>
{% endblock content %}
+15 -15
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en-gb">
<html lang="en-us">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -14,6 +14,7 @@
<link rel="stylesheet" href="{{ get_url(path="site.css") }}"/>
<link rel="icon" href="{{ get_url(path="favicon.ico") }}">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script> dataLayer = [{ 'visitorType': 'geek' }]; </script>
</head>
<body>
@@ -36,13 +37,13 @@
</nav>
</header>
<div class="content {% block extra_content_class %}{% endblock extra_content_class %}">
<div class="content content--reversed">
{% block content %}
<div class="hero">
<h1>Spark SDK</h1>
<p class="hero__tagline">
Spark consists of a client UI
(<a class="white" href="https://www.bluetradingsystems.com/bts-spark#ladder-algo-screen">Spark Client</a>),
(<a href="https://www.bluetradingsystems.com/bts-spark#ladder-algo-screen">Spark Client</a>),
a high-performance professional futures front end, connected via our proprietary protocol over TCP to our Spark Server, which in turn connects to execution venues via their native protocols.
Use the Spark SDK to extend Spark Server with your custom Algos, then use the Client SDK to launch and control them.
</p>
@@ -64,7 +65,7 @@
<a href="{{ get_url(path="@/server/_index.md") }}" class="button">Get started</a>
</div>
<div class="selling-point disabled">
<div class="selling-point">
<h2>
Client SDK
<i class="fa fa-gamepad" aria-hidden="true"></i>
@@ -72,19 +73,9 @@
<p>
The Spark client SDK allows you to integrate spark with your existing ecosystem. The Spark Client is built entirely on this simple, powerful API.
</p>
<a href="" class="button" disabled>Get started</a>
<a href="" class="button">Get started</a>
</div>
<!-- <div class="selling-point disabled">
<h2>
Microsoft Excel
<i class="fa fa-table" aria-hidden="true"></i>
</h2>
<p>
More of your business is built on excel than probably should be. Continue this worrying trend with the Spark Excel API.
</p>
<a href="" class="button" disabled>Get started</a>
</div> -->
</div>
</div>
@@ -94,6 +85,15 @@
© Blue Trading Systems
</footer>
<script>
if (location.hostname == "api.bluetradesys.com") {
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-56FHG8R');
}
</script>
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") }}"></script>
<script type="text/javascript" src="{{ get_url(path="search_index.en.js") }}"></script>
<script type="text/javascript" src="{{ get_url(path="search.js") }}"></script>
+36 -8
View File
@@ -1,13 +1,39 @@
{% extends "documentation.html" %}
{% extends "index.html" %}
{# this has access to the "page" variable but documentation.html does not #}
{% block title %}{{ page.title }} | {{ super() }} {% endblock title %}
{% block doc_content %}
<h1>{{page.title}}</h1>
{{page.content | safe}}
{% endblock doc_content %}
{% block next_link %}
<p>
{% endblock next_link %}
{% block content %}
{% set section = get_section(path=page.ancestors[1]) %}
{#
{#<div>{{ section.title }} </div>#}
<div class="documentation">
<aside class="documentation__sidebar">
<ul>
{% for p in section.subsections %}
{% set subsection = get_section(path=p) %}
<li>
<span class="documentation__sidebar__title">{{ subsection.title }}</span>
<ul>
{% for page in subsection.pages %}
<li class="{% if current_path == page.path %}active{% endif %}">
<a href="{{page.permalink}}">{{page.title}}</a>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</aside>
<div class="documentation__content">
<h1>{{page.title}}</h1>
{{page.content | safe}}
{# next/pre links #}
<p>
{% if page.lighter %}
<a href="{{ page.lighter.permalink }}">
<i class="fa fa-chevron-left fa-fw" aria-hidden="true"></i>
@@ -21,5 +47,7 @@
<i class="fa fa-chevron-right fa-fw" aria-hidden="true"></i>
</a>
{% endif %}
</p>
{% endblock next_link %}
</p>
</div>
</div>
{% endblock content %}
+1 -1
View File
@@ -1 +1 @@
set(sources /home/ppinto/Dropbox/bts/spark/doc/user/build.sh;content/_index.md;content/bts_spark/Glossary/_index.md;content/bts_spark/Help/_index.md;content/bts_spark/Help/about_spark.png;content/bts_spark/Help/image39.png;content/bts_spark/Help/image58.png;content/bts_spark/Launcher/_index.md;content/bts_spark/Launcher/image38.png;content/bts_spark/Launcher/image68.png;content/bts_spark/Logging-In-to-the-System/_index.md;content/bts_spark/Logging-In-to-the-System/image3.png;content/bts_spark/Logging-In-to-the-System/image64.png;content/bts_spark/Market/_index.md;content/bts_spark/Market/change_securities.png;content/bts_spark/Market/image11.png;content/bts_spark/Market/image14.png;content/bts_spark/Market/image20.png;content/bts_spark/Market/image21.png;content/bts_spark/Market/image23.png;content/bts_spark/Market/image24.png;content/bts_spark/Market/image34.png;content/bts_spark/Market/image49.png;content/bts_spark/Market/image53.png;content/bts_spark/Market/image66.png;content/bts_spark/Market/image69.png;content/bts_spark/Market/market_view.png;content/bts_spark/Market/settings_icon.png;content/bts_spark/Market/time_and_sales.png;content/bts_spark/My-Windows/_index.md;content/bts_spark/My-Windows/image15.png;content/bts_spark/My-Windows/image16.png;content/bts_spark/My-Windows/image37.png;content/bts_spark/Settings/_index.md;content/bts_spark/Settings/image51.png;content/bts_spark/Settings/image9.png;content/bts_spark/Spreader/_index.md;content/bts_spark/Spreader/image10.png;content/bts_spark/Spreader/image13.png;content/bts_spark/Spreader/image18.png;content/bts_spark/Spreader/image19.png;content/bts_spark/Spreader/image28.png;content/bts_spark/Spreader/image29.png;content/bts_spark/Spreader/image31.png;content/bts_spark/Spreader/image35.png;content/bts_spark/Spreader/image40.png;content/bts_spark/Spreader/image43.png;content/bts_spark/Spreader/image54.png;content/bts_spark/Spreader/image55.png;content/bts_spark/Spreader/image56.png;content/bts_spark/Spreader/image6.png;content/bts_spark/Spreader/image7.png;content/bts_spark/Spreader/image70.png;content/bts_spark/Spreader/image72.png;content/bts_spark/Spreader/image8.png;content/bts_spark/Trading/OrderTypes/index.md;content/bts_spark/Trading/_index.md;content/bts_spark/Trading/algo_studio.png;content/bts_spark/Trading/collapse_all_icon.png;content/bts_spark/Trading/cover_algo_control.png;content/bts_spark/Trading/expand_all_icon.png;content/bts_spark/Trading/image1.png;content/bts_spark/Trading/image17.png;content/bts_spark/Trading/image2.png;content/bts_spark/Trading/image25.png;content/bts_spark/Trading/image27.png;content/bts_spark/Trading/image33.png;content/bts_spark/Trading/image42.png;content/bts_spark/Trading/image44.png;content/bts_spark/Trading/image47.png;content/bts_spark/Trading/image48.png;content/bts_spark/Trading/image5.png;content/bts_spark/Trading/image50.png;content/bts_spark/Trading/image52.png;content/bts_spark/Trading/image57.png;content/bts_spark/Trading/image59.png;content/bts_spark/Trading/image60.png;content/bts_spark/Trading/image61.png;content/bts_spark/Trading/image62.png;content/bts_spark/Trading/image73.png;content/bts_spark/Trading/image74.png;content/bts_spark/Trading/join_algo_control.png;content/bts_spark/Trading/ladder.png;content/bts_spark/Trading/ladder_badges.png;content/bts_spark/Trading/ladder_main_part.png;content/bts_spark/Trading/lean_algo_control.png;content/bts_spark/Trading/mini_orderbook.png;content/bts_spark/Trading/oco_algo_control.png;content/bts_spark/Trading/offset_algo_control.png;content/bts_spark/Trading/pnl_calculation.png;content/bts_spark/Trading/pnl_window.png;content/bts_spark/Trading/recreate_icon.png;content/bts_spark/Trading/settings_icon.png;content/bts_spark/Trading/spark_menu_order_book.png;content/bts_spark/Trading/top_algo_control.png;content/bts_spark/Trading/trigger_algo_control.png;content/bts_spark/_index.md;content/release_notes/_index.md;content/system_requirements/_index.md;static/book.js;static/favicon.ico;static/image.js;templates/index.html;templates/page.html;templates/section.html;templates/shortcodes/back_button.html)
set(sources /home/bts/spark/doc/user/build.sh;content/_index.md;content/bts_spark/Glossary/_index.md;content/bts_spark/Help/_index.md;content/bts_spark/Help/about_spark.png;content/bts_spark/Help/image39.png;content/bts_spark/Help/image58.png;content/bts_spark/Launcher/_index.md;content/bts_spark/Launcher/image38.png;content/bts_spark/Launcher/image68.png;content/bts_spark/Logging-In-to-the-System/_index.md;content/bts_spark/Logging-In-to-the-System/image3.png;content/bts_spark/Logging-In-to-the-System/image64.png;content/bts_spark/Market/_index.md;content/bts_spark/Market/change_securities.png;content/bts_spark/Market/image11.png;content/bts_spark/Market/image14.png;content/bts_spark/Market/image20.png;content/bts_spark/Market/image21.png;content/bts_spark/Market/image23.png;content/bts_spark/Market/image24.png;content/bts_spark/Market/image34.png;content/bts_spark/Market/image49.png;content/bts_spark/Market/image53.png;content/bts_spark/Market/image66.png;content/bts_spark/Market/image69.png;content/bts_spark/Market/market_view.png;content/bts_spark/Market/settings_icon.png;content/bts_spark/Market/time_and_sales.png;content/bts_spark/My-Windows/_index.md;content/bts_spark/My-Windows/image15.png;content/bts_spark/My-Windows/image16.png;content/bts_spark/My-Windows/image37.png;content/bts_spark/Settings/_index.md;content/bts_spark/Settings/image51.png;content/bts_spark/Settings/image9.png;content/bts_spark/Spreader/_index.md;content/bts_spark/Spreader/image10.png;content/bts_spark/Spreader/image13.png;content/bts_spark/Spreader/image18.png;content/bts_spark/Spreader/image19.png;content/bts_spark/Spreader/image28.png;content/bts_spark/Spreader/image29.png;content/bts_spark/Spreader/image31.png;content/bts_spark/Spreader/image35.png;content/bts_spark/Spreader/image40.png;content/bts_spark/Spreader/image43.png;content/bts_spark/Spreader/image54.png;content/bts_spark/Spreader/image55.png;content/bts_spark/Spreader/image56.png;content/bts_spark/Spreader/image6.png;content/bts_spark/Spreader/image7.png;content/bts_spark/Spreader/image70.png;content/bts_spark/Spreader/image72.png;content/bts_spark/Spreader/image8.png;content/bts_spark/Trading/OrderTypes/index.md;content/bts_spark/Trading/_index.md;content/bts_spark/Trading/algo_studio.png;content/bts_spark/Trading/collapse_all_icon.png;content/bts_spark/Trading/cover_algo_control.png;content/bts_spark/Trading/expand_all_icon.png;content/bts_spark/Trading/image1.png;content/bts_spark/Trading/image17.png;content/bts_spark/Trading/image2.png;content/bts_spark/Trading/image25.png;content/bts_spark/Trading/image27.png;content/bts_spark/Trading/image33.png;content/bts_spark/Trading/image42.png;content/bts_spark/Trading/image44.png;content/bts_spark/Trading/image47.png;content/bts_spark/Trading/image48.png;content/bts_spark/Trading/image5.png;content/bts_spark/Trading/image50.png;content/bts_spark/Trading/image52.png;content/bts_spark/Trading/image57.png;content/bts_spark/Trading/image59.png;content/bts_spark/Trading/image60.png;content/bts_spark/Trading/image61.png;content/bts_spark/Trading/image62.png;content/bts_spark/Trading/image73.png;content/bts_spark/Trading/image74.png;content/bts_spark/Trading/join_algo_control.png;content/bts_spark/Trading/ladder.png;content/bts_spark/Trading/ladder_badges.png;content/bts_spark/Trading/ladder_main_part.png;content/bts_spark/Trading/lean_algo_control.png;content/bts_spark/Trading/mini_orderbook.png;content/bts_spark/Trading/oco_algo_control.png;content/bts_spark/Trading/offset_algo_control.png;content/bts_spark/Trading/pnl_calculation.png;content/bts_spark/Trading/pnl_window.png;content/bts_spark/Trading/recreate_icon.png;content/bts_spark/Trading/settings_icon.png;content/bts_spark/Trading/spark_menu_order_book.png;content/bts_spark/Trading/top_algo_control.png;content/bts_spark/Trading/trigger_algo_control.png;content/bts_spark/_index.md;content/release_notes/_index.md;content/system_requirements/_index.md;static/book.js;static/favicon.ico;static/image.js;templates/index.html;templates/page.html;templates/section.html;templates/shortcodes/back_button.html)
+9
View File
@@ -4,6 +4,15 @@ weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++
## 2.15.3
### Bug Fixes
- Fixed a bug where some CME currency spreads exhibited incorrect tick values
## 2.15.2
### User Visible Changes
- Excel RTD plugin can now receive ICE market data
## 2.15.1
### Bug Fixes
- Fixed a FIX log parsing issue that resulted in exchange gateway logon problems
## 2.15.0
### User Visible Changes
- Added ability to hide Ladder status messages via Ladder Settings -> Left Panel tab -> Show/Hide groupbox -> Status Message
+2 -1
View File
@@ -19,7 +19,8 @@
<LangVersion>7.2</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<Version>1.0.0</Version>
<Version>$(major).$(minor).$(patch)</Version>
<Version Condition="'$(version)'=='..'">1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../spark_api/spark_api.csproj" />
@@ -292,7 +292,9 @@ namespace mbts.spark {
int count = 0;
double factored_base = log10_diff > 0 ? reduced_target_base * Math.Pow(10, Math.Ceiling(log10_diff)) : reduced_target_base;
do {
if (factored_base % raw_base == 0)
// Note that the modulus operator is not used here due to rounding errors.
// Such a rounding errror was the cause of the bug https://bluetradesys.atlassian.net/browse/SP-283.
if (MathUtils.is_int(factored_base / raw_base))
return new TickFactors(factored_base, factored_base / raw_base);
factored_base *= 10;
} while (++count < 10);
+5 -5
View File
@@ -3,17 +3,19 @@
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Authors>Blue Trading Systems</Authors>
<Company>Blue Trading Systems</Company>
<Product>Spark</Product>
<Description />
<PackageId>Spark_API</PackageId>
<Product>Spark</Product>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>x64</Platforms>
<PlatformTarget>AnyCPU</PlatformTarget>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<Version>1.0.0</Version>
<Version>$(major).$(minor).$(patch)</Version>
<Version Condition="'$(version)'=='..'">0.0.0</Version>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
@@ -24,12 +26,10 @@
<Proto3 Include="**/*.proto" />
<Proto3 Include="../../lib/api/*.proto" />
<Proto3 Include="../../lib/api/services/*.proto" />
<!--Proto3 Remove="../../lib/api/services/MarketDataRelay.proto" /-->
<Proto3 Include="../../lib/md/protos/co2.proto" />
<Proto3 Include="../../lib/domain_model/Security.proto" />
<Proto3 Include="../../lib/sparkproto/SparkProtos.proto" />
<Proto3 Update="../../lib/api/services/OutOfProcessURLListener.proto">
<!-- <CompileOptions>internal_access:</CompileOptions> -->
</Proto3>
</ItemGroup>
</Project>
@@ -0,0 +1,10 @@
using Google.Protobuf;
namespace bts.api {
public sealed partial class Product : ICustomDiagnosticMessage {
public string ToDiagnosticString() {
return $"{this.Symbol}:{this.Type}:{this.Exchange}";
}
}
}
+2 -1
View File
@@ -7,7 +7,8 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<Version>1.0.0</Version>
<Version>$(major).$(minor).$(patch)</Version>
<Version Condition="'$(version)'=='..'">0.0.0</Version>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
@@ -66,9 +66,23 @@ namespace bts.excel.rtd
if (string.IsNullOrEmpty(contract))
return Observable.Return(new []{"Can't Parse Contract: " + contract ?? string.Empty});
Func<SecurityImmutable, bool> where = (x => x.Exchange == ven && x.Symbol == symbol && x.security_type() == sectype &&
x.Glbx.SecurityDesc == contract);
Func<SecurityImmutable, bool> desc = null;
switch(ven)
{
case Venue.Sim:
case Venue.Glbx:
desc = (x=> x.Glbx.SecurityDesc == contract);
break;
case Venue.Ice:
desc = (x=> x.Ice.SecurityDesc == contract);
break;
default:
desc = (x => true);
break;
}
Func<SecurityImmutable, bool> where = (x => x.Exchange == ven && x.Symbol == symbol && x.security_type() == sectype && desc(x) );
var stream = market_data(ven).subscribe_combined(where);
return stream;
}
+2 -1
View File
@@ -17,7 +17,8 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<Version>1.0.0</Version>
<Version>$(major).$(minor).$(patch)</Version>
<Version Condition="'$(version)'=='..'">1.0.0</Version>
</PropertyGroup>
<ItemGroup>
Binary file not shown.
@@ -19,6 +19,8 @@ namespace bts {
public bool admin { get; set; }
[Option(nameof(latency))]
public bool latency { get; set; }
[Option("md")]
public bool market_data { get; set; }
}
public class ServiceTest {
@@ -35,9 +37,24 @@ namespace bts {
if (o.latency) {
latency_test();
}
if (o.market_data) {
market_data();
}
return 0;
}
private static void market_data() {
using (var ctx = new ServiceContext()) {
var md = ctx.locate<MarketDataService>();
md.subscribe_securities().Table().Subscribe(update => {
Console.WriteLine($"got {update.state.Count} securities");
});
while(true) {
Thread.Sleep(1000);
}
}
}
static string try_get(string[] args, int index) {
if (args.Length < index) {
return args[index];
+1 -1
View File
@@ -1 +1 @@
set(sources files/cert_secure_logon.txt;files/futures.coconut.xz;files/onixs_ice/ConnectivityConfiguration.APITest.xml;files/onixs_ice/ConnectivityConfiguration.PerfTest.xml;files/onixs_ice/ConnectivityConfiguration.Production.xml;files/perf_trace/compiled.css;files/perf_trace/index.html;files/perf_trace/jquery-3.3.1.min.js;files/perf_trace/main.js;files/perf_trace/perf_log.sql;files/perf_trace/perf_trace_analysis.sql;files/perf_trace/plotly-latest.min.js)
set(sources files/cert_secure_logon.txt;files/cert_secure_logon.txt.orig;files/futures.coconut.xz;files/onixs_ice/ConnectivityConfiguration.APITest.xml;files/onixs_ice/ConnectivityConfiguration.PerfTest.xml;files/onixs_ice/ConnectivityConfiguration.Production.xml;files/perf_trace/compiled.css;files/perf_trace/index.html;files/perf_trace/jquery-3.3.1.min.js;files/perf_trace/main.js;files/perf_trace/perf_log.sql;files/perf_trace/perf_trace_analysis.sql;files/perf_trace/plotly-latest.min.js)
+7 -6
View File
@@ -1,12 +1,13 @@
Session ID Access ID Secret Key Creation Date Expiration Date Environment
Session ID Access ID Secret Key Creation Date Expiration Date Environment
M4D lLtjH74y1Kh5XUJTLyH2 f1K_tROQp2lTIplVp34WxKa7xDUgfFnIteolfik061o 2019-09-03 2020-09-03 CERT
M4D lLtjH74y1Kh5XUJTLyH2 f1K_tROQp2lTIplVp34WxKa7xDUgfFnIteolfik061o 2019-09-03 2020-09-03 CERT
MC1 VEMlkDuLz74OVHSuacQB IuHyYT3b-9KUo3WsuXykt-fXsjzp7L-JOrdCSQZLNl0 2019-09-03 2020-09-03 CERT
MC1 VEMlkDuLz74OVHSuacQB IuHyYT3b-9KUo3WsuXykt-fXsjzp7L-JOrdCSQZLNl0 2019-09-03 2020-09-03 CERT
MC5 77lzSUwPLlM9obaXh2mK z6aA9qfASDKfZkYTVKFqJd-78i0HZ2Q9ec3CKCYIqHg 2019-09-03 2020-09-03 CERT
MC5 77lzSUwPLlM9obaXh2mK z6aA9qfASDKfZkYTVKFqJd-78i0HZ2Q9ec3CKCYIqHg 2019-09-03 2020-09-03 CERT
MC7 RphzI3rn71oGUEiYnX9e y6OvvPPyoyj2S8YAnE1gFduXT8v29HIMjO5EngYxSNg 2019-09-03 2020-09-03 CERT
MC7 RphzI3rn71oGUEiYnX9e y6OvvPPyoyj2S8YAnE1gFduXT8v29HIMjO5EngYxSNg 2019-09-03 2020-09-03 CERT
MC8 PYBIm2TI9gFPIxmHbuYl 6o-ZolGH2DdeQOlGtJ5Zqoh_kg7VdbxkmjeOHmigKwU 2019-09-03 2020-09-03 CERT
MC8 PYBIm2TI9gFPIxmHbuYl 6o-ZolGH2DdeQOlGtJ5Zqoh_kg7VdbxkmjeOHmigKwU 2019-09-03 2020-09-03 CERT
NGG 1OXPqNxPhbqbzm0kF92e qlUrwY1KG1Pyq-TcbJgMqYXmBTQoAi-wEEBERRDRZPE 2019-12-20 2020-12-20 NEWRELEASE
+1 -1
View File
@@ -1 +1 @@
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/service_helpers/PositionUtilities.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/BasePositionService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/MoneyFileService.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/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/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/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/position_cfg.conf;config/defaults/span.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/keycode.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/position_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.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/sod.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/MBOProcessor.cpp;md/MBOServiceServer.cpp;md/MDClient.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityCache.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SecurityMapper.cpp;md/SecurityOracle.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/ice/ICEUtils.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/mbo_tests.cpp;md/test/md2_tests.cpp;md/test/md_test_utils.cpp;md/test/synthetic_book_merge_tests.cpp;md/vendor/OnixsUtils.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;orLine truncated
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/service_helpers/PositionUtilities.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/BasePositionService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/MarketDataService.proto;api/services/MoneyFileService.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/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/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/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/position_cfg.conf;config/defaults/span.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/keycode.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/position_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.proto;config/protos/spreader.proto;config/protos/subprocess.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/sod.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/MBOProcessor.cpp;md/MBOServiceServer.cpp;md/MDClient.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/Product.cpp;md/SecurityCache.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SecurityMapper.cpp;md/SecurityOracle.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/ice/ICEUtils.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/service/MarketDataServiceServer.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/mbo_tests.cpp;md/test/md2_tests.cpp;md/test/md_test_utils.cpp;md/test/synthetic_book_merge_tests.cpp;md/vendor/OnixsUtils.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;metricsLine truncated
+1 -1
View File
@@ -1 +1 @@
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/service_helpers/PositionUtilities.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/BasePositionService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/MoneyFileService.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/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/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/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/position_cfg.conf;config/defaults/span.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/keycode.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/position_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.proto;config/protos/spreader.proto;config/protos/subprocess.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/sod.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/MBOProcessor.cpp;md/MBOServiceServer.cpp;md/MDClient.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityCache.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SecurityMapper.cpp;md/SecurityOracle.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/ice/ICEUtils.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/mbo_tests.cpp;md/test/md2_tests.cpp;md/test/md_test_utils.cpp;md/test/synthetic_book_merge_tests.cpp;md/vendor/OnixsUtils.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/AuthSessionManager.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;Line truncated
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/service_helpers/PositionUtilities.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/BasePositionService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/MarketDataService.proto;api/services/MoneyFileService.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/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/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/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/position_cfg.conf;config/defaults/span.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/keycode.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/position_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.proto;config/protos/spreader.proto;config/protos/subprocess.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/sod.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/MBOProcessor.cpp;md/MBOServiceServer.cpp;md/MDClient.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/Product.cpp;md/SecurityCache.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SecurityMapper.cpp;md/SecurityOracle.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/ice/ICEUtils.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/service/MarketDataServiceServer.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/mbo_tests.cpp;md/test/md2_tests.cpp;md/test/md_test_utils.cpp;md/test/synthetic_book_merge_tests.cpp;md/vendor/OnixsUtils.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/AuthSessionManager.cpp;utils/AuthToken.cLine truncated
@@ -580,7 +580,14 @@ bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(const bt
rv.set_session(conn_ptr->name());
rv.set_operator_id(cme_user_data->operator_id());
rv.set_location(cme_user_data->location());
// smp_id should be 0 or 8 bytes so it can be encoded as a 64 bit number for ilink3
rv.set_smp_id(cme_user_data->smp_id());
if (!rv.smp_id().empty() && rv.smp_id().size() < 8) {
std::string smp_id = rv.smp_id();
while(smp_id.size() < 8) smp_id += "0";
rv.set_smp_id(smp_id);
}
if (cme_user_data->smp_instruction()== "O")
rv.set_smp_instruction(api::orderman::SelfMatchPreventionInstruction::SELF_MATCH_PREVENTION_INSTRUCTION_CANCEL_RESTING);
else if (cme_user_data->smp_instruction()== "N")
@@ -0,0 +1,46 @@
syntax="proto3";
package bts.api;
option csharp_namespace="bts.api";
option cc_enable_arenas=true;
import "lib/api/apioptions.proto";
import "lib/api/apicore.proto";
import "lib/domain_model/Security.proto";
import "lib/md/protos/co2.proto";
message ProductList {
repeated bts.api.Product products = 1;
}
// Should this cary int prices?
message PriceEntry {
double price = 1;
uint32 direct = 10;
uint32 implied = 11;
}
message BookEntry {
uint32 key = 1 [(bts.api.key)=true];
repeated PriceEntry bid = 10;
repeated PriceEntry ask = 20;
}
message TickerEntry {
uint32 key = 1 [(bts.api.key)=true];
int64 time = 2;
double price = 3;
uint32 size = 4;
uint32 total_volume = 5;
bts.co2.AggressorSide aggressor_side = 6;
bool from_spread = 7;
bool gap = 10;
}
service MarketDataService {
rpc get_products(bts.api.VoidMessage) returns (ProductList);
// stream all securities
rpc securities (bts.api.VoidMessage) returns (stream bts.api.Security);
rpc book (bts.api.Product) returns (stream BookEntry);
rpc trades(bts.api.VoidMessage) returns (stream TickerEntry);
// subscribe_misc(Product)
}
+4 -4
View File
@@ -1,12 +1,12 @@
#nusers: 1
#nusers: 2
#allow concurrent : true
#expires: 2020-Mar-31 00:00:00 637212096000000000
#generation_time: 2020-Jan-06 18:56:23.406931 5248825356261457214
#expires: 2021-Jan-01 00:00:00 637450560000000000
#generation_time: 2020-Apr-27 21:55:11.126045 5248922231538648354
EncryptedKeyCode {
value {
keycode: "Ixb/z6hwFQmojpm4GwNEpQmsqpYT9OTHbcKtROIqj38GwGqyVn54JMDB04V048quO+NAI78DKJXsUWgjDH0y5HQlwN6Lq48s/bdwKqR1OTBPr6xoTImtCb+l5b+8fUGlg7t3X8gfMdxohHgcUi9k9n7ZrnNvqcjdYKoP0CaTZT8zHuBQx3f4Lqrz32gq9rJ5skRjH6ZqNblNdlsF+kOAqXCkvI5p0QfyKgtCodr33qsW2cbqY5gUD9KwsnmFVa8/zuFBucsoM7dHB47yRaIeOFFu7xGayAdAHA8SwLyoxE5y+adIX1SYnAiqAu1raZpeXgRE1LNQk3c7uhUjt0coag=="
keycode: "jVEAueEfjx2MHzAOgJMSl8z9zwK9sUXp6iKr2+zTvgNrrZevi2I5pK1OCkHhE5IQZuRde5MyL8VpgBmZg/AnNVBo6719LT06MQBExbWKpx+2/LWF/JDv8m2sBUKdfze40vnPIGhXnLl/9mg74gD6uJgRU8uLEq3Hi5Xolqdi+kLKu9Qy4yuxy1hcYzdWPmYHvGcHGlaPH3jMN96m1DIcNYoV+RvoqlIv5zVDDWRWBMIiiwqrxlpwRJBw3R0pVpRVjUYqWw9dpfkIYevpCyvw+O4hqeGKuXCylie6wHiRPIa5Pxoxu3e5K2E1epGG6I7F56hQv+e1YPk1w4vwuEACWA=="
}
}
+53 -13
View File
@@ -2,17 +2,28 @@ OrdermanCfg {
rule: "DeploymentType.type == 'dev'"
value {
executor {
thread_name: "oman_orders"
poll: false
hosted_actor: "MDSource"
hosted_actor: "OrderManager"
hosted_actor: "ExecutionGateway"
thread_name: "oman0"
poll: false
hosted_actor: { type: "MDSource" }
hosted_actor: { type: "OrderManagerShard" qualifier: "om0" }
}
executor {
thread_name: "oman1"
poll: false
hosted_actor: { type: "MDSource" }
hosted_actor: { type: "OrderManagerShard" qualifier: "catch_all" }
}
executor {
thread_name: "oman_gw"
poll: false
hosted_actor: { type: "Gateway" qualifier: "gw0" }
}
executor {
thread_name: "oman_slow"
poll: false
hosted_actor: "*"
poll: false
hosted_actor: { type : "*" }
}
use_gateway: true
}
}
@@ -20,15 +31,44 @@ OrdermanCfg {
value {
executor {
thread_name: "oman_orders"
poll: true
hosted_actor: "MDSource"
hosted_actor: "OrderManager"
hosted_actor: "ExecutionGateway"
poll: true
hosted_actor: { type: "MDSource" }
hosted_actor: { type: "OrderManager" }
}
executor {
thread_name: "oman_gw"
poll: true
hosted_actor: { type: "Gateway" qualifier: "gw0" }
}
executor {
thread_name: "oman_slow"
poll: false
hosted_actor: "*"
poll: false
hosted_actor: { type: "*" }
}
use_gateway: true
}
}
OrdermanShardCfg {
value {
shard {
qualifier: "om0"
user_regex: "^.*(bts|cqg).*$"
}
shard {
qualifier: "catch_all"
user_regex: "^((?!(bts|cqg)).)*$"
is_unknown_order_catch_all: true
}
}
}
GatewayCfg {
value {
#note that multiple gws are possible but not well tested as of 4/23/2020
gateway {
qualifier: "gw0"
connection: "*"
}
}
}
+2 -1
View File
@@ -87,6 +87,7 @@ message JetFIX {
optional uint32 max_connection_attempts = 346 [default=10];
optional bool auto_fix_seq_num = 347 [default=false];
optional bool use_ilink3 = 348 [default=false] ;
}
repeated Connection connection = 10;
@@ -116,4 +117,4 @@ message CMECannedSecureLogon {
"MC8 AbEEtBn63WIAuItPDz1c n3ndjYb03Hx6wBO3me35HoONyDgO5TZKWk0tDSaX9KA 2018-04-05 2019-04-05 CERT \n"
"T39 UWggBgHWAe07aqW3ps2I tbb3it0rUQSSTa0TC9QcRwkrHEMDLWhaJH4VQ0FqGB4 2018-04-05 2019-04-05 NEWRELEASE \n"
];
}
}
+24 -1
View File
@@ -2,12 +2,35 @@ syntax='proto2';
package bts.config;
message OrdermanCfg {
message HostedActor {
required string type = 1;
optional string qualifier = 2;
}
message Executor {
required string thread_name = 1;
optional bool poll = 2 [ default = false];
repeated string hosted_actor = 3;
//repeated string hosted_actor = 3;
repeated HostedActor hosted_actor = 4;
}
repeated Executor executor = 1;
optional uint32 default_iceberg_pause_secs = 2 [default = 0];
optional string fallback_cust_order_handling_inst = 3 [default = "Y"];
optional bool use_gateway = 4 [default = true];
}
message OrdermanShardCfg {
message OrderManagerShard {
required string qualifier = 1;
required string user_regex = 2;
optional bool is_unknown_order_catch_all = 3;
}
repeated OrderManagerShard shard = 1;
}
message GatewayCfg {
message Gateway {
required string qualifier = 1;
repeated string connection = 2;
}
repeated Gateway gateway = 1;
}
+1 -1
View File
@@ -52,7 +52,7 @@ class FIXEncodingStream {
auto msg_offset = _buffer.size();
_current_msg = FIXFragment(_buffer);
_begin_string_bm = _current_msg.add<fix::BeginString>("FIX.4.2");
_begin_string_bm = _current_msg.add<fix::BeginString>(std::string_view {"FIX.4.2"});
_body_length_bm = _current_msg.add<fix::BodyLength>(0, 6);
char mt_encoding[4];
+1
View File
@@ -85,6 +85,7 @@ typedef StringField<307> UnderlyingSecurityDesc;
typedef StringField<336> TradingSessionID;
typedef StringField<35> MsgType;
typedef StringField<37> OrderID;
typedef BigIntField<37> OrderIDu64;
typedef StringField<41> OrigClOrdID;
typedef StringField<440> ClearingAccount;
typedef StringField<48> SecurityID;
+9
View File
@@ -2,6 +2,8 @@
#include <memory>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <string_view>
#include "lib/jetfix/codec/ReaderCursor.h"
#include "lib/utils/meta_programming.h"
#include "lib/utils/datetime.h"
@@ -203,6 +205,13 @@ public:
static std::pair<uint32_t,uint32_t> write (char*buffer,std::string const &str)
{return write (buffer,str.data (),str.size ());}
#if __cplusplus >= 201703L
static uint32_t max_value_size (std::string_view const&str) {return str.size ();}
static std::pair<uint32_t,uint32_t> write (char*buffer,std::string_view const &str)
{return write (buffer,str.data (),str.size ());}
#endif
static std::pair<uint32_t,uint32_t> write (char*buffer,const char*str,uint32_t sz)
{
memcpy (buffer,str,sz);
+1
View File
@@ -49,6 +49,7 @@ enum class MessageTypes : uint32_t
TestRequest = '1',
TradingSessionStatus = 'h',
TradingSessionStatusRequest = 'g',
MDIncrementalUpdate = 'X',
ICETraderLogin = ('U' << 16) + ('C' << 8) + 'G',
ICETraderLoginResponse = ('U' << 16) + ('C' << 8) + 'I',
ICETraderLogout = ('U' << 16) + ('C' << 8) + 'H',
+56 -56
View File
@@ -40,13 +40,13 @@ OutFIXPtr make_seq_reset(config::JetFIX::Connection const &session_cfg,
enum class Session::State {
WLOGON,
RECOVER,
WTR_REPLY,
READY,
TERMINATED,
WLOGOUT,
CERT_MODE
};
RECOVER,
WTR_REPLY,
READY,
TERMINATED,
WLOGOUT,
CERT_MODE
};
struct Session::RecoveryState {
RecoveryState() : buffered_msgs(), resend_request(0, 0) {}
@@ -59,14 +59,14 @@ struct Session::PImpl {
PImpl(config::JetFIX::Connection const &cfg, IConnection &connection,
IFIXStore &store, ICoreGatewayEventSink &sink, Clock const &clock,
trace::PerfLog &perf_log)
: cfg(cfg), state(State::TERMINATED), connection(connection),
store(store), event_sink(sink), now(clock), perf_log(perf_log),
begin_of_this_session(), last_seq_num(), last_seq_num_processed(),
last_sent_msg_timestamp(), last_sent_sync_timestamp(),
last_rcvd_msg_timestamp(), start_of_logon(), start_of_logout(),
current_time(std::make_shared<std::string>(
datetime::FIX_timestamp(datetime::now()))),
recovery_state() {}
: cfg(cfg), state(State::TERMINATED), connection(connection),
store(store), event_sink(sink), now(clock), perf_log(perf_log),
begin_of_this_session(), last_seq_num(), last_seq_num_processed(),
last_sent_msg_timestamp(), last_sent_sync_timestamp(),
last_rcvd_msg_timestamp(), start_of_logon(), start_of_logout(),
current_time(std::make_shared<std::string>(
datetime::FIX_timestamp(datetime::now()))),
recovery_state() {}
config::JetFIX::Connection cfg;
State state;
@@ -90,7 +90,7 @@ struct Session::PImpl {
Session::Session(config::JetFIX::Connection const &cfg, IConnection &connection,
IFIXStore &store, ICoreGatewayEventSink &sink,
Clock const &clock, trace::PerfLog &perf_log)
: me(new PImpl(cfg, connection, store, sink, clock, perf_log)) {}
: me(new PImpl(cfg, connection, store, sink, clock, perf_log)) {}
Session::~Session() {
if (me->state != State::TERMINATED)
@@ -248,16 +248,16 @@ void Session::on_logon(InMsgBuffer const &msg) {
} else {
if (their_last <= our_last_processed)
terminate_session(
JetFIXError::INCOMING_SN_TOO_SMALL,
(boost::format(
"Incoming sequence number was %d "
"but the last one we processed was %d. "
"Most likely the FIX sequencer numbers file "
"($SPARKDATA/data/jetfix/connection_name/current/seqnum) "
"was deleted. Update this file with the correct "
"incoming sequence number (second column)") %
their_last % our_last_processed)
.str());
JetFIXError::INCOMING_SN_TOO_SMALL,
(boost::format(
"Incoming sequence number was %d "
"but the last one we processed was %d. "
"Most likely the FIX sequencer numbers file "
"($SPARKDATA/data/jetfix/connection_name/current/seqnum) "
"was deleted. Update this file with the correct "
"incoming sequence number (second column)") %
their_last % our_last_processed)
.str());
else if (their_last == (our_last_processed + 1)) {
transition(State::WTR_REPLY);
@@ -329,9 +329,9 @@ void Session::on_test_request(InMsgBuffer const &msg) {
switch (me->state) {
case State::WLOGON:
terminate_session(
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (char)msg.type())
.str());
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (char)msg.type())
.str());
break;
case State::RECOVER:
internal_send(make_hb(me->cfg, msg.get_test_req_id()));
@@ -363,8 +363,8 @@ void Session::on_resend_request(InMsgBuffer const &msg) {
switch (me->state) {
case State::WLOGON:
terminate_session(
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
break;
case State::RECOVER:
case State::WTR_REPLY:
@@ -386,12 +386,12 @@ void Session::on_resend_request(InMsgBuffer const &msg) {
send_seq_reset(msg.get_begin_seq_no(), msg.get_end_seq_no());
else
logout(
JetFIXError::UNEXPECTED_RESEND_REQUEST,
(boost::format("Received resend request for messages "
"%d to %d but my initial sequence number is %d ") %
msg.get_begin_seq_no() % msg.get_end_seq_no() %
me->begin_of_this_session)
.str());
JetFIXError::UNEXPECTED_RESEND_REQUEST,
(boost::format("Received resend request for messages "
"%d to %d but my initial sequence number is %d ") %
msg.get_begin_seq_no() % msg.get_end_seq_no() %
me->begin_of_this_session)
.str());
break;
}
case State::WLOGOUT:
@@ -408,8 +408,8 @@ void Session::on_seq_reset(InMsgBuffer const &msg) {
switch (me->state) {
case State::WLOGON:
terminate_session(
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
break;
case State::RECOVER:
buffer_or_deliver(msg);
@@ -439,8 +439,8 @@ void Session::on_hb(InMsgBuffer const &msg) {
switch (me->state) {
case State::WLOGON:
terminate_session(
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
break;
case State::RECOVER:
buffer(msg);
@@ -471,8 +471,8 @@ void Session::on_app(InMsgBuffer const &msg) {
switch (me->state) {
case State::WLOGON:
terminate_session(
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
JetFIXError::EXPECTED_LOGON,
(boost::format("Received message type %c ") % (int)msg.type()).str());
break;
case State::RECOVER:
buffer_or_deliver(msg);
@@ -595,8 +595,8 @@ void Session::terminate_session(JetFIXError::Code reason) {
bool match_with_outgoing_sn_too_small(std::string const &msg, uint32_t *sn) {
std::string rx_str =
".*Sequence number received lower than expected. Expected "
"\\[(\\d+)\\] Received \\d+.*";
".*Sequence number received lower than expected. Expected "
"\\[(\\d+)\\] Received \\d+.*";
std::regex rx(rx_str);
std::smatch matches;
@@ -609,7 +609,7 @@ bool match_with_outgoing_sn_too_small(std::string const &msg, uint32_t *sn) {
bool match_with_incoming_sn_too_small(std::string const &msg, uint32_t *sn) {
std::string rx_str = ".*Incoming sequence number was (\\d+) "
"but the last one we processed was .*";
"but the last one we processed was .*";
std::regex rx(rx_str);
@@ -728,7 +728,7 @@ std::pair<uint32_t, uint32_t> Session::find_first_incoming_msg_gap() {
else
return std::make_pair(me->last_seq_num_processed + 1,
me->recovery_state->buffered_msgs.begin()->first -
1);
1);
}
bool Session::resend_request_active() {
@@ -786,9 +786,9 @@ OutFIXPtr make_logon(uint32_t seq_num, uint32_t last_seq_num_processed,
if(session_cfg.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_ICE ||
session_cfg.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_SIMICE)
{
buffer.add<ICEApplicationSystemName>(application);
buffer.add<ICEApplicationSystemVersion>("1.0");
buffer.add<ICEApplicationSystemVendor>("BTS");
buffer.add<ICEApplicationSystemName>(std::string_view{application});
buffer.add<ICEApplicationSystemVersion>(std::string_view{"1.0"});
buffer.add<ICEApplicationSystemVendor>(std::string_view{"BTS"});
buffer.add<UserName>(session_cfg.user_name());
buffer.add<RawDataLength>(session_cfg.raw_data().size());
@@ -799,9 +799,9 @@ OutFIXPtr make_logon(uint32_t seq_num, uint32_t last_seq_num_processed,
}
else
{
buffer.add<ApplicationSystemName>(application);
buffer.add<ApplicationSystemVersion>("1.0");
buffer.add<ApplicationSystemVendor>("BTS");
buffer.add<ApplicationSystemName>(std::string_view{application});
buffer.add<ApplicationSystemVersion>(std::string_view{"1.0"});
buffer.add<ApplicationSystemVendor>(std::string_view{"BTS"});
if (session_cfg.has_trading_session_id()) {
buffer.add<fix::NoTradingSessions>(1);
@@ -824,12 +824,12 @@ OutFIXPtr make_logon(uint32_t seq_num, uint32_t last_seq_num_processed,
std::to_string(session_cfg.seconds_between_hbs()),
session_cfg.sender_locationid(), last_seq_num_str, application, "1.0",
"BTS");
#ifndef BTS_EDGE
#ifndef BTS_EDGE
LOG(Jetfix, Info, "Canonical string for secure logon: {}", ld.canonical);
#endif
#endif
buffer.add<EncodedTextLen>(ld.access_key.size());
buffer.add<EncodedText>(ld.access_key);
buffer.add<EncryptedPasswordMethod>("CME-1-SHA-256");
buffer.add<EncryptedPasswordMethod>(std::string_view{"CME-1-SHA-256"});
buffer.add<EncryptedPasswordLen>(ld.signature.size());
buffer.add<EncryptedPassword>(ld.signature);
}
+9 -8
View File
@@ -18,8 +18,8 @@
#include <fmt/format.h>
#include <fstream>
#include <thread>
#include <regex>
#include <thread>
namespace bts {
namespace jetfix {
@@ -114,16 +114,17 @@ std::string store_path(std::string base_path,
return result.string();
}
bool is_valid_store_line(std::string const&line) {
std::regex rx("\\d\\d\\d\\d\\d\\d\\d\\d-"
"\\d\\d:\\d\\d:\\d\\d\\."
"\\d\\d\\d . 8=FIX\\.4\\.2.*");
return std::regex_match(line, rx);
static std::regex store_line_rx("\\d\\d\\d\\d\\d\\d\\d\\d-"
"\\d\\d:\\d\\d:\\d\\d\\."
"\\d\\d\\d . 8=FIX\\.4\\.2.*");
bool is_valid_store_line(std::string const &line) {
return std::regex_match(line, store_line_rx);
}
std::map<uint32_t, InMsgBuffer>
load_replay(config::JetFIX::Connection const &cfg, std::string const &path,
uint32_t ) {
uint32_t) {
std::map<uint32_t, InMsgBuffer> result;
if (boost::filesystem::exists(path)) {
@@ -137,7 +138,7 @@ load_replay(config::JetFIX::Connection const &cfg, std::string const &path,
if (!f.eof()) {
if (!is_valid_store_line(line_buffer))
continue;
if (line_buffer[22] == '<') {
auto ts =
datetime::parse_FIX_timestamp(line_buffer.substr(0, 21));
+7 -7
View File
@@ -81,9 +81,9 @@ TEST_CASE ("JetFIX Field2Tests", "[jetfix]")
std::string out (20, ' ');
typedef StringField<123> Field;
REQUIRE(Field::max_value_size ("hello")==5);
REQUIRE(Field::max_value_size (std::string_view{"hello"})==5);
auto result = Field::write (&out[0],"hello");
auto result = Field::write (&out[0],std::string_view{"hello"});
REQUIRE (result.first==5);
REQUIRE (result.second=='h'+'e'+'l'+'l'+'o');
REQUIRE (out.compare (0,5,"hello") == 0);
@@ -112,7 +112,7 @@ TEST_CASE ("JetFIX FIXFragmentTests" , "[jetfix]")
FIXFragment g (0);
g.add<CharField<1>> ('a');
g.add<FloatField<2>> (1.2,-1,6);
g.add<StringField<3>> ("hello");
g.add<StringField<3>> (std::string_view{"hello"});
g.add<IntField<4>> (123,3);
const char*t_s = "20150427-19:05:18.922";
g.add<TimeField<5>> (datetime::parse_FIX_timestamp (t_s));
@@ -141,14 +141,14 @@ TEST_CASE ("JetFIX FIXFragmentTests" , "[jetfix]")
FIXFragment g;
auto c_bm = g.add<CharField<1>> ('a');
auto f_bm = g.add<FloatField<2>> (1.2,-1,6);
auto s_bm = g.add<StringField<3>> ("hello");
auto s_bm = g.add<StringField<3>> (std::string_view{"hello"});
auto i_bm = g.add<IntField<4>> (123,3);
auto t_bm = g.add<TimeField<5>> (datetime::parse_FIX_timestamp (t_s1));
auto b_bm = g.add<BoolField<6>> (true);
g.overwrite (c_bm,'b');
g.overwrite (f_bm,1.3,-1,6);
g.overwrite (s_bm,"olleh");
g.overwrite (s_bm,std::string_view {"olleh"});
g.overwrite (i_bm,321,3);
g.overwrite (t_bm,(datetime::parse_FIX_timestamp (t_s2)));
g.overwrite (b_bm,false);
@@ -172,11 +172,11 @@ TEST_CASE ("JetFIX FIXFragmentTests" , "[jetfix]")
FIXFragment g1;;
g1.add<CharField<1>> ('a');
g1.add<FloatField<2>> (1.2,-1,6);
g1.add<StringField<3>> ("hello");
g1.add<StringField<3>> (std::string_view{"hello"});
auto chk1 = g1.checksum ();
FIXFragment g2;
g2.add<StringField<4>> ("goodbye");
g2.add<StringField<4>> (std::string_view{"goodbye"});
g2.add<IntField<5>> (321,3);
auto chk2 = g2.checksum ();
+12 -12
View File
@@ -172,12 +172,12 @@ TEST_CASE ("JetFIX FileStoreTests", "[jetfix]")
FIXEncodingStream stream (c);
auto &buf = stream.new_msg (MessageTypes::Logon);
buf.add<fix::TargetLocationID> ("US,NC");
buf.add<fix::TargetLocationID> (std::string_view {"US,NC"});
buf.add<fix::EncryptMethod> (0);
buf.add<fix::HeartBtInt>(30);
buf.add<fix::ApplicationSystemName> ("O2");
buf.add<fix::ApplicationSystemVersion> ("1.0");
buf.add<fix::ApplicationSystemVendor> ("BTS");
buf.add<fix::ApplicationSystemName> (std::string_view{"O2"});
buf.add<fix::ApplicationSystemVersion> (std::string_view {"1.0"});
buf.add<fix::ApplicationSystemVendor> (std::string_view {"BTS"});
stream.close ();
stream.stamp (2,3,datetime::FIX_timestamp (datetime::now ()));
auto fix = stream.to_str ();
@@ -213,12 +213,12 @@ TEST_CASE ("JetFIX FileStoreTests", "[jetfix]")
auto msg_vec = std::make_shared<OutFIX>(c);
auto &stream = msg_vec->fix.back ();
auto &buf = stream.new_msg (MessageTypes::Logon);
buf.add<fix::TargetLocationID> ("US,NC");
buf.add<fix::TargetLocationID> (std::string_view{"US,NC"});
buf.add<fix::EncryptMethod> (0);
buf.add<fix::HeartBtInt>(30);
buf.add<fix::ApplicationSystemName> ("O2");
buf.add<fix::ApplicationSystemVersion> ("1.0");
buf.add<fix::ApplicationSystemVendor> ("BTS");
buf.add<fix::ApplicationSystemName> (std::string_view{"O2"});
buf.add<fix::ApplicationSystemVersion> (std::string_view{"1.0"});
buf.add<fix::ApplicationSystemVendor> (std::string_view{"BTS"});
stream.close ();
stream.stamp (2,3,datetime::FIX_timestamp (datetime::now ()));
@@ -255,12 +255,12 @@ TEST_CASE ("JetFIX FileStoreTests", "[jetfix]")
msg_vec->emplace_back (c);
auto &stream = msg_vec->back ();
auto &buf = stream.new_msg (MessageTypes::Logon);
buf.add<fix::TargetLocationID> ("US,NC");
buf.add<fix::TargetLocationID> (std::string_view{"US,NC"});
buf.add<fix::EncryptMethod> (0);
buf.add<fix::HeartBtInt>(30);
buf.add<fix::ApplicationSystemName> ("O2");
buf.add<fix::ApplicationSystemVersion> ("1.0");
buf.add<fix::ApplicationSystemVendor> ("BTS");
buf.add<fix::ApplicationSystemName> (std::string_view{"O2"});
buf.add<fix::ApplicationSystemVersion> (std::string_view{"1.0"});
buf.add<fix::ApplicationSystemVendor> (std::string_view{"BTS"});
stream.close ();
stream.stamp (i,3,datetime::FIX_timestamp (datetime::now () - boost::gregorian::days (1)));
fs.store (InMsgBuffer (stream.to_str ()));
+37
View File
@@ -0,0 +1,37 @@
#ifndef _WIN32
#include "Product.h"
#include <boost/tokenizer.hpp>
#include <vector>
namespace bts {
namespace api {
std::string product_to_string(const api::Product& p) {
std::string buffer = p.symbol();
buffer += ":";
buffer += SecurityType_Name(p.type());
buffer += ":";
buffer += Venue_Name(p.exchange());
return buffer;
}
std::optional<api::Product> string_to_product(const std::string& s) {
boost::tokenizer<boost::char_separator<char>> tok { s };
std::vector<std::string> parts;
for (const auto& t : tok) {
parts.push_back(t);
}
if (parts.size() != 3) return std::nullopt;
SecurityType type = SecurityType::SECURITYTYPE_UNSET;
if (!SecurityType_Parse(parts[1], &type)) return std::nullopt;
Venue v = Venue::VENUE_UNSET;
if (!Venue_Parse(parts[2], &v)) return std::nullopt;
Product p;
p.set_symbol(parts[0]);
p.set_type(type);
p.set_exchange(v);
return {p};
}
}}//ns
#endif
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "lib/domain_model/Security.pb.h"
#include "lib/utils/optional.h"
#include <string>
namespace bts {
namespace api {
std::string product_to_string(const api::Product&);
std::optional<api::Product> string_to_product(const std::string&);
} }
@@ -0,0 +1,116 @@
#ifndef _WIN32
#include "MarketDataServiceServer.h"
#include "lib/metrics/metrics.h"
#include "lib/md/UserSymbol.h"
#include "lib/md/get_symbols.h"
#include "lib/md/Product.h"
#include "lib/utils/AuthToken.h"
#include <atomic>
#include <set>
namespace bts {
namespace md {
struct MarketDataServiceImpl {
MarketDataServiceImpl(api::MarketDataServiceBase::SecuritiesStatefulPublisher);
utils::Dispatcher& dispatcher;
api::MarketDataServiceBase::SecuritiesStatefulPublisher security_publisher;
std::atomic<uint32_t> sec_outstanding;
void add_security(const SecurityPtr& sec) {
++sec_outstanding;
dispatcher.post([this,sec]() {
security_publisher.add_or_update(*sec);
auto flush = (--sec_outstanding) == 0;
if (flush) {
security_publisher.flush();
}
});
}
};
MarketDataServiceImpl::MarketDataServiceImpl(
api::MarketDataServiceBase::SecuritiesStatefulPublisher security_pub) :
dispatcher(utils::Dispatcher::get_named("MDService")),
security_publisher(security_pub),
sec_outstanding(0)
{
}
MarketDataService::MarketDataService(
MDClient& md,
api::ServiceContext ctx,
metrics::MetricsContainer&) :
api::AuthenticatedMarketDataServiceBase(ctx)
{
_me = std::make_shared<MarketDataServiceImpl>(make_securities_stateful_publisher());
md.current_consumer().on_security([me=_me](const SecurityPtr& sec, MDConsumerHandle) {
me->add_security(sec);
});
}
// This method duplicates MarketDataRelayServer::request_products()
void MarketDataService::get_products(
const api::AuthToken&,
const ::bts::api::VoidMessage&,
const api::Response<::bts::api::ProductList>& reply) {
api::ProductList list;
std::set<md::UserSymbol> syms;
md::get_system_md_symbols(syms);
for(const auto& i : syms) {
auto prod = list.add_products();
prod->set_exchange(i.exchange());
prod->set_type(i.type());
prod->set_symbol(i.symbol());
}
reply(list);
}
api::StreamAccessResponse authorized(bool is_authorized) {
api::StreamAccessResponse r;
r.set_authorized(is_authorized);
return r;
}
void MarketDataService::allow_securities(
const bts::api::AuthToken&,
const std::string& qualifier,
const api::Response<bts::api::StreamAccessResponse>& reply) {
// Non-empty qualifier is invalid and rejected
reply(authorized(qualifier.empty()));
}
void MarketDataService::allow_book(
const bts::api::AuthToken& token,
const std::string& qualifier,
const api::Response<bts::api::StreamAccessResponse>& reply) {
api::user::TokenPayload payload;
if (api::auth::decode_token(token, &payload)) {
auto product = api::string_to_product(qualifier);
if (product) {
// todo: start streaming
reply(authorized(true));
}
}
reply(authorized(false));
}
void MarketDataService::allow_trades(
const bts::api::AuthToken& token,
const std::string& qualifier,
const api::Response<bts::api::StreamAccessResponse>& reply) {
api::user::TokenPayload payload;
if (api::auth::decode_token(token, &payload)) {
auto product = api::string_to_product(qualifier);
if (product) {
// todo: start streaming
reply(authorized(true));
}
}
reply(authorized(false));
}
}} //namespace
#endif
@@ -0,0 +1,43 @@
#pragma once
#include "lib/utils/Dispatcher.h"
#include "lib/api/public/ServiceContext.h"
#include "lib/api/services/MarketDataService.server.pb.h"
#include "lib/md/MDClient.h"
#include <memory>
namespace bts {
namespace metrics { class MetricsContainer; }
namespace md {
struct MarketDataServiceImpl;
class MarketDataService : public api::AuthenticatedMarketDataServiceBase {
std::shared_ptr<MarketDataServiceImpl> _me;
public:
MarketDataService(
MDClient& md,
api::ServiceContext ctx,
metrics::MetricsContainer& stats);
void get_products(
const api::AuthToken&,
const ::bts::api::VoidMessage&,
const api::Response<::bts::api::ProductList>&) override;
void allow_securities(
const bts::api::AuthToken&,
const std::string& qualifier,
const api::Response<bts::api::StreamAccessResponse>& reply) override;
void allow_book(
const bts::api::AuthToken& token,
const std::string& qualifier,
const api::Response<bts::api::StreamAccessResponse>& reply) override;
void allow_trades(
const bts::api::AuthToken& token,
const std::string& qualifier,
const api::Response<bts::api::StreamAccessResponse>& reply) override;
};
}} //namespace
+81
View File
@@ -0,0 +1,81 @@
#include "ActorThread.h"
#include "lib/utils/thread_manager.h"
#include "lib/utils/type_name.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>
namespace bts {
namespace orderman {
ActorThread::ActorThread(const config::OrdermanCfg::Executor &cfg, metrics::MetricsContainer &stats)
: cfg(cfg), thread(), executor(), loop_metric(), done(false)
{
std::array<double, 30> buckets;
auto i = 0;
for (auto &b : buckets)
b = (i += 1000);
loop_metric = std::make_shared<metrics::HistogramMetric<30>>(
fmt::format("spark_metrics_{}_thread_loop_ns", cfg.thread_name()),
buckets);
stats.publish(loop_metric);
}
ActorThread::~ActorThread()
{
done = true;
thread.join();
}
void ActorThread::start(trace::PerfLog &log)
{
if (cfg.poll())
thread = threading::make_thread(cfg.thread_name(), [this, &log]()
{
for (;;)
executor.do_work(log);
});
else
{
thread = threading::make_thread(cfg.thread_name(), [this, &log]()
{
const auto inner_iter = 1000;
while (!done)
{
auto start = Timer::now();
for (auto i = 0; i < inner_iter; i++)
executor.do_work(log);
auto stop = Timer::now();
loop_metric->observe(ns_diff(stop, start) / inner_iter);
std::this_thread::sleep_for(10ms);
}
});
}
}
ActorThread* ActorThread::find_thread_for_actor(const std::string& actor_name,
const std::vector<std::unique_ptr<ActorThread>>& all_executors,
const std::string& qualifier)
{
for (auto const &ex : all_executors)
{
for (auto const &hosted : ex->cfg.hosted_actor())
{
if (hosted.type() == "*" || boost::algorithm::to_lower_copy(hosted.type()) ==
boost::algorithm::to_lower_copy(actor_name))
{
if(qualifier != "")
{
if(boost::algorithm::to_lower_copy(qualifier) == boost::algorithm::to_lower_copy(hosted.qualifier()))
return ex.get();
}
else
return ex.get();
}
}
}
return nullptr;
}
}}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include "lib/mercury/executor/Executor.h"
#include "lib/metrics/metrics.h"
#include "lib/utils/thread_manager.h"
#include "lib/config/config.h"
#include "lib/config/protos/jetfix.pb.h"
#include "lib/config/protos/orderman_cfg.pb.h"
namespace bts {
namespace orderman {
struct ActorThread
{
ActorThread(const config::OrdermanCfg::Executor &cfg, metrics::MetricsContainer &stats);
void start(trace::PerfLog &log);
~ActorThread();
static ActorThread* find_thread_for_actor(const std::string&actor_name,
const std::vector<std::unique_ptr<ActorThread>>& all_executors,
const std::string& qualifier = "");
config::OrdermanCfg::Executor cfg;
std::thread thread;
mercury::Executor executor;
std::shared_ptr<metrics::HistogramMetric<30>> loop_metric;
std::atomic<bool> done;
};
}}
+2 -1
View File
@@ -59,7 +59,8 @@ void AsyncFactory::init() {
response.reserve(ev.n_buffers);
while (response.size() < ev.n_buffers)
response.push_back(std::make_shared<jetfix::OutFIX>(*ev.cfg));
this->publish(me->fix_buffer_stream, std::move(response), ev.cfg);
this->publish(me->fix_buffer_stream, std::move(response), ev.cfg,
ev.request_qualifier);
}
});
}
@@ -18,6 +18,7 @@ class GLBXExecutionGateway : public IExecutionGateway {
void on_securities(const mercury::Update<NewSecuritiesEvent> &) override;
void on_admin_data(const mercury::Update<NewAdminDataEvent> &) override;
void send_fix(jetfix::OutFIXPtr const &fix, trace::CorID trace) override;
void send_msgs(std::vector<OrderMsg> const&, trace::CorID) override {bts_assert(false);}
OnExeReport& on_exe_report() override;
OnGwStatusChange& on_gw_status_change() override;
@@ -0,0 +1,175 @@
#include "lib/orderman/actors/GLBXiLink3ExecutionGateway.h"
#include "lib/config/config.h"
#include "lib/config/protos/orderman_cfg.pb.h"
#include "lib/jetfix/common/OutFIX.h"
#include "lib/orderman/actors/GLBXExecutionGateway.h"
#include "lib/orderman/orderman_utils/fix_order_codec.h"
namespace bts {
namespace orderman {
struct GLBXiLink3ExecutionGateway::PImpl {
PImpl(config::JetFIX::Connection const &cfg, trace::PerfLog &l,
md::SecurityOracle o)
: cfg(cfg), gw(cfg, l, o) {}
config::JetFIX::Connection const cfg;
GLBXExecutionGateway gw;
};
GLBXiLink3ExecutionGateway::GLBXiLink3ExecutionGateway(
config::JetFIX::Connection const &cfg, trace::PerfLog &log,
md::SecurityOracle o)
: me(new PImpl(cfg, log, o)) {}
GLBXiLink3ExecutionGateway::~GLBXiLink3ExecutionGateway() {}
void GLBXiLink3ExecutionGateway::start() { me->gw.start(); }
void GLBXiLink3ExecutionGateway::dispatch_incoming_fix_messages() {
me->gw.dispatch_incoming_fix_messages();
}
void GLBXiLink3ExecutionGateway::on_securities(
const mercury::Update<NewSecuritiesEvent> &ev) {
me->gw.on_securities(ev);
}
void GLBXiLink3ExecutionGateway::on_admin_data(
const mercury::Update<NewAdminDataEvent> &ev) {
me->gw.on_admin_data(ev);
}
static std::string
get_cust_order_handling_inst(api::orderman::RoutingRecord const &rr) {
if (rr.cust_order_handling_inst().size())
return rr.cust_order_handling_inst();
else
return config::get<config::OrdermanCfg>()
.fallback_cust_order_handling_inst();
}
template <class F, class MSG>
static void add_clorid(jetfix::FIXFragment &fix,MSG const&msg) {
std::string clordid(clordid_sz(), ' ');
encode_clorid(msg.key, SecurityKey(msg.security->id()), &clordid);
fix.add<F>(clordid);
}
template <class MSG>
static void encode_common_fields(jetfix::FIXFragment &fix, MSG const &msg) {
using namespace jetfix;
using namespace api::orderman;
auto &rr = *msg.routing_record;
fix.add<fix::SenderSubID>(msg.routing_record->operator_id());
fix.add<fix::SenderLocationID>(msg.routing_record->location());
fix.add<fix::Account>(rr.account());
fix.add<fix::Side>(msg.side);
fix.add<fix::ManualOrderIndicator>(msg.manual_order_indicator);
fix.add<fix::SecurityDesc>(msg.security->glbx().security_desc());
add_clorid<fix::ClOrdID>(fix,msg);
fix.add<fix::TransactTimeStr>(datetime::FIX_timestamp(datetime::now()));
}
static void encode_create_fields(jetfix::FIXFragment &fix,
CreateOrderMsg const &create_fields) {
using namespace jetfix;
using namespace api::orderman;
encode_common_fields(fix, create_fields);
auto &rr = *create_fields.routing_record;
fix.add<fix::CustomerOrFirm>(rr.customer_or_firm());
fix.add<fix::CtiCode>(rr.cti_code());
fix.add<fix::CustOrderHandlingInst>(get_cust_order_handling_inst(rr));
if (rr.smp_id().size()) {
fix.add<fix::SelfMatchPreventionID>(rr.smp_id());
if (rr.smp_instruction() !=
api::orderman::SELF_MATCH_PREVENTION_INSTRUCTION_UNDEFINED)
fix.add<fix::SelfMatchPreventionInstruction>(rr.smp_instruction());
}
fix.add<fix::OrderQty>(create_fields.quantity.value());
fix.add<fix::OrdType>(create_fields.order_type);
fix.add<fix::TimeInForce>(create_fields.time_in_force);
switch (create_fields.order_type) {
case NATIVE_ORDER_TYPE_MARKET:
break;
case NATIVE_ORDER_TYPE_LIMIT:
fix.add<fix::Price>(create_fields.price.value(), 8, -1);
break;
case NATIVE_ORDER_TYPE_STOP:
fix.add<fix::StopPx>(create_fields.stop_px.value(), 8, -1);
break;
case NATIVE_ORDER_TYPE_STOP_LIMIT:
fix.add<fix::Price>(create_fields.price.value(), 8, -1);
fix.add<fix::StopPx>(create_fields.stop_px.value(), 8, -1);
break;
default:
bts_assert(false);
break;
}
if (create_fields.display_quantity.value())
fix.add<fix::MaxShow>(create_fields.display_quantity.value());
}
void GLBXiLink3ExecutionGateway::send_msgs(std::vector<OrderMsg> const &msgs,
trace::CorID corid) {
using namespace jetfix;
auto fix = std::make_shared<jetfix::OutFIX>(me->cfg);
auto &stream = fix->first_stream();
for (auto &m : msgs) {
// NewOrderSingle
auto create_ptr = std::get_if<CreateOrderMsg>(&m);
if (create_ptr) {
auto &create_fix = stream.new_msg(jetfix::MessageTypes::NewOrderSingle);
encode_create_fields(create_fix, *create_ptr);
break;
}
// CancelReplace
auto cancel_replace_ptr = std::get_if<CancelReplaceOrderMsg>(&m);
if (cancel_replace_ptr) {
auto &update_fix = stream.new_msg(jetfix::MessageTypes::CancelReplace);
auto create_ptr = &cancel_replace_ptr->create_fields;
encode_create_fields(update_fix, *create_ptr);
update_fix.add<fix::OrderIDu64>(
cancel_replace_ptr->exchange_order_id.value());
add_clorid<fix::OrigClOrdID>(update_fix,*create_ptr);
add_clorid<fix::CorrelationClOrdID>(update_fix,*create_ptr);
update_fix.add<fix::InFlightMitigation>(true);
break;
}
// Cancel
auto cancel_ptr = std::get_if<CancelOrderMsg>(&m);
if (cancel_ptr) {
auto &cancel_fix = stream.new_msg(jetfix::MessageTypes::Cancel);
encode_common_fields(cancel_fix, *cancel_ptr);
cancel_fix.add<fix::OrderIDu64>(cancel_ptr->exchange_order_id.value());
add_clorid<fix::OrigClOrdID>(cancel_fix,*cancel_ptr);
add_clorid<fix::CorrelationClOrdID>(cancel_fix,*cancel_ptr);
break;
}
}
stream.close();
me->gw.send_fix(fix, corid);
}
OnExeReport &GLBXiLink3ExecutionGateway::on_exe_report() {
return me->gw.on_exe_report();
}
OnGwStatusChange &GLBXiLink3ExecutionGateway::on_gw_status_change() {
return me->gw.on_gw_status_change();
}
OnCancelReject &GLBXiLink3ExecutionGateway::on_cancel_reject() {
return me->gw.on_cancel_reject();
}
} // namespace orderman
} // namespace bts
@@ -0,0 +1,31 @@
#pragma once
#include "IExecutionGateway.h"
namespace bts {
namespace orderman {
class GLBXiLink3ExecutionGateway : public IExecutionGateway {
public:
GLBXiLink3ExecutionGateway(config::JetFIX::Connection const &, trace::PerfLog &,
md::SecurityOracle);
virtual ~GLBXiLink3ExecutionGateway();
void start() override;
void dispatch_incoming_fix_messages() override;
void on_securities(const mercury::Update<NewSecuritiesEvent> &) override;
void on_admin_data(const mercury::Update<NewAdminDataEvent> &) override;
void send_fix(jetfix::OutFIXPtr const &, trace::CorID ) override {bts_assert(false);}
void send_msgs(std::vector<OrderMsg> const&, trace::CorID) override;
OnExeReport& on_exe_report() override;
OnGwStatusChange& on_gw_status_change() override;
OnCancelReject &on_cancel_reject() override;
private:
struct PImpl;
std::unique_ptr<PImpl> me;
};
} // namespace orderman
} // namespace bts
@@ -17,6 +17,7 @@ class ICEExecutionGateway : public IExecutionGateway {
void on_securities(const mercury::Update<NewSecuritiesEvent> &) override;
void on_admin_data(const mercury::Update<NewAdminDataEvent> &) override;
void send_fix(const jetfix::OutFIXPtr& fix, trace::CorID trace) override;
void send_msgs(std::vector<OrderMsg> const&, trace::CorID) override {bts_assert(false);}
OnExeReport& on_exe_report() override;
OnGwStatusChange& on_gw_status_change() override;
+41 -5
View File
@@ -1,17 +1,53 @@
#include "IExecutionGateway.h"
#include "ICEExecutionGateway.h"
#include "GLBXExecutionGateway.h"
#include "ICEExecutionGateway.h"
#include "lib/orderman/actors/gateway/GatewayProxy.h"
#include "lib/utils/ValueWrapper.h"
#include "lib/orderman/actors/GLBXiLink3ExecutionGateway.h"
#include "lib/config/config.h"
#include "lib/config/protos/orderman_cfg.pb.h"
#include <utility>
namespace bts {
namespace orderman {
std::unique_ptr<IExecutionGateway>
ExecutionGatewayFactory::create_gateway(const config::JetFIX::Connection& conn, trace::PerfLog& pl, md::SecurityOracle o)
std::atomic<bool> ExecutionGatewayFactory::_registration_open = true;
std::map<std::string, std::shared_ptr<IExecutionGateway>> ExecutionGatewayFactory::_proxies;
void ExecutionGatewayFactory::register_proxy(const config::JetFIX::Connection& conn, std::shared_ptr<IExecutionGateway> prox)
{
if(conn.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_ICE ||
conn.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_SIMICE)
bts_assert_msg(_registration_open, "attempt to register gw after construction");
auto it = _proxies.insert(std::make_pair(conn.name(), prox));
bts_assert_msg(it.second, "duplicate gw proxy");
}
std::shared_ptr<IExecutionGateway>
ExecutionGatewayFactory::create_gateway(const config::JetFIX::Connection &conn,
trace::PerfLog &pl,
md::SecurityOracle o)
{
if(config::get<config::OrdermanCfg>().use_gateway())
{
_registration_open = false;
auto it = _proxies.find(conn.name());
bts_assert_msg(it != _proxies.end(), "can't find gw proxy.");
return it->second;
}
else
return create_local_gateway(conn, pl, o);
}
std::unique_ptr<IExecutionGateway>
ExecutionGatewayFactory::create_local_gateway(const config::JetFIX::Connection &conn,
trace::PerfLog &pl,
md::SecurityOracle o)
{
if (conn.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_ICE ||
conn.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_SIMICE)
return std::make_unique<ICEExecutionGateway>(conn, pl, o);
else if (conn.use_ilink3())
return std::make_unique<GLBXiLink3ExecutionGateway>(conn, pl, o);
else
return std::make_unique<GLBXExecutionGateway>(conn, pl, o);
}
+46 -3
View File
@@ -9,6 +9,9 @@
#include "lib/utils/bts_no_copy.h"
#include <memory>
#include <variant>
#include <map>
#include <atomic>
namespace bts {
namespace trace {struct CorID;class PerfLog;}
@@ -18,6 +21,38 @@ class NewAdminDataEvent;
class ExecutionReport;
struct CreateOrderMsg {
OrderKey key;
Price price;
Quantity quantity;
api::Security const *security;
api::Side side;
Price stop_px;
Quantity display_quantity;
api::orderman::NativeOrderType order_type;
api::orderman::TimeInForce time_in_force;
api::orderman::ManualOrderIndicator manual_order_indicator;
api::orderman::RoutingRecord const *routing_record;
};
struct CancelReplaceOrderMsg {
CreateOrderMsg create_fields;
ExchangeOrderIDu64 exchange_order_id;
};
struct CancelOrderMsg {
OrderKey key;
ExchangeOrderIDu64 exchange_order_id;
api::orderman::ManualOrderIndicator manual_order_indicator;
std::string_view clordid;
api::Security const *security;
api::orderman::RoutingRecord const *routing_record;
api::Side side;
};
using OrderMsg =
std::variant<CreateOrderMsg, CancelReplaceOrderMsg, CancelOrderMsg>;
using OnGwStatusChange = std::function<void(bool)>;
using OnExeReport = std::function<void(ExecutionReport const &, trace::CorID const &)>;
using OnCancelReject = std::function<void(OrderKey, std::string const &)>;
@@ -33,7 +68,7 @@ class IExecutionGateway {
virtual void on_securities(const mercury::Update<NewSecuritiesEvent> &) = 0;
virtual void on_admin_data(const mercury::Update<NewAdminDataEvent> &) = 0;
virtual void send_fix(const jetfix::OutFIXPtr&, trace::CorID) = 0;
virtual void send_msgs(std::vector<OrderMsg> const&, trace::CorID) = 0;
virtual OnExeReport& on_exe_report() = 0;
virtual OnGwStatusChange& on_gw_status_change() = 0;
virtual OnCancelReject &on_cancel_reject() = 0;
@@ -44,8 +79,16 @@ private:
class ExecutionGatewayFactory
{
public:
static std::unique_ptr<IExecutionGateway> create_gateway(const config::JetFIX::Connection&, trace::PerfLog&, md::SecurityOracle);
static std::shared_ptr<IExecutionGateway>
create_gateway(const config::JetFIX::Connection&, trace::PerfLog&, md::SecurityOracle);
static std::unique_ptr<IExecutionGateway>
create_local_gateway(const config::JetFIX::Connection&, trace::PerfLog&, md::SecurityOracle);
private:
friend class GatewayProxy;
static void register_proxy(const config::JetFIX::Connection&, std::shared_ptr<IExecutionGateway>);
static std::map<std::string, std::shared_ptr<IExecutionGateway>> _proxies;
static std::atomic<bool> _registration_open;
};
} // namespace orderman
+75 -12
View File
@@ -31,9 +31,9 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
public:
MDSource(md::MDConsumer &consumer, metrics::MetricsContainer &stats,
trace::PerfLog &log)
: _handles(), _status_subs(), _md_consumer(consumer),
: _handles(), _pending_handles(), _status_subs(), _md_consumer(consumer),
_book_update(), _ticker_update(), _status_update(),
_perf_log(log), _stats(stats), _loop_timer() {
_perf_log(log), _stats(stats), _loop_timer(), _counter(0) {
_trades_buffer.Reserve(1000);
auto cme_channels = md::get_configured_cme_channels();
@@ -169,6 +169,47 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
// Publish stats
auto stop = utils::TimeStamp::now();
_loop_timer->observe((start - stop).nanoseconds());
_counter += 1;
if (_counter % (2<<20) == 0) {
// Invoke periodic work every 2M calls on on_poll
// This is approximately 20-30 seconds
do_periodic_work();
}
}
void do_periodic_work() {
if (!_pending_handles.empty()) {
for (auto iter = _pending_handles.begin(); iter != _pending_handles.end(); ++iter) {
if (iter->handle->is_initialized()) {
auto handle = *(iter->handle);
LOG(OrderMan, Info, "Found md for {}. Pending handle removed.", handle.key());
switch(iter->type) {
case MDRequestType::BOOK:
_handles.push_back({utils::TimeStamp(), handle,
get_external_event_channel(handle.get_usersymbol()),
std::make_unique<std::string>(securities::descriptor(
handle.get_normalized_security()))});
break;
case MDRequestType::STATUS:
for (auto& h : _status_subs) {
// no need to reset status
if (h.handle.key() == handle.key()) break;
}
_status_subs.push_back(
StatusRecord{ handle, co2::TRADINGSTATUS_UNKNOWN });
case MDRequestType::TICKER:
// We aren't currently monitoring for pending ticker requests
break;
}
}
}
_pending_handles.erase(
std::remove_if(_pending_handles.begin(),
_pending_handles.end(),
[](const auto& h) { return h.handle->is_initialized(); }),
_pending_handles.end());
}
}
void on_book_sub(SecurityKey sk,
@@ -184,14 +225,23 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
LOG(OrderMan, Warn,
"Starting to publish book updates for security key: {}", k);
auto handle = _md_consumer.get_handle(k);
_handles.push_back({utils::TimeStamp(), handle,
get_external_event_channel(handle.get_usersymbol()),
std::make_unique<std::string>(securities::descriptor(
handle.get_normalized_security()))});
if (handle.is_synthetic())
synthetic_count_metric.increment();
auto mhandle = _md_consumer.get_managed_handle(k);
if (mhandle->is_initialized()) {
auto handle = *mhandle;
_handles.push_back({utils::TimeStamp(), handle,
get_external_event_channel(handle.get_usersymbol()),
std::make_unique<std::string>(securities::descriptor(
handle.get_normalized_security()))});
if (handle.is_synthetic())
synthetic_count_metric.increment();
}
else {
// A pending handle is a handle for security we are reasonbly sure exists
// but we haven't yet found live market data for.
LOG(OrderMan, Warn, "No market data for {}. Pending handle added.", k);
_pending_handles.push_back({ mhandle, MDRequestType::BOOK });
}
}
const char *get_external_event_channel(const md::UserSymbol &user_symbol) {
@@ -205,7 +255,7 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
metrics::CounterMetric<int> &channel_count_metric) {
auto user_symbol = _md_consumer.get_handle(sk.value()).get_usersymbol();
for (auto &ch : _channels)
for (auto &ch : _channels) {
if (ch.user_symbol == user_symbol) {
auto it =
std::find_if(ch.securities.begin(), ch.securities.end(),
@@ -222,6 +272,7 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
}
return;
}
}
// this is a channel we are not subscribed to
channel_count_metric.increment();
@@ -250,8 +301,14 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
return;
}
}
auto handle = _md_consumer.get_handle(k);
_status_subs.push_back(StatusRecord{ handle, co2::TRADINGSTATUS_UNKNOWN });
auto handle = _md_consumer.get_managed_handle(k);
if (handle->is_initialized()) {
_status_subs.push_back(StatusRecord{ *handle, co2::TRADINGSTATUS_UNKNOWN });
}
else {
LOG(OrderMan, Warn, "No market data for {}. Pending handle added.", k);
_pending_handles.push_back({ handle, MDRequestType::STATUS });
}
}
struct HandleRecord {
@@ -261,6 +318,11 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
std::unique_ptr<std::string> symbol;
};
boost::container::small_vector<HandleRecord, 100> _handles;
struct PendingRecord {
std::shared_ptr<md::MDConsumerHandle> handle;
MDRequestType type;
};
boost::container::small_vector<PendingRecord, 4> _pending_handles;
struct ChannelRecord {
int64_t cursor;
@@ -285,6 +347,7 @@ class MDSource : public mercury::Actor, public mercury::IPollableActor {
metrics::MetricsContainer &_stats;
std::shared_ptr<metrics::HistogramMetric<30>> _loop_timer;
std::map<md::UserSymbol, std::string> _symbol_to_channel;
uint64_t _counter;
};
} // namespace orderman
} // namespace bts
+160
View File
@@ -0,0 +1,160 @@
#include "Gateway.h"
#include "GatewayProxy.h"
#include "lib/mercury/executor/Executor.h"
#include "lib/mercury/events/Update.h"
#include "lib/mercury/events/Stream.h"
#include "lib/orderman/events/NewSecuritiesEvent.h"
#include "lib/orderman/events/NewAdminDataEvent.h"
#include "lib/orderman/events/SendFixEvent.h"
#include "lib/orderman/events/SendOrderMsgsEvent.h"
#include "lib/orderman/events/GatewayStartEvent.h"
#include "lib/orderman/events/GatewayStatusChangeEvent.h"
#include "lib/orderman/events/CancelRejectEvent.h"
#include "lib/orderman/events/NewExecutionReportEvent.h"
#include "lib/orderman/orderman_utils/orderman_common.h"
#include "lib/orderman/orderman_utils/ExecutionReport.h"
#include "lib/jetfix/common/OutFIXPtr.h"
#include "lib/jetfix/common/OutFIX.h"
#include "lib/utils/bts_assert.h"
#include "lib/utils/helper_macros.h"
#include "lib/utils/type_name.h"
#include "lib/config/config.h"
#include "lib/config/protos/mercury_cfg.pb.h"
#include "lib/config/protos/jetfix.pb.h"
#include <map>
#include <atomic>
namespace bts {
namespace orderman {
void Gateway::spawn_gateways(const std::vector<std::unique_ptr<ActorThread>>& actor_threads,
trace::PerfLog& pl, md::SecurityOracle oracle)
{
if(!config::get<config::OrdermanCfg>().use_gateway())
return;
bts_assert_msg(config::get<config::OrdermanCfg>().use_gateway(), "invalid gw config");
std::map<std::string, config::JetFIX::Connection> connections;
for(auto& conn : config::get<config::JetFIX>().connection())
connections[conn.name()] = conn;
bool spawned_one = false;
for(auto& e : config::get<config::OrdermanCfg>().executor())
{
for(auto& h : e.hosted_actor())
{
if(h.type() == "Gateway")
{
auto thread = ActorThread::find_thread_for_actor(h.type(), actor_threads, h.qualifier());
for(auto& g : config::get<config::GatewayCfg>().gateway())
{
if(g.qualifier() == h.qualifier())
{
for(auto& cc : g.connection())
{
if(cc == "*")
{
for(auto& allconn : connections)
{
thread->executor.spawn<Gateway>(allconn.second, pl, oracle);
thread->executor.spawn<GatewayProxy>(allconn.second, pl, oracle);
spawned_one = true;
}
}
else
{
auto& conn = connections[cc];
thread->executor.spawn<Gateway>(conn, pl, oracle);
thread->executor.spawn<GatewayProxy>(conn, pl, oracle);
connections.erase(cc);
spawned_one = true;
}
}
}
}
}
}
}
bts_assert_msg(spawned_one, "no Gateway spawned");
}
struct Gateway::PImpl
{
PImpl(const config::JetFIX::Connection& conn, trace::PerfLog& pl, md::SecurityOracle orc)
: gw(ExecutionGatewayFactory::create_local_gateway(conn, pl, orc)),
gateway_name(GatewayName(conn.name()))
{
}
std::unique_ptr<IExecutionGateway> gw;
GatewayName gateway_name;
std::atomic<bool> started;
mercury::Stream<NewExecutionReportEvent> new_executionreport_pub;
mercury::Stream<GatewayStatusChangeEvent> gatewaystatus_pub;
mercury::Stream<CancelRejectEvent> cancelreject_pub;
};
Gateway::Gateway(const config::JetFIX::Connection& conn, trace::PerfLog& pl, md::SecurityOracle orc)
: me(new PImpl(conn, pl, orc))
{
}
Gateway::~Gateway()
{
}
void Gateway::init()
{
me->new_executionreport_pub = make_stream<NewExecutionReportEvent>(me->gateway_name);
me->gw->on_exe_report() = [this](const auto& er, const auto& t)
{
publish(me->new_executionreport_pub, &er, t);
};
me->gatewaystatus_pub = make_stream<GatewayStatusChangeEvent>(me->gateway_name);
me->gw->on_gw_status_change() = [this](bool b)
{
publish(me->gatewaystatus_pub, me->gateway_name, b);
};
me->cancelreject_pub = make_stream<CancelRejectEvent>(me->gateway_name);
me->gw->on_cancel_reject() = [this](const auto& k,const auto& msg)
{
publish(me->cancelreject_pub, k, msg);
};
subscribe<SendFixEvent>(me->gateway_name, [this](const mercury::Update<SendFixEvent>& update) //for GWNAME
{
if(update.events)
for (const auto& ev : *update.events)
me->gw->send_fix(ev.fix, ev.corid);
});
subscribe<SendOrderMsgsEvent>(me->gateway_name, [this](const mercury::Update<SendOrderMsgsEvent>& update)
{
if(update.events)
for (const auto& ev : *update.events)
me->gw->send_msgs(*ev.msgs, ev.corid);
});
subscribe<NewAdminDataEvent>([this](const auto& admin_update)
{
me->gw->on_admin_data(admin_update);
});
subscribe<NewSecuritiesEvent>([this](const auto& secs)
{
me->gw->on_securities(secs);
});
subscribe<GatewayStartEvent>(me->gateway_name, [this](const auto& ev)
{
if (ev.events && !me->started) //this is kind of a hack because messages go through once at startup with a null events
{
me->started = true;
me->gw->start();
}
});
}
void Gateway::on_poll(trace::PerfLog&)
{
me->gw->dispatch_incoming_fix_messages();
}
}}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "lib/orderman/actors/IExecutionGateway.h"
#include "lib/jetfix/common/OutFIXPtr.h"
#include "lib/md/SecurityOracle.h"
#include "lib/utils/bts_no_copy.h"
#include "lib/mercury/actors/Actor.h"
#include "lib/mercury/actors/IPollableActor.h"
#include "lib/tracing/PerfLog.h"
#include "lib/tracing/bts_trace.h"
#include "lib/utils/TimeStamp.h"
#include "lib/orderman/actors/ActorThread.h"
#include <memory>
namespace bts {
namespace trace {struct CorID;class PerfLog;}
namespace orderman {
class Gateway : public mercury::Actor, public mercury::IPollableActor
{
public:
static void spawn_gateways(const std::vector<std::unique_ptr<ActorThread>>& actor_threads,
trace::PerfLog&, md::SecurityOracle);
public:
Gateway(const config::JetFIX::Connection&, trace::PerfLog&, md::SecurityOracle);
virtual ~Gateway();
void init() override;
void on_poll(trace::PerfLog&) override;
private:
BTS_NO_COPY(Gateway);
struct PImpl;
std::unique_ptr<PImpl> me;
};
}}
@@ -0,0 +1,114 @@
#include "GatewayProxy.h"
#include "lib/mercury/broker/BrokerProxy.h"
#include "lib/mercury/events/Update.h"
#include "lib/mercury/events/Stream.h"
#include "lib/orderman/events/NewSecuritiesEvent.h"
#include "lib/orderman/events/NewAdminDataEvent.h"
#include "lib/orderman/events/SendFixEvent.h"
#include "lib/orderman/events/SendOrderMsgsEvent.h"
#include "lib/orderman/events/GatewayStatusChangeEvent.h"
#include "lib/orderman/events/GatewayStartEvent.h"
#include "lib/orderman/events/CancelRejectEvent.h"
#include "lib/orderman/orderman_utils/orderman_common.h"
#include "lib/jetfix/common/OutFIXPtr.h"
#include "lib/jetfix/common/OutFIX.h"
#include "lib/utils/helper_macros.h"
#include "lib/utils/bts_assert.h"
#include "lib/config/config.h"
#include <variant>
#include <tuple>
namespace bts {
namespace orderman {
struct GatewayProxy::PImpl
{
PImpl(const config::JetFIX::Connection &cfg, trace::PerfLog &l, md::SecurityOracle o)
: cfg(cfg), perf_log(l), sec_oracle(o), gateway_name(cfg.name())
{
}
const config::JetFIX::Connection& cfg;
trace::PerfLog& perf_log;
md::SecurityOracle sec_oracle;
GatewayName gateway_name;
mercury::Stream<GatewayStartEvent> start_pub;
mercury::Stream<SendFixEvent> send_fix_pub;
mercury::Stream<SendOrderMsgsEvent> send_ordermsgs_pub;
OnExeReport on_exe_report;
OnGwStatusChange on_gw_status_change;
OnCancelReject on_cancel_reject;
};
GatewayProxy::GatewayProxy(const config::JetFIX::Connection& conn, trace::PerfLog& pl, md::SecurityOracle md)
: me(new PImpl(conn, pl, md))
{
ExecutionGatewayFactory::register_proxy(conn, std::shared_ptr<GatewayProxy>(this));
}
GatewayProxy::~GatewayProxy() { }
//actor init
void GatewayProxy::init()
{
me->start_pub = make_stream<GatewayStartEvent>(me->gateway_name);
me->send_fix_pub = make_stream<SendFixEvent>(me->gateway_name);
me->send_ordermsgs_pub = make_stream<SendOrderMsgsEvent>(me->gateway_name);
}
//start the gateway
void GatewayProxy::start()
{
publish<GatewayStartEvent>(me->start_pub, me->gateway_name);
}
void GatewayProxy::dispatch_incoming_fix_messages()
{
//called on GW thread and sent back through queue
}
void GatewayProxy::on_securities(const mercury::Update<NewSecuritiesEvent>& )
{
//the actual gateway subscribes to these, no-op here
}
void GatewayProxy::on_admin_data(const mercury::Update<NewAdminDataEvent>& )
{
//the actual gateway subscribes to these, no-op here
}
void GatewayProxy::send_fix(const jetfix::OutFIXPtr& fixptr, trace::CorID corid)
{
//jetfix::OutFIXPtr copy(new jetfix::OutFIX(*fixptr)); //copy not necessary see OrderManager::reload_fix_buffer
publish<SendFixEvent>(me->send_fix_pub, fixptr, corid);
}
void GatewayProxy::send_msgs(const std::vector<OrderMsg>& msgs, trace::CorID corid)
{
SendOrderMsgsEvent::MsgsPtr copy(new SendOrderMsgsEvent::Msgs(msgs));
publish<SendOrderMsgsEvent>(me->send_ordermsgs_pub, copy, corid);
}
OnExeReport& GatewayProxy::on_exe_report()
{
bts_assert_msg(false, "GatewayProxy");
return me->on_exe_report;
}
OnGwStatusChange& GatewayProxy::on_gw_status_change()
{
bts_assert_msg(false, "GatewayProxy");
return me->on_gw_status_change;
}
OnCancelReject& GatewayProxy::on_cancel_reject()
{
bts_assert_msg(false, "GatewayProxy");
return me->on_cancel_reject;
}
}}
@@ -0,0 +1,44 @@
#pragma once
#include "lib/orderman/actors/IExecutionGateway.h"
#include "lib/mercury/actors/Actor.h"
#include "lib/jetfix/common/OutFIXPtr.h"
#include "lib/md/SecurityOracle.h"
#include "lib/config/config.h"
#include "lib/config/protos/jetfix.pb.h"
#include "lib/utils/bts_no_copy.h"
#include <memory>
namespace bts {
namespace trace {struct CorID;class PerfLog;}
namespace orderman {
class GatewayProxy : public mercury::Actor, public IExecutionGateway
{
public:
GatewayProxy(const config::JetFIX::Connection&, trace::PerfLog&, md::SecurityOracle);
virtual ~GatewayProxy();
//Actor
virtual void init();
//IExecutionGateway
virtual void start();
virtual void dispatch_incoming_fix_messages();
virtual void on_securities(const mercury::Update<NewSecuritiesEvent> &);
virtual void on_admin_data(const mercury::Update<NewAdminDataEvent> &);
virtual void send_fix(const jetfix::OutFIXPtr&, trace::CorID);
virtual void send_msgs(std::vector<OrderMsg> const&, trace::CorID);
virtual OnExeReport& on_exe_report();
virtual OnGwStatusChange& on_gw_status_change();
virtual OnCancelReject &on_cancel_reject();
private:
BTS_NO_COPY(GatewayProxy);
struct PImpl;
std::unique_ptr<PImpl> me;
};
}}
@@ -0,0 +1,17 @@
#pragma once
#include "IL3ConnectionHandler.h"
#include <string>
namespace bts {
namespace orderman {
namespace ilink3 {
struct IL3Connection {
virtual void connect(IL3ConnectionHandler&) = 0;
virtual void disconnect() = 0;
// Switch connection but do not connect()
virtual void failover() = 0;
virtual void send(const std::string_view) = 0;
};
}}}//namespace
@@ -0,0 +1,16 @@
#pragma once
#include <cstddef>
#include <string>
namespace bts {
namespace orderman {
namespace ilink3 {
struct IL3ConnectionHandler {
virtual void on_connect_success() = 0;
virtual void on_disconnect() = 0;
// Send available data and length. Handler will return what it consumed
virtual size_t on_data(const std::string_view&) = 0;
};
}}}//namespace
@@ -0,0 +1,113 @@
#pragma once
#include <cstdint>
#include "IL3GeneratedFull.h"
#include "IL3MessageFramer.h"
namespace bts {
namespace orderman {
namespace ilink3 {
template <class Handler, class T>
void handle(Handler& h, const char* data, uint16_t len) {
h.handle(
T {
const_cast<char*>(data),
sizeof(FramingHeader) + iLinkBinary::MessageHeader::encodedLength(),
len,
T::sbeBlockLength(),
T::sbeSchemaVersion() });
}
template <class H>
void dispatch_message(H& handler, const FramingHeader* header, const char* data) {
using namespace iLinkBinary;
bts_assert_d(header->encoding_type == 0XCAFE);
MessageHeader mheader {
(char*)data, sizeof(FramingHeader), header->message_size,
MessageHeader::sbeSchemaVersion() };
switch(mheader.templateId()) {
case 501: handle<H, NegotiationResponse501>(handler, data, header->message_size); break;
case 502: handle<H, NegotiationReject502>(handler, data, header->message_size); break;
case 504: handle<H, EstablishmentAck504>(handler, data, header->message_size); break;
case 505: handle<H, EstablishmentReject505>(handler, data, header->message_size); break;
case 506: handle<H, Sequence506>(handler, data, header->message_size); break;
case 507: handle<H, Terminate507>(handler, data, header->message_size); break;
case 509: handle<H, Retransmission509>(handler, data, header->message_size); break;
case 510: handle<H, RetransmitReject510>(handler, data, header->message_size); break;
case 513: handle<H, NotApplied513>(handler, data, header->message_size); break;
case 519: handle<H, PartyDetailsDefinitionRequestAck519>(handler, data, header->message_size); break;
case 521: handle<H, BusinessReject521>(handler, data, header->message_size); break;
case 522: handle<H, ExecutionReportNew522>(handler, data, header->message_size); break;
case 523: handle<H, ExecutionReportReject523>(handler, data, header->message_size); break;
case 524: handle<H, ExecutionReportElimination524>(handler, data, header->message_size); break;
case 525: handle<H, ExecutionReportTradeOutright525>(handler, data, header->message_size); break;
case 526: handle<H, ExecutionReportTradeSpread526>(handler, data, header->message_size); break;
case 527: handle<H, ExecutionReportTradeSpreadLeg527>(handler, data, header->message_size); break;
case 531: handle<H, ExecutionReportModify531>(handler, data, header->message_size); break;
case 532: handle<H, ExecutionReportStatus532>(handler, data, header->message_size); break;
case 534: handle<H, ExecutionReportCancel534>(handler, data, header->message_size); break;
case 535: handle<H, OrderCancelReject535>(handler, data, header->message_size); break;
case 536: handle<H, OrderCancelReplaceReject536>(handler, data, header->message_size); break;
// case 538: handle<H, PartyDetailsListReport538>(handler, data, header->message_size); break;
case 539: handle<H, ExecutionAck539>(handler, data, header->message_size); break;
// case 544: handle<H, NewOrderCross544>(handler, data, header->message_size); break;
// case 545: handle<H, MassQuoteAck545>(handler, data, header->message_size); break;
// case 546: handle<H, RequestForQuoteAck546>(handler, data, header->message_size); break;
// case 547: handle<H, QuoteCancelAck547>(handler, data, header->message_size); break;
case 548: handle<H, ExecutionReportTradeAddendumOutright548>(handler, data, header->message_size); break;
case 549: handle<H, ExecutionReportTradeAddendumSpread549>(handler, data, header->message_size); break;
case 550: handle<H, ExecutionReportTradeAddendumSpreadLeg550>(handler, data, header->message_size); break;
// case 558: handle<H, iLinkBinary::OrderMassActionReport558>(handler, data, header->message_size); break;
// case 561: handle<H, iLinkBinary::SecurityDefinitionResponse561>(handler, data, header->message_size); break;
}
}
// This handler handles exchange messages for testing
template <class H>
void dispatch_exchange_message(H& handler, const FramingHeader* header, const char* data) {
using namespace iLinkBinary;
bts_assert_d(header->encoding_type == 0XCAFE);
MessageHeader mheader {
(char*)data, sizeof(FramingHeader), header->message_size,
MessageHeader::sbeSchemaVersion() };
// Rather than trying to be exhaustive like the client
// we will only add handlers for the messages we use for testing
switch(mheader.templateId()) {
case 500: handle<H, Negotiate500>(handler, data, header->message_size); break;
case 503: handle<H, Establish503>(handler, data, header->message_size); break;
case 506: handle<H, Sequence506>(handler, data, header->message_size); break;
case 508: handle<H, RetransmitRequest508>(handler, data, header->message_size); break;
case 518: handle<H, PartyDetailsDefinitionRequest518>(handler, data, header->message_size); break;
case 514: handle<H, NewOrderSingle514>(handler, data, header->message_size); break;
case 515: handle<H, OrderCancelReplaceRequest515>(handler, data, header->message_size); break;
case 516: handle<H, OrderCancelRequest516>(handler, data, header->message_size); break;
}
}
template <class Handler, class Dispatcher>
size_t consume_messages(
Handler& handler, const char* data, size_t len, Dispatcher dispatch) {
// void(*dispatch)(Handler&, const FramingHeader*, const char*)) {
size_t read = 0;
while(len > sizeof(FramingHeader)) {
// read the FramingHeader
const FramingHeader* header = reinterpret_cast<const FramingHeader*>(data);
// Check if we can consume the message
auto msize = header->message_size;
if (msize <= len) {
read += msize;
dispatch(handler, header, data);
data += msize;
len -= msize;
}
else {
return read;
}
}
return read;
}
}}}//namespace
@@ -0,0 +1,56 @@
#pragma once
//
// Message templates
// BTS -> CME
#include "generated/Negotiate500.h"
#include "generated/Establish503.h"
#include "generated/RetransmitRequest508.h"
#include "generated/NewOrderSingle514.h"
#include "generated/OrderCancelReplaceRequest515.h"
#include "generated/OrderCancelRequest516.h"
// #include "generated/MassQuote517.h"
#include "generated/PartyDetailsDefinitionRequest518.h"
// #include "generated/QuoteCancel528.h"
// #include "generated/OrderMassActionRequest529.h"
// #include "generated/OrderMassStatusRequest530.h"
// #include "generated/OrderStatusRequest533.h"
// #include "generated/PartyDetailsListRequest537.h"
// #include "generated/RequestForQuote543.h"
// #include "generated/SecurityDefinitionRequest560.h"
// CME -> BTS
#include "generated/NegotiationResponse501.h"
#include "generated/NegotiationReject502.h"
#include "generated/EstablishmentAck504.h"
#include "generated/EstablishmentReject505.h"
#include "generated/Sequence506.h"
#include "generated/Terminate507.h"
#include "generated/Retransmission509.h"
#include "generated/RetransmitReject510.h"
#include "generated/NotApplied513.h"
#include "generated/PartyDetailsDefinitionRequestAck519.h"
#include "generated/BusinessReject521.h"
#include "generated/ExecutionReportNew522.h"
#include "generated/ExecutionReportReject523.h"
#include "generated/ExecutionReportElimination524.h"
#include "generated/ExecutionReportTradeOutright525.h"
#include "generated/ExecutionReportTradeSpread526.h"
#include "generated/ExecutionReportTradeSpreadLeg527.h"
#include "generated/ExecutionReportModify531.h"
#include "generated/ExecutionReportStatus532.h"
#include "generated/ExecutionReportCancel534.h"
#include "generated/OrderCancelReject535.h"
#include "generated/OrderCancelReplaceReject536.h"
// #include "generated/PartyDetailsListReport538.h"
#include "generated/ExecutionAck539.h"
// #include "generated/NewOrderCross544.h"
// #include "generated/MassQuoteAck545.h"
// #include "generated/RequestForQuoteAck546.h"
// #include "generated/QuoteCancelAck547.h"
#include "generated/ExecutionReportTradeAddendumOutright548.h"
#include "generated/ExecutionReportTradeAddendumSpread549.h"
#include "generated/ExecutionReportTradeAddendumSpreadLeg550.h"
// #include "generated/OrderMassActionReport558.h"
// #include "generated/SecurityDefinitionResponse561.h"
@@ -0,0 +1,37 @@
#pragma once
namespace iLinkBinary {
class Negotiate500;
class Establish503;
class RetransmitRequest508;
class NewOrderSingle514;
class OrderCancelReplaceRequest515;
class OrderCancelRequest516;
class PartyDetailsDefinitionRequest518;
class NegotiationResponse501;
class NegotiationReject502;
class EstablishmentAck504;
class EstablishmentReject505;
class Sequence506;
class Terminate507;
class Retransmission509;
class RetransmitReject510;
class NotApplied513;
class PartyDetailsDefinitionRequestAck519;
class BusinessReject521;
class ExecutionReportNew522;
class ExecutionReportReject523;
class ExecutionReportElimination524;
class ExecutionReportTradeOutright525;
class ExecutionReportTradeSpread526;
class ExecutionReportTradeSpreadLeg527;
class ExecutionReportModify531;
class ExecutionReportStatus532;
class ExecutionReportCancel534;
class OrderCancelReject535;
class OrderCancelReplaceReject536;
class ExecutionAck539;
class ExecutionReportTradeAddendumOutright548;
class ExecutionReportTradeAddendumSpread549;
class ExecutionReportTradeAddendumSpreadLeg550;
}
@@ -0,0 +1,80 @@
#pragma once
#include <memory>
#include <cstring>
#include "IL3Connection.h"
#include "generated/MessageHeader.h"
namespace bts {
namespace orderman {
namespace ilink3 {
struct FramingHeader {
uint16_t message_size;
uint16_t encoding_type;
};
class IL3MessageFramer {
size_t _buffer_size;
size_t _next;
std::unique_ptr<char[]> _buffer;
public:
IL3MessageFramer():
_buffer_size(16384),
_next(0),
_buffer(new char[_buffer_size])
{
memset(_buffer.get(), 0, _buffer_size);
}
~IL3MessageFramer() = default;
//
// Framing
template <class Msg>
Msg frame(size_t extra=0) {
auto size =
sizeof(FramingHeader) +
iLinkBinary::MessageHeader::encodedLength() +
Msg::sbeBlockLength() +
extra;
auto end = _next + size;
if (end > _buffer_size) {
// Guaranteed to be enough space in buffer by after the realloc call
reallocate(end);
}
bts_assert_d(_buffer[_next] == 0);
FramingHeader* fhead = reinterpret_cast<FramingHeader*>(&_buffer[_next]);
fhead->message_size = size;
fhead->encoding_type = 0xCAFE;
Msg msg;
msg.wrapAndApplyHeader(&_buffer[_next], sizeof(FramingHeader), size+sizeof(FramingHeader));
_next = end;
return msg;
}
bool overflow() const {
return _buffer[_next] != 0;
}
void flush(IL3Connection& connection) {
if (_next > 0) {
std::string_view data(_buffer.get(), _next);
connection.send(data);
// If we're careful to set every field we could technically avoid this memset (NARRATOR: they are not that careful)
memset(_buffer.get(), 0, _next);
_next = 0;
}
}
protected:
void reallocate(size_t sz) {
sz = std::max(sz, _buffer_size*2);
std::unique_ptr<char[]> new_buffer(new char[sz]);
std::memcpy(new_buffer.get(), _buffer.get(), _buffer_size);
_buffer_size = sz;
_buffer.swap(new_buffer);
}
};
}}} //namespace
@@ -0,0 +1,198 @@
#include "IL3Reactor.h"
#include "lib/utils/bts_assert.h"
#include "IL3ReceiveBuffer.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <fstream>
#include <netinet/tcp.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <array>
#include <queue>
namespace bts {
namespace orderman {
namespace ilink3 {
struct Reactor::Connection : public IL3Connection {
int epoll_fd;
int fd;
bool is_connected;
IL3ConnectionHandler* handler;
std::queue<TCPEndpoint> end_points;
IL3ReceiveBuffer rc_buffer;
Connection(int epoll_fd, const std::vector<TCPEndpoint>& end_points):
epoll_fd(epoll_fd), fd(0), is_connected(false), handler(nullptr),
end_points(std::deque<TCPEndpoint> { end_points.begin(), end_points.end() }),
rc_buffer()
{ }
~Connection() {
if (is_connected) disconnect();
}
void connect(IL3ConnectionHandler& h) override {
bts_assert(!is_connected);
handler = &h;
fd = socket(AF_INET, SOCK_STREAM, 0);
int flag = 1;
auto result = ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
bts_assert(result == 0);
bts_assert(fd >= 0);
struct sockaddr_in serv_addr;
memset(&serv_addr, '0', sizeof(serv_addr));
auto end_point = current_end_point();
auto& host = end_point.host;
auto port = end_point.port;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
result = inet_pton(AF_INET, host.c_str(), &serv_addr.sin_addr);
bts_assert(result > 0);
result = ::connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (result < 0) {
auto er = errno;
char msg[256];
LOG(OrderMan, Error, "Failed to connect: {} {}:{}",
std::string(strerror_r(er, msg, sizeof(msg))),host,port);
disconnect();
}
else {
int flag = 1;
result = ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag,
sizeof(int));
bts_assert(result == 0);
epoll_event ev;
ev.events = EPOLLIN | EPOLLHUP | EPOLLERR | EPOLLRDHUP;
ev.data.ptr = this;
auto result = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
bts_assert_msg(result == 0, "epoll");
is_connected = true;
handler->on_connect_success();
}
}
void disconnect() override {
if (fd) close(fd);
fd = 0;
is_connected = false;
handler->on_disconnect();
}
void send(const std::string_view data) override {
if (!is_connected) {
LOG(OrderMan, Error, "Attempted to send on closed connection. {}:{}", current_end_point().host, current_end_point().port);
return;
}
auto result = write(fd, data.data(), data.size());
if (result < 0) {
auto er = errno;
char msg[256];
auto host = current_end_point().host;
auto port = current_end_point().port;
LOG(OrderMan, Warn, "Could not write to reactor connection. {}:{}",
std::string(strerror_r(er, msg, sizeof(msg))),host,port);
disconnect();
}
}
void on_data(const std::string_view data) {
bts_assert_d(is_connected);
// Copy input data into a permanent buffer
rc_buffer.append(data);
bts_assert_d(rc_buffer.unread() > 0);
auto read = handler->on_data(rc_buffer.data());
rc_buffer.advance(read);
}
void failover() override {
bts_assert(!is_connected);
next_end_point();
}
TCPEndpoint current_end_point() {
return end_points.front();
}
void next_end_point() {
auto next = end_points.front();
end_points.pop();
end_points.push(next);
}
};
struct Reactor::PImpl {
int epoll_fd = -1;
std::vector<std::unique_ptr<Connection>> connections;
};
Reactor::Reactor() : me(new PImpl()) {
me->epoll_fd = epoll_create(100);
bts_assert(me->epoll_fd >= 0);
}
Reactor::~Reactor() {
me->connections.clear();
close(me->epoll_fd);
me->epoll_fd = -1;
}
IL3Connection& Reactor::register_connection(const std::vector<TCPEndpoint>& end_points) {
me->connections.emplace_back(
std::make_unique<Connection>(me->epoll_fd, end_points));
return *me->connections.back();
}
[[gnu::noinline]]
void non_inline_assert() {
bts_assert(false);
}
constexpr bool has_error(int events) {
return events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP);
}
void Reactor::do_work() {
std::array<epoll_event, 100> ev_list;
auto ready = epoll_wait(me->epoll_fd, ev_list.data(), ev_list.size(), 0);
if (ready == -1) {
if (errno == EINTR) return;
else non_inline_assert();
}
for (int i = 0; i < ready; ++i) {
auto& ev = ev_list[i];
auto handler = (Connection*)(ev.data.ptr);
if (ev.events & EPOLLIN) {
char buffer[4096];
auto sz = read(handler->fd, buffer, sizeof(buffer));
if (sz > 0) {
bts_assert_d(handler->is_connected);
handler->on_data(std::string_view(buffer, sz));
}
else if (has_error(ev.events)) {
handler->disconnect();
}
}
else if (has_error(ev.events)) {
// if EPOLLIN was set along with
// EPOLLHUP/EPOLLERR/EPOLLRDHUP, we pretend it is a normal
// read so that we drain the bytes in the socket. The error
// or hup condition would remain and we would catch in the
// next iteration.
handler->disconnect();
}
}
}
}}} //namespace
@@ -0,0 +1,33 @@
#pragma once
#include "IL3Connection.h"
#include "IL3ConnectionHandler.h"
#include <vector>
#include <memory>
namespace bts {
namespace orderman {
namespace ilink3 {
struct TCPEndpoint {
std::string host;
uint16_t port;
};
class Reactor {
struct PImpl;
struct Connection;
std::unique_ptr<PImpl> me;
public:
Reactor();
~Reactor();
IL3Connection& register_connection(const std::vector<TCPEndpoint>&);
void do_work();
};
}}} //namespace
@@ -0,0 +1,72 @@
#pragma once
#include "lib/utils/bts_assert.h"
#include <string>
#include <vector>
#include <list>
namespace bts {
namespace orderman {
namespace ilink3 {
class IL3ReceiveBuffer {
std::list<std::vector<char>> buffers;
size_t read_pos, write_pos;
size_t buffer_size;
public:
IL3ReceiveBuffer(size_t size = 1024*1024) : buffers(), read_pos(0), write_pos(0), buffer_size(size) {
add_buffer(size);
}
void append(const std::string_view& data) {
// If we have enough space append the data
if (data.size() <= available_write_space()) {
void* write_ptr = buffers.back().data() + write_pos;
memcpy(write_ptr, data.data(), data.size());
write_pos += data.size();
}
else {
// If we don't have enough space...
// Compute the minimum size of the new buffer
auto min_size = unread() + data.size();
// allocate a new buffer
const auto& prev_buffer = buffers.back();
auto prev_read = read_pos;
auto prev_write = write_pos;
add_buffer(std::max(buffer_size, min_size));
// copy unread portion of old buffer + the new data into the new buffer
auto unread_sz = prev_write - prev_read;
memcpy(buffers.back().data(), prev_buffer.data()+prev_read, unread_sz);
write_pos = unread_sz;
bts_assert_d(data.size() <= available_write_space());
append(data);
}
}
void advance(size_t consumed) {
read_pos += consumed;
bts_assert_d(read_pos <= write_pos);
}
size_t unread() const {
return write_pos - read_pos;
}
const std::string_view data() const {
return std::string_view(buffers.back().data()+read_pos, unread());
}
private:
size_t available_write_space() const {
return buffers.back().size() - write_pos;
}
void add_buffer(size_t size) {
buffers.emplace_back(std::vector<char>());
buffers.back().resize(size);
read_pos = write_pos = 0;
}
};
}}} //namespace
@@ -0,0 +1,57 @@
#if 0
#include "ILink3ExecutionGateway.h"
#include "ILink3Utils.h"
#include "ILinkGW.h"
#include "lib/logging/logging.h"
namespace bts {
namespace orderman {
enum class State {
INIT,
UNRECOVERABLE
};
struct ILink3ExecutionGateway::PImpl {
State state;
ILinkConnection& con;
trace::PerfLog& perf;
md::SecurityOracle oracle;
OnExeReport on_exe_report;
OnGwStatusChange on_gw_status_change;
OnCancelReject on_cancel_reject;
};
ILink3ExecutionGateway::ILink3ExecutionGateway(
ILinkConnection& c,
trace::PerfLog& p,
md::SecurityOracle o) :
me(new PImpl{State::INIT, c, p, o, {}, {}, {}})
{
me->state = State::INIT;
}
void ILink3ExecutionGateway::start() {
}
void ILink3ExecutionGateway::dispatch_incoming_fix_messages() {
}
void ILink3ExecutionGateway::on_securities(const mercury::Update<NewSecuritiesEvent>&) {
}
void ILink3ExecutionGateway::on_admin_data(const mercury::Update<NewAdminDataEvent>&) {
}
void ILink3ExecutionGateway::send_fix(const jetfix::OutFIXPtr&, trace::CorID) {
LOG(OrderMan, Error, "ILink3Gateway cannot accept fix");
me->state = State::UNRECOVERABLE;
me->on_gw_status_change(false);
}
void ILink3ExecutionGateway::send_msgs(std::vector<OrderMsg> const&, trace::CorID) {
// the real one
}
OnExeReport& ILink3ExecutionGateway::on_exe_report() { return me->on_exe_report; }
OnGwStatusChange& ILink3ExecutionGateway::on_gw_status_change() { return me->on_gw_status_change; }
OnCancelReject& ILink3ExecutionGateway::on_cancel_reject() { return me->on_cancel_reject; }
}} // namespace
#endif
@@ -0,0 +1,34 @@
#pragma once
#include "../IExecutionGateway.h"
namespace bts {
namespace orderman {
struct ILinkConnection;
struct ILink3ExecutionGateway : public IExecutionGateway {
ILink3ExecutionGateway(
ILinkConnection&,
trace::PerfLog&,
md::SecurityOracle);
virtual ~ILink3ExecutionGateway() {};
void start() override;
void dispatch_incoming_fix_messages() override;
void on_securities(const mercury::Update<NewSecuritiesEvent> &) override;
void on_admin_data(const mercury::Update<NewAdminDataEvent> &) override;
void send_fix(const jetfix::OutFIXPtr&, trace::CorID) override;
void send_msgs(std::vector<OrderMsg> const&, trace::CorID) override;
OnExeReport& on_exe_report() override;
OnGwStatusChange& on_gw_status_change() override;
OnCancelReject &on_cancel_reject() override;
private:
struct PImpl;
std::unique_ptr<PImpl> me;
};
} // namespace orderman
} // namespace bts
@@ -0,0 +1,194 @@
#include "ILink3Utils.h"
namespace bts {
namespace orderman {
namespace ilink3 {
iLinkBinary::SideReq::Value map_side(api::Side side) {
switch(side) {
case api::Side::SIDE_BUY:
return iLinkBinary::SideReq::Buy;
case api::Side::SIDE_SELL:
return iLinkBinary::SideReq::Sell;
default:
return iLinkBinary::SideReq::NULL_VALUE;
}
}
iLinkBinary::OrderTypeReq::Value map_order_type(api::orderman::NativeOrderType ot) {
using namespace api::orderman;
using namespace iLinkBinary;
switch(ot) {
case NativeOrderType::NATIVE_ORDER_TYPE_MARKET:
return OrderTypeReq::MarketwithProtection;
case NativeOrderType::NATIVE_ORDER_TYPE_LIMIT:
return OrderTypeReq::Limit;
case NativeOrderType::NATIVE_ORDER_TYPE_STOP:
return OrderTypeReq::StopwithProtection;
case NativeOrderType::NATIVE_ORDER_TYPE_STOP_LIMIT:
return OrderTypeReq::StopLimit;
case NativeOrderType::NATIVE_ORDER_TYPE_MARKET_LIMIT:
return OrderTypeReq::MarketWithLeftoverAsLimit;
default:
return iLinkBinary::OrderTypeReq::NULL_VALUE;
}
}
iLinkBinary::TimeInForce::Value map_time_in_force(api::orderman::TimeInForce tif) {
using namespace api::orderman;
switch(tif) {
case TimeInForce::TIME_IN_FORCE_DAY:
return iLinkBinary::TimeInForce::Day;
case TimeInForce::TIME_IN_FORCE_GTC:
return iLinkBinary::TimeInForce::GoodTillCancel;
case TimeInForce::TIME_IN_FORCE_IOC:
return iLinkBinary::TimeInForce::FillOrKill;
default:
return iLinkBinary::TimeInForce::NULL_VALUE;
}
}
iLinkBinary::ManualOrdIndReq::Value map_manual_order_indicator(api::orderman::ManualOrderIndicator moi) {
using namespace api::orderman;
using namespace iLinkBinary;
switch(moi) {
case ManualOrderIndicator::MANUAL_ORDER_INDICATOR_NO:
return ManualOrdIndReq::Automated;
case ManualOrderIndicator::MANUAL_ORDER_INDICATOR_YES:
return ManualOrdIndReq::Manual;
default:
return ManualOrdIndReq::NULL_VALUE;
}
}
iLinkBinary::ClearingAcctType::Value map_customer_or_firm(api::orderman::CustomerOrFirm c) {
using namespace api::orderman;
using namespace iLinkBinary;
switch(c) {
case CustomerOrFirm::CUSTOMER_OR_FIRM_CUSTOMER:
return ClearingAcctType::Customer;
case CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM:
return ClearingAcctType::Firm;
default:
return ClearingAcctType::NULL_VALUE;
}
}
iLinkBinary::SMPI::Value map_smp_instruction(api::orderman::SelfMatchPreventionInstruction smpi) {
using namespace api::orderman;
using namespace iLinkBinary;
switch(smpi) {
case SELF_MATCH_PREVENTION_INSTRUCTION_CANCEL_RESTING:
return SMPI::CancelOldest;
case SELF_MATCH_PREVENTION_INSTRUCTION_CANCEL_AGRESSING:
return SMPI::CancelNewest;
default:
return SMPI::NULL_VALUE;
}
}
const char* translate_business_reject_reason(int reason) {
switch(reason) {
case 0: return "Other";
case 1: return "Unknown ID (unknown PartyDetailsListReqID being referenced in business message)";
case 2: return "Unknown Security";
case 3: return "Unsupported Message Type (for example using messages specific to cash markets for futures)";
case 5: return "Required Field Missing";
case 6: return "Not Authorized";
case 8: return "Throttle Limit Exceeded (volume controls)";
case 100: return "Value is incorrect (out of range) for this tag (for example using a value outside defined range of integer) ";
case 101: return "Incorrect data format for value (for example using ASCII character outside 32-126 in string field)";
case 102: return "Rejected due to Kill Switch";
case 103: return "Rejected due to Risk Management API";
case 104: return "Rejected due to Globex Credit Controls";
case 105: return "Not Authorized to trade Deliverable Swap Futures";
case 106: return "Not Authorized to trade Interest Rate Swap Futures";
case 107: return "Rejected due to Inline Credit Controls";
case 108: return "Invalid PartyDetailsListReqID (reusing already existing PartyDetailsListReqID while creating Party Details Definition Request)";
case 109: return "Incoming message could not be decoded. (Check schema version)";
case 110: return "Same repeating group entry appears more than once";
case 111: return "Exceeded maximum number of allowable Party Details Definition Requests";
case 112: return "Technical Error in Registering Party Details";
case 113: return "Rejected due to Cross Venue Risk";
case 114: return "Order Status Not Available";
case 115: return "Enum Not Supported";
case 116: return "Order Status Not Found";
case 117: return "Mass Order Status Cannot be Completed";
case 118: return "Exceeded Maximum Number of Allowable RequestingPartyID's in Party Details List Request";
case 119: return "Duplicate Order Threshold Exceeded";
case 120: return "On-Demand Message Rejected Due to Preceding Party Details Definition Request Being Rejected";
case 121: return "Message Rejected Since PartyDetailsListReqID Does Not Match with Immediately Preceding Party Details Definition Request sent to MSGW when using On-demand administrative information";
case 122: return "Party Details Definition Request sent to MSGW Being Rejected Due to Corresponding Business Message Being Rejected";
case 123: return "Another Message Sent in Between Party Details Definition Request and Business Message when using On-demand administrative information";
case 124: return "Cannot Have More Than One In-Flight Mass Order Status Request in Progress";
case 125: return "Exceeded Maximum Number of In-Flight Order Status Requests";
case 126: return "Cannot Have More Than One In-Flight Party Details List Request in Progress";
case 127: return "Party Details List Request is Missing Requesting Party ID and Party ID";
case 128: return "Party Details List Request cannot contain both RequestingPartyID and PartyID";
case 129: return "Party Details Definition Request Being Rejected Since Another Message was sent in Between On-Demand Message";
case 130: return "Buy Side Firm ID Does Not Match Sell Side Firm ID in New Order Cross";
case 131: return "Message Type Not Supported on Backup Instance";
case 132: return "New Order Cross Does Not Contain Buy Side Followed by Sell Side";
}
return "Unknown or invalid business reject reason.";
}
const char* translate_negotiation_reject(int reason) {
// https://www.cmegroup.com/confluence/display/EPICSANDBOX/Negotiation+Reject
// 01/13/2020
switch(reason) {
case 0: return "HMACNotAuthenticated: failed authentication because identity is not recognized";
case 1: return "HMACNotAvailable: HMAC component is not responding (5sec)";
case 2: return "InvalidUUID: UUID is not greater than the one last used or value sent by the client is out of acceptable range (MIN, MAX)";
case 3: return "InvalidTimestamp: Timestamp is not greater than the one last used or value sent by the client is out of acceptable range (MIN, MAX)";
case 4: return "RequiredHMACSignatureMissing: empty bytes in HMACSignature field";
case 5: return "RequiredAccessKeyIDMissing: empty bytes in AccessKeyID field";
case 6: return "RequiredSessionMissing: empty bytes in Session field";
case 7: return "RequiredFirmMissing: empty bytes in Firm field";
case 8: return "RequiredUUIDMisssing: null value in UUID field";
case 9: return "RequiredRequestTimestampMissing: null value in RequestTimestamp field";
case 10: return "SessionBlocked: session and firm are not authorized for this port";
case 12: return "InvalidAccessKeyID: contains non-printable ASCII character";
case 13: return "InvalidSession: contains non-printable ASCII character";
case 14: return "InvalidFirm: contains non-printable ASCII character";
case 15: return "Volume Controls - exceeding TPS limit as defined for volume controls (reject action)";
case 16: return "SplitMessageRejected - Messages queued due to split message penalty being rejected because of logout or disconnect";
case 17: return "SplitMessageQueue - Reached threshold of messages queued due to split message penalty";
case 27: return "DesignatedBackup - Using Designated backup before designated primary not allowed";
}
return "Unknown or invalid Negotiate reject reason.";
}
const char* translate_establish_reject(int reason) {
switch(reason) {
case 0: return "HMACNotAuthenticated: failed authentication because identity is not recognized";
case 1: return "HMACNotAvailable: HMAC component is not responding (5sec)";
case 2: return "InvalidUUID: UUID is not greater than the one last used or value sent by the client is out of acceptable range (MIN, MAX)";
case 3: return "InvalidTimestamp: Timestamp is not greater than the one last used or value sent by the client is out of acceptable range (MIN, MAX)";
case 4: return "RequiredHMACSignatureMissing: empty bytes in HMACSignature field";
case 5: return "RequiredAccessKeyIDMissing: empty bytes in AccessKeyID field";
case 6: return "RequiredSessionMissing: empty bytes in Session field";
case 7: return "RequiredFirmMissing: empty bytes in Firm field";
case 8: return "RequiredUUIDMisssing: null value in UUID field";
case 9: return "RequiredRequestTimestampMissing: null value in RequestTimestamp field";
case 10: return "SessionBlocked: session and firm are not authorized for this port";
case 11: return "InvalidKeepAliveInterval: value is out of acceptable range (MIN, MAX)";
case 12: return "InvalidAccessKeyID: contains non-printable ASCII character";
case 13: return "InvalidSession: contains non-printable ASCII character";
case 14: return "InvalidFirm: contains non-printable ASCII character";
case 15: return "Volume Controls - exceeding TPS limit as defined for volume controls (reject action)";
case 16: return "SplitMessageRejected - Messages queued due to split message penalty being rejected because of logout or disconnect";
case 17: return "SplitMessageQueue - Reached threshold of messages queued due to split message penalty";
case 18: return "RequiredTradingSystemNameMissing: empty bytes in TradingSystemName";
case 19: return "RequiredTradingSystemVersionMissing: empty bytes in TradingSystemVersion";
case 20: return "RequiredTradingSystemVendorMissing: empty bytes in TradingSystemVendor";
case 21: return "RequiredKeepAliveIntervalMissing: null value in KeepAliveInterval field";
case 22: return "RequiredNextSeqNoMissing: empty bytes in NextSeqNo field";
case 23: return "InvalidTradingSystemName: contains non-prinatable ASCII character";
case 24: return "InvalidTradingSystemVersion: contains non-prinatable ASCII character";
case 25: return "InvalidTradingSystemVendor: contains non-prinatable ASCII character";
case 26: return "DesignatedBackup - Using Designated backup before designated primary not allowed";
case 27: return "DesignatedBackup - Using Designated backup before designated primary not allowed";
}
return "Unknown or invalid Establish reject reason.";
}
}}}//namespace
@@ -0,0 +1,34 @@
#pragma once
#include "lib/domain_model/common.h"
#include "lib/domain_model/Security.pb.h"
#include "lib/api/services/OrderService.pb.h"
#include "generated/SideReq.h"
#include "generated/OrderTypeReq.h"
#include "generated/TimeInForce.h"
#include "generated/ManualOrdInd.h"
#include "generated/ManualOrdIndReq.h"
#include "generated/ClearingAcctType.h"
#include "generated/SMPI.h"
namespace bts {
namespace orderman {
namespace ilink3 {
iLinkBinary::SideReq::Value map_side(api::Side side);
inline int64_t to_price9(Price p) {
return p.value() * 1E9;
}
iLinkBinary::OrderTypeReq::Value map_order_type(api::orderman::NativeOrderType ot);
iLinkBinary::TimeInForce::Value map_time_in_force(api::orderman::TimeInForce tif);
iLinkBinary::ManualOrdIndReq::Value map_manual_order_indicator(api::orderman::ManualOrderIndicator moi) ;
iLinkBinary::ClearingAcctType::Value map_customer_or_firm(api::orderman::CustomerOrFirm c) ;
iLinkBinary::SMPI::Value map_smp_instruction(api::orderman::SelfMatchPreventionInstruction smpi) ;
const char* translate_business_reject_reason(int reason) ;
const char* translate_negotiation_reject(int reason) ;
const char* translate_establish_reject(int reason) ;
}}}//namespace
+471
View File
@@ -0,0 +1,471 @@
#include "ILinkGW.h"
#include "lib/utils/bts_assert.h"
#include "lib/utils/SecureLogon.h"
#include "ILink3Utils.h"
#include "IL3GeneratedFull.h"
#include "IL3Dispatcher.h"
/*
# Some notes about session binding and initialization: #
## Official documentation:
https://www.cmegroup.com/confluence/display/EPICSANDBOX/iLink+3+Binary+Order+Entry+-+Session+Layer#iLink3BinaryOrderEntry-SessionLayer-WeeklyReset
## Begining of week (new session?)
- config.session = X
- config.outgoing_sequence = 1
-> Negotiate session=X
<- NegotiateResponse session=X, oldsession=Y, oldSeq=N
if oldSeq > 0 -> ReplayRequest
-> Establish seq=1
<- EstablishAck oldsession=Y, oldSeq=N
## Middle of week (same session)
- config.session = X
- config.outgoing_sequence > 1
-> Establish seq=N
*/
namespace bts {
namespace orderman {
namespace ilink3 {
log::CharPtrWrapper wrap(const char* str) { return log::CharPtrWrapper{ str }; }
ILinkGW::ILinkGW(IL3Connection& con, const Session& session, const Config& conf) :
_config(conf),
_x_state(State::INIT),
_buffer(),
_on_state_change([](auto){}),
_connection(con),
_session(session),
_msg_count(0),
_time()
{
}
void ILinkGW::connect() {
bts_assert(state() == State::INIT);
set_state(State::CONNECTING);
_connection.connect(*this); // -> on_connect_success
}
// This determines the session uuid
void ILinkGW::send_negotiate() {
// add 2 bytes for the empty 'credentials' (39008) length which must be present
auto msg = _buffer.frame<iLinkBinary::Negotiate500>(
iLinkBinary::Negotiate500::credentialsHeaderLength());
msg.uUID(_session.uuid);
msg.requestTimestamp(_time.now());
msg.putSession(_config.cme_session);
// We need this call to set the length of the credential block to 0
// This behavior is specific to "data" in the xml template
msg.putCredentials("", 0);
msg.putFirm(_config.firm);
const auto ld = glbx::calculate_hmac(
_config.cme_session,
std::to_string(msg.requestTimestamp()),
std::to_string(msg.uUID()),
_config.cme_session,
_config.firm
);
msg.putAccessKeyID(ld.access_key);
msg.putHMACSignature(ld.hmac);
// expect -> NegotiationResponse501 or NegotiationReject502
}
void ILinkGW::send_establish() {
// add 2 bytes for the empty 'credentials' (39008) length which must be present
auto msg = _buffer.frame<iLinkBinary::Establish503>(2);
msg.uUID(_session.uuid);
msg.requestTimestamp(_time.now());
msg.putSession(_config.cme_session);
msg.putCredentials("", 0);
msg.putFirm(_config.firm);
msg.putTradingSystemName(std::string_view("SPARK"));
msg.putTradingSystemVersion(std::string_view("1.0"));
msg.putTradingSystemVendor(std::string_view("BTS"));
// On primary connection, the expected message sequence number of the next business message from customer to CME
msg.nextSeqNo(_session.to_sequence);
msg.keepAliveInterval(60000);
const auto ld = glbx::calculate_hmac(
_config.cme_session,
std::to_string(msg.requestTimestamp()),
std::to_string(msg.uUID()),
_config.cme_session,
_config.firm
);
msg.putAccessKeyID(ld.access_key);
msg.putHMACSignature(ld.hmac);
// expect -> EstablishmentAck504 or EstablishmentReject505
}
void ILinkGW::send_heartbeat() { send_sequence(); }
void ILinkGW::send_sequence() {
auto msg = _buffer.frame<iLinkBinary::Sequence506>();
msg.uUID(_session.uuid);
msg.nextSeqNo(_session.to_sequence);
msg.faultToleranceIndicator(iLinkBinary::FTI::NULL_VALUE);
msg.keepAliveIntervalLapsed(iLinkBinary::KeepAliveLapsed::NotLapsed);
}
void ILinkGW::send_retransmit_request(uint64_t uuid, uint32_t from, size_t count) {
using namespace iLinkBinary;
auto msg = _buffer.frame<RetransmitRequest508>();
msg.uUID(_session.uuid);
msg.lastUUID(uuid);
msg.requestTimestamp(_time.now());
msg.fromSeqNo(from);
msg.msgCount(count);
}
uint64_t ILinkGW::send_party_details(const api::orderman::RoutingRecord& route) {
using namespace iLinkBinary;
auto msg = _buffer.frame<PartyDetailsDefinitionRequest518>(
// 2 repeating group header.
// 1 for party details and 1 for trade reg
// This seems wildly unsafe but the api doesn't seem to want you to know
// how to size buffers ahead of time
2 * PartyDetailsDefinitionRequest518::NoPartyDetails::sbeHeaderSize() +
// N * size of each block
1 * PartyDetailsDefinitionRequest518::NoPartyDetails::sbeBlockLength() +
1 * PartyDetailsDefinitionRequest518::NoTrdRegPublications::sbeBlockLength()
);
msg.partyDetailsListReqID(++_msg_count);
msg.sendingTimeEpoch(_time.now());
msg.listUpdateAction(ListUpdAct::Add);
msg.seqNum(next_seq());
// msg.putMemo("") -- not supported
if (route.smp_id().empty()) {
msg.selfMatchPreventionID(
PartyDetailsDefinitionRequest518::selfMatchPreventionIDNullValue());
}
else {
bts_assert_d(route.smp_id().size() == 8);
const uint64_t* smp_id = reinterpret_cast<const uint64_t*>(&route.smp_id());
msg.selfMatchPreventionID(*smp_id);
}
msg.cmtaGiveupCD(CmtaGiveUpCD::NULL_VALUE);
msg.custOrderCapacity(CustOrderCapacity::NULL_VALUE);
msg.clearingAccountType(map_customer_or_firm(route.customer_or_firm()));
msg.selfMatchPreventionInstruction(map_smp_instruction(route.smp_instruction()));
msg.avgPxIndicator(AvgPxInd::NULL_VALUE);
msg.clearingTradePriceType(SLEDS::NULL_VALUE);
msg.custOrderHandlingInst(CustOrdHandlInst::NULL_VALUE);
msg.executor(PartyDetailsDefinitionRequest518::executorNullValue());
msg.iDMShortCode(PartyDetailsDefinitionRequest518::iDMShortCodeNullValue());
auto details = msg.noPartyDetailsCount(1);
details.next();
details.partyDetailRole(PartyDetailRole::CustomerAccount);
msg.noTrdRegPublicationsCount(0);
// In the future we may check for existing party details definitions and return that id
return 0;
}
bool needs_stop_px(api::orderman::NativeOrderType order_type) {
return order_type == api::orderman::NativeOrderType::NATIVE_ORDER_TYPE_STOP ||
order_type == api::orderman::NativeOrderType::NATIVE_ORDER_TYPE_STOP_LIMIT;
}
void ILinkGW::send_order(const CreateOrderMsg& create) {
bts_assert_d(create.routing_record);
bts_assert_d(create.security);
bts_assert_d(create.security->has_glbx());
auto party = send_party_details(*create.routing_record);
auto msg = _buffer.frame<iLinkBinary::NewOrderSingle514>();
msg.price().mantissa(to_price9(create.price));
msg.orderQty(create.quantity.value());
msg.securityID(create.security->glbx().exchange_id());
msg.side(map_side(create.side));
msg.seqNum(next_seq());
msg.putSenderID(create.routing_record->operator_id());
// msg.putClOrdID(create.clordid);
msg.partyDetailsListReqID(party);
msg.orderRequestID(++_msg_count);
msg.sendingTimeEpoch(_time.now());
if (needs_stop_px(create.order_type)) {
msg.stopPx().mantissa(to_price9(create.stop_px));
}
else msg.stopPx().mantissa(iLinkBinary::PRICENULL9::mantissaNullValue());
msg.putLocation(create.routing_record->location());
msg.minQty(iLinkBinary::NewOrderSingle514::minQtyNullValue());
msg.displayQty(create.display_quantity.value());
msg.expireDate(iLinkBinary::NewOrderSingle514::expireDateNullValue());
msg.ordType(map_order_type(create.order_type));
msg.timeInForce(map_time_in_force(create.time_in_force));
msg.manualOrderIndicator(map_manual_order_indicator(create.manual_order_indicator));
msg.execInst().clear();
msg.executionMode(iLinkBinary::ExecMode::NULL_VALUE);
msg.liquidityFlag(iLinkBinary::BooleanNULL::NULL_VALUE);
msg.managedOrder(iLinkBinary::BooleanNULL::NULL_VALUE);
msg.shortSaleType(iLinkBinary::ShortSaleType::NULL_VALUE);
}
void ILinkGW::send_cancel_replace(const CancelReplaceOrderMsg& replace) {
const auto& create = replace.create_fields;
bts_assert_d(create.routing_record);
bts_assert_d(create.security);
bts_assert_d(create.security->has_glbx());
auto party = send_party_details(*create.routing_record);
auto msg = _buffer.frame<iLinkBinary::OrderCancelReplaceRequest515>();
msg.orderID(replace.exchange_order_id.value());
msg.price().mantissa(to_price9(create.price));
msg.orderQty(create.quantity.value());
msg.securityID(create.security->glbx().exchange_id());
msg.side(map_side(create.side));
msg.seqNum(next_seq());
msg.putSenderID(create.routing_record->operator_id());
// msg.putClOrdID(create.clordid);
msg.partyDetailsListReqID(party);
msg.orderRequestID(++_msg_count);
msg.sendingTimeEpoch(_time.now());
if (needs_stop_px(create.order_type)) {
msg.stopPx().mantissa(to_price9(create.stop_px));
}
else msg.stopPx().mantissa(iLinkBinary::PRICENULL9::mantissaNullValue());
msg.putLocation(create.routing_record->location());
msg.minQty(iLinkBinary::NewOrderSingle514::minQtyNullValue());
msg.displayQty(create.display_quantity.value());
msg.expireDate(iLinkBinary::NewOrderSingle514::expireDateNullValue());
msg.ordType(map_order_type(create.order_type));
msg.timeInForce(map_time_in_force(create.time_in_force));
msg.manualOrderIndicator(map_manual_order_indicator(create.manual_order_indicator));
msg.oFMOverride(iLinkBinary::OFMOverrideReq::Disabled);
msg.execInst().clear();
msg.executionMode(iLinkBinary::ExecMode::NULL_VALUE);
msg.liquidityFlag(iLinkBinary::BooleanNULL::NULL_VALUE);
msg.managedOrder(iLinkBinary::BooleanNULL::NULL_VALUE);
msg.shortSaleType(iLinkBinary::ShortSaleType::NULL_VALUE);
}
void ILinkGW::send_cancel(const CancelOrderMsg& cancel) {
bts_assert_d(cancel.routing_record);
bts_assert_d(cancel.security);
bts_assert_d(cancel.security->has_glbx());
auto party = send_party_details(*cancel.routing_record);
auto msg = _buffer.frame<iLinkBinary::OrderCancelRequest516>();
msg.orderID(cancel.exchange_order_id.value());
msg.partyDetailsListReqID(party);
msg.manualOrderIndicator(map_manual_order_indicator(cancel.manual_order_indicator));
msg.seqNum(next_seq());
msg.putSenderID(cancel.routing_record->operator_id());
msg.putClOrdID(cancel.clordid);
msg.orderRequestID(++_msg_count);
msg.sendingTimeEpoch(_time.now());
msg.putLocation(cancel.routing_record->location());
msg.securityID(cancel.security->glbx().exchange_id());
msg.side(map_side(cancel.side));
msg.liquidityFlag(iLinkBinary::BooleanNULL::NULL_VALUE);
}
void ILinkGW::flush() {
_buffer.flush(_connection);
}
const char* state_string(State s) {
switch(s) {
case State::INIT: return "INIT";
case State::CONNECTING: return "CONNECTING";
case State::NEGOTATING: return "NEGOTATING";
case State::ESTABLISHING: return "ESTABLISHING";
case State::RETRANSMISSING_LAST: return "RETRANSMITTING LAST";
case State::RETRANSMITTING: return "RETRANSMITTING";
case State::READY: return "READY";
case State::ERROR: return "ERROR";
}
return "UNKNOWN";
}
log::CharPtrWrapper wstate_string(State s) { return wrap(state_string(s)); }
void ILinkGW::set_state(State s) {
LOG(OrderMan, Diag, "ILinkGW {}: {}->{}",
_session.uuid, wstate_string(_x_state), wstate_string(s));
_x_state = s;
if (_on_state_change) _on_state_change(s);
}
//
// IConnectionHandler
void ILinkGW::on_connect_success() {
if (_session.from_sequence == 1) {
LOG(OrderMan, Info, "Creating new iLink session. {}", _session.uuid);
set_state(State::NEGOTATING);
// Sequence = 1 indicates a new session
// so we have to go through a negotiate
// to create the session at CME
send_negotiate();
}
else {
// We only need to establish the current sequence number
LOG(OrderMan, Info, "re-establishing existing iLink session. {}", _session.uuid);
set_state(State::ESTABLISHING);
send_establish();
}
flush();
}
void ILinkGW::on_disconnect() {
LOG(OrderMan, Error, "Disconnected.");
set_state(State::ERROR);
if (_config.failover_on_disconnect) {
LOG(OrderMan, Error, "Attempting failover");
_connection.failover();
connect();
}
}
void ILinkGW::on_retransmit_complete() {
if (state() == State::RETRANSMISSING_LAST) {
send_establish();
flush();
}
_rt_session = std::nullopt;
}
size_t ILinkGW::on_data(const std::string_view& data) {
return consume_messages(*this, data.data(), data.size(), dispatch_message<ILinkGW>);
}
template <class T>
std::string to_string(const T& t) {
std::stringstream buf;
buf << t;
return buf.str();
}
// Message Handlers
void ILinkGW::handle(const iLinkBinary::NegotiationResponse501& msg) {
auto cme_prev_uuid = msg.previousUUID();
auto cme_prev_seq = msg.previousSeqNo();
// Check if cme sent us a previous session
if (cme_prev_uuid != iLinkBinary::NegotiationResponse501::previousUUIDNullValue()) {
auto my_session = _config.previous_session.value_or(Session {0,0,0});
if (my_session.uuid == cme_prev_uuid) {
// There is a previous session and we knew about it
// Replay any missing messages
if (my_session.from_sequence < cme_prev_seq) {
set_state(State::RETRANSMISSING_LAST);
send_retransmit_request(cme_prev_uuid, my_session.from_sequence);
}
}
else {
// there is a previous session we didn't know about
// It could be an automatically created start of week session
// replay all messages
set_state(State::RETRANSMISSING_LAST);
send_retransmit_request(cme_prev_uuid, 0);
}
}
else {
// There is no previous session, continue to negotiate
send_establish();
}
flush();
}
void ILinkGW::handle(const iLinkBinary::NegotiationReject502& msg) {
LOG(OrderMan, Error, "Negotiate Reject: {} '{}'.\nRaw: \"{}\"",
msg.errorCodes(),
std::string(translate_negotiation_reject(msg.errorCodes())),
to_string(msg));
set_state(State::ERROR);
_connection.disconnect();
}
void ILinkGW::handle(const iLinkBinary::EstablishmentAck504&) {
// This message may indicate missed messages from *this* session. (different from NegotiationResponse501)
// If no missed messagse send the Sequence
send_sequence();
flush();
set_state(State::READY);
}
void ILinkGW::handle(const iLinkBinary::EstablishmentReject505& msg) {
LOG(OrderMan, Error, "Establishment Reject: {} '{}'. NextSeq: {}.\nRaw: \"{}\"",
msg.errorCodes(),
std::string(translate_establish_reject(msg.errorCodes())),
msg.nextSeqNo(),
to_string(msg));
set_state(State::ERROR);
_connection.disconnect();
}
void ILinkGW::handle(const iLinkBinary::Sequence506& s) {
if (s.keepAliveIntervalLapsed() == iLinkBinary::KeepAliveLapsed::Lapsed) {
send_heartbeat();
flush();
}
}
void ILinkGW::handle(const iLinkBinary::Terminate507& msg) {
LOG(OrderMan, Error, "Terminated by exchange. Code: {} Reason: {}",
msg.errorCodes(),
wrap(msg.reason())
);
set_state(State::ERROR);
_connection.disconnect();
}
void ILinkGW::handle(const iLinkBinary::Retransmission509&) {
// Accepted retransmit
}
void ILinkGW::handle(const iLinkBinary::RetransmitReject510&) {
// ?!
}
void ILinkGW::handle(const iLinkBinary::NotApplied513&) {
// Sequence number problem?
}
void ILinkGW::handle(const iLinkBinary::PartyDetailsDefinitionRequestAck519&) {
// Future:
// We can handle the party details
}
void ILinkGW::handle(const iLinkBinary::BusinessReject521& msg) {
LOG(OrderMan, Error, "Business Reject: {} '{}'.\nRaw: \"{}\"",
msg.businessRejectReason(),
wrap(translate_business_reject_reason(msg.businessRejectReason())),
to_string(msg));
set_state(State::ERROR);
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportNew522& msg) {
if (msg.uUID() != _session.uuid) {
// handle retransmit
return;
}
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportReject523&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportElimination524&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportTradeOutright525&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportTradeSpread526&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportTradeSpreadLeg527&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportModify531&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportStatus532&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportCancel534&) {
}
void ILinkGW::handle(const iLinkBinary::OrderCancelReject535&) {
}
void ILinkGW::handle(const iLinkBinary::OrderCancelReplaceReject536&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionAck539&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportTradeAddendumOutright548&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportTradeAddendumSpread549&) {
}
void ILinkGW::handle(const iLinkBinary::ExecutionReportTradeAddendumSpreadLeg550&) {
}
}}} //namespace
+134
View File
@@ -0,0 +1,134 @@
#pragma once
#include <string>
#include <functional>
#include <cstdint>
#include <vector>
#include "../IExecutionGateway.h"
#include "TimeKeeper.h"
#include "IL3Connection.h"
#include "IL3ConnectionHandler.h"
#include "IL3MessageFramer.h"
#include "generated/MessageHeader.h"
#include "IL3GeneratedFwd.h"
namespace bts {
namespace orderman {
class ExecutionReport;
namespace ilink3 {
struct Session {
uint64_t uuid;
// bts->cme
uint32_t to_sequence;
// cme->bts
uint32_t from_sequence;
};
struct RetransmitState {
uint64_t uuid;
uint32_t sequence;
uint32_t end;
};
struct Config {
std::optional<Session> previous_session;
std::string cme_session; // NGG
std::string firm; // 004
bool failover_on_disconnect;
};
enum class State {
INIT,
CONNECTING,
NEGOTATING,
ESTABLISHING,
RETRANSMISSING_LAST, // of Session
RETRANSMITTING, // of Session
READY,
ERROR
};
typedef std::function<void(State)> OnStateChange;
typedef std::function<void(const ExecutionReport&)> OnExecutionReport;
// Does not allow re-entrance
class ILinkGW : IL3ConnectionHandler {
const Config _config;
State _x_state;
IL3MessageFramer _buffer;
OnStateChange _on_state_change;
OnExecutionReport _on_exe_report;
OnExecutionReport _on_replay_exe_report;
IL3Connection& _connection;
Session _session;
std::optional<RetransmitState> _rt_session;
uint32_t _msg_count;
TimeKeeper _time;
public:
ILinkGW(IL3Connection&, const Session&, const Config&);
void connect();
void send_negotiate();
void send_establish();
void send_heartbeat();
void send_sequence();
void send_retransmit_request(uint64_t uuid, uint32_t from, size_t count = 0);
uint64_t send_party_details(const api::orderman::RoutingRecord&);
void send_order(const CreateOrderMsg&);
void send_cancel_replace(const CancelReplaceOrderMsg&);
void send_cancel(const CancelOrderMsg&);
void flush();
// state change
State state() { return _x_state; }
void subscribe_state(OnStateChange o) { _on_state_change = o; }
void subscribe_execution_reports(OnExecutionReport sub, OnExecutionReport rsub) {
_on_exe_report = sub;
_on_replay_exe_report = rsub;
}
private: // Functions
void set_state(State);
uint32_t next_seq() { return ++_session.to_sequence; }
void on_connect_success() override;
void on_disconnect() override;
void on_retransmit_complete();
//
// Message handlers
size_t on_data(const std::string_view&) override;
public:
void handle(const iLinkBinary::NegotiationResponse501&);
void handle(const iLinkBinary::NegotiationReject502&);
void handle(const iLinkBinary::EstablishmentAck504&);
void handle(const iLinkBinary::EstablishmentReject505&);
void handle(const iLinkBinary::Sequence506&);
void handle(const iLinkBinary::Terminate507&);
void handle(const iLinkBinary::Retransmission509&);
void handle(const iLinkBinary::RetransmitReject510&);
void handle(const iLinkBinary::NotApplied513&);
void handle(const iLinkBinary::PartyDetailsDefinitionRequestAck519&);
void handle(const iLinkBinary::BusinessReject521&);
void handle(const iLinkBinary::ExecutionReportNew522&);
void handle(const iLinkBinary::ExecutionReportReject523&);
void handle(const iLinkBinary::ExecutionReportElimination524&);
void handle(const iLinkBinary::ExecutionReportTradeOutright525&);
void handle(const iLinkBinary::ExecutionReportTradeSpread526&);
void handle(const iLinkBinary::ExecutionReportTradeSpreadLeg527&);
void handle(const iLinkBinary::ExecutionReportModify531&);
void handle(const iLinkBinary::ExecutionReportStatus532&);
void handle(const iLinkBinary::ExecutionReportCancel534&);
void handle(const iLinkBinary::OrderCancelReject535&);
void handle(const iLinkBinary::OrderCancelReplaceReject536&);
void handle(const iLinkBinary::ExecutionAck539&);
void handle(const iLinkBinary::ExecutionReportTradeAddendumOutright548&);
void handle(const iLinkBinary::ExecutionReportTradeAddendumSpread549&);
void handle(const iLinkBinary::ExecutionReportTradeAddendumSpreadLeg550&);
};
}}} //namespace
@@ -0,0 +1,25 @@
#pragma once
#include "lib/utils/datetime.h"
#include "lib/utils/TimeStamp.h"
namespace bts {
namespace orderman {
namespace ilink3 {
struct TimeKeeper {
uint64_t unix_time;
utils::TimeStamp start;
TimeKeeper() :
unix_time(datetime::unix_nano_now()),
start(utils::TimeStamp::now())
{}
uint64_t now() const {
auto now = utils::TimeStamp::now();
auto delta = now - start;
return unix_time + delta.microseconds();
}
};
}}} //namespace
@@ -0,0 +1,144 @@
/* Generated SBE (Simple Binary Encoding) message codec */
#ifndef _ILINKBINARY_AVGPXIND_H_
#define _ILINKBINARY_AVGPXIND_H_
#if defined(SBE_HAVE_CMATH)
/* cmath needed for std::numeric_limits<double>::quiet_NaN() */
# include <cmath>
# define SBE_FLOAT_NAN std::numeric_limits<float>::quiet_NaN()
# define SBE_DOUBLE_NAN std::numeric_limits<double>::quiet_NaN()
#else
/* math.h needed for NAN */
# include <math.h>
# define SBE_FLOAT_NAN NAN
# define SBE_DOUBLE_NAN NAN
#endif
#if __cplusplus >= 201103L
# define SBE_CONSTEXPR constexpr
# define SBE_NOEXCEPT noexcept
#else
# define SBE_CONSTEXPR
# define SBE_NOEXCEPT
#endif
#if __cplusplus >= 201402L
# define SBE_CONSTEXPR_14 constexpr
#else
# define SBE_CONSTEXPR_14
#endif
#if __cplusplus >= 201703L
# include <string_view>
# define SBE_NODISCARD [[nodiscard]]
#else
# define SBE_NODISCARD
#endif
#if !defined(__STDC_LIMIT_MACROS)
# define __STDC_LIMIT_MACROS 1
#endif
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <limits>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#if defined(WIN32) || defined(_WIN32)
# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) _byteswap_ulong(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) _byteswap_uint64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SBE_BIG_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_BIG_ENDIAN_ENCODE_16(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) (v)
#else
# error "Byte Ordering of platform not determined. Set __BYTE_ORDER__ manually before including this file."
#endif
#if defined(SBE_NO_BOUNDS_CHECK)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)
#elif defined(_MSC_VER)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)
#else
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))
#endif
#define SBE_NULLVALUE_INT8 (std::numeric_limits<std::int8_t>::min)()
#define SBE_NULLVALUE_INT16 (std::numeric_limits<std::int16_t>::min)()
#define SBE_NULLVALUE_INT32 (std::numeric_limits<std::int32_t>::min)()
#define SBE_NULLVALUE_INT64 (std::numeric_limits<std::int64_t>::min)()
#define SBE_NULLVALUE_UINT8 (std::numeric_limits<std::uint8_t>::max)()
#define SBE_NULLVALUE_UINT16 (std::numeric_limits<std::uint16_t>::max)()
#define SBE_NULLVALUE_UINT32 (std::numeric_limits<std::uint32_t>::max)()
#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()
namespace iLinkBinary {
class AvgPxInd
{
public:
enum Value
{
NoAveragePricing = (std::uint8_t)0,
TradeispartofanAveragePriceGroupIdentifiedbytheAvgPxGrpID = (std::uint8_t)1,
TradeispartofaNotionalValueAveragePriceGroup = (std::uint8_t)3,
NULL_VALUE = (std::uint8_t)255
};
static AvgPxInd::Value get(const std::uint8_t value)
{
switch (value)
{
case 0: return NoAveragePricing;
case 1: return TradeispartofanAveragePriceGroupIdentifiedbytheAvgPxGrpID;
case 3: return TradeispartofaNotionalValueAveragePriceGroup;
case 255: return NULL_VALUE;
}
throw std::runtime_error("unknown value for enum AvgPxInd [E103]");
}
static const char* c_str(const AvgPxInd::Value value)
{
switch (value)
{
case NoAveragePricing: return "NoAveragePricing";
case TradeispartofanAveragePriceGroupIdentifiedbytheAvgPxGrpID: return "TradeispartofanAveragePriceGroupIdentifiedbytheAvgPxGrpID";
case TradeispartofaNotionalValueAveragePriceGroup: return "TradeispartofaNotionalValueAveragePriceGroup";
case NULL_VALUE: return "NULL_VALUE";
}
throw std::runtime_error("unknown value for enum AvgPxInd [E103]:");
}
template<typename CharT, typename Traits>
friend std::basic_ostream<CharT, Traits>& operator << (
std::basic_ostream<CharT, Traits>& os, AvgPxInd::Value m)
{
return os << AvgPxInd::c_str(m);
}
};
}
#endif
@@ -0,0 +1,141 @@
/* Generated SBE (Simple Binary Encoding) message codec */
#ifndef _ILINKBINARY_BOOLEANFLAG_H_
#define _ILINKBINARY_BOOLEANFLAG_H_
#if defined(SBE_HAVE_CMATH)
/* cmath needed for std::numeric_limits<double>::quiet_NaN() */
# include <cmath>
# define SBE_FLOAT_NAN std::numeric_limits<float>::quiet_NaN()
# define SBE_DOUBLE_NAN std::numeric_limits<double>::quiet_NaN()
#else
/* math.h needed for NAN */
# include <math.h>
# define SBE_FLOAT_NAN NAN
# define SBE_DOUBLE_NAN NAN
#endif
#if __cplusplus >= 201103L
# define SBE_CONSTEXPR constexpr
# define SBE_NOEXCEPT noexcept
#else
# define SBE_CONSTEXPR
# define SBE_NOEXCEPT
#endif
#if __cplusplus >= 201402L
# define SBE_CONSTEXPR_14 constexpr
#else
# define SBE_CONSTEXPR_14
#endif
#if __cplusplus >= 201703L
# include <string_view>
# define SBE_NODISCARD [[nodiscard]]
#else
# define SBE_NODISCARD
#endif
#if !defined(__STDC_LIMIT_MACROS)
# define __STDC_LIMIT_MACROS 1
#endif
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <limits>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#if defined(WIN32) || defined(_WIN32)
# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) _byteswap_ulong(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) _byteswap_uint64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SBE_BIG_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_BIG_ENDIAN_ENCODE_16(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) (v)
#else
# error "Byte Ordering of platform not determined. Set __BYTE_ORDER__ manually before including this file."
#endif
#if defined(SBE_NO_BOUNDS_CHECK)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)
#elif defined(_MSC_VER)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)
#else
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))
#endif
#define SBE_NULLVALUE_INT8 (std::numeric_limits<std::int8_t>::min)()
#define SBE_NULLVALUE_INT16 (std::numeric_limits<std::int16_t>::min)()
#define SBE_NULLVALUE_INT32 (std::numeric_limits<std::int32_t>::min)()
#define SBE_NULLVALUE_INT64 (std::numeric_limits<std::int64_t>::min)()
#define SBE_NULLVALUE_UINT8 (std::numeric_limits<std::uint8_t>::max)()
#define SBE_NULLVALUE_UINT16 (std::numeric_limits<std::uint16_t>::max)()
#define SBE_NULLVALUE_UINT32 (std::numeric_limits<std::uint32_t>::max)()
#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()
namespace iLinkBinary {
class BooleanFlag
{
public:
enum Value
{
False = (std::uint8_t)0,
True = (std::uint8_t)1,
NULL_VALUE = (std::uint8_t)255
};
static BooleanFlag::Value get(const std::uint8_t value)
{
switch (value)
{
case 0: return False;
case 1: return True;
case 255: return NULL_VALUE;
}
throw std::runtime_error("unknown value for enum BooleanFlag [E103]");
}
static const char* c_str(const BooleanFlag::Value value)
{
switch (value)
{
case False: return "False";
case True: return "True";
case NULL_VALUE: return "NULL_VALUE";
}
throw std::runtime_error("unknown value for enum BooleanFlag [E103]:");
}
template<typename CharT, typename Traits>
friend std::basic_ostream<CharT, Traits>& operator << (
std::basic_ostream<CharT, Traits>& os, BooleanFlag::Value m)
{
return os << BooleanFlag::c_str(m);
}
};
}
#endif
@@ -0,0 +1,141 @@
/* Generated SBE (Simple Binary Encoding) message codec */
#ifndef _ILINKBINARY_BOOLEANNULL_H_
#define _ILINKBINARY_BOOLEANNULL_H_
#if defined(SBE_HAVE_CMATH)
/* cmath needed for std::numeric_limits<double>::quiet_NaN() */
# include <cmath>
# define SBE_FLOAT_NAN std::numeric_limits<float>::quiet_NaN()
# define SBE_DOUBLE_NAN std::numeric_limits<double>::quiet_NaN()
#else
/* math.h needed for NAN */
# include <math.h>
# define SBE_FLOAT_NAN NAN
# define SBE_DOUBLE_NAN NAN
#endif
#if __cplusplus >= 201103L
# define SBE_CONSTEXPR constexpr
# define SBE_NOEXCEPT noexcept
#else
# define SBE_CONSTEXPR
# define SBE_NOEXCEPT
#endif
#if __cplusplus >= 201402L
# define SBE_CONSTEXPR_14 constexpr
#else
# define SBE_CONSTEXPR_14
#endif
#if __cplusplus >= 201703L
# include <string_view>
# define SBE_NODISCARD [[nodiscard]]
#else
# define SBE_NODISCARD
#endif
#if !defined(__STDC_LIMIT_MACROS)
# define __STDC_LIMIT_MACROS 1
#endif
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <limits>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#if defined(WIN32) || defined(_WIN32)
# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) _byteswap_ulong(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) _byteswap_uint64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SBE_BIG_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_BIG_ENDIAN_ENCODE_16(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) (v)
#else
# error "Byte Ordering of platform not determined. Set __BYTE_ORDER__ manually before including this file."
#endif
#if defined(SBE_NO_BOUNDS_CHECK)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)
#elif defined(_MSC_VER)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)
#else
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))
#endif
#define SBE_NULLVALUE_INT8 (std::numeric_limits<std::int8_t>::min)()
#define SBE_NULLVALUE_INT16 (std::numeric_limits<std::int16_t>::min)()
#define SBE_NULLVALUE_INT32 (std::numeric_limits<std::int32_t>::min)()
#define SBE_NULLVALUE_INT64 (std::numeric_limits<std::int64_t>::min)()
#define SBE_NULLVALUE_UINT8 (std::numeric_limits<std::uint8_t>::max)()
#define SBE_NULLVALUE_UINT16 (std::numeric_limits<std::uint16_t>::max)()
#define SBE_NULLVALUE_UINT32 (std::numeric_limits<std::uint32_t>::max)()
#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()
namespace iLinkBinary {
class BooleanNULL
{
public:
enum Value
{
False = (std::uint8_t)0,
True = (std::uint8_t)1,
NULL_VALUE = (std::uint8_t)255
};
static BooleanNULL::Value get(const std::uint8_t value)
{
switch (value)
{
case 0: return False;
case 1: return True;
case 255: return NULL_VALUE;
}
throw std::runtime_error("unknown value for enum BooleanNULL [E103]");
}
static const char* c_str(const BooleanNULL::Value value)
{
switch (value)
{
case False: return "False";
case True: return "True";
case NULL_VALUE: return "NULL_VALUE";
}
throw std::runtime_error("unknown value for enum BooleanNULL [E103]:");
}
template<typename CharT, typename Traits>
friend std::basic_ostream<CharT, Traits>& operator << (
std::basic_ostream<CharT, Traits>& os, BooleanNULL::Value m)
{
return os << BooleanNULL::c_str(m);
}
};
}
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,141 @@
/* Generated SBE (Simple Binary Encoding) message codec */
#ifndef _ILINKBINARY_CLEARINGACCTTYPE_H_
#define _ILINKBINARY_CLEARINGACCTTYPE_H_
#if defined(SBE_HAVE_CMATH)
/* cmath needed for std::numeric_limits<double>::quiet_NaN() */
# include <cmath>
# define SBE_FLOAT_NAN std::numeric_limits<float>::quiet_NaN()
# define SBE_DOUBLE_NAN std::numeric_limits<double>::quiet_NaN()
#else
/* math.h needed for NAN */
# include <math.h>
# define SBE_FLOAT_NAN NAN
# define SBE_DOUBLE_NAN NAN
#endif
#if __cplusplus >= 201103L
# define SBE_CONSTEXPR constexpr
# define SBE_NOEXCEPT noexcept
#else
# define SBE_CONSTEXPR
# define SBE_NOEXCEPT
#endif
#if __cplusplus >= 201402L
# define SBE_CONSTEXPR_14 constexpr
#else
# define SBE_CONSTEXPR_14
#endif
#if __cplusplus >= 201703L
# include <string_view>
# define SBE_NODISCARD [[nodiscard]]
#else
# define SBE_NODISCARD
#endif
#if !defined(__STDC_LIMIT_MACROS)
# define __STDC_LIMIT_MACROS 1
#endif
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <limits>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#if defined(WIN32) || defined(_WIN32)
# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) _byteswap_ulong(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) _byteswap_uint64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SBE_BIG_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_BIG_ENDIAN_ENCODE_16(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) (v)
#else
# error "Byte Ordering of platform not determined. Set __BYTE_ORDER__ manually before including this file."
#endif
#if defined(SBE_NO_BOUNDS_CHECK)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)
#elif defined(_MSC_VER)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)
#else
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))
#endif
#define SBE_NULLVALUE_INT8 (std::numeric_limits<std::int8_t>::min)()
#define SBE_NULLVALUE_INT16 (std::numeric_limits<std::int16_t>::min)()
#define SBE_NULLVALUE_INT32 (std::numeric_limits<std::int32_t>::min)()
#define SBE_NULLVALUE_INT64 (std::numeric_limits<std::int64_t>::min)()
#define SBE_NULLVALUE_UINT8 (std::numeric_limits<std::uint8_t>::max)()
#define SBE_NULLVALUE_UINT16 (std::numeric_limits<std::uint16_t>::max)()
#define SBE_NULLVALUE_UINT32 (std::numeric_limits<std::uint32_t>::max)()
#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()
namespace iLinkBinary {
class ClearingAcctType
{
public:
enum Value
{
Customer = (std::uint8_t)0,
Firm = (std::uint8_t)1,
NULL_VALUE = (std::uint8_t)255
};
static ClearingAcctType::Value get(const std::uint8_t value)
{
switch (value)
{
case 0: return Customer;
case 1: return Firm;
case 255: return NULL_VALUE;
}
throw std::runtime_error("unknown value for enum ClearingAcctType [E103]");
}
static const char* c_str(const ClearingAcctType::Value value)
{
switch (value)
{
case Customer: return "Customer";
case Firm: return "Firm";
case NULL_VALUE: return "NULL_VALUE";
}
throw std::runtime_error("unknown value for enum ClearingAcctType [E103]:");
}
template<typename CharT, typename Traits>
friend std::basic_ostream<CharT, Traits>& operator << (
std::basic_ostream<CharT, Traits>& os, ClearingAcctType::Value m)
{
return os << ClearingAcctType::c_str(m);
}
};
}
#endif
@@ -0,0 +1,141 @@
/* Generated SBE (Simple Binary Encoding) message codec */
#ifndef _ILINKBINARY_CMTAGIVEUPCD_H_
#define _ILINKBINARY_CMTAGIVEUPCD_H_
#if defined(SBE_HAVE_CMATH)
/* cmath needed for std::numeric_limits<double>::quiet_NaN() */
# include <cmath>
# define SBE_FLOAT_NAN std::numeric_limits<float>::quiet_NaN()
# define SBE_DOUBLE_NAN std::numeric_limits<double>::quiet_NaN()
#else
/* math.h needed for NAN */
# include <math.h>
# define SBE_FLOAT_NAN NAN
# define SBE_DOUBLE_NAN NAN
#endif
#if __cplusplus >= 201103L
# define SBE_CONSTEXPR constexpr
# define SBE_NOEXCEPT noexcept
#else
# define SBE_CONSTEXPR
# define SBE_NOEXCEPT
#endif
#if __cplusplus >= 201402L
# define SBE_CONSTEXPR_14 constexpr
#else
# define SBE_CONSTEXPR_14
#endif
#if __cplusplus >= 201703L
# include <string_view>
# define SBE_NODISCARD [[nodiscard]]
#else
# define SBE_NODISCARD
#endif
#if !defined(__STDC_LIMIT_MACROS)
# define __STDC_LIMIT_MACROS 1
#endif
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <limits>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#if defined(WIN32) || defined(_WIN32)
# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) _byteswap_ulong(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) _byteswap_uint64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SBE_BIG_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_BIG_ENDIAN_ENCODE_16(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) (v)
#else
# error "Byte Ordering of platform not determined. Set __BYTE_ORDER__ manually before including this file."
#endif
#if defined(SBE_NO_BOUNDS_CHECK)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)
#elif defined(_MSC_VER)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)
#else
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))
#endif
#define SBE_NULLVALUE_INT8 (std::numeric_limits<std::int8_t>::min)()
#define SBE_NULLVALUE_INT16 (std::numeric_limits<std::int16_t>::min)()
#define SBE_NULLVALUE_INT32 (std::numeric_limits<std::int32_t>::min)()
#define SBE_NULLVALUE_INT64 (std::numeric_limits<std::int64_t>::min)()
#define SBE_NULLVALUE_UINT8 (std::numeric_limits<std::uint8_t>::max)()
#define SBE_NULLVALUE_UINT16 (std::numeric_limits<std::uint16_t>::max)()
#define SBE_NULLVALUE_UINT32 (std::numeric_limits<std::uint32_t>::max)()
#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()
namespace iLinkBinary {
class CmtaGiveUpCD
{
public:
enum Value
{
GiveUp = (char)71,
SGXoffset = (char)83,
NULL_VALUE = (char)0
};
static CmtaGiveUpCD::Value get(const char value)
{
switch (value)
{
case 71: return GiveUp;
case 83: return SGXoffset;
case 0: return NULL_VALUE;
}
throw std::runtime_error("unknown value for enum CmtaGiveUpCD [E103]");
}
static const char* c_str(const CmtaGiveUpCD::Value value)
{
switch (value)
{
case GiveUp: return "GiveUp";
case SGXoffset: return "SGXoffset";
case NULL_VALUE: return "NULL_VALUE";
}
throw std::runtime_error("unknown value for enum CmtaGiveUpCD [E103]:");
}
template<typename CharT, typename Traits>
friend std::basic_ostream<CharT, Traits>& operator << (
std::basic_ostream<CharT, Traits>& os, CmtaGiveUpCD::Value m)
{
return os << CmtaGiveUpCD::c_str(m);
}
};
}
#endif
@@ -0,0 +1,153 @@
/* Generated SBE (Simple Binary Encoding) message codec */
#ifndef _ILINKBINARY_CUSTORDHANDLINST_H_
#define _ILINKBINARY_CUSTORDHANDLINST_H_
#if defined(SBE_HAVE_CMATH)
/* cmath needed for std::numeric_limits<double>::quiet_NaN() */
# include <cmath>
# define SBE_FLOAT_NAN std::numeric_limits<float>::quiet_NaN()
# define SBE_DOUBLE_NAN std::numeric_limits<double>::quiet_NaN()
#else
/* math.h needed for NAN */
# include <math.h>
# define SBE_FLOAT_NAN NAN
# define SBE_DOUBLE_NAN NAN
#endif
#if __cplusplus >= 201103L
# define SBE_CONSTEXPR constexpr
# define SBE_NOEXCEPT noexcept
#else
# define SBE_CONSTEXPR
# define SBE_NOEXCEPT
#endif
#if __cplusplus >= 201402L
# define SBE_CONSTEXPR_14 constexpr
#else
# define SBE_CONSTEXPR_14
#endif
#if __cplusplus >= 201703L
# include <string_view>
# define SBE_NODISCARD [[nodiscard]]
#else
# define SBE_NODISCARD
#endif
#if !defined(__STDC_LIMIT_MACROS)
# define __STDC_LIMIT_MACROS 1
#endif
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <limits>
#include <ostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#if defined(WIN32) || defined(_WIN32)
# define SBE_BIG_ENDIAN_ENCODE_16(v) _byteswap_ushort(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) _byteswap_ulong(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) _byteswap_uint64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SBE_BIG_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) (v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) (v)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SBE_LITTLE_ENDIAN_ENCODE_16(v) __builtin_bswap16(v)
# define SBE_LITTLE_ENDIAN_ENCODE_32(v) __builtin_bswap32(v)
# define SBE_LITTLE_ENDIAN_ENCODE_64(v) __builtin_bswap64(v)
# define SBE_BIG_ENDIAN_ENCODE_16(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_32(v) (v)
# define SBE_BIG_ENDIAN_ENCODE_64(v) (v)
#else
# error "Byte Ordering of platform not determined. Set __BYTE_ORDER__ manually before including this file."
#endif
#if defined(SBE_NO_BOUNDS_CHECK)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)
#elif defined(_MSC_VER)
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)
#else
# define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))
#endif
#define SBE_NULLVALUE_INT8 (std::numeric_limits<std::int8_t>::min)()
#define SBE_NULLVALUE_INT16 (std::numeric_limits<std::int16_t>::min)()
#define SBE_NULLVALUE_INT32 (std::numeric_limits<std::int32_t>::min)()
#define SBE_NULLVALUE_INT64 (std::numeric_limits<std::int64_t>::min)()
#define SBE_NULLVALUE_UINT8 (std::numeric_limits<std::uint8_t>::max)()
#define SBE_NULLVALUE_UINT16 (std::numeric_limits<std::uint16_t>::max)()
#define SBE_NULLVALUE_UINT32 (std::numeric_limits<std::uint32_t>::max)()
#define SBE_NULLVALUE_UINT64 (std::numeric_limits<std::uint64_t>::max)()
namespace iLinkBinary {
class CustOrdHandlInst
{
public:
enum Value
{
FCMprovidedscreen = (char)67,
Otherprovidedscreen = (char)68,
FCMAPIorFIX = (char)71,
AlgoEngine = (char)72,
DeskElectronic = (char)87,
ClientElectronic = (char)89,
NULL_VALUE = (char)0
};
static CustOrdHandlInst::Value get(const char value)
{
switch (value)
{
case 67: return FCMprovidedscreen;
case 68: return Otherprovidedscreen;
case 71: return FCMAPIorFIX;
case 72: return AlgoEngine;
case 87: return DeskElectronic;
case 89: return ClientElectronic;
case 0: return NULL_VALUE;
}
throw std::runtime_error("unknown value for enum CustOrdHandlInst [E103]");
}
static const char* c_str(const CustOrdHandlInst::Value value)
{
switch (value)
{
case FCMprovidedscreen: return "FCMprovidedscreen";
case Otherprovidedscreen: return "Otherprovidedscreen";
case FCMAPIorFIX: return "FCMAPIorFIX";
case AlgoEngine: return "AlgoEngine";
case DeskElectronic: return "DeskElectronic";
case ClientElectronic: return "ClientElectronic";
case NULL_VALUE: return "NULL_VALUE";
}
throw std::runtime_error("unknown value for enum CustOrdHandlInst [E103]:");
}
template<typename CharT, typename Traits>
friend std::basic_ostream<CharT, Traits>& operator << (
std::basic_ostream<CharT, Traits>& os, CustOrdHandlInst::Value m)
{
return os << CustOrdHandlInst::c_str(m);
}
};
}
#endif
Loaded 100 of 267 files, more files were not shown because too many files have changed in this diff. Show more