Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b320a1075 | ||
|
|
e838413541 | ||
|
|
7d6d72b423 | ||
|
|
891d674ca4 | ||
|
|
92c1508b8c | ||
|
|
466915f6e9 | ||
|
|
1c68cfa08e | ||
|
|
cc75872c04 | ||
|
|
7e93866596 | ||
|
|
f4213eefe9 | ||
|
|
72bfafb376 | ||
|
|
5dbacfddd5 | ||
|
|
e29ea5d89b | ||
|
|
2885d929a8 | ||
|
|
a3e5bc4fba | ||
|
|
7944338516 | ||
|
|
bb19f737d5 | ||
|
|
77854a3cf0 | ||
|
|
d29ec26beb | ||
|
|
d64810e234 | ||
|
|
f3d2c9e5b9 | ||
|
|
63ac084a17 | ||
|
|
29f7c24a00 | ||
|
|
58c298fed8 | ||
|
|
ee825f76c7 | ||
|
|
dfb33efd45 | ||
|
|
dd7ebc54a2 | ||
|
|
8f99d8d9ca | ||
|
|
c411a0c792 | ||
|
|
bc8513778b | ||
|
|
501dc37e94 | ||
|
|
c58b5fb0e6 | ||
|
|
f89f2b8ad0 | ||
|
|
5e3e85641d | ||
|
|
4a5f71e7f2 | ||
|
|
92d7503528 | ||
|
|
773f3db976 | ||
|
|
dd5b489e8f | ||
|
|
7bda1cc1cc | ||
|
|
58e88812b1 | ||
|
|
db80631901 | ||
|
|
593944266d | ||
|
|
b8883fc8ae | ||
|
|
efac4a6077 | ||
|
|
cb22d21f70 | ||
|
|
f6b17d9541 | ||
|
|
7a1298e015 | ||
|
|
0a81521e6e | ||
|
|
8771281954 | ||
|
|
b50381d386 | ||
|
|
91345cf9d2 | ||
|
|
19b3ba6615 | ||
|
|
6b68029b6d | ||
|
|
15c8a8bf28 | ||
|
|
2b2fe02315 | ||
|
|
1f4c91a344 | ||
|
|
92f8f74d8f | ||
|
|
ad2869ea6f | ||
|
|
979506d5be | ||
|
|
bc6e792855 | ||
|
|
5df90f27c8 | ||
|
|
d571642454 | ||
|
|
0695ddc33e | ||
|
|
c97e7675fd | ||
|
|
526805680a | ||
|
|
03e3549895 | ||
|
|
ebbc48771b | ||
|
|
2d6fb5c15c |
No files matched your search
@@ -24,3 +24,4 @@ project.lock.json
|
||||
src/server/sparkd/orderman/perf_analysis/data
|
||||
src/server/sparkd/orderman/perf_analysis/logs/
|
||||
src/server/sparkd/orderman/perf_analysis/trace_data/
|
||||
src/lib/orderman/perf_analysis/logs/latency_data/
|
||||
@@ -54,6 +54,8 @@ else ()
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/web ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/data_files ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
|
||||
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
|
||||
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
|
||||
COMMENT "Creating server runtime layout"
|
||||
DEPENDS sparkd data_files_dir)
|
||||
|
||||
|
||||
+59
-55
@@ -4,7 +4,7 @@ VisualStudioVersion = 15.0.27130.2024
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
@@ -12,11 +12,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\spar
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{9AD1A867-93A9-301D-BF77-0113E18E9E39}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3} = {8530E0E8-3768-37EC-B1E1-8248C5A92FE3}
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C} = {69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
@@ -57,22 +57,22 @@ Global
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x64.Build.0 = Debug|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x64.ActiveCfg = Release|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x64.Build.0 = Release|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x86.ActiveCfg = Release|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x64.Build.0 = Debug|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x64.ActiveCfg = Release|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x64.Build.0 = Release|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x86.ActiveCfg = Release|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -93,26 +93,30 @@ Global
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -133,22 +137,22 @@ Global
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x64.Build.0 = Debug|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x64.ActiveCfg = Release|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x64.Build.0 = Release|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x86.ActiveCfg = Release|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.Build.0 = Debug|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.ActiveCfg = Release|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.Build.0 = Release|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x86.ActiveCfg = Release|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
|
||||
|
||||
@@ -5,11 +5,9 @@ using mbts.collections;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.settings;
|
||||
using mbts.ui.spark;
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
using bts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -18,7 +16,6 @@ using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class MarketViewVM {
|
||||
public class Row : SecurityMDRow, IDisposable, IEquatable<Row>, DIYGrid.IRowVM, DIYGrid.IActionableRowVM {
|
||||
@@ -78,16 +75,29 @@ namespace mbts.spark {
|
||||
ask_price_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.Ask));
|
||||
ask_size_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.AskSize));
|
||||
working_asks_click = new DelegateCommand(() => _show_order_book(MarketViewView.Columns.WorkingAsks));
|
||||
|
||||
_position.value_set += position_value_set;
|
||||
_inside_bids.value_set += inside_bids_value_set;
|
||||
_inside_asks.value_set += inside_asks_value_set;
|
||||
_day_change.Changed += day_change_Changed;
|
||||
_animation.AnimationsChanged += on_animations_changed;
|
||||
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
_orders_model.on_security_root_orders(security.Id).OnDispatcher().Subscribe(_on_orders),
|
||||
_position.OnDispatcher().Subscribe(v => _animation.animate_position(v.newval > v.oldval)),
|
||||
_inside_bids.OnDispatcher().Subscribe(v => _animation.animate_working_bids_inside(v.newval)),
|
||||
_inside_asks.OnDispatcher().Subscribe(v => _animation.animate_working_asks_inside(v.newval)),
|
||||
_day_change.OnDispatcher().Subscribe(v => _animation.animate_day_change(v.newval > v.oldval)),
|
||||
Disposable.Create(() => _animation.AnimationsChanged -= on_animations_changed)
|
||||
Disposable.Create(() => {
|
||||
_position.value_set -= position_value_set;
|
||||
_inside_bids.value_set -= inside_bids_value_set;
|
||||
_inside_asks.value_set -= inside_asks_value_set;
|
||||
_day_change.Changed -= day_change_Changed;
|
||||
_animation.AnimationsChanged -= on_animations_changed;
|
||||
})
|
||||
);
|
||||
|
||||
void position_value_set((int oldval, int newval) v) => _animation.animate_position(v.newval > v.oldval);
|
||||
void inside_bids_value_set((bool oldval, bool newval) v) => _animation.animate_working_bids_inside(v.newval);
|
||||
void inside_asks_value_set((bool oldval, bool newval) v) => _animation.animate_working_asks_inside(v.newval);
|
||||
void day_change_Changed(double oldval, double newval) => _animation.animate_day_change(newval > oldval);
|
||||
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
|
||||
}
|
||||
|
||||
public event Action invalidated;
|
||||
@@ -129,27 +139,52 @@ namespace mbts.spark {
|
||||
|
||||
public void raise_invalidated() => invalidated?.Invoke();
|
||||
|
||||
public void refresh() {
|
||||
/// <summary>
|
||||
/// Returns a list of IDisposable 'update jobs.' Each item represents a job that will be executed when disposed; all jobs should be executed on the dispatcher thread.
|
||||
/// </summary>
|
||||
// Note: not guarenteed to be on the dispatcher thread, so all view-notifying actions should be wrapped in a IDisposable.
|
||||
// Having said that, perform as much work as possible locally.
|
||||
public List<IDisposable> refresh() {
|
||||
var update_jobs = new List<IDisposable>();
|
||||
bool dirty = false;
|
||||
if (md.md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
|
||||
_bid_price.set(b.price);
|
||||
_bid_size.set(b.size);
|
||||
_ask_price.set(a.price);
|
||||
_ask_size.set(a.size);
|
||||
_inside_bids.on_next_distinct(_bid_price.Value >= _working_best_bid.value, ref dirty);
|
||||
_inside_asks.on_next_distinct(_ask_price.Value <= _working_best_ask.value, ref dirty);
|
||||
prop_job(_bid_price, b.price);
|
||||
prop_job(_bid_size, b.size);
|
||||
prop_job(_ask_price, a.price);
|
||||
prop_job(_ask_size, a.size);
|
||||
cell_prop_job(_inside_bids, b.price >= _working_best_bid.value);
|
||||
cell_prop_job(_inside_asks, a.price >= _working_best_ask.value);
|
||||
}
|
||||
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
|
||||
_last_price.set(ps.price);
|
||||
_last_size.on_next_distinct(ps.size, ref dirty);
|
||||
_volume.on_next_distinct(v, ref dirty);
|
||||
double new_last_price = last_price;
|
||||
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
|
||||
new_last_price = ps.price;
|
||||
prop_job(_last_price, new_last_price);
|
||||
cell_prop_job(_last_size, ps.size);
|
||||
cell_prop_job(_volume, v);
|
||||
}
|
||||
double new_settlement = md.md.settlement_price;
|
||||
prop_job(_settlement, new_settlement);
|
||||
prop_job(_session_low, md.md.session_low);
|
||||
prop_job(_session_high, md.md.session_high);
|
||||
prop_job(_day_change, new_last_price - new_settlement);
|
||||
|
||||
if (dirty) {
|
||||
update_jobs.Add(Disposable.Create(() => {
|
||||
invalidated?.Invoke();
|
||||
}));
|
||||
}
|
||||
return update_jobs;
|
||||
|
||||
void prop_job<T>(Property<T> p, T newval) {
|
||||
var uj = p.set_as_job(newval);
|
||||
if (uj != null)
|
||||
update_jobs.Add(uj);
|
||||
}
|
||||
void cell_prop_job<T>(CellProperty<T> p, T newval) {
|
||||
var uj = p.on_next_distinct_as_job(newval, ref dirty);
|
||||
if (uj != null)
|
||||
update_jobs.Add(uj);
|
||||
}
|
||||
_settlement.set(md.md.settlement_price);
|
||||
_session_low.set(md.md.session_low);
|
||||
_session_high.set(md.md.session_high);
|
||||
_day_change.set(last_price - settlement);
|
||||
if (dirty)
|
||||
invalidated?.Invoke();
|
||||
}
|
||||
|
||||
public bool Equals(Row other) =>
|
||||
|
||||
@@ -3,10 +3,13 @@ using mbts.spark.filters;
|
||||
using mbts.ui;
|
||||
using mbts.ui.utility;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using static bts.shell.MarketViewWindowFactory;
|
||||
@@ -14,7 +17,7 @@ using static mbts.ui.controls.DIYGrid;
|
||||
using static mbts.ui.spark.MarketViewView;
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD> {
|
||||
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD>, IPrepareUpdateForDispatcher {
|
||||
readonly IBus _bus;
|
||||
readonly OrdersModel _orders_model;
|
||||
|
||||
@@ -112,8 +115,7 @@ namespace mbts.spark {
|
||||
}), DataGridFilterHelper.hook_filters(rows_view,
|
||||
security_filter, bid_price_filter, bid_size_filter, ask_price_filter, ask_size_filter, last_price_filter, last_size_filter, day_change_filter, settlement_filter,
|
||||
session_low_filter, session_high_filter, position_filter, working_bid_volume_filter, working_ask_volume_filter, volume_filter, security_key_filter),
|
||||
securities_connectable.Connect(),
|
||||
WorkLoop.Start("MarketView", _refresh)
|
||||
securities_connectable.Connect()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -159,6 +161,25 @@ namespace mbts.spark {
|
||||
}
|
||||
#endregion
|
||||
|
||||
public IDisposable prepare_update() {
|
||||
ConcurrentBag<List<IDisposable>> to_update = new ConcurrentBag<List<IDisposable>>();
|
||||
try {
|
||||
Parallel.For(0, _row_vms.Count, i => {
|
||||
var r = _row_vms[i];
|
||||
var update_jobs = r.refresh();
|
||||
if (update_jobs.Count > 0)
|
||||
to_update.Add(update_jobs);
|
||||
});
|
||||
} catch (IndexOutOfRangeException) {
|
||||
// since rows (securities) will only be added/removed through rare user intervention,
|
||||
// it is worth catching the occassional exception in exchange for lock-free code.
|
||||
// if a row misses an update, or gets updated more than once, that's okay too;
|
||||
// in 100ms it will tick again, so the data should never be more than a few 100 ms old, and rarely older than 100.
|
||||
}
|
||||
// return null, rather than an empty IDisposable; this signals to the UpdateMaster that it may skip the call to Dispatcher.InvokeAsync() as there is nothing to dispose.
|
||||
return to_update.Count == 0 ? null : Disposable.Create(() => to_update.SelectMany(_ => _).DisposeAll());
|
||||
}
|
||||
|
||||
protected override Row row_factory(SecurityMD smd) => new Row(_bus, smd, _orders_model);
|
||||
protected override void on_row_removed(Row row) => row.Dispose();
|
||||
protected override IEnumerable<SortingCriteria> get_default_sorting() { yield return new SortingCriteria(nameof(Row.security), true); }
|
||||
@@ -167,4 +188,4 @@ namespace mbts.spark {
|
||||
foreach (var r in _row_vms) r.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,18 @@ using System.Windows;
|
||||
namespace mbts.spark {
|
||||
class MarketViewWindow : SparkWindow<MarketViewWindowFactory.StartupData>, ISharedWindow {
|
||||
const string _window_type = "MarketView", _thread_id = "MarketView", _window_type_display_name = "Market View";
|
||||
readonly DispatcherUpdateMaster _dispatcher_update_master;
|
||||
readonly OrdersModel _orders_model;
|
||||
readonly AllowOnce _init_guard = new AllowOnce("MarketView");
|
||||
MarketViewVM _vm;
|
||||
MarketViewView _view;
|
||||
MarketViewWindowFactory.StartupData _state;
|
||||
IReadOnlyList<SparkCommand> _commands;
|
||||
IDisposable _subscriptions;
|
||||
IDisposable _resources;
|
||||
|
||||
public MarketViewWindow(MarketViewWindowFactory factory, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
|
||||
public MarketViewWindow(MarketViewWindowFactory factory, DispatcherUpdateMaster dispatcher_update_master, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
|
||||
: base("Market View", bus, factory, SparkCommands.ShowMarketView.icon) {
|
||||
_dispatcher_update_master = dispatcher_update_master;
|
||||
_orders_model = orders_model;
|
||||
_state = state;
|
||||
Icon.Freeze();
|
||||
@@ -57,12 +59,14 @@ namespace mbts.spark {
|
||||
SparkCommands.ShowSyntheticCreate.complete(_vm.selected_securities_observable(), secs => secs.Count > 0 && secs.Count <= 24, secs => new SecurityCriteria(secs)),
|
||||
SparkCommands.change_securities_command(() => (update_securities_cmd, _state.security_criteria))
|
||||
};
|
||||
_subscriptions = _bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(c =>
|
||||
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states())));
|
||||
_resources = Disposable.Create(
|
||||
_bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(
|
||||
c => _state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states()))),
|
||||
_dispatcher_update_master.attach(_vm));
|
||||
}
|
||||
|
||||
public override void Dispose() {
|
||||
Disposable.dispose(ref _subscriptions);
|
||||
Disposable.dispose(ref _resources);
|
||||
_vm.Dispose();
|
||||
Commands.OfType<IDisposable>().DisposeAll();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace bts.shell {
|
||||
class MarketViewWindowFactory : ShellWindowFactory<MarketViewWindowFactory.StartupData> {
|
||||
readonly IBus _bus;
|
||||
readonly OrdersModel _orders_model;
|
||||
readonly DispatcherUpdateMaster _dispatcher_update_master = new DispatcherUpdateMaster("MarketView DispatcherUpdateMaster");
|
||||
|
||||
public MarketViewWindowFactory(MarketShellModule module, IBus bus, OrdersModel orders_model) : base(module, "MarketView") {
|
||||
_bus = bus;
|
||||
@@ -25,7 +26,7 @@ namespace bts.shell {
|
||||
void _show(SecurityCriteria criteria) =>
|
||||
_bus.post(SparkTags.ShowWindow, _create(new StartupData(criteria, new List<SortingCriteria> { new SortingCriteria(nameof(MarketViewVM.Row.security), true) }, null)));
|
||||
|
||||
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _bus, _orders_model, state);
|
||||
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _dispatcher_update_master, _bus, _orders_model, state);
|
||||
|
||||
[ProtoContract]
|
||||
public class StartupData {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.utils;
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
using System;
|
||||
@@ -11,6 +12,60 @@ using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace mbts.spark {
|
||||
struct OrderTemplateKey : IEquatable<OrderTemplateKey> {
|
||||
public readonly CustomOrderDefinition.CustomOneofCase type;
|
||||
public readonly string name;
|
||||
|
||||
public OrderTemplateKey(CustomOrderDefinition.CustomOneofCase type)
|
||||
: this(type, OrderUtils.order_type_display_name(type)) { }
|
||||
|
||||
public OrderTemplateKey(CustomOrderDefinition.CustomOneofCase type, string name) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public bool Equals(OrderTemplateKey other) =>
|
||||
type == other.type &&
|
||||
name == other.name;
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is OrderTemplateKey other && Equals(other);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
EqualityComparer.aggregate_hash(
|
||||
type.GetHashCode(),
|
||||
name == null ? 0 : name.GetHashCode());
|
||||
|
||||
public override string ToString() => $"{name}:{type}";
|
||||
|
||||
public static bool operator ==(OrderTemplateKey a, OrderTemplateKey b) => a.Equals(b);
|
||||
public static bool operator !=(OrderTemplateKey a, OrderTemplateKey b) => !a.Equals(b);
|
||||
}
|
||||
|
||||
struct OrderTemplateHeader : IEquatable<OrderTemplateHeader> {
|
||||
public readonly OrderTemplateKey key;
|
||||
// Note: display_name is NOT part of EQUALITY
|
||||
public readonly string display_name;
|
||||
|
||||
public OrderTemplateHeader(CustomOrderDefinition.CustomOneofCase type)
|
||||
: this(new OrderTemplateKey(type), OrderUtils.order_type_display_name(type)) { }
|
||||
|
||||
public OrderTemplateHeader(OrderTemplateKey key, string display_name) {
|
||||
this.key = key;
|
||||
this.display_name = display_name;
|
||||
}
|
||||
|
||||
public bool Equals(OrderTemplateHeader other) =>
|
||||
key.Equals(other.key);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is OrderTemplateHeader other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => key.GetHashCode();
|
||||
|
||||
public override string ToString() => $"{display_name} ({key})";
|
||||
}
|
||||
|
||||
class InlineOrderProperties {
|
||||
public readonly InlineUserProperty<AccountTuple> account;
|
||||
public readonly InlineUserProperty<TimeInForce> time_in_force;
|
||||
@@ -39,7 +94,7 @@ namespace mbts.spark {
|
||||
class OrderPropertiesEditorVM : DisposableViewModelBase {
|
||||
readonly OrdersModel _model;
|
||||
readonly Property<SecurityImmutable> _security;
|
||||
readonly SelectorProperty<AccountTuple> _accounts;
|
||||
readonly SelectorProperty<AccountTuple, AccountTuple?> _accounts;
|
||||
readonly SelectorProperty<TimeInForce> _time_in_force;
|
||||
readonly SelectorProperty<IOrderTypeVM> _order_type;
|
||||
IDisposable _order_type_param_errors_sub;
|
||||
@@ -58,14 +113,21 @@ namespace mbts.spark {
|
||||
nameof(selected_account),
|
||||
model.factory.subscribe_account_tuples(),
|
||||
order_properties.Select(ops => ops.account),
|
||||
() => accounts?.FirstOrDefault() ?? default,
|
||||
val => (!string.IsNullOrWhiteSpace(val.name) && accounts.Contains(val), "Please select an account"));
|
||||
a => new AccountTuple?(a),
|
||||
() => {
|
||||
foreach (var a in accounts) {
|
||||
return a;
|
||||
}
|
||||
return new AccountTuple?();
|
||||
},
|
||||
EqualityComparer<AccountTuple?>.Default,
|
||||
new[] { new PropertyValidation<AccountTuple?>(a => (a.HasValue && !string.IsNullOrWhiteSpace(a.Value.name) && accounts.Contains(a.Value), "Please select an account")) }.ToReadOnlyList());
|
||||
_order_type = backing(
|
||||
nameof(selected_order_type),
|
||||
security_source.Select(s => model.factory.default_order_type_defs(s).Select(create_order_type_vm)),
|
||||
security_source.Select(s => model.factory.default_order_type_templates(s).Select(kv => create_order_type_vm(kv.Value, kv.Key.key.name, kv.Key.display_name))),
|
||||
order_properties.Select(get_order_type_vm_prop),
|
||||
get_default_order_type_vm,
|
||||
(a, b) => a.order_type == b.order_type);
|
||||
EqualityComparer.null_check_wrapper(OrderTypeVMExtensions.key_comparer));
|
||||
_order_type.Changed += on_selected_order_type_changed;
|
||||
_time_in_force = backing(
|
||||
nameof(selected_time_in_force),
|
||||
@@ -77,19 +139,22 @@ namespace mbts.spark {
|
||||
tif => time_in_forces.Contains(tif));
|
||||
_dispose = Disposable.Create(() => _order_type.Changed -= on_selected_order_type_changed);
|
||||
// local methods
|
||||
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable cd) {
|
||||
IOrderTypeVM create_order_type_vm(CustomOrderDefinitionImmutable cd, string id, string display_name) {
|
||||
IOrderTypeVM vm = null;
|
||||
if(cd.CustomCase == CustomOrderDefinition.CustomOneofCase.Dynamic)
|
||||
vm = OrderTypeVMFactory.create(cd.CustomCase, model, security_md_source, cd.Dynamic.DynamicOrderType);
|
||||
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source, cd.Dynamic.DynamicOrderType);
|
||||
else
|
||||
vm = OrderTypeVMFactory.create(cd.CustomCase, model, security_md_source);
|
||||
vm = OrderTypeVMFactory.create(cd.CustomCase, id, display_name, model, security_md_source);
|
||||
vm.load_from(cd);
|
||||
return vm;
|
||||
}
|
||||
InlineUserProperty<IOrderTypeVM> get_order_type_vm_prop(InlineOrderProperties p) {
|
||||
if (!p.order_type_def.has_value)
|
||||
return new InlineUserProperty<IOrderTypeVM>();
|
||||
return new InlineUserProperty<IOrderTypeVM>(create_order_type_vm(p.order_type_def.value), p.order_type_def.force_override);
|
||||
return new InlineUserProperty<IOrderTypeVM>(
|
||||
create_order_type_vm(p.order_type_def.value, p.order_type_def.value.CustomCase.ToString(),
|
||||
OrderUtils.order_type_display_name(p.order_type_def.value.CustomCase)),
|
||||
p.order_type_def.force_override);
|
||||
}
|
||||
IOrderTypeVM get_default_order_type_vm() {
|
||||
var ot = model.factory.default_order_type(security);
|
||||
@@ -114,13 +179,13 @@ namespace mbts.spark {
|
||||
|
||||
public SecurityImmutable security => _security.Value;
|
||||
public ReadOnlyObservableCollection<AccountTuple> accounts => _accounts.items;
|
||||
public AccountTuple selected_account { get => _accounts.selected_item; set => _accounts.selected_item = value; }
|
||||
public AccountTuple? selected_account { get => _accounts.selected_item; set => _accounts.selected_item = value; }
|
||||
public ReadOnlyObservableCollection<TimeInForce> time_in_forces => _time_in_force.items;
|
||||
public TimeInForce selected_time_in_force { get => _time_in_force.selected_item; set => _time_in_force.selected_item = value; }
|
||||
public ReadOnlyObservableCollection<IOrderTypeVM> order_types => _order_type.items;
|
||||
public IOrderTypeVM selected_order_type { get => _order_type.selected_item; set => _order_type.selected_item = value; }
|
||||
|
||||
public IObservable<AccountTuple> observe_account(bool start_immediately = false) =>
|
||||
public IObservable<AccountTuple?> observe_account(bool start_immediately = false) =>
|
||||
_accounts.observe_current(start_immediately);
|
||||
|
||||
public IObservable<TimeInForce> observe_time_in_force(bool start_immediately = false) =>
|
||||
|
||||
@@ -17,22 +17,22 @@ namespace mbts.spark
|
||||
{
|
||||
class InlineCoverOrderProperties
|
||||
{
|
||||
public InlineCoverOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
|
||||
public InlineCoverOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
|
||||
{
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
|
||||
var hedgetype = CustomOneofCase.Limit;
|
||||
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
|
||||
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
|
||||
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
|
||||
hedge_ticks = new InlineUserProperty<int>(1, false);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_hedge_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> hedge_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_hedge_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> hedge_order_types;
|
||||
|
||||
public readonly InlineUserProperty<int> hedge_ticks;
|
||||
|
||||
@@ -42,25 +42,25 @@ namespace mbts.spark
|
||||
{
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineCoverOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _hedge_order_choices;
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
|
||||
IOrderTypeVM _hedge_order;
|
||||
IDisposable _hedge_order_errors_sub;
|
||||
|
||||
public int hedge_ticks { get; set; } = 1;
|
||||
|
||||
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineCoverOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
|
||||
new InlineCoverOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name)
|
||||
{ }
|
||||
|
||||
public CoverOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
|
||||
IObservable<InlineCoverOrderProperties> inline_properties) : base(model)
|
||||
IObservable<InlineCoverOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
|
||||
{
|
||||
_security_md_source = security_md_source;
|
||||
_dispose = Disposable.Create(
|
||||
@@ -75,11 +75,11 @@ namespace mbts.spark
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
|
||||
{
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
|
||||
{
|
||||
_select_hedge_order(p.selected_hedge_order_type.value);
|
||||
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
|
||||
}
|
||||
if (p.hedge_ticks.force_override)
|
||||
{
|
||||
@@ -116,7 +116,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_child_order_choices == null)
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _child_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_hedge_order_choices == null)
|
||||
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _hedge_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -200,7 +200,7 @@ namespace mbts.spark
|
||||
void _select_child_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ namespace mbts.spark
|
||||
void _select_hedge_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_hedge_order_type.has_value ?
|
||||
_inline_props.selected_hedge_order_type.value :
|
||||
_inline_props.selected_hedge_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_hedge_order(ot);
|
||||
}
|
||||
|
||||
@@ -20,23 +20,23 @@ namespace mbts.spark
|
||||
public static void add_dynamic_order_defs(List<CustomOrderDefinitionImmutable> defs,
|
||||
Func<CustomOrderDefinition.CustomOneofCase, CustomOrderDefinition> factory)
|
||||
{
|
||||
var dyntypes = _list.Value;
|
||||
foreach (var d in dyntypes.dynamic_orders)
|
||||
{
|
||||
var dorder = factory(CustomOrderDefinition.CustomOneofCase.Dynamic);
|
||||
dorder.Dynamic.DynamicOrderType = d.type_name;
|
||||
foreach (var p in d.parameter_keys)
|
||||
dorder.Dynamic.Parameters.Add(p, string.Empty);
|
||||
defs.Add(new CustomOrderDefinitionImmutable(dorder));
|
||||
}
|
||||
// var dyntypes = _list.Value;
|
||||
// foreach (var d in dyntypes.dynamic_orders)
|
||||
// {
|
||||
// var dorder = factory(CustomOrderDefinition.CustomOneofCase.Dynamic);
|
||||
// dorder.Dynamic.DynamicOrderType = d.type_name;
|
||||
// foreach (var p in d.parameter_keys)
|
||||
// dorder.Dynamic.Parameters.Add(p, string.Empty);
|
||||
// defs.Add(new CustomOrderDefinitionImmutable(dorder));
|
||||
// }
|
||||
}
|
||||
|
||||
internal static List<NameValueVM> get_parameters(string dyntype)
|
||||
{
|
||||
List<NameValueVM> par = new List<NameValueVM>();
|
||||
var order = _list.Value.dynamic_orders.FirstOrDefault(x => x.type_name == dyntype);
|
||||
if (order != null)
|
||||
par.AddRange(order.parameter_keys.Select(x => new NameValueVM() { name = x, value = string.Empty }));
|
||||
// var order = _list.Value.dynamic_orders.FirstOrDefault(x => x.type_name == dyntype);
|
||||
// if (order != null)
|
||||
// par.AddRange(order.parameter_keys.Select(x => new NameValueVM() { name = x, value = string.Empty }));
|
||||
return par;
|
||||
}
|
||||
}
|
||||
@@ -53,14 +53,14 @@ namespace mbts.spark
|
||||
{
|
||||
class InlineDynamicOrderProperties
|
||||
{
|
||||
public InlineDynamicOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
|
||||
public InlineDynamicOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
|
||||
{
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
}
|
||||
|
||||
class DynamicOrderVM : OrderTypeVMBase<DynamicOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
|
||||
@@ -68,8 +68,8 @@ namespace mbts.spark
|
||||
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineDynamicOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
@@ -77,13 +77,13 @@ namespace mbts.spark
|
||||
string _dyn_type;
|
||||
List<NameValueVM> _parameters;
|
||||
|
||||
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type)
|
||||
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type, string id, string display_name)
|
||||
: this(model, security_md_source, dyn_type, security_md_source.Select(smd =>
|
||||
new InlineDynamicOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
|
||||
new InlineDynamicOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name)
|
||||
{ }
|
||||
|
||||
public DynamicOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string dyn_type,
|
||||
IObservable<InlineDynamicOrderProperties> inline_properties) : base(model)
|
||||
IObservable<InlineDynamicOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
|
||||
{
|
||||
_security_md_source = security_md_source;
|
||||
_dyn_type = dyn_type;
|
||||
@@ -100,7 +100,7 @@ namespace mbts.spark
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
|
||||
{
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
_inline_props = p;
|
||||
_validate();
|
||||
@@ -115,17 +115,17 @@ namespace mbts.spark
|
||||
|
||||
public override void assign_to(CustomOrderDefinition value)
|
||||
{
|
||||
if (_child_order == null)
|
||||
_select_child_order(model.factory.default_order_type(_security.Value, true));
|
||||
_validate();
|
||||
if (!HasErrors)
|
||||
{
|
||||
var i = factory.dynamic_order();
|
||||
i.DynamicOrderType = _dyn_type;
|
||||
set_parameter_dictionary(i.Parameters);
|
||||
child_order.assign_to(i.Child);
|
||||
value.Dynamic = i;
|
||||
}
|
||||
// if (_child_order == null)
|
||||
// _select_child_order(model.factory.default_order_type(_security.Value, true));
|
||||
// _validate();
|
||||
// if (!HasErrors)
|
||||
// {
|
||||
// var i = factory.dynamic_order();
|
||||
// i.DynamicOrderType = _dyn_type;
|
||||
// set_parameter_dictionary(i.Parameters);
|
||||
// child_order.assign_to(i.Child);
|
||||
// value.Dynamic = i;
|
||||
// }
|
||||
}
|
||||
|
||||
void set_parameter_dictionary(Google.Protobuf.Collections.MapField<string, string> par)
|
||||
@@ -139,7 +139,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_child_order_choices == null)
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _child_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ namespace mbts.spark
|
||||
void _select_child_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
@@ -208,4 +208,4 @@ namespace mbts.spark
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
using bts.api.orderman;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Input;
|
||||
using static bts.api.orderman.CustomOrderDefinition;
|
||||
|
||||
namespace mbts.spark {
|
||||
interface IOrderTypeVM : IPropertyWrapperVM<CustomOrderDefinition, CustomOrderDefinitionImmutable> {
|
||||
string id { get; }
|
||||
CustomOneofCase order_type { get; }
|
||||
string type_name { get; }
|
||||
bool is_bts_type { get; }
|
||||
@@ -21,4 +23,12 @@ namespace mbts.spark {
|
||||
ICollection<IOrderTypeVM> child_order_types { get; }
|
||||
IOrderTypeVM child_order { get; }
|
||||
}
|
||||
|
||||
static class OrderTypeVMExtensions {
|
||||
public static IEqualityComparer<IOrderTypeVM> key_comparer =>
|
||||
EqualityComparer.Create<IOrderTypeVM, OrderTemplateKey>(a => a.key());
|
||||
|
||||
public static OrderTemplateKey key(this IOrderTypeVM vm) =>
|
||||
new OrderTemplateKey(vm.order_type, vm.id);
|
||||
}
|
||||
}
|
||||
@@ -14,34 +14,34 @@ using static bts.api.orderman.CustomOrderDefinition;
|
||||
namespace mbts.spark {
|
||||
static partial class OrderTypeVMFactory {
|
||||
class InlineIcebergOrderProperties {
|
||||
public InlineIcebergOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types) {
|
||||
public InlineIcebergOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
show_quantity = new InlineUserProperty<double>(1, true);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
public readonly InlineUserProperty<double> show_quantity;
|
||||
}
|
||||
|
||||
class IcebergOrderVM : OrderTypeVMBase<IcebergOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable {
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineIcebergOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
|
||||
public IcebergOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public IcebergOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineIcebergOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
|
||||
new InlineIcebergOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
|
||||
|
||||
public IcebergOrderVM(OrdersModel model,
|
||||
IObservable<SecurityMD> security_md_source,
|
||||
IObservable<InlineIcebergOrderProperties> inline_properties)
|
||||
: base(model) {
|
||||
IObservable<InlineIcebergOrderProperties> inline_properties, string id, string display_name)
|
||||
: base(model, id, display_name) {
|
||||
_security_md_source = security_md_source;
|
||||
_dispose = Disposable.Create(
|
||||
security_md_source.OnDispatcher()
|
||||
@@ -52,7 +52,7 @@ namespace mbts.spark {
|
||||
_order_types.SetItems(p.child_order_types.value);
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override)) {
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
if (p.show_quantity.force_override) {
|
||||
show_quantity = p.show_quantity.value;
|
||||
@@ -68,7 +68,7 @@ namespace mbts.spark {
|
||||
public ICollection<IOrderTypeVM> child_order_types {
|
||||
get {
|
||||
if (_child_order_choices == null) {
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
}
|
||||
return _child_order_choices;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ namespace mbts.spark {
|
||||
|
||||
void _select_child_order() {
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
|
||||
@@ -17,19 +17,19 @@ namespace mbts.spark
|
||||
{
|
||||
class InlineJoinOrderProperties
|
||||
{
|
||||
public InlineJoinOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
|
||||
public InlineJoinOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
|
||||
{
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
|
||||
var hedgetype = CustomOneofCase.Lean;
|
||||
if(!child_order_types.Contains(hedgetype))
|
||||
if(!child_order_types.Any(t => t.key.type == hedgetype))
|
||||
hedgetype = CustomOneofCase.Limit;
|
||||
|
||||
//ExceptionAssert.InvalidOperation.That(child_order_types.Contains(hedgetype), $"Hedge order type {hedgetype} is not in hedge_order_types");
|
||||
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
|
||||
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
|
||||
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
|
||||
tick_offset_on_deploy = new InlineUserProperty<uint>(0, false);
|
||||
join_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
|
||||
@@ -37,10 +37,10 @@ namespace mbts.spark
|
||||
enable_hedge = new InlineUserProperty<bool>(false, false);
|
||||
hedge_ticks = new InlineUserProperty<int>(1, false);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_hedge_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> hedge_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_hedge_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> hedge_order_types;
|
||||
|
||||
|
||||
public readonly InlineUserProperty<uint> tick_offset_on_deploy;
|
||||
@@ -55,13 +55,13 @@ namespace mbts.spark
|
||||
{
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineJoinOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _hedge_order_choices;
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
|
||||
IOrderTypeVM _hedge_order;
|
||||
IDisposable _hedge_order_errors_sub;
|
||||
|
||||
@@ -79,12 +79,12 @@ namespace mbts.spark
|
||||
}
|
||||
public int hedge_ticks { get; set; } = 1;
|
||||
|
||||
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineJoinOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
|
||||
new InlineJoinOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
|
||||
|
||||
public JoinOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
|
||||
IObservable<InlineJoinOrderProperties> inline_properties) : base(model)
|
||||
IObservable<InlineJoinOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
|
||||
{
|
||||
_security_md_source = security_md_source;
|
||||
_dispose = Disposable.Create(
|
||||
@@ -98,11 +98,11 @@ namespace mbts.spark
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
|
||||
{
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
|
||||
{
|
||||
_select_hedge_order(p.selected_hedge_order_type.value);
|
||||
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
|
||||
}
|
||||
if (p.tick_offset_on_deploy.force_override)
|
||||
{
|
||||
@@ -157,7 +157,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_child_order_choices == null)
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _child_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_hedge_order_choices == null)
|
||||
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _hedge_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ namespace mbts.spark
|
||||
void _select_child_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
@@ -257,7 +257,7 @@ namespace mbts.spark
|
||||
void _select_hedge_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_hedge_order_type.has_value ?
|
||||
_inline_props.selected_hedge_order_type.value :
|
||||
_inline_props.selected_hedge_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_hedge_order(ot);
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@ namespace mbts.spark
|
||||
{
|
||||
class InlineLeanOrderProperties
|
||||
{
|
||||
public InlineLeanOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
|
||||
public InlineLeanOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
|
||||
{
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
cross_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
|
||||
new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1}, false);
|
||||
max_chase_ticks = new InlineUserProperty<uint>(10, false);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
|
||||
public readonly InlineUserProperty<bts.spark.QuantityMeasure> cross_threshold;
|
||||
public readonly InlineUserProperty<uint> max_chase_ticks;
|
||||
@@ -37,8 +37,8 @@ namespace mbts.spark
|
||||
{
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineLeanOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
@@ -46,12 +46,12 @@ namespace mbts.spark
|
||||
public bts.spark.QuantityMeasure cross_threshold { get; set; } = new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1 };
|
||||
public uint max_chase_ticks { get; set; } = 10;
|
||||
|
||||
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineLeanOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
|
||||
new InlineLeanOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
|
||||
|
||||
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
|
||||
IObservable<InlineLeanOrderProperties> inline_properties) : base(model)
|
||||
IObservable<InlineLeanOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
|
||||
{
|
||||
_security_md_source = security_md_source;
|
||||
_dispose = Disposable.Create(
|
||||
@@ -65,7 +65,7 @@ namespace mbts.spark
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
|
||||
{
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
if (p.cross_threshold.force_override)
|
||||
{
|
||||
@@ -104,7 +104,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_child_order_choices == null)
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _child_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ namespace mbts.spark
|
||||
void _select_child_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace mbts.spark {
|
||||
static partial class OrderTypeVMFactory {
|
||||
private class LimitOrderVM : OrderTypeVMBase<LimitOrderDefinition> {
|
||||
internal LimitOrderVM(OrdersModel model) : base(model) { }
|
||||
internal LimitOrderVM(OrdersModel model) : base(model, "Limit", OrderUtils.order_type_display_name(CustomOrderDefinition.CustomOneofCase.Limit)) { }
|
||||
|
||||
public override void assign_to(CustomOrderDefinition value) =>
|
||||
value.Limit = factory.limit_order();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace mbts.spark {
|
||||
static partial class OrderTypeVMFactory {
|
||||
private class MarketOrderVM : OrderTypeVMBase<MarketOrderDefinition> {
|
||||
internal MarketOrderVM(OrdersModel model) : base(model) { }
|
||||
internal MarketOrderVM(OrdersModel model) : base(model, "Market", OrderUtils.order_type_display_name(CustomOrderDefinition.CustomOneofCase.Market)) { }
|
||||
|
||||
public override void assign_to(CustomOrderDefinition parent) =>
|
||||
parent.Market = factory.market_order();
|
||||
|
||||
@@ -12,36 +12,36 @@ namespace mbts.spark {
|
||||
static partial class OrderTypeVMFactory {
|
||||
public static IOrderTypeVM market(OrdersModel model) => new MarketOrderVM(model);
|
||||
public static IOrderTypeVM limit(OrdersModel model) => new LimitOrderVM(model);
|
||||
public static IOrderTypeVM stop(OrdersModel model) => new StopOrderVM(model);
|
||||
public static IOrderTypeVM stop_limit(OrdersModel model, IObservable<SecurityMD> security_md_source) => new StopLimitOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM time_box(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TimeBoxOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM tick(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TickOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM lean(OrdersModel model, IObservable<SecurityMD> security_md_source) => new LeanOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM join(OrdersModel model, IObservable<SecurityMD> security_md_source) => new JoinOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM top(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TopOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM cover(OrdersModel model, IObservable<SecurityMD> security_md_source) => new CoverOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM trigger(OrdersModel model, IObservable<SecurityMD> security_md_source) => new TriggerOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM iceberg(OrdersModel model, IObservable<SecurityMD> security_md_source) => new IcebergOrderVM(model, security_md_source);
|
||||
public static IOrderTypeVM spreader(OrdersModel model, IObservable<SecurityImmutable> security_source) => new SpreaderOrderVM(model, security_source);
|
||||
public static IOrderTypeVM dynamic(OrdersModel model, IObservable<SecurityMD> security_md_source, string type) => new DynamicOrderVM(model, security_md_source, type);
|
||||
public static IOrderTypeVM stop(OrdersModel model, string id, string display_name) => new StopOrderVM(model, id, display_name);
|
||||
public static IOrderTypeVM stop_limit(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new StopLimitOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM time_box(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TimeBoxOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM tick(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TickOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM lean(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new LeanOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM join(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new JoinOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM top(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TopOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM cover(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new CoverOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM trigger(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TriggerOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM iceberg(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new IcebergOrderVM(model, security_md_source, id, display_name);
|
||||
public static IOrderTypeVM spreader(OrdersModel model, IObservable<SecurityImmutable> security_source, string id, string display_name) => new SpreaderOrderVM(model, security_source, id, display_name);
|
||||
public static IOrderTypeVM dynamic(OrdersModel model, IObservable<SecurityMD> security_md_source, string dynamic_type, string id, string display_name) => new DynamicOrderVM(model, security_md_source, dynamic_type, id, display_name);
|
||||
|
||||
public static IOrderTypeVM create(CustomOneofCase order_type, OrdersModel model,
|
||||
public static IOrderTypeVM create(CustomOneofCase order_type, string id, string display_name, OrdersModel model,
|
||||
IObservable<SecurityMD> security_md_source, string dynamic_type = null ) {
|
||||
switch (order_type) {
|
||||
case CustomOneofCase.Market: return market(model);
|
||||
case CustomOneofCase.Limit: return limit(model);
|
||||
case CustomOneofCase.Stop: return stop(model);
|
||||
case CustomOneofCase.StopLimit: return stop_limit(model, security_md_source);
|
||||
case CustomOneofCase.TimeBox: return time_box(model, security_md_source);
|
||||
case CustomOneofCase.Tick: return tick(model, security_md_source);
|
||||
case CustomOneofCase.Lean: return lean(model, security_md_source);
|
||||
case CustomOneofCase.Join: return join(model, security_md_source);
|
||||
case CustomOneofCase.Top: return top(model, security_md_source);
|
||||
case CustomOneofCase.Cover: return cover(model, security_md_source);
|
||||
case CustomOneofCase.Trigger: return trigger(model, security_md_source);
|
||||
case CustomOneofCase.Iceberg: return iceberg(model, security_md_source);
|
||||
case CustomOneofCase.Spreader: return spreader(model, security_md_source.Select(smd => smd.security));
|
||||
case CustomOneofCase.Dynamic: return dynamic(model, security_md_source, dynamic_type);
|
||||
case CustomOneofCase.Stop: return stop(model, id, display_name);
|
||||
case CustomOneofCase.StopLimit: return stop_limit(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.TimeBox: return time_box(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Tick: return tick(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Lean: return lean(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Join: return join(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Top: return top(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Cover: return cover(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Trigger: return trigger(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Iceberg: return iceberg(model, security_md_source, id, display_name);
|
||||
case CustomOneofCase.Spreader: return spreader(model, security_md_source.Select(smd => smd.security), id, display_name);
|
||||
case CustomOneofCase.Dynamic: return dynamic(model, security_md_source, dynamic_type, id, display_name);
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -51,12 +51,17 @@ namespace mbts.spark {
|
||||
protected readonly OrdersModel model;
|
||||
protected OrderFactory factory => model.factory;
|
||||
|
||||
protected OrderTypeVMBase(OrdersModel model) => this.model = model;
|
||||
protected OrderTypeVMBase(OrdersModel model, string id, string display_name) {
|
||||
this.model = model;
|
||||
this.id = id;
|
||||
this.display_name = display_name;
|
||||
}
|
||||
|
||||
public abstract CustomOneofCase order_type { get; }
|
||||
public abstract string type_name { get; }
|
||||
public bool is_bts_type => display_name.StartsWith("BTS");
|
||||
public string display_name => OrderUtils.order_type_display_name(order_type);
|
||||
public string id { get; }
|
||||
public string display_name { get; }
|
||||
public OrderMetadata meta => factory.get_metadata(order_type);
|
||||
public virtual bool has_editable_properties => !meta.NoProps;
|
||||
public virtual bool editable_properties_open { get; set; }
|
||||
@@ -76,7 +81,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
private abstract class OrderTypeVMBase<T> : OrderTypeVMBase where T : Google.Protobuf.IMessage, new() {
|
||||
protected OrderTypeVMBase(OrdersModel model) : base(model) { }
|
||||
protected OrderTypeVMBase(OrdersModel model, string id, string display_name) : base(model, id, display_name) { }
|
||||
|
||||
public override CustomOneofCase order_type =>
|
||||
OrderDataHelper.get_order_type(new T());
|
||||
|
||||
@@ -13,20 +13,20 @@ namespace mbts.spark {
|
||||
readonly StrategyEditorWrapper _strategy_editor_wrapper;
|
||||
IDisposable _dispose;
|
||||
|
||||
public SpreaderOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source)
|
||||
public SpreaderOrderVM(OrdersModel model, IObservable<SecurityImmutable> security_source, string id, string display_name)
|
||||
: this(model, security_source, security_source.SelectMany(s => model.spreader.security_strategy(s.Id)
|
||||
.Select(strategy => {
|
||||
var so = model.factory.spreader_order();
|
||||
so.Security = s.CloneToMutable();
|
||||
so.ExecutionStrategy = strategy.CloneToMutable();
|
||||
return new InlineUserProperty<SpreaderOrderDefinitionImmutable>(so, true);
|
||||
}))) { }
|
||||
})), id, display_name) { }
|
||||
|
||||
public SpreaderOrderVM(
|
||||
OrdersModel model,
|
||||
IObservable<SecurityImmutable> security_source,
|
||||
IObservable<InlineUserProperty<SpreaderOrderDefinitionImmutable>> order_template_source)
|
||||
: base(model) {
|
||||
IObservable<InlineUserProperty<SpreaderOrderDefinitionImmutable>> order_template_source, string id, string display_name)
|
||||
: base(model, id, display_name) {
|
||||
_template = backing(nameof(template), new SpreaderOrderDefinitionImmutable?());
|
||||
_strategy_editor_wrapper = new StrategyEditorWrapper(this);
|
||||
_dispose = Disposable.Create(
|
||||
|
||||
@@ -29,10 +29,11 @@ namespace mbts.spark {
|
||||
InlineStopLimitOrderProperties _inline_props;
|
||||
IDisposable _dispose;
|
||||
|
||||
internal StopLimitOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
: this(model, security_md_source.Select(smd => smd.security.spec_or_default()), InlineStopLimitOrderProperties.subscribe(security_md_source)) { }
|
||||
internal StopLimitOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source.Select(smd => smd.security.spec_or_default()), InlineStopLimitOrderProperties.subscribe(security_md_source), id, display_name) { }
|
||||
|
||||
internal StopLimitOrderVM(OrdersModel model, IObservable<ContractSpecificationImmutable> spec_source, IObservable<InlineStopLimitOrderProperties> inline_properties) : base(model) {
|
||||
internal StopLimitOrderVM(OrdersModel model, IObservable<ContractSpecificationImmutable> spec_source, IObservable<InlineStopLimitOrderProperties> inline_properties, string id, string display_name)
|
||||
: base(model, id, display_name) {
|
||||
_stop_price = new UserProperty<double>(backing(nameof(stop_price), double.NaN));
|
||||
_dispose = Disposable.Create(
|
||||
spec_source.OnDispatcher().Subscribe(s => {
|
||||
|
||||
@@ -6,8 +6,7 @@ namespace mbts.spark {
|
||||
private class StopOrderVM : OrderTypeVMBase<StopOrderDefinition> {
|
||||
double _stop_price = 0;
|
||||
|
||||
internal StopOrderVM(OrdersModel model) : base(model) { }
|
||||
|
||||
internal StopOrderVM(OrdersModel model, string id, string display_name) : base(model, id, display_name) { }
|
||||
|
||||
public double stop_price {
|
||||
get => _stop_price;
|
||||
|
||||
@@ -17,11 +17,11 @@ namespace mbts.spark
|
||||
{
|
||||
class InlineTickOrderProperties
|
||||
{
|
||||
public InlineTickOrderProperties (CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
|
||||
public InlineTickOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
|
||||
{
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
tick_offset_on_deploy = new InlineUserProperty<uint>(0, false);
|
||||
cross_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
|
||||
new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1}, false);
|
||||
@@ -29,8 +29,8 @@ namespace mbts.spark
|
||||
max_chase_ticks = new InlineUserProperty<uint>(10, false);
|
||||
detach_on_toward = new InlineUserProperty<bool>(true, false);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
|
||||
public readonly InlineUserProperty<uint> tick_offset_on_deploy;
|
||||
public readonly InlineUserProperty<bts.spark.QuantityMeasure> cross_threshold;
|
||||
@@ -43,8 +43,8 @@ namespace mbts.spark
|
||||
{
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineTickOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
@@ -55,12 +55,12 @@ namespace mbts.spark
|
||||
public uint max_chase_ticks { get; set; } = 10;
|
||||
public bool detach_on_toward { get; set; } = true;
|
||||
|
||||
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineTickOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
|
||||
new InlineTickOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
|
||||
|
||||
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
|
||||
IObservable<InlineTickOrderProperties> inline_properties) : base(model)
|
||||
IObservable<InlineTickOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
|
||||
{
|
||||
_security_md_source = security_md_source;
|
||||
_dispose = Disposable.Create(
|
||||
@@ -74,7 +74,7 @@ namespace mbts.spark
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
|
||||
{
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
if (p.tick_offset_on_deploy.force_override)
|
||||
{
|
||||
@@ -131,7 +131,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_child_order_choices == null)
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _child_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ namespace mbts.spark
|
||||
void _select_child_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
|
||||
@@ -14,15 +14,15 @@ using static bts.api.orderman.CustomOrderDefinition;
|
||||
namespace mbts.spark {
|
||||
static partial class OrderTypeVMFactory {
|
||||
class InlineTimeBoxOrderProperties {
|
||||
public InlineTimeBoxOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types) {
|
||||
public InlineTimeBoxOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
start = new InlineUserProperty<DateTime>(DateTime.Now, true);
|
||||
stop = new InlineUserProperty<DateTime>(DateTime.Now.AddMinutes(5), true);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
public readonly InlineUserProperty<DateTime> start, stop;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace mbts.spark {
|
||||
const double _start_immediately_delay_ms = 500;
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineTimeBoxOrderProperties _inline_props;
|
||||
TimeTextTuple _absolute_start = TimeTextTuple.FromDateTime(DateTime.Now.AddMinutes(5)), _absolute_stop = TimeTextTuple.FromDateTime(DateTime.Now.AddMinutes(10));
|
||||
TimeSpan? _relative_start = TimeSpan.FromMinutes(5), _relative_stop = TimeSpan.FromMinutes(5);
|
||||
@@ -40,14 +40,14 @@ namespace mbts.spark {
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
|
||||
public TimeBoxOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public TimeBoxOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineTimeBoxOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
|
||||
new InlineTimeBoxOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
|
||||
|
||||
public TimeBoxOrderVM(OrdersModel model,
|
||||
IObservable<SecurityMD> security_md_source,
|
||||
IObservable<InlineTimeBoxOrderProperties> inline_properties)
|
||||
: base(model) {
|
||||
IObservable<InlineTimeBoxOrderProperties> inline_properties, string id, string display_name)
|
||||
: base(model, id, display_name) {
|
||||
_security_md_source = security_md_source;
|
||||
_dispose = Disposable.Create(
|
||||
security_md_source.OnDispatcher()
|
||||
@@ -58,7 +58,7 @@ namespace mbts.spark {
|
||||
_order_types.SetItems(p.child_order_types.value);
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override)) {
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
if (p.start.force_override) {
|
||||
absolute_start = TimeTextTuple.FromDateTime(p.start.value);
|
||||
@@ -94,7 +94,7 @@ namespace mbts.spark {
|
||||
public ICollection<IOrderTypeVM> child_order_types {
|
||||
get {
|
||||
if (_child_order_choices == null) {
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
}
|
||||
return _child_order_choices;
|
||||
}
|
||||
@@ -173,7 +173,7 @@ namespace mbts.spark {
|
||||
|
||||
void _select_child_order() {
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@ namespace mbts.spark
|
||||
{
|
||||
class InlineTopOrderProperties
|
||||
{
|
||||
public InlineTopOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types)
|
||||
public InlineTopOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
|
||||
{
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
|
||||
var hedgetype = CustomOneofCase.Lean;
|
||||
if(!child_order_types.Contains(hedgetype))
|
||||
if(!child_order_types.Any(ct => ct.key.type == hedgetype))
|
||||
hedgetype = CustomOneofCase.Limit;
|
||||
this.selected_hedge_order_type = new InlineUserProperty<CustomOneofCase>(hedgetype, true);
|
||||
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_hedge_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(hedgetype), true);
|
||||
this.hedge_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
|
||||
watch_level_tick_offset = new InlineUserProperty<uint>(0, false);
|
||||
top_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
|
||||
@@ -35,10 +35,10 @@ namespace mbts.spark
|
||||
enable_hedge = new InlineUserProperty<bool>(false, false);
|
||||
hedge_ticks = new InlineUserProperty<int>(1, false);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_hedge_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> hedge_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_hedge_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> hedge_order_types;
|
||||
|
||||
|
||||
public readonly InlineUserProperty<uint> watch_level_tick_offset;
|
||||
@@ -53,13 +53,13 @@ namespace mbts.spark
|
||||
{
|
||||
readonly IObservable<SecurityMD> _security_md_source;
|
||||
SecurityImmutable? _security;
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineTopOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _hedge_order_choices;
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _hedge_order_choices;
|
||||
IOrderTypeVM _hedge_order;
|
||||
IDisposable _hedge_order_errors_sub;
|
||||
|
||||
@@ -77,13 +77,13 @@ namespace mbts.spark
|
||||
}
|
||||
public int hedge_ticks { get; set; } = 1;
|
||||
|
||||
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineTopOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList())))
|
||||
new InlineTopOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name)
|
||||
{ }
|
||||
|
||||
public TopOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
|
||||
IObservable<InlineTopOrderProperties> inline_properties) : base(model)
|
||||
IObservable<InlineTopOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
|
||||
{
|
||||
_security_md_source = security_md_source;
|
||||
_dispose = Disposable.Create(
|
||||
@@ -98,11 +98,11 @@ namespace mbts.spark
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
|
||||
{
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
if (_hedge_order_choices != null && (_hedge_order == null || p.selected_hedge_order_type.force_override))
|
||||
{
|
||||
_select_hedge_order(p.selected_hedge_order_type.value);
|
||||
_select_hedge_order(p.selected_hedge_order_type.value.key.type);
|
||||
}
|
||||
if (p.watch_level_tick_offset.force_override)
|
||||
{
|
||||
@@ -157,7 +157,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_child_order_choices == null)
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _child_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ namespace mbts.spark
|
||||
get
|
||||
{
|
||||
if (_hedge_order_choices == null)
|
||||
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_hedge_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _hedge_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ namespace mbts.spark
|
||||
void _select_child_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
@@ -257,7 +257,7 @@ namespace mbts.spark
|
||||
void _select_hedge_order()
|
||||
{
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_hedge_order_type.has_value ?
|
||||
_inline_props.selected_hedge_order_type.value :
|
||||
_inline_props.selected_hedge_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_hedge_order(ot);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ using static bts.api.orderman.CustomOrderDefinition;
|
||||
namespace mbts.spark {
|
||||
static partial class OrderTypeVMFactory {
|
||||
class InlineTriggerOrderProperties {
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
|
||||
public readonly InlineUserProperty<TriggerPriceType> trigger_price_type;
|
||||
public readonly InlineUserProperty<TriggerPayupPrice.Types.TriggerPayupPriceType> payup_price_type;
|
||||
public readonly InlineUserProperty<double> fixed_price;
|
||||
@@ -23,10 +23,10 @@ namespace mbts.spark {
|
||||
public readonly InlineUserProperty<bool> use_fixed_price, is_priceout_checked, is_timeout_checked;
|
||||
public readonly InlineUserProperty<int> timeout_secs;
|
||||
|
||||
public InlineTriggerOrderProperties(CustomOneofCase selected_child_order_type, IReadOnlyCollection<CustomOneofCase> child_order_types) {
|
||||
public InlineTriggerOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types) {
|
||||
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
|
||||
this.selected_child_order_type = new InlineUserProperty<CustomOneofCase>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
|
||||
trigger_price_type = new InlineUserProperty<TriggerPriceType>(TriggerPriceType.Bid, false);
|
||||
payup_price_type = new InlineUserProperty<TriggerPayupPrice.Types.TriggerPayupPriceType>();
|
||||
use_fixed_price = new InlineUserProperty<bool>(false);
|
||||
@@ -47,19 +47,20 @@ namespace mbts.spark {
|
||||
readonly UserProperty<bool> _use_fixed_price, _is_timeout_checked, _is_priceout_checked;
|
||||
SecurityMD? _security_md;
|
||||
SecurityImmutable? _security => _security_md.security();
|
||||
ObservableCollection<CustomOneofCase> _order_types = new ObservableCollection<CustomOneofCase>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase> _child_order_choices;
|
||||
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
|
||||
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
|
||||
InlineTriggerOrderProperties _inline_props;
|
||||
IOrderTypeVM _child_order;
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
ulong _bbo_ref = 0, _last_trade_ref = 0;
|
||||
double _best_bid = double.NaN, _best_ask = double.NaN, _last_trade_price = double.NaN;
|
||||
|
||||
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
new InlineTriggerOrderProperties(model.factory.default_order_type(smd.security), model.factory.default_order_types(smd.security).ToList()))) { }
|
||||
new InlineTriggerOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
|
||||
|
||||
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineTriggerOrderProperties> inline_properties) : base(model) {
|
||||
public TriggerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineTriggerOrderProperties> inline_properties, string id, string display_name)
|
||||
: base(model, id, display_name) {
|
||||
_trigger_price_type = create_user_prop(nameof(trigger_price_type), TriggerPriceType.Bid);
|
||||
_use_fixed_price = create_user_prop(nameof(use_fixed_price), true);
|
||||
_fixed_price = create_user_prop(nameof(fixed_price), double.NaN);
|
||||
@@ -88,7 +89,7 @@ namespace mbts.spark {
|
||||
_order_types.SetItems(p.child_order_types.value);
|
||||
}
|
||||
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override)) {
|
||||
_select_child_order(p.selected_child_order_type.value);
|
||||
_select_child_order(p.selected_child_order_type.value.key.type);
|
||||
}
|
||||
// trigger price
|
||||
_trigger_price_type.on_inline_prop(p.trigger_price_type);
|
||||
@@ -135,7 +136,7 @@ namespace mbts.spark {
|
||||
public ICollection<IOrderTypeVM> child_order_types {
|
||||
get {
|
||||
if (_child_order_choices == null)
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, CustomOneofCase>(_order_types, ot => create(ot, model, _security_md_source));
|
||||
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
|
||||
return _child_order_choices;
|
||||
}
|
||||
}
|
||||
@@ -210,13 +211,13 @@ namespace mbts.spark {
|
||||
_security_md.Value.md.get_bbo(ref _bbo_ref, out co2.NativePriceSize bid, out co2.NativePriceSize ask);
|
||||
_best_bid = bid.price;
|
||||
_best_ask = ask.price;
|
||||
_security_md.Value.md.get_last_trade(ref _last_trade_ref, out co2.NativePriceSize ps, out DateTime ts, out ulong v);
|
||||
_security_md.Value.md.get_last_trade(ref _last_trade_ref, out co2.NativePriceSize ps, out ulong v);
|
||||
}
|
||||
}
|
||||
|
||||
void _select_child_order() {
|
||||
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
|
||||
_inline_props.selected_child_order_type.value :
|
||||
_inline_props.selected_child_order_type.value.key.type :
|
||||
model.factory.default_order_type(_security.Value, true);
|
||||
_select_child_order(ot);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using bts;
|
||||
using bts.utils;
|
||||
using mbts.collections;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace mbts.spark {
|
||||
interface IPrepareUpdateForDispatcher {
|
||||
IDisposable prepare_update();
|
||||
}
|
||||
|
||||
class DispatcherUpdateMaster : IDisposable {
|
||||
readonly string _name;
|
||||
readonly DispatcherPriority _invocation_priority;
|
||||
SetMap<Dispatcher, IPrepareUpdateForDispatcher> _vms;
|
||||
int _state = States.ReadyForUpdate;
|
||||
IDisposable _dispose;
|
||||
|
||||
public DispatcherUpdateMaster(string name)
|
||||
: this(name, WorkLoop.default_interval, WorkLoop.default_priority) { }
|
||||
|
||||
public DispatcherUpdateMaster(string name, TimeSpan period, DispatcherPriority invocation_priority) {
|
||||
_name = name;
|
||||
_vms = new SetMap<Dispatcher, IPrepareUpdateForDispatcher>(EqualityComparer.Create<Dispatcher, int>(d => d.Thread.ManagedThreadId));
|
||||
_dispose = ThreadPoolScheduler.Instance.SchedulePeriodic(period, _update_async);
|
||||
_invocation_priority = invocation_priority;
|
||||
}
|
||||
|
||||
public IDisposable attach(IPrepareUpdateForDispatcher vm, Dispatcher dispatcher) {
|
||||
var clone = _vms.clone();
|
||||
clone.add(dispatcher, vm);
|
||||
_vms = clone;
|
||||
return Disposable.Create(() => _detach(vm, dispatcher));
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Thread.VolatileWrite(ref _state, States.Disposed);
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
|
||||
void _detach(IPrepareUpdateForDispatcher preper, Dispatcher dispatcher) {
|
||||
var clone = _vms.clone();
|
||||
clone.remove(dispatcher, preper);
|
||||
_vms = clone;
|
||||
}
|
||||
|
||||
async void _update_async() {
|
||||
if (Interlocked.CompareExchange(ref _state, States.UpdateInProgress, States.ReadyForUpdate) != States.ReadyForUpdate) {
|
||||
return;
|
||||
}
|
||||
var temp = _vms;
|
||||
try {
|
||||
ConcurrentBag<(Dispatcher dispatcher, ConcurrentBag<IDisposable> update)> update_jobs =
|
||||
new ConcurrentBag<(Dispatcher dispatcher, ConcurrentBag<IDisposable> update_jobs)>();
|
||||
await Task.Run(() => {
|
||||
Parallel.ForEach(temp, dispatcher_group => {
|
||||
ConcurrentBag<IDisposable> update = new ConcurrentBag<IDisposable>();
|
||||
Parallel.ForEach(dispatcher_group, vm => {
|
||||
// need to check for null, that indicates an empty update (rather than an actual empty enumerable)
|
||||
var ujs = vm.prepare_update();
|
||||
if (ujs != null)
|
||||
update.Add(ujs);
|
||||
});
|
||||
if (update.Count > 0)
|
||||
update_jobs.Add((dispatcher_group.Key, update));
|
||||
});
|
||||
});
|
||||
await Task.WhenAll(update_jobs.Select(_update_dispatcher_group_async));
|
||||
} catch (Exception ex) {
|
||||
Log.Ui.error($"{_name} error during parallel update: {ex}");
|
||||
} finally {
|
||||
// signal that the update is complete, and we are ready for another
|
||||
Interlocked.CompareExchange(ref _state, States.ReadyForUpdate, States.UpdateInProgress);
|
||||
}
|
||||
}
|
||||
|
||||
async Task _update_dispatcher_group_async((Dispatcher dispatcher, ConcurrentBag<IDisposable> update_jobs) t) =>
|
||||
await t.dispatcher.InvokeAsync(() => t.update_jobs.DisposeAll(), _invocation_priority);
|
||||
|
||||
static class States {
|
||||
public const int
|
||||
ReadyForUpdate = 0,
|
||||
UpdateInProgress = 1,
|
||||
Disposed = 2;
|
||||
}
|
||||
}
|
||||
|
||||
static class DispatcherUpdateMasterExtensions {
|
||||
public static IDisposable attach(this DispatcherUpdateMaster dum, IPrepareUpdateForDispatcher preparer) =>
|
||||
dum.attach(preparer, Dispatcher.CurrentDispatcher);
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using bts;
|
||||
using bts.api;
|
||||
|
||||
namespace mbts.ui.utility
|
||||
{
|
||||
class ExpirationFormatter
|
||||
{
|
||||
private static class DateFormatter
|
||||
{
|
||||
private static string[] month_codes = new string[] { "F", "G", "H", "J", "K", "M", "N", "Q", "U", "V", "X", "Z" };
|
||||
private static string[] month_three_letters = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
|
||||
public static string format_condensed(DateTime date, bool use_month_code, bool show_year)
|
||||
{
|
||||
return String.Format("{0}{1}{2}", date.Day, month_codes[date.Month - 1], show_year ? (date.Year - 2000).ToString() : String.Empty);
|
||||
}
|
||||
|
||||
public static string format(DateTime date, bool use_month_code, bool show_day) {
|
||||
string month_text = use_month_code ? "{0}{1:00}".fmt(month_codes[date.Month - 1], date.Year - 2000) : "{0} {1:00}".fmt(month_three_letters[date.Month - 1], date.Year - 2000);
|
||||
return show_day ? "{0} {1}".fmt(date.Day, month_text) : month_text;
|
||||
}
|
||||
|
||||
public static string format_standard(DateTime date) { return "{0} {1} {2:00}".fmt(date.Day, month_three_letters[date.Month - 1], date.Year - 2000); }
|
||||
public static string format_coded(DateTime date) { return "{0} {1}{2:00}".fmt(date.Day, month_codes[date.Month - 1], date.Year - 2000); }
|
||||
public static string format_coded_hide_day(DateTime date) { return "{0}{1}".fmt(month_codes[date.Month - 1], date.Year - 2000); }
|
||||
|
||||
public static DateTime parse_standard(string date_text) {
|
||||
string[] split = date_text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
int year = 0;
|
||||
int month = Array.IndexOf(month_three_letters, split[1]) + 1;
|
||||
int day = 0;
|
||||
int.TryParse(split[2], out year);
|
||||
int.TryParse(split[0], out day);
|
||||
return new DateTime(year + 2000, month, day);
|
||||
}
|
||||
|
||||
public static DateTime parse_coded(string date_text) {
|
||||
string[] split = date_text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string year_text = split[1].Substring(1);
|
||||
string month_text = split[1].Substring(0, 1);
|
||||
string day_text = split[0];
|
||||
int month = Array.IndexOf(month_codes, month_text) + 1;
|
||||
int day, year;
|
||||
int.TryParse(year_text, out year);
|
||||
int.TryParse(day_text, out day);
|
||||
return new DateTime(year + 2000, month, day);
|
||||
}
|
||||
|
||||
public static DateTime parse_coded_hide_day(string date_text) {
|
||||
string year_text = date_text.Substring(1);
|
||||
string month_text = date_text.Substring(0, 1);
|
||||
int month = Array.IndexOf(month_codes, month_text) + 1;
|
||||
int year;
|
||||
int.TryParse(year_text, out year);
|
||||
return new DateTime(year + 2000, month, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static IDictionary<SecurityType, IDictionary<string, bts.config.ExpirationDisplayOffsetEntry>> _offset_map;
|
||||
|
||||
static ExpirationFormatter()
|
||||
{
|
||||
try
|
||||
{
|
||||
_offset_map = new Dictionary<SecurityType, IDictionary<string, bts.config.ExpirationDisplayOffsetEntry>>();
|
||||
_offset_map[SecurityType.Option] = new Dictionary<string, bts.config.ExpirationDisplayOffsetEntry>();
|
||||
_offset_map[SecurityType.Future] = new Dictionary<string, bts.config.ExpirationDisplayOffsetEntry>();
|
||||
|
||||
bts.config.ExpirationDisplayOffset offset_list = mbts.config.Configuration.get<bts.config.ExpirationDisplayOffset>();
|
||||
foreach (bts.config.ExpirationDisplayOffsetEntry e in offset_list.entries)
|
||||
{
|
||||
string security_name = e.security_name;
|
||||
string security_type_text = e.security_type;
|
||||
SecurityType security_type = SecurityType.Unset;
|
||||
Enum.TryParse<SecurityType>(security_type_text, true, out security_type);
|
||||
if (security_type == SecurityType.Option || security_type == SecurityType.Future)
|
||||
_offset_map[security_type][security_name] = e;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Ui.error(String.Format("Exception message = {0}", ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
private static bts.config.ExpirationDisplayOffsetEntry _get_offset_entry(SecurityType security_type, string security_name)
|
||||
{
|
||||
bts.config.ExpirationDisplayOffsetEntry rv = null;
|
||||
IDictionary<string, bts.config.ExpirationDisplayOffsetEntry> this_security_type_map = null;
|
||||
if (_offset_map.TryGetValue(security_type, out this_security_type_map))
|
||||
if (this_security_type_map.TryGetValue(security_name, out rv))
|
||||
return rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static DateTime convert_real_to_mapped(SecurityType security_type, string security_name, DateTime security_expiration)
|
||||
{
|
||||
bts.config.ExpirationDisplayOffsetEntry offset_entry = _get_offset_entry(security_type, security_name);
|
||||
DateTime rv = security_expiration;
|
||||
if (offset_entry != null)
|
||||
{
|
||||
if (offset_entry.addition_type == bts.config.ExpirationOffsetType.type.Month)
|
||||
rv = security_expiration.AddMonths(offset_entry.addition_count);
|
||||
else if (offset_entry.addition_type == bts.config.ExpirationOffsetType.type.MonthMoveToStart)
|
||||
{
|
||||
rv = security_expiration.AddMonths(offset_entry.addition_count);
|
||||
rv = new DateTime(rv.Year, rv.Month, 1);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static string format_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration) {
|
||||
return format_expiration_standard(security_type, security_name, security_expiration, map_expiration, false);
|
||||
}
|
||||
|
||||
public static string format_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool use_month_code) {
|
||||
return format_expiration_standard(security_type, security_name, security_expiration, map_expiration, use_month_code, true);
|
||||
}
|
||||
|
||||
public static string format_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool use_month_code, bool show_day) {
|
||||
DateTime mapped_expiration = map_expiration ? convert_real_to_mapped(security_type, security_name, security_expiration) : security_expiration;
|
||||
return DateFormatter.format(mapped_expiration, use_month_code, show_day);
|
||||
}
|
||||
|
||||
public static string format_symbol_expiration_standard (SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration) {
|
||||
return format_symbol_expiration_standard(security_type, security_name, security_expiration, map_expiration, false, false, true);
|
||||
}
|
||||
|
||||
public static string format_symbol_expiration_standard (SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool show_security_type) {
|
||||
return format_symbol_expiration_standard(security_type, security_name, security_expiration, map_expiration, show_security_type, false, true);
|
||||
}
|
||||
|
||||
public static string format_symbol_expiration_standard(SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool show_security_type, bool use_month_code) {
|
||||
return format_symbol_expiration_standard(security_type, security_name, security_expiration, map_expiration, show_security_type, use_month_code, true);
|
||||
}
|
||||
|
||||
public static string format_symbol_expiration_standard (SecurityType security_type, string security_name, DateTime security_expiration, bool map_expiration, bool show_security_type, bool use_month_code, bool show_day) {
|
||||
string exp_text = format_expiration_standard(security_type, security_name, security_expiration, map_expiration, use_month_code, show_day);
|
||||
return !show_security_type ? String.Format("{0} {1}", security_name, exp_text) : String.Format("{0} {1} {2}", security_type.ToString().ToUpper(), security_name, exp_text);
|
||||
}
|
||||
|
||||
public static string format_option_expiration_condensed(string option_name, DateTime option_expiration, bool map_expiration, bool show_symbol_name, bool show_year)
|
||||
{
|
||||
DateTime mapped_expiration = map_expiration ? convert_real_to_mapped(SecurityType.Option, option_name, option_expiration) : option_expiration;
|
||||
return String.Format("{0}{1}", show_symbol_name ? option_name : String.Empty, DateFormatter.format_condensed(mapped_expiration, true, show_year));
|
||||
}
|
||||
|
||||
public static DateTime parse_standard_formatted_expiration(SecurityType security_type, string security_name, string security_expiration) { return DateFormatter.parse_standard(security_expiration); }
|
||||
}
|
||||
}
|
||||
@@ -156,15 +156,13 @@ namespace mbts.ui.shell
|
||||
public string name => _propname;
|
||||
|
||||
public void set(T value) {
|
||||
if (!Equals(value, _value)) {
|
||||
Changing?.Invoke(_value, value);
|
||||
var old = _value;
|
||||
_value = value;
|
||||
Changed?.Invoke(old, value);
|
||||
_owner.RaisePropertyChanged(_propname);
|
||||
}
|
||||
if (!Equals(value, _value))
|
||||
_apply_new_value(value);
|
||||
}
|
||||
|
||||
public IDisposable set_as_job(T value) =>
|
||||
Equals(value, _value) ? null : Disposable.Create(() => _apply_new_value(value));
|
||||
|
||||
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
|
||||
Changed += pch;
|
||||
return Disposable.Create(() => Changed -= pch);
|
||||
@@ -182,6 +180,14 @@ namespace mbts.ui.shell
|
||||
get { return _value; }
|
||||
set { set(value); }
|
||||
}
|
||||
|
||||
void _apply_new_value(T new_value) {
|
||||
Changing?.Invoke(_value, new_value);
|
||||
var old = _value;
|
||||
_value = new_value;
|
||||
Changed?.Invoke(old, new_value);
|
||||
_owner.RaisePropertyChanged(_propname);
|
||||
}
|
||||
}
|
||||
|
||||
protected class DelegateProperty<T> : Property<T> {
|
||||
@@ -529,7 +535,7 @@ namespace mbts.ui.shell
|
||||
/// <para/>If the user has not selected an item, but the current items do not contain the desired item, it will re-evaluate whether or not to select the item when new items arrive.
|
||||
/// </summary>
|
||||
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IReadOnlyList<PropertyValidation<T>> validation_steps) =>
|
||||
backing(name, items, desired_item, select_default, null, validation_steps);
|
||||
backing(name, items, desired_item, select_default, EqualityComparer<T>.Default, validation_steps);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a SelectorProperty<T> that observes an items source, and a desired item. When either observable ticks, it determines whether or not to assign the selected_item property.
|
||||
@@ -541,8 +547,8 @@ namespace mbts.ui.shell
|
||||
/// <param name="desired_item">The observable sequence of a desired item.</param>
|
||||
/// <param name="select_default">The fallback function to select an item by default.</param>
|
||||
/// <param name="items_match">The item-matching function used to preserve a selected item when new items arrive.</param>
|
||||
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, Func<T, T, bool> items_match) =>
|
||||
backing(name, items, desired_item, select_default, items_match, new List<PropertyValidation<T>>(0));
|
||||
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IEqualityComparer<T> comparer) =>
|
||||
backing(name, items, desired_item, select_default, comparer, new List<PropertyValidation<T>>(0));
|
||||
|
||||
/// <summary>
|
||||
/// Returns a SelectorProperty<T> that observes an items source, and a desired item. When either observable ticks, it determines whether or not to assign the selected_item property.
|
||||
@@ -555,14 +561,24 @@ namespace mbts.ui.shell
|
||||
/// <param name="select_default">The fallback function to select an item by default.</param>
|
||||
/// <param name="items_match">The item-matching function used to preserve a selected item when new items arrive.</param>
|
||||
/// <param name="validation_steps">The validation steps to take when selected_item changes.</param>
|
||||
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, Func<T, T, bool> items_match, IReadOnlyList<PropertyValidation<T>> validation_steps) {
|
||||
if (_observable_properties == null) _observable_properties = new List<IDisposable>();
|
||||
var prop = new SelectorProperty<T>(this, name, select_default, items_match, validation_steps);
|
||||
_observable_properties.Add(items.OnDispatcher().Subscribe(prop));
|
||||
_observable_properties.Add(desired_item.OnDispatcher().Subscribe(prop));
|
||||
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IEqualityComparer<T> comparer, IReadOnlyList<PropertyValidation<T>> validation_steps) {
|
||||
var prop = new SelectorProperty<T>(this, name, select_default, comparer, validation_steps);
|
||||
attach(prop, items, desired_item);
|
||||
return prop;
|
||||
}
|
||||
|
||||
protected SelectorProperty<T, V> backing<T, V>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T, V> item_to_value, Func<V> select_default, IEqualityComparer<V> comparer, IReadOnlyList<PropertyValidation<V>> validation_steps) {
|
||||
var prop = new SelectorProperty<T, V>(this, name, item_to_value, select_default, comparer, validation_steps);
|
||||
attach(prop, items, desired_item);
|
||||
return prop;
|
||||
}
|
||||
|
||||
protected void attach<T, V>(SelectorProperty<T, V> selector_property, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item) {
|
||||
if (_observable_properties == null) _observable_properties = new List<IDisposable>();
|
||||
_observable_properties.Add(items.OnDispatcher().Subscribe(selector_property));
|
||||
_observable_properties.Add(desired_item.OnDispatcher().Subscribe(selector_property));
|
||||
}
|
||||
|
||||
protected void set_dispose(IDisposable disposable) {
|
||||
if (_dispose != null) throw new InvalidOperationException("Cannot set disposable twice");
|
||||
_dispose = disposable;
|
||||
@@ -579,37 +595,44 @@ namespace mbts.ui.shell
|
||||
OnDisposed?.Invoke(true);
|
||||
}
|
||||
|
||||
protected class SelectorProperty<T> : SelectorProperty<T, T> {
|
||||
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<T> select_default, IEqualityComparer<T> comparer, IReadOnlyList<PropertyValidation<T>> validation_steps)
|
||||
: base(owner, prop_name, i => i, select_default, comparer, validation_steps) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Designed to observe an items source, and a [settings-driven] desired item. When a new desired item is observed, it will evaluate it's current state and determine if it should be assigned to the selected_item.
|
||||
/// <para/>Notes: If the user has selected an item (ie the selected_item has been assigned through the public setter), the desired item will be ignored unless force_override is true.
|
||||
/// <para/>If the user has not selected an item, but the current items do not contain the desired item, it will re-evaluate whether or not to select the item when new items arrive.
|
||||
/// </summary>
|
||||
protected class SelectorProperty<T> : IObserver<InlineUserProperty<T>>, IObserver<IEnumerable<T>>, IObservable<(T oldval, T newval)> {
|
||||
protected class SelectorProperty<TItem, TValue> : IObserver<InlineUserProperty<TItem>>, IObserver<IEnumerable<TItem>>, IObservable<(TValue oldval, TValue newval)> {
|
||||
readonly DisposableViewModelBase _owner;
|
||||
readonly string _prop_name;
|
||||
readonly IReadOnlyList<PropertyValidation<T>> _validation_steps;
|
||||
readonly ObservableCollection<T> _items = new ObservableCollection<T>();
|
||||
readonly Func<T> _select_default;
|
||||
readonly Func<T, T, bool> _items_match; // used to maintain selected_item through an items-change
|
||||
T _selected_item;
|
||||
InlineUserProperty<T> _desired_item;
|
||||
readonly IReadOnlyList<PropertyValidation<TValue>> _validation_steps;
|
||||
readonly ObservableCollection<TItem> _items = new ObservableCollection<TItem>();
|
||||
readonly Func<TValue> _select_default;
|
||||
readonly IEqualityComparer<TValue> _value_comparer;
|
||||
readonly Func<TItem, TValue> _item_to_value;
|
||||
TValue _selected_item;
|
||||
InlineUserProperty<TItem> _desired_item = new InlineUserProperty<TItem>();
|
||||
bool _is_user_selected_item;
|
||||
|
||||
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<T> select_default, Func<T, T, bool> items_match, IReadOnlyList<PropertyValidation<T>> validation_steps) {
|
||||
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<TItem, TValue> item_to_value, Func<TValue> select_default, IEqualityComparer<TValue> value_comparer, IReadOnlyList<PropertyValidation<TValue>> validation_steps) {
|
||||
_owner = owner;
|
||||
_prop_name = prop_name;
|
||||
_item_to_value = item_to_value;
|
||||
_select_default = select_default;
|
||||
_items_match = items_match;
|
||||
_value_comparer = value_comparer ?? EqualityComparer<TValue>.Default;
|
||||
_validation_steps = validation_steps;
|
||||
items = new ReadOnlyObservableCollection<T>(_items);
|
||||
items = new ReadOnlyObservableCollection<TItem>(_items);
|
||||
}
|
||||
|
||||
public event PropertyChange<T> Changing;
|
||||
public event PropertyChange<T> Changed;
|
||||
public event PropertyChange<TValue> Changing;
|
||||
public event PropertyChange<TValue> Changed;
|
||||
|
||||
public ReadOnlyObservableCollection<T> items { get; }
|
||||
public ReadOnlyObservableCollection<TItem> items { get; }
|
||||
|
||||
public T selected_item {
|
||||
public TValue selected_item {
|
||||
get => _selected_item;
|
||||
set {
|
||||
_is_user_selected_item = true;
|
||||
@@ -617,31 +640,31 @@ namespace mbts.ui.shell
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
|
||||
public IDisposable Subscribe(IObserver<(TValue oldval, TValue newval)> observer) {
|
||||
Changed += pch;
|
||||
return Disposable.Create(() => Changed -= pch);
|
||||
void pch(T o, T n) => observer.OnNext((o, n));
|
||||
void pch(TValue o, TValue n) => observer.OnNext((o, n));
|
||||
}
|
||||
|
||||
public IObservable<T> observe_current(bool start_now = false) {
|
||||
public IObservable<TValue> observe_current(bool start_now = false) {
|
||||
var source = this.Select(vals => vals.newval);
|
||||
if (start_now)
|
||||
source = source.StartWith(_selected_item);
|
||||
source = source.StartWith(selected_item);
|
||||
return source;
|
||||
}
|
||||
|
||||
void IObserver<InlineUserProperty<T>>.OnNext(InlineUserProperty<T> iup) {
|
||||
void IObserver<InlineUserProperty<TItem>>.OnNext(InlineUserProperty<TItem> iup) {
|
||||
_desired_item = iup;
|
||||
_try_auto_select();
|
||||
}
|
||||
void IObserver<InlineUserProperty<T>>.OnError(Exception error) { }
|
||||
void IObserver<InlineUserProperty<T>>.OnCompleted() { }
|
||||
void IObserver<InlineUserProperty<TItem>>.OnError(Exception error) { }
|
||||
void IObserver<InlineUserProperty<TItem>>.OnCompleted() { }
|
||||
|
||||
void IObserver<IEnumerable<T>>.OnNext(IEnumerable<T> value) {
|
||||
if (_items_match != null && _is_user_selected_item) {
|
||||
void IObserver<IEnumerable<TItem>>.OnNext(IEnumerable<TItem> value) {
|
||||
if (_is_user_selected_item) {
|
||||
var curr_selected_item = selected_item;
|
||||
_items.sync_with(value);
|
||||
if (_try_match_item(curr_selected_item, out T match))
|
||||
if (_try_match_item(curr_selected_item, out TValue match))
|
||||
selected_item = match;
|
||||
else {
|
||||
_is_user_selected_item = false;
|
||||
@@ -649,18 +672,13 @@ namespace mbts.ui.shell
|
||||
}
|
||||
} else {
|
||||
_items.sync_with(value);
|
||||
if (_is_user_selected_item) {
|
||||
_is_user_selected_item = _items.Contains(_selected_item);
|
||||
}
|
||||
if (!_is_user_selected_item) {
|
||||
_try_auto_select();
|
||||
}
|
||||
_try_auto_select();
|
||||
}
|
||||
}
|
||||
void IObserver<IEnumerable<T>>.OnError(Exception error) { }
|
||||
void IObserver<IEnumerable<T>>.OnCompleted() { }
|
||||
void IObserver<IEnumerable<TItem>>.OnError(Exception error) { }
|
||||
void IObserver<IEnumerable<TItem>>.OnCompleted() { }
|
||||
|
||||
void _run_validation(T val) {
|
||||
void _run_validation(TValue val) {
|
||||
var invalid_steps = _validation_steps.Select(v => v.validate(val)).Where(r => !r.valid);
|
||||
if (invalid_steps.Count() > 0) {
|
||||
var error_msg = string.Join("\n", invalid_steps.Where(r => !string.IsNullOrEmpty(r.msg)).Select(r => r.msg));
|
||||
@@ -670,15 +688,15 @@ namespace mbts.ui.shell
|
||||
|
||||
void _try_auto_select() {
|
||||
if (_is_user_selected_item) {
|
||||
if (desired_item_valid() && _desired_item.force_override && _try_match_item(_desired_item.value, out T match)) {
|
||||
if (desired_item_valid() && _desired_item.force_override && _try_match_item(_desired_item.value, out TValue match)) {
|
||||
_set_selected_item(match);
|
||||
return;
|
||||
}
|
||||
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out T match)) {
|
||||
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out TValue match)) {
|
||||
_set_selected_item(match);
|
||||
return;
|
||||
}
|
||||
if (_try_match_item(_select_default(), out T default_match))
|
||||
if (_try_match_item(_select_default(), out TValue default_match))
|
||||
_set_selected_item(default_match);
|
||||
else {
|
||||
// the _set_selected_item has never been entered, so validation has never ran, force it here
|
||||
@@ -688,8 +706,8 @@ namespace mbts.ui.shell
|
||||
bool desired_item_valid() => (_desired_item?.has_value).GetValueOrDefault();
|
||||
}
|
||||
|
||||
void _set_selected_item(T value) {
|
||||
if (!Equals(value, _selected_item)) {
|
||||
void _set_selected_item(TValue value) {
|
||||
if (!_value_comparer.Equals(value, _selected_item)) {
|
||||
Changing?.Invoke(_selected_item, value);
|
||||
var old = _selected_item;
|
||||
_selected_item = value;
|
||||
@@ -699,10 +717,20 @@ namespace mbts.ui.shell
|
||||
}
|
||||
}
|
||||
|
||||
bool _try_match_item(T item, out T match) =>
|
||||
_items_match != null ?
|
||||
_items.TryGetFirst(i => _items_match(i, item), out match) :
|
||||
_items.TryGetFirst(i => i.Equals(item), out match);
|
||||
bool _try_match_item(TValue value, out TValue match) {
|
||||
foreach (TItem item in _items) {
|
||||
TValue v = _item_to_value(item);
|
||||
if (_value_comparer.Equals(v, value)) {
|
||||
match = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
match = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _try_match_item(TItem item, out TValue match) =>
|
||||
_try_match_item(_item_to_value(item), out match);
|
||||
}
|
||||
|
||||
public event Action<bool> OnDisposed;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace mbts.spark {
|
||||
value = initial_value;
|
||||
}
|
||||
|
||||
event Action<(T oldval, T newval)> _value_set;
|
||||
public event Action<(T oldval, T newval)> value_set;
|
||||
|
||||
public T value { get; private set; }
|
||||
public string text => _text ?? (_text = _format(value));
|
||||
@@ -27,14 +27,22 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable on_next_distinct_as_job(T value, ref bool dirty) {
|
||||
if (!value.Equals(this.value)) {
|
||||
dirty = true;
|
||||
return Disposable.Create(() => OnNext(value));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnCompleted() { }
|
||||
public void OnError(Exception error) { }
|
||||
public void OnNext(T value) {
|
||||
if (_value_set != null) {
|
||||
if (value_set != null) {
|
||||
T prev = this.value;
|
||||
this.value = value;
|
||||
_text = null;
|
||||
_value_set.Invoke((prev, value));
|
||||
value_set.Invoke((prev, value));
|
||||
} else {
|
||||
this.value = value;
|
||||
_text = null;
|
||||
@@ -42,7 +50,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) =>
|
||||
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => _value_set += cb, cb => _value_set -= cb)
|
||||
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => value_set += cb, cb => value_set -= cb)
|
||||
.Subscribe(observer);
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
</ComboBox.GroupStyle>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<usp:OrderTypeItem OrderType="{Binding order_type}" Metadata="{Binding meta}"/>
|
||||
<usp:OrderTypeItem OrderType="{Binding order_type}" DisplayName="{Binding display_name}" Metadata="{Binding meta}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
Width="15"
|
||||
Height="10"
|
||||
/>
|
||||
<TextBlock
|
||||
<TextBlock x:Name="text"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Margin="20,0,0,0"
|
||||
|
||||
@@ -3,23 +3,49 @@ using bts.spark;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace mbts.ui.spark
|
||||
{
|
||||
namespace mbts.ui.spark {
|
||||
/// <summary>
|
||||
/// Interaction logic for OrderTypeItem.xaml
|
||||
/// </summary>
|
||||
public partial class OrderTypeItem : Control
|
||||
{
|
||||
static OrderTypeItem() {
|
||||
partial class OrderTypeItem : Control {
|
||||
static OrderTypeItem() =>
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(OrderTypeItem), new FrameworkPropertyMetadata(typeof(OrderTypeItem)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrderTypeProperty = DependencyProperty.Register(nameof(OrderType), typeof(CustomOrderDefinition.CustomOneofCase), typeof(OrderTypeItem),
|
||||
new PropertyMetadata(CustomOrderDefinition.CustomOneofCase.None));
|
||||
public CustomOrderDefinition.CustomOneofCase OrderType { get => (CustomOrderDefinition.CustomOneofCase)GetValue(OrderTypeProperty); set => SetValue(OrderTypeProperty, value); }
|
||||
|
||||
public static readonly DependencyProperty DisplayNameProperty =
|
||||
WPFHelper.create_dp<string, OrderTypeItem>(nameof(DisplayName), (o, v) => {
|
||||
o._display_name = v;
|
||||
o._update_text();
|
||||
});
|
||||
|
||||
public string DisplayName {
|
||||
get => GetValue(DisplayNameProperty) as string;
|
||||
set => SetValue(DisplayNameProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MetadataProperty = DependencyProperty.Register(nameof(Metadata), typeof(OrderMetadata), typeof(OrderTypeItem),
|
||||
new PropertyMetadata(new OrderMetadata { Color = 0, KeyBinding = string.Empty }));
|
||||
public OrderMetadata Metadata { get => GetValue(MetadataProperty) as OrderMetadata; set => SetValue(MetadataProperty, value); }
|
||||
|
||||
string _display_name;
|
||||
TextBlock _text;
|
||||
|
||||
public override void OnApplyTemplate() {
|
||||
this.try_get_template_child("text", out _text);
|
||||
_update_text();
|
||||
}
|
||||
|
||||
void _update_text() {
|
||||
if (_text != null) {
|
||||
if (string.IsNullOrEmpty(_display_name)) {
|
||||
_text.ClearValue(TextBlock.TextProperty);
|
||||
} else {
|
||||
_text.SetCurrentValue(TextBlock.TextProperty, _display_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using bts.api;
|
||||
using mbts.ui.utility;
|
||||
using System;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace mbts.ui.converters
|
||||
{
|
||||
public class SecurityTypeStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
return SecurityDisplay.format_security_type((SecurityType)value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
using bts.api;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mbts.ui.converters
|
||||
{
|
||||
[ValueConversion(typeof(SecurityType), typeof(Brush))]
|
||||
public class SecurityTypeForegroundConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
if (value is SecurityType) return _convert((SecurityType)value);
|
||||
//else if (value is SecurityTuple) return _convert(((SecurityTuple)value).security_type);
|
||||
//else if (value is SecurityExpiration) return _convert(((SecurityExpiration)value).security_type);
|
||||
else return SystemColors.ControlTextBrush;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Brush _convert(SecurityType type) {
|
||||
switch (type) {
|
||||
case SecurityType.Option: return (Brush)BTSColors.header_text;
|
||||
case SecurityType.Future: return new SolidColorBrush(Colors.Gold);
|
||||
case SecurityType.Spread: return new SolidColorBrush(Colors.SlateBlue);
|
||||
default: return new SolidColorBrush(Colors.PaleGreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,6 @@
|
||||
<cv:CellPathConverter x:Key="CellPathConverter" />
|
||||
<cv:CellKeyConverter x:Key="CellKeyConverter" />
|
||||
<cv:SecurityDisplayTextConverter x:Key="SecurityTextConverter"/>
|
||||
<cv:SecurityTypeForegroundConverter x:Key="SecurityTypeForegroundConverter" />
|
||||
<cv:SecurityTypeStringConverter x:Key="SecurityTypeStringConverter" />
|
||||
<cv:NumericSignBrushConverter x:Key="NumericSignBrushConverter" />
|
||||
<cv:TickDisplayTextConverter x:Key="TickTextConverter" />
|
||||
<cv:DoubleTextConverter x:Key="DoubleTextConverter" />
|
||||
|
||||
@@ -386,7 +386,7 @@ namespace mbts.spark {
|
||||
void _tick() {
|
||||
if (_settings != null) {
|
||||
ulong unused = 0;
|
||||
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out DateTime _, out ulong __);
|
||||
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out ulong __);
|
||||
bool depth_changed = _vm.md.get_depth(ref _prices_updated, ref _bids, ref _asks);
|
||||
_mkt_break_lines.refresh();
|
||||
bool prices_changed =
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace mbts.spark {
|
||||
_dispose = Disposable.Create(
|
||||
settings_command,
|
||||
order_properties_vm,
|
||||
order_properties_vm.observe_account(true).Select(a => a.name).Subscribe(account_positions),
|
||||
order_properties_vm.observe_account(true).Select(a => a?.name ?? string.Empty).Subscribe(account_positions),
|
||||
account_positions,
|
||||
size_calculator = new CalculatorLogic(0, _settings_manager.subscribe_current().Select(s => s.calculator_buttons)),
|
||||
bus.subscribe(SparkTags.LogActivity).OnDispatcher().Subscribe(status_update),
|
||||
@@ -275,7 +275,7 @@ namespace mbts.spark {
|
||||
_open.set(md.open_price);
|
||||
_settlement.set(md.settlement_price);
|
||||
ulong unused = 0;
|
||||
md.get_last_trade(ref unused, out NativePriceSize last, out DateTime time, out ulong volume);
|
||||
md.get_last_trade(ref unused, out NativePriceSize last, out ulong volume);
|
||||
if (!double.IsNaN(last.price)) {
|
||||
_change.set(last.price - md.settlement_price);
|
||||
} else {
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace mbts.spark {
|
||||
if (!sec_md.md.get_bbo(ref bbo_time, out NativePriceSize bid, out NativePriceSize ask)) return false;
|
||||
// last is only used in waterfall and last calculations, so if neither of those types are selected
|
||||
// we should not exit early if last is somehow not avaialble
|
||||
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out DateTime unused1, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
|
||||
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
|
||||
|
||||
if (pnl_request.HasFlag(pnl_calc_type.waterfall)) {
|
||||
// last price is available and withing range of available bid and ask
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace mbts.spark.utilities
|
||||
internal interface ISecurityMDPump
|
||||
{
|
||||
IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo { get; }
|
||||
IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade { get; }
|
||||
IObservable<(double last, uint last_size, ulong volume)> last_trade { get; }
|
||||
IObservable<double> bid_price { get; }
|
||||
IObservable<uint> bid_size { get; }
|
||||
IObservable<double> ask_price { get; }
|
||||
@@ -61,7 +61,6 @@ namespace mbts.spark.utilities
|
||||
private double _bid_price, _ask_price, _last_price;
|
||||
private uint _bid_size, _ask_size, _last_size;
|
||||
private ulong _volume;
|
||||
private DateTime _last_time;
|
||||
|
||||
private bool _refresh_bbo(MDConsumerHandle md) {
|
||||
if (md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
|
||||
@@ -75,10 +74,9 @@ namespace mbts.spark.utilities
|
||||
}
|
||||
|
||||
private bool _refresh_last(MDConsumerHandle md) {
|
||||
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
|
||||
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
|
||||
_last_price = ps.price;
|
||||
_last_size = ps.size;
|
||||
_last_time = ts;
|
||||
_volume = v;
|
||||
return true;
|
||||
}
|
||||
@@ -86,17 +84,16 @@ namespace mbts.spark.utilities
|
||||
}
|
||||
|
||||
private (double, uint, double, uint) _select_bbo() { return (_bid_price, _bid_size, _ask_price, _ask_size); }
|
||||
private (double, uint, DateTime, ulong) _select_last() { return (_last_price, _last_size, _last_time, _volume); }
|
||||
private (double, uint, ulong) _select_last() { return (_last_price, _last_size, _volume); }
|
||||
|
||||
public IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo => _bbo_pump.Select(_ => _select_bbo()).StartWith(_select_bbo());
|
||||
public IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
|
||||
public IObservable<(double last, uint last_size, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
|
||||
public IObservable<double> bid_price => _bbo_pump.Select(_ => _bid_price).DistinctUntilChanged().StartWith(_bid_price);
|
||||
public IObservable<uint> bid_size => _bbo_pump.Select(_ => _bid_size).DistinctUntilChanged().StartWith(_bid_size);
|
||||
public IObservable<double> ask_price => _bbo_pump.Select(_ => _ask_price).DistinctUntilChanged().StartWith(_ask_price);
|
||||
public IObservable<uint> ask_size => _bbo_pump.Select(_ => _ask_size).DistinctUntilChanged().StartWith(_ask_size);
|
||||
public IObservable<double> last_price => _bbo_pump.Select(_ => _last_price).DistinctUntilChanged().StartWith(_last_price);
|
||||
public IObservable<uint> last_size => _bbo_pump.Select(_ => _last_size).DistinctUntilChanged().StartWith(_last_size);
|
||||
public IObservable<DateTime> last_time => _last_pump.Select(_ => _last_time).DistinctUntilChanged().StartWith(_last_time);
|
||||
public IObservable<ulong> volume => _last_pump.Select(_ => _volume).DistinctUntilChanged().StartWith(_volume);
|
||||
public IObservable<double> session_low => _root_pump.Select(md => md.session_low).DistinctUntilChanged();
|
||||
public IObservable<double> session_high => _root_pump.Select(md => md.session_high).DistinctUntilChanged();
|
||||
|
||||
@@ -110,6 +110,29 @@ namespace mbts.spark.utilities {
|
||||
return defs;
|
||||
}
|
||||
|
||||
public Dictionary<OrderTemplateHeader, CustomOrderDefinitionImmutable> default_order_type_templates(SecurityImmutable security, bool is_child = false) {
|
||||
const int name_ref_seed = 1;
|
||||
// standard types
|
||||
var defs = default_order_types(security, is_child)
|
||||
.Except(new[] { CustomOrderDefinition.CustomOneofCase.Dynamic })
|
||||
.ToDictionary(ot => new OrderTemplateHeader(new OrderTemplateKey(ot), OrderUtils.order_type_display_name(ot)), ot => new CustomOrderDefinitionImmutable(custom_order(ot)));
|
||||
// TODO: replace with better naming scheme (right now, the order type ref count 'n' is appended to the order-type name)
|
||||
var order_type_ref_count = defs.ToDictionary(kv => kv.Key, kv => name_ref_seed);
|
||||
var dynamic_defs = new List<CustomOrderDefinitionImmutable>();
|
||||
DynamicOrderHelper.add_dynamic_order_defs(dynamic_defs, ot => custom_order(ot));
|
||||
foreach (var ddef in dynamic_defs) {
|
||||
var header = new OrderTemplateHeader(new OrderTemplateKey(ddef.CustomCase, ddef.Dynamic.DynamicOrderType), ddef.Dynamic.DynamicOrderType );
|
||||
// if (order_type_ref_count.TryGetValue(header, out int count)) {
|
||||
// order_type_ref_count[header]++;
|
||||
// header = new OrderTemplateHeader(new OrderTemplateKey(header.key.type, $"{header.key.name}{count}"), $"{header.display_name}{count}");
|
||||
// } else {
|
||||
// order_type_ref_count[header] = name_ref_seed;
|
||||
// }
|
||||
defs.Add(header, ddef);
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
|
||||
public IEnumerable<CustomOrderDefinition.CustomOneofCase> default_order_types(SecurityImmutable? security, bool is_child=false) =>
|
||||
security.HasValue ? default_order_types(security.Value, is_child) : default_order_types();
|
||||
|
||||
@@ -212,7 +235,7 @@ namespace mbts.spark.utilities {
|
||||
|
||||
public DynamicOrderDefinition dynamic_order() => new DynamicOrderDefinition
|
||||
{
|
||||
Child = custom_order(),
|
||||
//Child = custom_order(),
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ using System.Windows.Threading;
|
||||
namespace mbts.spark {
|
||||
static class WorkLoop {
|
||||
public const double default_excessive_cycle_ratio = 1.2;
|
||||
static readonly DispatcherPriority default_priority;
|
||||
static readonly TimeSpan default_interval;
|
||||
public static readonly TimeSpan default_interval;
|
||||
public static readonly DispatcherPriority default_priority;
|
||||
|
||||
static WorkLoop() {
|
||||
var timer_params = config.Configuration.get<bts.config.LadderKnobs>();
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
using bts.api;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace mbts.ui.utility
|
||||
{
|
||||
public enum DateFormat { Standard, DayMonthAbvDiff2000, DayMonthCodeDiff2000 }
|
||||
static class SecurityDisplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a shorthand string representation of a security type appropriate for UIs.
|
||||
/// </summary>
|
||||
public static string format_security_type(SecurityType type) {
|
||||
switch (type) {
|
||||
case SecurityType.Option: return "Opt";
|
||||
case SecurityType.Future: return "Fut";
|
||||
case SecurityType.Stock: return "Stk";
|
||||
case SecurityType.Spread: return "Spd";
|
||||
default: return type.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a concise string representation of a security expiration appropriate for UIs (e.g. es March 22, 2019: es 22 Mar 19).
|
||||
/// </summary>
|
||||
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date) { return format_expiration(sec_type, symbol, exp_date, false, true, true, DateFormat.DayMonthAbvDiff2000); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a concise string representation of a security expiration (using symbol-mapped expiration dates, and single-letter month codes) appropriate for UIs (e.g. es March 22, 2019: [Opt] [es] 22 Mar 19).
|
||||
/// </summary>
|
||||
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date, bool show_type, bool show_symbol, bool use_mapped_exp) { return format_expiration(sec_type, symbol, exp_date, show_type, show_symbol, use_mapped_exp, DateFormat.Standard); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a concise string representation of a security expiration (using symbol-mapped expiration dates, and single-letter month codes) appropriate for UIs (e.g. es March 22, 2019: [Opt] [es] 22 Mar 19, or [Opt] [es] 22 H19).
|
||||
/// </summary>
|
||||
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date, bool show_type, bool show_symbol, bool use_mapped_exp, DateFormat date_format) {
|
||||
if (use_mapped_exp) exp_date = ExpirationFormatter.convert_real_to_mapped(sec_type, symbol, exp_date);
|
||||
string result = format_date(exp_date);
|
||||
if (show_symbol) result = (symbol + " " + result);
|
||||
if (show_type) result = (format_security_type(sec_type) + " " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a concise string representation of a future trade appropriate for UIs.
|
||||
/// </summary>
|
||||
public static string format_future_trade(string symbol, DateTime exp_date, int size, double marginal_price) { return "{0} {1} lots @ {2:C}".fmt(format_expiration(SecurityType.Future, symbol, exp_date, false, true, true), size, marginal_price); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a concise string representation of an option trade appropriate for UIs.
|
||||
/// </summary>
|
||||
public static string format_option_trade(string symbol, DateTime exp_date, double strike, bool is_call, int size, double marginal_price) {
|
||||
return "{0} {1} {2} {3} lots @ {4:C}".fmt(format_expiration(SecurityType.Option, symbol, exp_date, false, true, true), strike, is_call ? "C" : "P", size, marginal_price);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a concise string representation of a date (using standard month abbreviations) appropriate for UIs (e.g. March 22, 2019: 22 Mar 19).
|
||||
/// </summary>
|
||||
public static string format_date(DateTime date) { return format_date(date.Year, date.Month, date.Day, DateFormat.DayMonthAbvDiff2000); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a concise string representation of a date (using single-letter month codes) appropriate for UIs (e.g. March 22, 2019: 22 Mar 19, or 22 H19).
|
||||
/// </summary>
|
||||
public static string format_date(int year, int month, int day, DateFormat format) {
|
||||
switch(format) {
|
||||
case DateFormat.DayMonthAbvDiff2000: return "{0} {1} {2}".fmt(day, get_month_abv(month), year - 2000);
|
||||
case DateFormat.DayMonthCodeDiff2000: return "{0} {1}{2}".fmt(day, get_month_code(month), year - 2000);
|
||||
case DateFormat.Standard: goto default;
|
||||
default: return "{0}/{1}/{2}".fmt(day, month, year);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the option industry standard month code.
|
||||
/// </summary>
|
||||
public static string get_month_code(int month) { _check_month(month); return _month_codes[month - 1]; }
|
||||
/// <summary>
|
||||
/// Returns the standard month abbreviation (Jan, Feb, Mar, etc.).
|
||||
/// </summary>
|
||||
public static string get_month_abv(int month) { _check_month(month); return _month_abvs[month - 1]; }
|
||||
#region Private Members
|
||||
private static void _check_month(int month) { if (month < 1 || month > 12) throw new ArgumentException("There are only twelve months in a year", "month"); }
|
||||
private static string[] _month_codes = new string[] { "F", "G", "H", "J", "K", "M", "N", "Q", "U", "V", "X", "Z" };
|
||||
private static string[] _month_abvs = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,8 @@ namespace bts {
|
||||
Mercury,
|
||||
Testing,
|
||||
Latency,
|
||||
DataFlow
|
||||
DataFlow,
|
||||
Plugin
|
||||
// Please keep this list in sync with logging.h/logging.cpp
|
||||
}
|
||||
readonly struct Logger {
|
||||
|
||||
@@ -72,7 +72,12 @@ namespace mbts.co2
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out DateTime timestamp, out ulong total_volume) {
|
||||
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out ulong total_volume) {
|
||||
total_volume = _cold->total_volume;
|
||||
return (_cold->last_trade.load_if_new(ref time, out ps));
|
||||
}
|
||||
|
||||
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out utils.LLDateTime timestamp, out ulong total_volume) {
|
||||
timestamp = _cold->last_trade_time;
|
||||
total_volume = _cold->total_volume;
|
||||
return (_cold->last_trade.load_if_new(ref time, out ps));
|
||||
@@ -88,15 +93,15 @@ namespace mbts.co2
|
||||
public ulong total_volume { get { return _cold->total_volume; } }
|
||||
|
||||
public double settlement_price { get { return _cold->settlement_price;} }
|
||||
public DateTime settlement_date { get { return _cold->settlement_date;} }
|
||||
public utils.LLDate settlement_date { get { return _cold->settlement_date;} }
|
||||
public double previous_settlement_price { get { return _cold->previous_settlement_price;} }
|
||||
public DateTime previous_settlement_date { get { return _cold->previous_settlement_date;} }
|
||||
public utils.LLDate previous_settlement_date { get { return _cold->previous_settlement_date;} }
|
||||
|
||||
public double open_price { get { return _cold->open_price;} }
|
||||
public DateTime open_date { get { return _cold->open_date; } }
|
||||
public utils.LLDate open_date { get { return _cold->open_date; } }
|
||||
|
||||
public double close_price { get { return _cold->close_price;} }
|
||||
public DateTime close_date { get { return _cold->close_date; } }
|
||||
public utils.LLDate close_date { get { return _cold->close_date; } }
|
||||
public double session_high { get { return _cold->session_high;} }
|
||||
public double session_low { get { return _cold->session_low; } }
|
||||
public double open_interest { get { return _cold->open_interest; } }
|
||||
|
||||
@@ -27,6 +27,9 @@ namespace bts.utils {
|
||||
public static IEqualityComparer<T?> CreateNullable<T>(Func<T, T, bool> equals) where T : struct =>
|
||||
new AnonymousEqualityComparer<T?>(nullable_equals);
|
||||
|
||||
public static IEqualityComparer<T> null_check_wrapper<T>(IEqualityComparer<T> comparer) where T : class =>
|
||||
new AnonymousEqualityComparer<T>((a, b) => NullCheckEquals(a, b, comparer.Equals), comparer.GetHashCode);
|
||||
|
||||
public static bool safe_sequence_equals<T>(IEnumerable<T> source, IEnumerable<T> other) =>
|
||||
NullCheckEquals(source, other, (a, b) => a.SequenceEqual(b));
|
||||
|
||||
|
||||
@@ -210,19 +210,24 @@ namespace mbts.co2.tests
|
||||
Assert.IsTrue(ask.size == 202);
|
||||
|
||||
time = 0;
|
||||
DateTime trade_date;
|
||||
ulong total_volume;
|
||||
NativePriceSize last_trade;
|
||||
Assert.IsTrue(handle.get_last_trade(ref time, out last_trade, out trade_date, out total_volume));
|
||||
Assert.IsTrue(handle.get_last_trade(ref time, out NativePriceSize last_trade, out utils.LLDateTime ll_trade_date, out ulong total_volume));
|
||||
// trade date
|
||||
DateTime trade_date = ll_trade_date;
|
||||
Assert.IsTrue(last_trade.price == 5.5 && last_trade.size == 505);
|
||||
Assert.IsTrue(trade_date.Year == 2015 && trade_date.Month == 9 && trade_date.Day == 22);
|
||||
Assert.IsTrue(total_volume == 4200);
|
||||
Assert.IsTrue(handle.settlement_date.Year == 2000 && handle.settlement_date.Day == 9 && handle.settlement_date.Month == 8);
|
||||
// settlement date
|
||||
DateTime settlement_dt = handle.settlement_date;
|
||||
Assert.IsTrue(settlement_dt.Year == 2000 && settlement_dt.Day == 9 && settlement_dt.Month == 8);
|
||||
Assert.IsTrue(handle.settlement_price == 6.6);
|
||||
Assert.IsTrue(handle.open_price == 7.7);
|
||||
Assert.IsTrue(handle.open_date.Year == 2001 && handle.open_date.Month == 1 && handle.open_date.Day == 2);
|
||||
// open date
|
||||
DateTime open_dt = handle.open_date;
|
||||
Assert.IsTrue(open_dt.Year == 2001 && open_dt.Month == 1 && open_dt.Day == 2);
|
||||
Assert.IsTrue(handle.close_price == 8.8);
|
||||
Assert.IsTrue(handle.close_date.Year == 2002 && handle.close_date.Month == 3 && handle.close_date.Day == 4);
|
||||
// close date
|
||||
DateTime close_dt = handle.close_date;
|
||||
Assert.IsTrue(close_dt.Year == 2002 && close_dt.Month == 3 && close_dt.Day == 4);
|
||||
|
||||
Assert.IsTrue(handle.session_high == 9.9);
|
||||
Assert.IsTrue(handle.session_low == 10.1);
|
||||
|
||||
@@ -13,8 +13,5 @@ namespace sparkcmd {
|
||||
ConsoleCommandDispatcher.DispatchCommand(commands, args, Console.Out);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
<Authors>Blue Trading Systems</Authors>
|
||||
<Company>Blue Trading Systems</Company>
|
||||
<Product>Spark</Product>
|
||||
<Platforms>x64</Platforms>
|
||||
<Platform>x64</Platform>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Version>1.0.0</Version>
|
||||
<LangVersion>7.2</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1 +1 @@
|
||||
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cpp_config.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/expiration_display_offset.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cpp_config.proto;config/protos/dynamic_orders.proto;config/protos/environment.proto;config/protos/expiration_display_offset.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/Actor.cpp;mercury/broker/AsyncEventBroker.cpp;mercury/broker/CoreEventBroker.cpp;mercury/broker/IEventBroker.cpp;mercury/events/TimerEvent.cpp;mercury/mercury_utils/Executor.cpp;mercury/mercury_utils/IPollableActor.cpp;mercury/mercury_utils/mercury_common.cpp;mercury/synopsis/SynopsisBuilder.cpp;mercury/topics/ITopic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/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/services/AdminService.proto;api/services/ApiUnitTestService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/services/UserService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/Executor.conf;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/dynamic_orders.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/logging.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/dynamic_orders.proto;config/protos/environment.proto;config/protos/jetfix.proto;config/protos/logging.proto;config/protos/orders_fills_cleanup.proto;config/protos/quickbus_cfg.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;jetfix/codec/FIXArray.cpp;jetfix/common/OutFIX.cpp;jetfix/connection/AsyncReader.cpp;jetfix/connection/IConnection.cpp;jetfix/connection/SocketConnection.cpp;jetfix/gateway/CoreGateway.cpp;jetfix/gateway/JetFIXGateway.cpp;jetfix/gateway/Session.cpp;jetfix/store/FIXFileStore.cpp;jetfix/store/session_name.cpp;jetfix/tests/async_reader_tests.cpp;jetfix/tests/decoding_tests.cpp;jetfix/tests/fix_encoding_stream_tests.cpp;jetfix/tests/fix_fragment_tests.cpp;jetfix/tests/jetfix_performance_tests.cpp;jetfix/tests/sample_fix.cpp;jetfix/tests/store_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPriceLantencyTester.cpp;md/Diag/ShmDumper.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MDRecoverableConsumer.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/md2_tests.cpp;md/test/synthetic_book_merge_tests.cpp;mercury/actors/Actor.cpp;mercury/broker/AsyncEventBroker.cpp;mercury/broker/CoreEventBroker.cpp;mercury/broker/IEventBroker.cpp;mercury/events/TimerEvent.cpp;mercury/mercury_utils/Executor.cpp;mercury/mercury_utils/IPollableActor.cpp;mercury/mercury_utils/mercury_common.cpp;mercury/synopsis/SynopsisBuilder.cpp;mercury/topics/ITopic.cpp;metrics/metrics.cpp;metrics/system_metrics.cpp;orderman/actors/AsyncFactory.cpp;orderman/actors/ExecutionGateway.cpp;orderman/actors/FillStore.cpp;orderman/actors/OrderStore.cpp;orderman/actors/SODPosition.cpp;orderman/actors/SecuritySrc.cpp;orderman/actors/ServiceBridge.cpp;orderman/actors/order_manager/OrderBuilder.cpp;orderman/actors/order_manager/OrderManager.cpp;orderman/actors/order_manager/OrderServicesData.cpp;orderman/events/CancelRejectEvent.cpp;orderman/events/NewExecutionReportEvent.cpp;orderman/limiter/LimitStore.cpp;orderman/limiter/Limiter.cpp;orderman/limiter/ProductLimitNode.cpp;orderman/limiter/ProductLimitTree.cpp;orderman/limiter/SecurityLimitNode.cpp;orderman/limiter/SecurityLimitTree.cpp;orderman/limiter/tests/limit_tests.cpp;orderman/order_factory/DynamicOrderRegistry.cpp;ordermanLine truncated
|
||||
@@ -1,34 +1,40 @@
|
||||
#include "lib/api/services/AdminService.server.pb.h"
|
||||
#include "lib/api/service_helpers/AdminServiceUtils.h"
|
||||
#include "lib/md/get_symbols.h"
|
||||
#include "lib/config/protos/cme_reference_data.pb.h"
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/config/config.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace bts{
|
||||
namespace admin{
|
||||
////////////////////////////////////////////
|
||||
// connection accessors ////////////////////
|
||||
////////////////////////////////////////////
|
||||
uint32_t AdminServiceUtils::find_max_connection_id (const bts::api::admin::AdminData& data){
|
||||
uint32_t AdminServiceUtils::find_max_connection_id (const AdminData& data){
|
||||
uint32_t rv = 0;
|
||||
for(const auto &conn : data.connections())
|
||||
if (conn.id() > rv)
|
||||
rv = conn.id();
|
||||
return rv;
|
||||
}
|
||||
const bts::api::admin::ExchangeConnection* AdminServiceUtils::find_connection(const bts::api::admin::AdminData& data,
|
||||
const std::string& connection_name){
|
||||
const ExchangeConnection* AdminServiceUtils::find_connection(
|
||||
const AdminData& data,
|
||||
const std::string& connection_name){
|
||||
for(const auto& connection : data.connections())
|
||||
if(connection.name()==connection_name)
|
||||
return &connection;
|
||||
return nullptr;
|
||||
}
|
||||
bool AdminServiceUtils::has_exchange(const bts::api::admin::ExchangeConnection& conn,
|
||||
bts::api::Venue exchange){
|
||||
bool AdminServiceUtils::has_exchange(const ExchangeConnection& conn,
|
||||
api::Venue exchange){
|
||||
bool rv = false;
|
||||
switch(exchange)
|
||||
{
|
||||
case api::Venue::VENUE_GLBX:
|
||||
rv = conn.has_cme_connection() &&
|
||||
(conn.cme_connection().has_cgw_connection() || conn.cme_connection().has_msgw_connection());
|
||||
(conn.cme_connection().has_cgw_connection() ||
|
||||
conn.cme_connection().has_msgw_connection());
|
||||
break;
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_SIM:
|
||||
@@ -870,6 +876,89 @@ void AdminServiceUtils::validate_user_exchange_data (const bts::api::admin::BTSU
|
||||
}
|
||||
}
|
||||
}
|
||||
void AdminServiceUtils::get_md_entitlement_report(const AdminData& admin_data,
|
||||
std::vector<MDEntitlementReportUnit>& entitlements){
|
||||
for (const auto& user : admin_data.users()){
|
||||
const CMEUserData* cme_data=AdminServiceUtils::get_user_cme_data(user,
|
||||
admin_data);
|
||||
if(cme_data!=nullptr){
|
||||
for (const auto& cme_mic_data : cme_data->md_permissions()){
|
||||
MDEntitlementReportUnit rv=get_cme_md_entitlement_unit(user.name(),
|
||||
cme_mic_data);
|
||||
entitlements.push_back(rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MDEntitlementReportUnit AdminServiceUtils::get_cme_md_entitlement_unit(
|
||||
const std::string& user,
|
||||
const CMEMicData& cme_mic_data){
|
||||
MDEntitlementReportUnit rv;
|
||||
rv.set_user(user);
|
||||
rv.set_exchange("GLBX");
|
||||
switch(cme_mic_data.mic())
|
||||
{
|
||||
case api::CMEMics::CME:
|
||||
rv.set_mic("CME");
|
||||
break;
|
||||
case api::CMEMics::NYMEX:
|
||||
rv.set_mic("NYMEX");
|
||||
break;
|
||||
case api::CMEMics::CBT:
|
||||
rv.set_mic("CBT");
|
||||
break;
|
||||
case api::CMEMics::COMEX:
|
||||
rv.set_mic("COMEX");
|
||||
break;
|
||||
case api::CMEMics::MGE:
|
||||
rv.set_mic("MGE");
|
||||
break;
|
||||
case api::CMEMics::DME:
|
||||
rv.set_mic("DME");
|
||||
break;
|
||||
case api::CMEMics::NYMSW:
|
||||
rv.set_mic("NYMSW");
|
||||
break;
|
||||
case api::CMEMics::FXS:
|
||||
rv.set_mic("FXS");
|
||||
break;
|
||||
case api::CMEMics::UNSET:
|
||||
case api::CMEMics::CMEMics_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::CMEMics::CMEMics_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
rv.set_mic("");
|
||||
break;
|
||||
}
|
||||
rv.set_enabled(cme_mic_data.enabled());
|
||||
std::ostringstream key;
|
||||
key << rv.user() << rv.exchange() << rv.mic();
|
||||
rv.set_record_id(key.str());
|
||||
return rv;
|
||||
}
|
||||
void AdminServiceUtils::get_user_symbol_permissions(const AdminData& data,
|
||||
const BTSUser& user,
|
||||
std::vector<UserSymbolMDPermissionUnit>& rv){
|
||||
std::map<api::CMEMics, bool> mic_perm_map;
|
||||
auto exchange = api::Venue::VENUE_GLBX;
|
||||
const CMEUserData* cme_data=get_user_cme_data(user,data);
|
||||
if(cme_data!=nullptr)
|
||||
for(const auto& mic_data : cme_data->md_permissions())
|
||||
if(mic_data.enabled())
|
||||
mic_perm_map[mic_data.mic()]=true;
|
||||
const auto& cme_symb_mics = config::get<config::CmeSymbolMics>().cme_mic();
|
||||
for(auto it=cme_symb_mics.begin();it!=cme_symb_mics.end();it++){
|
||||
const std::string& symbol=it->first;
|
||||
api::CMEMics mic=it->second;
|
||||
UserSymbolMDPermissionUnit u;
|
||||
std::ostringstream key;
|
||||
key << exchange << user.name() << symbol;
|
||||
u.set_record_id(key.str());
|
||||
u.set_user(user.name());
|
||||
u.set_exchange(exchange);
|
||||
u.set_symbol(symbol);
|
||||
u.set_enabled(mic_perm_map.find(mic)!=mic_perm_map.end());
|
||||
rv.push_back(u);
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////
|
||||
// user mutators ///////////////////////////
|
||||
////////////////////////////////////////////
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
#include "lib/api/services/AdminService.server.pb.h"
|
||||
#include "lib/api/services/OrderService.server.pb.h"
|
||||
#include "lib/domain_model/Security.h"
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/config/config.h"
|
||||
|
||||
namespace bts{
|
||||
namespace admin{
|
||||
|
||||
using namespace bts::api::admin;
|
||||
using namespace bts::api::orderman;
|
||||
|
||||
class AdminServiceUtils{
|
||||
public:
|
||||
////////////////////////////////////////////
|
||||
@@ -17,233 +18,286 @@ public:
|
||||
////////////////////////////////////////////
|
||||
// finds the max id out of all the existing connections
|
||||
// (todo: deleted connections)
|
||||
static uint32_t find_max_connection_id (const bts::api::admin::AdminData& data);
|
||||
static uint32_t find_max_connection_id (const AdminData& data);
|
||||
// finds a connection by name and returns a mutable pointer to it
|
||||
static const bts::api::admin::ExchangeConnection* find_connection(const bts::api::admin::AdminData& data,
|
||||
const std::string& connection_name);
|
||||
static const ExchangeConnection* find_connection(const AdminData& data,
|
||||
const std::string& connection_name);
|
||||
// finds the presence of an exchange in a connection
|
||||
static bool has_exchange(const bts::api::admin::ExchangeConnection& conn,
|
||||
static bool has_exchange(const ExchangeConnection& conn,
|
||||
bts::api::Venue exchange);
|
||||
// finds the default connections for an exchange
|
||||
// in a given account
|
||||
static const bts::api::admin::ExchangeConnection* find_default_account_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
bts::api::Venue exchange);
|
||||
static const bts::api::admin::ExchangeConnection* resolve_cme_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::Security& sec);
|
||||
static const bts::api::admin::ExchangeConnection* resolve_sim_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::Security& sec);
|
||||
static const bts::api::admin::ExchangeConnection* resolve_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::Security& sec);
|
||||
static const ExchangeConnection* find_default_account_connection(
|
||||
const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
bts::api::Venue exchange);
|
||||
static const ExchangeConnection* resolve_cme_connection(
|
||||
const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
const api::Security& sec);
|
||||
static const ExchangeConnection* resolve_sim_connection(
|
||||
const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
const api::Security& sec);
|
||||
static const ExchangeConnection* resolve_connection(
|
||||
const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
const bts::api::Security& sec);
|
||||
////////////////////////////////////////////
|
||||
// connection mutators /////////////////////
|
||||
////////////////////////////////////////////
|
||||
// adds a new connection (does not check for name uniqueness)
|
||||
static bts::api::admin::ExchangeConnection* add_connection(bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::ExchangeConnection& new_connection);
|
||||
static ExchangeConnection* add_connection(AdminData& data,
|
||||
const ExchangeConnection& new_connection);
|
||||
// reads the connections from config and fills in the
|
||||
// admin data (with names only)
|
||||
static void fill_connections_from_config(bts::api::admin::AdminData& admin_data);
|
||||
static void fill_connections_from_config(AdminData& admin_data);
|
||||
////////////////////////////////////////////
|
||||
// account accessors ///////////////////////
|
||||
////////////////////////////////////////////
|
||||
// finds the account from the name and returns
|
||||
// a mutable pointer to the account
|
||||
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, const std::string& acct_name, bool include_deleted=false);
|
||||
static BTSAccount* find_account (AdminData& data,
|
||||
const std::string& acct_name,
|
||||
bool include_deleted=false);
|
||||
// same as above for const pointer
|
||||
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::AdminData& data, const std::string& acct_name, bool include_deleted=false);
|
||||
static const BTSAccount* find_account (const AdminData& data,
|
||||
const std::string& acct_name,
|
||||
bool include_deleted=false);
|
||||
// finds the account from the id and returns
|
||||
// a mutable pointer to the account
|
||||
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
|
||||
static BTSAccount* find_account (AdminData& data,
|
||||
uint32_t id,
|
||||
bool include_deleted=false);
|
||||
// like above but returns a const pointer
|
||||
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
|
||||
static const BTSAccount* find_account (const AdminData& data,
|
||||
uint32_t id,
|
||||
bool include_deleted=false);
|
||||
// this function is an indirection layer for account access
|
||||
// so deletions are dealt in a more deliberate manner
|
||||
static std::vector<const bts::api::admin::BTSAccount*> accounts (const bts::api::admin::AdminData& data, bool include_deleted);
|
||||
static std::vector<bts::api::admin::BTSAccount*> accounts_mutable (bts::api::admin::AdminData& data, bool include_deleted);
|
||||
static std::vector<const BTSAccount*> accounts (const AdminData& data,
|
||||
bool include_deleted);
|
||||
static std::vector<BTSAccount*> accounts_mutable (AdminData& data,
|
||||
bool include_deleted);
|
||||
// finds the max id amongts all the existing accounts
|
||||
static uint32_t find_max_acct_id (const bts::api::admin::AdminData& data);
|
||||
static uint32_t find_max_acct_id (const AdminData& data);
|
||||
// gets the account data for cme (and goes up the hierarchy
|
||||
// if needed)
|
||||
static const bts::api::admin::CMEAccountData* get_account_cme_data(const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::admin::AdminData& data);
|
||||
static const bts::api::admin::SIMAccountData* get_account_sim_data(const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::admin::AdminData& data);
|
||||
static const CMEAccountData* get_account_cme_data(const BTSAccount& account,
|
||||
const AdminData& data);
|
||||
static const SIMAccountData* get_account_sim_data(const BTSAccount& account,
|
||||
const AdminData& data);
|
||||
// returns true if an account has a connection
|
||||
bool static account_has_connection(const bts::api::admin::BTSAccount& account, const std::string& connection_name);
|
||||
bool static account_has_connection(const BTSAccount& account,
|
||||
const std::string& connection_name);
|
||||
// finds the external/clearing account associated
|
||||
// with an account
|
||||
static std::string find_account_exchange_account (const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
api::Venue exchange,
|
||||
bts::api::admin::AdminServiceOperationResult& out_result);
|
||||
static std::string find_account_exchange_account (const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
api::Venue exchange,
|
||||
AdminServiceOperationResult& out_result);
|
||||
// returns a map of the accounts vs their 'is_active'
|
||||
static std::map<uint32_t,bool> accounts_map(const bts::api::admin::AdminData& admin_data);
|
||||
static std::map<uint32_t,bool> accounts_map(const AdminData& admin_data);
|
||||
// validates that the update to the account is valid
|
||||
static void validate_account_update (const bts::api::admin::AdminData& admin_data,
|
||||
const bts::api::admin::BTSAccount& updated_account,
|
||||
bts::api::admin::AdminServiceOperationResult& result);
|
||||
static void validate_account_update (const AdminData& admin_data,
|
||||
const BTSAccount& updated_account,
|
||||
AdminServiceOperationResult& result);
|
||||
// validates that the account exchange changes are valid
|
||||
// (ex > 12 characters for accounts at CME)
|
||||
static void validate_account_exchange_data (const bts::api::admin::BTSAccount& account,
|
||||
bts::api::admin::AdminServiceOperationResult& out_result);
|
||||
static bts::api::orderman::RoutingRecord get_routing_record(const bts::api::admin::AdminData& data,
|
||||
const std::string& account_name,
|
||||
const std::string& user_name,
|
||||
const bts::api::Security& sec,
|
||||
bts::api::admin::AdminServiceOperationResult& out_result);
|
||||
static bts::api::orderman::RoutingRecord get_routing_record(const bts::api::admin::AdminData& data,
|
||||
uint32_t account_id,
|
||||
uint32_t user_id,
|
||||
const bts::api::Security& sec,
|
||||
bts::api::admin::AdminServiceOperationResult& out_result);
|
||||
static void validate_account_exchange_data (const BTSAccount& account,
|
||||
AdminServiceOperationResult& out_result);
|
||||
static RoutingRecord get_routing_record(
|
||||
const AdminData& data,
|
||||
const std::string& account_name,
|
||||
const std::string& user_name,
|
||||
const bts::api::Security& sec,
|
||||
AdminServiceOperationResult& out_result);
|
||||
static RoutingRecord get_routing_record(const AdminData& data,
|
||||
uint32_t account_id,
|
||||
uint32_t user_id,
|
||||
const bts::api::Security& sec,
|
||||
AdminServiceOperationResult& out_result);
|
||||
////////////////////////////////////////////
|
||||
// account mutators ////////////////////////
|
||||
////////////////////////////////////////////
|
||||
static bts::api::admin::BTSAccount* create_account(bts::api::admin::AdminData& data,
|
||||
uint32_t parent_account_id,
|
||||
const std::string& account_name,
|
||||
const std::string& description,
|
||||
bool is_active,
|
||||
bts::api::admin::AdminServiceCreateAccountResult& result);
|
||||
static BTSAccount* create_account(AdminData& data,
|
||||
uint32_t parent_account_id,
|
||||
const std::string& account_name,
|
||||
const std::string& description,
|
||||
bool is_active,
|
||||
AdminServiceCreateAccountResult& result);
|
||||
// writes over the account data completely
|
||||
static void update_account(bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& updated_account,
|
||||
bts::api::admin::AdminServiceOperationResult& result);
|
||||
static void delete_account (bts::api::admin::AdminData& admin_data,
|
||||
const bts::api::admin::IDAPIArgument& id,
|
||||
bts::api::admin::AdminServiceOperationResult& result);
|
||||
static void set_account_exchange_data(bts::api::admin::BTSAccount* account,
|
||||
const bts::api::admin::ExchangeAccountData& exchange_data);
|
||||
static void update_account(AdminData& data,
|
||||
const BTSAccount& updated_account,
|
||||
AdminServiceOperationResult& result);
|
||||
static void delete_account (AdminData& admin_data,
|
||||
const IDAPIArgument& id,
|
||||
AdminServiceOperationResult& result);
|
||||
static void set_account_exchange_data(BTSAccount* account,
|
||||
const ExchangeAccountData& exchange_data);
|
||||
// this is not a generally useful function but since
|
||||
// connection are in config, this cleans up the account's
|
||||
// connections and syncs it with the list in AdminData
|
||||
static void sync_account_connections(const bts::api::admin::AdminData& data,
|
||||
bts::api::admin::BTSAccount& account);
|
||||
static void sync_account_connections(const AdminData& data,
|
||||
BTSAccount& account);
|
||||
////////////////////////////////////////////
|
||||
// group accessors /////////////////////////
|
||||
////////////////////////////////////////////
|
||||
// given an id, finds the mutable pointer to a group
|
||||
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, uint32_t id);
|
||||
static BTSUserGroup* find_group (AdminData& data, uint32_t id);
|
||||
// given an id, finds the const pointer to a group
|
||||
static const bts::api::admin::BTSUserGroup* const find_group (const bts::api::admin::AdminData& data, uint32_t id);
|
||||
static const BTSUserGroup* const find_group (const AdminData& data,
|
||||
uint32_t id);
|
||||
// given a name, finds the mutable pointer to a group
|
||||
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, const std::string& group_name);
|
||||
static BTSUserGroup* find_group (AdminData& data,
|
||||
const std::string& group_name);
|
||||
// finds the max id out of all the groups
|
||||
static uint32_t find_max_group_id (const bts::api::admin::AdminData& data);
|
||||
static uint32_t find_max_group_id (const AdminData& data);
|
||||
// travels up the group tree until it finds a populated cme data
|
||||
static const bts::api::admin::CMEUserData* get_group_cme_data(const bts::api::admin::BTSUserGroup& group,
|
||||
const bts::api::admin::AdminData& data);
|
||||
static const bts::api::admin::SIMUserData* get_group_sim_data(const bts::api::admin::BTSUserGroup& group,
|
||||
const bts::api::admin::AdminData& data);
|
||||
static const bts::api::admin::UserAccountPermissions* const get_group_user_permissions (const bts::api::admin::AdminData& admin_data,
|
||||
uint32_t group_id);
|
||||
static const CMEUserData* get_group_cme_data(const BTSUserGroup& group,
|
||||
const AdminData& data);
|
||||
static const SIMUserData* get_group_sim_data(const BTSUserGroup& group,
|
||||
const AdminData& data);
|
||||
static const UserAccountPermissions* const get_group_user_permissions (
|
||||
const bts::api::admin::AdminData& admin_data,
|
||||
uint32_t group_id);
|
||||
////////////////////////////////////////////
|
||||
// group mutators/ /////////////////////////
|
||||
////////////////////////////////////////////
|
||||
static bts::api::admin::BTSUserGroup* create_group(bts::api::admin::AdminData& data,
|
||||
uint32_t parent_group_id,
|
||||
const std::string& group_name,
|
||||
bts::api::admin::AdminServiceOperationResult& result);
|
||||
static BTSUserGroup* create_group(AdminData& data,
|
||||
uint32_t parent_group_id,
|
||||
const std::string& group_name,
|
||||
AdminServiceOperationResult& result);
|
||||
////////////////////////////////////////////
|
||||
// user accessors //////////////////////////
|
||||
////////////////////////////////////////////
|
||||
static bts::api::admin::BTSUser* find_user (bts::api::admin::AdminData& data, const std::string& user_name, bool include_deleted=false);
|
||||
static const bts::api::admin::BTSUser* find_user (const bts::api::admin::AdminData& data, const std::string& user_name, bool include_deleted=false);
|
||||
static bts::api::admin::BTSUser* find_user (bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
|
||||
static const bts::api::admin::BTSUser* const find_user (const bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
|
||||
static std::vector<const bts::api::admin::BTSUser*> users (const bts::api::admin::AdminData& data, bool include_deleted);
|
||||
static std::vector<bts::api::admin::BTSUser*> users_mutable (bts::api::admin::AdminData& data, bool include_deleted);
|
||||
static uint32_t find_max_user_id (const bts::api::admin::AdminData& data);
|
||||
static const bts::api::admin::CMEUserData* get_user_cme_data(const bts::api::admin::BTSUser& user,
|
||||
const bts::api::admin::AdminData& data);
|
||||
static const bts::api::admin::SIMUserData* get_user_sim_data(const bts::api::admin::BTSUser& user,
|
||||
const bts::api::admin::AdminData& data);
|
||||
static BTSUser* find_user (AdminData& data,
|
||||
const std::string& user_name,
|
||||
bool include_deleted=false);
|
||||
static const BTSUser* find_user (const AdminData& data,
|
||||
const std::string& user_name,
|
||||
bool include_deleted=false);
|
||||
static BTSUser* find_user (AdminData& data,
|
||||
uint32_t id,
|
||||
bool include_deleted=false);
|
||||
static const BTSUser* const find_user (const AdminData& data,
|
||||
uint32_t id,
|
||||
bool include_deleted=false);
|
||||
static std::vector<const BTSUser*> users (const AdminData& data,
|
||||
bool include_deleted);
|
||||
static std::vector<BTSUser*> users_mutable (AdminData& data,
|
||||
bool include_deleted);
|
||||
static uint32_t find_max_user_id (const AdminData& data);
|
||||
static const CMEUserData* get_user_cme_data(const BTSUser& user,
|
||||
const AdminData& data);
|
||||
static const SIMUserData* get_user_sim_data(const BTSUser& user,
|
||||
const AdminData& data);
|
||||
// finds the "exchange user" (ex: "operator_id" at CME or "authorized_trader"
|
||||
// at ICE) for a user
|
||||
static std::string find_user_exchange_id (const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSUser& user,
|
||||
api::Venue exchange,
|
||||
bts::api::admin::AdminServiceOperationResult& out_result);
|
||||
static std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>
|
||||
find_user_account_matches (const bts::api::admin::AdminData& admin_data,
|
||||
const std::string& connection, const std::string& exchange_account,
|
||||
static std::string find_user_exchange_id (
|
||||
const AdminData& data,
|
||||
const BTSUser& user,
|
||||
api::Venue exchange,
|
||||
AdminServiceOperationResult& out_result);
|
||||
static std::pair<const BTSAccount*, const BTSUser*>
|
||||
find_user_account_matches (const AdminData& admin_data,
|
||||
const std::string& connection,
|
||||
const std::string& exchange_account,
|
||||
const std::string& exchange_user,
|
||||
api::Venue exchange);
|
||||
// for a given user finds the account permissions (if permissions are
|
||||
// derived from the group, it traverses the group hierarcy to find the
|
||||
// correct permissions.
|
||||
static const bts::api::admin::UserAccountPermissions* get_user_permissions (const bts::api::admin::AdminData& admin_data, uint32_t user_id);
|
||||
static const UserAccountPermissions* get_user_permissions (
|
||||
const AdminData& admin_data,
|
||||
uint32_t user_id);
|
||||
// for a given user, fills in the associated_accounts ref arg
|
||||
// with the accounts the user has permission to trade in
|
||||
static void find_user_trading_accounts (const bts::api::admin::AdminData& admin_data,
|
||||
uint32_t user_id,
|
||||
std::vector<const api::admin::BTSAccount*>& associated_accounts);
|
||||
static void find_user_trading_accounts (
|
||||
const AdminData& admin_data,
|
||||
uint32_t user_id,
|
||||
std::vector<const BTSAccount*>& associated_accounts);
|
||||
// validates that changes in user data satisfy all the
|
||||
// constraints
|
||||
static void validate_user_update (const bts::api::admin::AdminData& admin_data,
|
||||
const bts::api::admin::BTSUser& updated_user,
|
||||
bts::api::admin::AdminServiceOperationResult& result);
|
||||
static void validate_user_update (const AdminData& admin_data,
|
||||
const BTSUser& updated_user,
|
||||
AdminServiceOperationResult& result);
|
||||
// vaidates the exchange part of user data updates
|
||||
static void validate_user_exchange_data (const bts::api::admin::BTSUser& updated_user,
|
||||
bts::api::admin::AdminServiceOperationResult& out_result);
|
||||
static void validate_user_exchange_data (
|
||||
const BTSUser& updated_user,
|
||||
AdminServiceOperationResult& out_result);
|
||||
static void get_md_entitlement_report(const AdminData& admin_data,
|
||||
std::vector<MDEntitlementReportUnit>& entitlements);
|
||||
// Gets a reporting unit out of CMEMicData
|
||||
static MDEntitlementReportUnit get_cme_md_entitlement_unit(
|
||||
const std::string& user,
|
||||
const CMEMicData& cme_mic_data);
|
||||
static void get_user_symbol_permissions(
|
||||
const AdminData& data,
|
||||
const BTSUser& user,
|
||||
std::vector<UserSymbolMDPermissionUnit>& res);
|
||||
////////////////////////////////////////////
|
||||
// user mutators ///////////////////////////
|
||||
////////////////////////////////////////////
|
||||
static bts::api::admin::BTSUser* create_user (bts::api::admin::AdminData& data,
|
||||
uint32_t parent_group_id,
|
||||
const std::string& name,
|
||||
const std::string& password,
|
||||
bool is_active,
|
||||
const bts::api::admin::LicenseData& license_data,
|
||||
const bts::api::admin::LicenseEntitlements& license_entitlements,
|
||||
bts::api::admin::AdminServiceCreateEntityResult& result);
|
||||
static bts::api::admin::BTSUser* update_user(bts::api::admin::AdminData& admin_data,
|
||||
const bts::api::admin::BTSUser& updated_user,
|
||||
bts::api::admin::AdminServiceOperationResult& result);
|
||||
static void delete_user (bts::api::admin::AdminData& admin_data,
|
||||
const bts::api::admin::IDAPIArgument& id,
|
||||
bts::api::admin::AdminServiceOperationResult& result);
|
||||
static void set_user_exchange_data(bts::api::admin::BTSUser* user,
|
||||
const bts::api::admin::ExchangeUserData& exchange_user_data);
|
||||
static void set_user_md_entitlement_data(bts::api::admin::BTSUser* user,
|
||||
const bts::api::admin::ExchangeUserMarketDataEntitlementData& exchange_user_md_entitelemnt_data);
|
||||
static void clear_user_accounts (bts::api::admin::BTSUser* user);
|
||||
static void set_user_accounts (bts::api::admin::BTSUser* user,
|
||||
const bts::api::admin::UserAccountPermissions& user_account_permissions);
|
||||
static BTSUser* create_user (AdminData& data,
|
||||
uint32_t parent_group_id,
|
||||
const std::string& name,
|
||||
const std::string& password,
|
||||
bool is_active,
|
||||
const LicenseData& license_data,
|
||||
const LicenseEntitlements& license_entitlements,
|
||||
AdminServiceCreateEntityResult& result);
|
||||
static BTSUser* update_user(AdminData& admin_data,
|
||||
const BTSUser& updated_user,
|
||||
AdminServiceOperationResult& result);
|
||||
static void delete_user (AdminData& admin_data,
|
||||
const IDAPIArgument& id,
|
||||
AdminServiceOperationResult& result);
|
||||
static void set_user_exchange_data(
|
||||
BTSUser* user,
|
||||
const ExchangeUserData& exchange_user_data);
|
||||
static void set_user_md_entitlement_data(BTSUser* user,
|
||||
const ExchangeUserMarketDataEntitlementData&);
|
||||
static void clear_user_accounts (BTSUser* user);
|
||||
static void set_user_accounts (BTSUser* user,
|
||||
const UserAccountPermissions& user_account_permissions);
|
||||
////////////////////////////////////////////
|
||||
//risk limits //////////////////////////////
|
||||
////////////////////////////////////////////
|
||||
// sorting function used by sort_limits to
|
||||
// sort SecurityScope's
|
||||
static bool _sort_security_scopes (const bts::api::admin::SecurityScope& a, const bts::api::admin::SecurityScope& b);
|
||||
static bool _sort_security_scopes (const SecurityScope& a,
|
||||
const SecurityScope& b);
|
||||
// sorting function used by sort_limits to
|
||||
// sort ProductScope's
|
||||
static bool _sort_product_scopes (const bts::api::admin::ProductScope& a, const bts::api::admin::ProductScope&);
|
||||
static bool _sort_product_scopes (const ProductScope& a,
|
||||
const ProductScope&);
|
||||
// this sorts the rules such that the most
|
||||
// specific ones are at the top. this makes it
|
||||
// easier to match rules with securities/products
|
||||
static void sort_limits (bts::api::admin::BTSAccount& account);
|
||||
static void sort_limits (BTSAccount& account);
|
||||
// creates a copy of AdminData with sorted rules
|
||||
static bts::api::admin::AdminData sort_limits (const bts::api::admin::AdminData& admin_data);
|
||||
static AdminData sort_limits (const AdminData& admin_data);
|
||||
// find the clip size for a security, account
|
||||
static const uint32_t find_account_security_clip_size(const bts::api::admin::BTSAccount& account,
|
||||
const api::Security& security);
|
||||
static const uint32_t find_account_security_clip_size(
|
||||
const BTSAccount& account,
|
||||
const api::Security& security);
|
||||
// find the position limit for an account, security
|
||||
static const bts::api::admin::AccountSecurityPositionLimitUnit* find_account_security_position_limit(const bts::api::admin::BTSAccount& account,
|
||||
static const AccountSecurityPositionLimitUnit*
|
||||
find_account_security_position_limit(const BTSAccount& account,
|
||||
const api::Security& security);
|
||||
// find the position limit for an account, product
|
||||
static const bts::api::admin::AccountProductPositionLimitUnit* find_account_product_position_limit(const bts::api::admin::BTSAccount& account,
|
||||
static const AccountProductPositionLimitUnit*
|
||||
find_account_product_position_limit(const BTSAccount& account,
|
||||
const api::Product& product);
|
||||
static bool match_security_scope (const bts::api::admin::SecurityScope& scope,
|
||||
const bts::api::Security& security);
|
||||
static bool match_product_scope (const bts::api::admin::ProductScope& scope,
|
||||
const bts::api::Product& product);
|
||||
static bool match_product(const api::Security& security, const api::Product& product);
|
||||
static bool _match_limit_rule_symbol (const std::string& symbol, const std::string& limit_symbol);
|
||||
static bool match_security_scope (const SecurityScope& scope,
|
||||
const api::Security& security);
|
||||
static bool match_product_scope (const ProductScope& scope,
|
||||
const api::Product& product);
|
||||
static bool match_product(const api::Security& security,
|
||||
const api::Product& product);
|
||||
static bool _match_limit_rule_symbol (const std::string& symbol,
|
||||
const std::string& limit_symbol);
|
||||
static api::SecurityType security_type(const api::Security& security);
|
||||
////////////////////////////////////////////
|
||||
// misc//////// ////////////////////////////
|
||||
|
||||
@@ -182,6 +182,17 @@ message AccountExchangeConnections{
|
||||
/***************************Exchange Data********************************/
|
||||
/************************************************************************/
|
||||
|
||||
message CMEMicData{
|
||||
api.CMEMics mic=10;
|
||||
bool enabled=20;
|
||||
// there are other things here
|
||||
}
|
||||
|
||||
message ICEMicData{
|
||||
api.CMEMics mic=10;
|
||||
bool enabled=20;
|
||||
}
|
||||
|
||||
message ExchangeUserMarketDataEntitlementData{
|
||||
CMEUserMarketDataEntitlementData cme_data = 10;
|
||||
ICEUserMarketDataEntitlementData ice_data = 20;
|
||||
@@ -276,6 +287,8 @@ message CMEUserData{
|
||||
string smp_instruction = 70;
|
||||
string max_order_rate_per_connection = 80;
|
||||
string location = 90;
|
||||
// add suff here
|
||||
repeated CMEMicData md_permissions = 1000;
|
||||
}
|
||||
|
||||
message SIMUserData {
|
||||
@@ -331,6 +344,48 @@ message ICEUserData{
|
||||
message ICEUserMarketDataEntitlementData{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Order Auxiliary Service ////////////////////////////////
|
||||
|
||||
message OrdersSummaryUnit{
|
||||
string account = 10;
|
||||
string user = 20;
|
||||
uint32 total_orders = 30;
|
||||
uint32 total_contracts = 40;
|
||||
}
|
||||
message OrdersSummary{
|
||||
repeated OrdersSummaryUnit units = 10;
|
||||
}
|
||||
message OrderSummaryRequest{
|
||||
}
|
||||
// top level orders that have account
|
||||
// and user that are present here, will
|
||||
// be cancelled. wild cards are not
|
||||
// supported.
|
||||
message OrderCancelRequest{
|
||||
repeated string accounts = 10;
|
||||
repeated string users = 20;
|
||||
}
|
||||
///////////////////////////////////////////////////////////
|
||||
// Reporting //////////////////////////////////////////////
|
||||
message MDEntitlementReportUnit{
|
||||
string record_id = 1 [(bts.api.key)=true];
|
||||
string user = 10;
|
||||
string exchange = 20;
|
||||
string mic = 30;
|
||||
bool enabled = 40;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Misc ///////////////////////////////////////////////////
|
||||
message UserSymbolMDPermissionUnit{
|
||||
string record_id = 1 [(bts.api.key)=true];
|
||||
string user=10;
|
||||
api.Venue exchange=20;
|
||||
string symbol=30;
|
||||
bool enabled=40;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/************************************************************************/
|
||||
/************************************************************************/
|
||||
@@ -385,4 +440,11 @@ service AdminService {
|
||||
// subscription
|
||||
rpc admin_data(bts.api.VoidMessage) returns (stream AdminData);
|
||||
rpc get_admin_data(bts.api.VoidMessage) returns (AdminData);
|
||||
// orders
|
||||
rpc get_order_summary(bts.api.VoidMessage) returns (OrdersSummary);
|
||||
rpc cancel_orders(OrderCancelRequest) returns (bts.api.VoidMessage);
|
||||
// reports
|
||||
rpc md_entitlement_data(bts.api.VoidMessage) returns (stream MDEntitlementReportUnit);
|
||||
// misc
|
||||
rpc md_permissions_data(bts.api.VoidMessage) returns (stream UserSymbolMDPermissionUnit);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
syntax="proto3";
|
||||
package bts.api.md.auxiliary;
|
||||
option csharp_namespace="bts.api.md.auxiliary";
|
||||
import "lib/api/apioptions.proto";
|
||||
import "lib/api/apicore.proto";
|
||||
|
||||
message VolumeAtPriceLevel{
|
||||
int32 record_id = 1 [(bts.api.key)=true];
|
||||
uint32 security_id = 20;
|
||||
double price = 30;
|
||||
uint32 volume = 40;
|
||||
}
|
||||
|
||||
service MarketDataAuxiliaryService{
|
||||
option (bts.api.service_description)="Provides non-core supplementary market data";
|
||||
rpc volume_at_price(bts.api.VoidMessage) returns (stream VolumeAtPriceLevel);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import "lib/api/apioptions.proto";
|
||||
import "lib/domain_model/Security.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "lib/sparkproto/SparkProtos.proto";
|
||||
import "lib/api/apicore.proto";
|
||||
|
||||
service OrderService {
|
||||
option (bts.api.service_description)="Implements order management";
|
||||
@@ -15,9 +16,12 @@ service OrderService {
|
||||
rpc cancel_order(Cancel) returns (Response);
|
||||
rpc update_order(Update) returns (Response);
|
||||
rpc crack_order(Crack) returns (Response);
|
||||
rpc get_registered_dynamic_order_types(bts.api.VoidMessage) returns (RegisteredDynamicOrderTypes);
|
||||
|
||||
// streams
|
||||
rpc orders (OrdersSub) returns (stream OrderRecord);
|
||||
|
||||
|
||||
rpc fills (FillsSub) returns (stream Fill);
|
||||
}
|
||||
|
||||
@@ -139,8 +143,7 @@ message CoverOrderDefinition {
|
||||
}
|
||||
message DynamicOrderDefinition {
|
||||
string dynamic_order_type = 1;
|
||||
map<string,string> parameters = 2;
|
||||
CustomOrderDefinition child = 3;
|
||||
map<string, DynamicOrderParam> order_params = 2;
|
||||
}
|
||||
// End custom order definitions
|
||||
|
||||
@@ -259,7 +262,7 @@ message TopOrderState {}
|
||||
message TriggerOrderState {}
|
||||
message CoverOrderState {}
|
||||
message DynamicOrderState {
|
||||
map<string,string> state = 2;
|
||||
map<string,string> state = 1;
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
@@ -465,3 +468,76 @@ message TriggerExitCondition{
|
||||
uint32 timeout_seconds=20; //seconds
|
||||
bool conditional_cancel=30;
|
||||
}
|
||||
|
||||
|
||||
// Dynamic Orders
|
||||
|
||||
enum DynamicOrderPrimitiveDescriptor {
|
||||
DYNAMIC_ORDER_PRIMITIVE_INT = 0;
|
||||
DYNAMIC_ORDER_PRIMITIVE_UINT = 1;
|
||||
DYNAMIC_ORDER_PRIMITIVE_DOUBLE = 2;
|
||||
DYNAMIC_ORDER_PRIMITIVE_STRING = 3;
|
||||
DYNAMIC_ORDER_PRIMITIVE_BOOL = 4;
|
||||
DYNAMIC_ORDER_PRIMITIVE_ORDER_DEF = 5;
|
||||
}
|
||||
|
||||
message DynamicOrderTypeDescriptor {
|
||||
oneof descriptor {
|
||||
DynamicOrderPrimitiveDescriptor primitive = 2;
|
||||
DynamicOrderArrayDescriptor array = 3;
|
||||
DynamicOrderStructDescriptor structure = 4;
|
||||
DynamicOrderEnumeratedDescriptor enumerated = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message DynamicOrderArrayDescriptor {
|
||||
DynamicOrderTypeDescriptor element_type = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderParamDescriptor {
|
||||
string param_name = 1;
|
||||
DynamicOrderTypeDescriptor param_type = 2;
|
||||
}
|
||||
|
||||
message DynamicOrderStructDescriptor {
|
||||
repeated DynamicOrderParamDescriptor field = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderEnumeratedDescriptor {
|
||||
repeated string element = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderDescriptor {
|
||||
string dynamic_order_type = 1;
|
||||
repeated DynamicOrderParamDescriptor param_desc = 3;
|
||||
}
|
||||
|
||||
message RegisteredDynamicOrderTypes {
|
||||
repeated DynamicOrderDescriptor dynamic_order_desc = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderParam {
|
||||
oneof value {
|
||||
uint32 as_int32 = 1;
|
||||
uint32 as_uint32 = 2;
|
||||
double as_double = 3;
|
||||
string as_string = 4;
|
||||
bool as_bool = 5;
|
||||
CustomOrderDefinition as_order_def = 6;
|
||||
DynamicOrderArray as_array = 7;
|
||||
DynamicOrderStruct as_struct = 8;
|
||||
DynamicOrderEnumerated as_enumerated = 9;
|
||||
}
|
||||
}
|
||||
|
||||
message DynamicOrderArray {
|
||||
repeated DynamicOrderParam element = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderStruct {
|
||||
map<string,DynamicOrderParam> field = 1;
|
||||
}
|
||||
|
||||
message DynamicOrderEnumerated {
|
||||
string enum_value = 1;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -2,17 +2,17 @@
|
||||
|
||||
DynamicOrderList {
|
||||
value {
|
||||
# dynamic_orders
|
||||
# {
|
||||
# type_name: 'DynamicOrder1'
|
||||
# parameter_keys: 'param1'
|
||||
# parameter_keys: 'param2'
|
||||
# }
|
||||
# dynamic_orders
|
||||
# {
|
||||
# type_name: 'DynamicOrder2'
|
||||
# parameter_keys: 'param3'
|
||||
# parameter_keys: 'param4'
|
||||
# }
|
||||
dynamic_orders
|
||||
{
|
||||
type_name: 'DynamicOrder1'
|
||||
parameter_keys: 'param1'
|
||||
parameter_keys: 'param2'
|
||||
}
|
||||
dynamic_orders
|
||||
{
|
||||
type_name: 'DynamicOrder2'
|
||||
parameter_keys: 'param3'
|
||||
parameter_keys: 'param4'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
ExpirationDisplayOffset
|
||||
{
|
||||
value
|
||||
{
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "lo"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "CL"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "ob"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "RB"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "oh"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "HO"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "wbs"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "WBS"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "so"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "SI"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "og"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "GC"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "hxe"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "HG"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "ozs"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "ozw"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "osd"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "ZS"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "ozm"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "ZM"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "ozl"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "ZL"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "ozc"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "ZC"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "OPTION"
|
||||
security_name: "ozn"
|
||||
addition_count: 1
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
entries
|
||||
{
|
||||
security_type: "FUTURE"
|
||||
security_name: "ZN"
|
||||
addition_count: 0
|
||||
addition_type: MonthMoveToStart
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
syntax='proto2';
|
||||
package bts.config;
|
||||
import "lib/domain_model/Security.proto";
|
||||
|
||||
message CppConfig {
|
||||
map<string, double> cpp_entry = 1;
|
||||
}
|
||||
|
||||
message CmeSymbolMics {
|
||||
map<string, bts.api.CMEMics> cme_mic = 1;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
syntax='proto2';
|
||||
package bts.config;
|
||||
|
||||
message CppConfig {
|
||||
map<string, double> cpp_entry = 1;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
syntax='proto2';
|
||||
package bts.config;
|
||||
|
||||
message ExpirationOffsetType
|
||||
{
|
||||
enum type
|
||||
{
|
||||
Month=0;
|
||||
MonthMoveToStart=1;
|
||||
}
|
||||
}
|
||||
|
||||
message ExpirationDisplayOffsetEntry
|
||||
{
|
||||
required string security_type = 1;
|
||||
required string security_name = 2;
|
||||
required int32 addition_count = 3;
|
||||
required ExpirationOffsetType.type addition_type = 4;
|
||||
}
|
||||
|
||||
message ExpirationDisplayOffset
|
||||
{
|
||||
repeated ExpirationDisplayOffsetEntry entries = 1;
|
||||
}
|
||||
@@ -26,4 +26,8 @@ message OrdersSoftCleanup{
|
||||
|
||||
message ToastNotifications {
|
||||
optional bool enabled = 1 [default = false];
|
||||
}
|
||||
|
||||
message VolumeAtPrice{
|
||||
optional bool enabled = 1 [default = true];
|
||||
}
|
||||
@@ -40,6 +40,22 @@ enum Currency {
|
||||
CURRENCY_RMB = 14;
|
||||
}
|
||||
|
||||
enum CMEMics {
|
||||
UNSET = 0;
|
||||
CME = 1;
|
||||
NYMEX = 2;
|
||||
CBT = 3;
|
||||
COMEX = 4;
|
||||
MGE = 5;
|
||||
DME = 6;
|
||||
NYMSW = 7;
|
||||
FXS = 8;
|
||||
}
|
||||
|
||||
enum ICEMics{
|
||||
ICE_FUTURES_CANADA=0;
|
||||
}
|
||||
|
||||
enum Side {
|
||||
SIDE_UNDEFINED = 0;
|
||||
SIDE_BUY = 49;
|
||||
|
||||
@@ -116,6 +116,7 @@ void configure_logging(bts::config::Logging const&cfg)
|
||||
{log::Testing,"Testing"},
|
||||
{log::Latency,"Latency"},
|
||||
{log::DataFlow,"DataFlow"},
|
||||
{log::Plugin,"Plugin"},
|
||||
};
|
||||
|
||||
real_cfg.sinks["console"] =
|
||||
|
||||
@@ -42,6 +42,7 @@ constexpr log::Subsystem Mercury {ExSim.ordinal+1 };
|
||||
constexpr log::Subsystem Testing {Mercury.ordinal+1 };
|
||||
constexpr log::Subsystem Latency {Testing.ordinal+1 };
|
||||
constexpr log::Subsystem DataFlow {Latency.ordinal+1 };
|
||||
constexpr log::Subsystem Plugin {DataFlow.ordinal+1 };
|
||||
|
||||
struct LoggerHandle {
|
||||
LoggerHandle(LoggerHandle const&) = delete;
|
||||
|
||||
@@ -209,10 +209,15 @@ void MDProducerHandle::mark_deleted() {
|
||||
TimeStamp ts = TimeStamp::now();
|
||||
cdata().deleted = true;
|
||||
std::array<PriceSize,COCONUT_MAX_DEPTH> blank;
|
||||
std::array<PriceSize,COCONUT_MAX_IMPLIED_DEPTH> iblank;
|
||||
for (size_t x = 0; x < blank.size(); ++x) {
|
||||
blank[x] = PriceSize::NO_MARKET;
|
||||
if (x < COCONUT_MAX_IMPLIED_DEPTH) {
|
||||
iblank[x] = PriceSize::NO_MARKET;
|
||||
}
|
||||
}
|
||||
update_book(ts, blank, blank, 0);
|
||||
update_direct(ts, blank, blank, 0);
|
||||
update_implied(ts, iblank, iblank, 0);
|
||||
}
|
||||
|
||||
}}//namespace
|
||||
|
||||
@@ -34,8 +34,8 @@ public:
|
||||
}
|
||||
void set_legs(const std::vector<security_key>& legs);
|
||||
|
||||
void update_bbo(TimeStamp time, const PriceSize bid_price, const PriceSize ask_price, uint16_t seq=0); // hot
|
||||
void update_book(TimeStamp time, std::array<PriceSize,COCONUT_MAX_DEPTH>& bids, std::array<PriceSize,COCONUT_MAX_DEPTH>& asks, uint32_t seq=0) {
|
||||
void update_bbo(TimeStamp time, const PriceSize bid_price, const PriceSize ask_price, uint16_t seq=0);
|
||||
void update_direct(TimeStamp time, std::array<PriceSize,COCONUT_MAX_DEPTH>& bids, std::array<PriceSize,COCONUT_MAX_DEPTH>& asks, uint32_t seq=0) {
|
||||
if (!has_depth()) {
|
||||
update_bbo(time, bids[0], asks[0], seq);
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
hheader().direct_count += 1;
|
||||
}
|
||||
}
|
||||
void update_implied(TimeStamp time, std::array<PriceSize,COCONUT_IMPLIED_DEPTH>& bids, std::array<PriceSize,COCONUT_IMPLIED_DEPTH>& asks, uint32_t seq=0) {
|
||||
void update_implied(TimeStamp time, std::array<PriceSize,COCONUT_MAX_IMPLIED_DEPTH>& bids, std::array<PriceSize,COCONUT_MAX_IMPLIED_DEPTH>& asks, uint32_t seq=0) {
|
||||
if (has_depth()) {
|
||||
auto& book = hdepth();
|
||||
book.set_time(TimeStamp::invalid());
|
||||
|
||||
@@ -52,7 +52,7 @@ class HotEntry {
|
||||
static_assert(sizeof(HotEntry) <= CACHE_LINE, "HotEntry should be small");
|
||||
|
||||
const uint32_t COCONUT_MAX_DEPTH = 10;
|
||||
const uint32_t COCONUT_IMPLIED_DEPTH = 2;
|
||||
const uint32_t COCONUT_MAX_IMPLIED_DEPTH = 2;
|
||||
class HotDepthEntry {
|
||||
std::atomic<TimeStamp> timestamp; // 8
|
||||
public:
|
||||
@@ -68,7 +68,7 @@ class HotDepthEntry {
|
||||
security_key key; // 4 NOTE: key is at a different offset than it is in HotEntry
|
||||
uint32_t sequence; // 4
|
||||
std::array<PriceLevel, COCONUT_MAX_DEPTH> direct; // 240
|
||||
std::array<PriceLevel, COCONUT_IMPLIED_DEPTH> implied; // 48
|
||||
std::array<PriceLevel, COCONUT_MAX_IMPLIED_DEPTH> implied; // 48
|
||||
uint8_t status; // 1
|
||||
|
||||
const PriceLevel* at(uint32_t depth) const {
|
||||
|
||||
@@ -60,7 +60,7 @@ class RelayProducer : public IRelayWriter {
|
||||
bids[x] = book_at(update.book().bids(), x);
|
||||
asks[x] = book_at(update.book().asks(), x);
|
||||
}
|
||||
handle.update_book(updated, bids, asks);
|
||||
handle.update_direct(updated, bids, asks);
|
||||
}
|
||||
if (update.has_misc()) {
|
||||
auto& misc = update.misc();
|
||||
|
||||
@@ -38,7 +38,7 @@ void setup_market(MDProducerHandle producer, const vector<PS>& bids, const vecto
|
||||
std::transform(bids.begin(), bids.end(), bids_a.begin(), [](const PS& ps) { return PriceSize::from_double<7>(ps.price, ps.size); });
|
||||
std::transform(asks.begin(), asks.end(), asks_a.begin(), [](const PS& ps) { return PriceSize::from_double<7>(ps.price, ps.size); });
|
||||
|
||||
producer.update_book(ts, bids_a, asks_a);
|
||||
producer.update_direct(ts, bids_a, asks_a);
|
||||
}
|
||||
|
||||
void expect_market(const MDConsumerHandle& handle, const vector<PS> bids, const vector<PS>& asks) {
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace orderman {
|
||||
|
||||
struct AsyncFactory::PImpl
|
||||
{
|
||||
PImpl() :
|
||||
PImpl(DynamicOrderRegistry const&b) :
|
||||
orders_stream(),
|
||||
fix_buffer_stream(),
|
||||
db(),
|
||||
order_router(),
|
||||
order_factory(db,order_router)
|
||||
order_factory(db,order_router,b)
|
||||
{}
|
||||
|
||||
mercury::Stream<CreateOrderReplyEvent> orders_stream;
|
||||
@@ -32,7 +32,7 @@ struct AsyncFactory::PImpl
|
||||
OrderFactory order_factory;
|
||||
};
|
||||
|
||||
AsyncFactory::AsyncFactory() : me(new PImpl()) {}
|
||||
AsyncFactory::AsyncFactory(DynamicOrderRegistry const&b) : me(new PImpl(b)) {}
|
||||
AsyncFactory::~AsyncFactory () {}
|
||||
|
||||
void AsyncFactory::init()
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
class DynamicOrderRegistry;
|
||||
|
||||
// used to asynchronously build fix buffers and orders
|
||||
class AsyncFactory : public mercury::Actor
|
||||
{
|
||||
public:
|
||||
AsyncFactory();
|
||||
AsyncFactory(DynamicOrderRegistry const&);
|
||||
~AsyncFactory();
|
||||
|
||||
void init() override;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "ServiceBridge.h"
|
||||
|
||||
#include "lib/api/public/ServiceContext.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/orderman/events/ActivateOrderEvent.h"
|
||||
#include "lib/orderman/events/CancelOrderEvent.h"
|
||||
#include "lib/orderman/events/CrackOrderEvent.h"
|
||||
#include "lib/orderman/events/NewAdminDataEvent.h"
|
||||
#include "lib/orderman/events/NewSecuritiesEvent.h"
|
||||
#include "lib/orderman/events/OrderManagerReadyEvent.h"
|
||||
#include "lib/orderman/events/StoredFillEvent.h"
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "lib/orderman/order_factory/OrderFactory.h"
|
||||
#include "lib/orderman/order_router/OrderRouter.h"
|
||||
#include "lib/orderman/securities/MapSecurityDB.h"
|
||||
#include "lib/orderman/events/NewAdminDataEvent.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
@@ -24,12 +24,13 @@ namespace orderman {
|
||||
|
||||
struct ServiceBridge::PImpl {
|
||||
PImpl(OnReady const &on_ready, OnOrders const &on_orders,
|
||||
OnFills const &on_fills)
|
||||
OnFills const &on_fills,
|
||||
DynamicOrderRegistry const &dyn_order_registry)
|
||||
: on_ready(on_ready), on_orders(on_orders), on_fills(on_fills),
|
||||
have_orders(false), have_securities(false), order_manager_ready(false),
|
||||
sec_db(), order_router(), order_factory(sec_db, order_router),
|
||||
known_orders() {
|
||||
}
|
||||
sec_db(), order_router(),
|
||||
order_factory(sec_db, order_router, dyn_order_registry),
|
||||
known_orders() {}
|
||||
|
||||
OnReady on_ready;
|
||||
OnOrders on_orders;
|
||||
@@ -47,20 +48,18 @@ struct ServiceBridge::PImpl {
|
||||
mercury::Stream<NewAdminDataEvent> new_admin_data_pub;
|
||||
std::unordered_set<OrderKey> known_orders;
|
||||
std::vector<std::shared_ptr<const api::admin::AdminData>> admin_data_updates;
|
||||
|
||||
|
||||
std::promise<void> ready;
|
||||
};
|
||||
|
||||
ServiceBridge::ServiceBridge(OnReady const &on_ready, OnOrders const &on_orders,
|
||||
OnFills const &on_fills)
|
||||
: me(new PImpl(on_ready, on_orders, on_fills)) {}
|
||||
OnFills const &on_fills,
|
||||
DynamicOrderRegistry const &dyn_order_registry)
|
||||
: me(new PImpl(on_ready, on_orders, on_fills, dyn_order_registry)) {}
|
||||
|
||||
ServiceBridge::~ServiceBridge() {}
|
||||
|
||||
void ServiceBridge::block_until_ready()
|
||||
{
|
||||
me->ready.get_future().wait();
|
||||
}
|
||||
void ServiceBridge::block_until_ready() { me->ready.get_future().wait(); }
|
||||
|
||||
void ServiceBridge::init() {
|
||||
subscribe<NewAdminDataEvent>([this](auto const &u) { this->on(u); });
|
||||
@@ -125,8 +124,8 @@ void ServiceBridge::on(mercury::Update<OrderManagerReadyEvent> const &update) {
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceBridge::on(mercury::Update<NewAdminDataEvent> const&update) {
|
||||
if (update.events)
|
||||
void ServiceBridge::on(mercury::Update<NewAdminDataEvent> const &update) {
|
||||
if (update.events)
|
||||
for (auto ev : *(update.events))
|
||||
me->order_router.update(*ev.admin_data);
|
||||
}
|
||||
@@ -233,12 +232,12 @@ ServiceBridge::crack_order(api::orderman::Crack const &c) {
|
||||
return f.get();
|
||||
}
|
||||
|
||||
void ServiceBridge::update_admin_data(std::shared_ptr<const api::admin::AdminData> const&admin)
|
||||
{
|
||||
void ServiceBridge::update_admin_data(
|
||||
std::shared_ptr<const api::admin::AdminData> const &admin) {
|
||||
post_action([this, admin]() {
|
||||
me->admin_data_updates.push_back (admin);
|
||||
publish(me->new_admin_data_pub,*admin);
|
||||
});
|
||||
me->admin_data_updates.push_back(admin);
|
||||
publish(me->new_admin_data_pub, *admin);
|
||||
});
|
||||
}
|
||||
|
||||
bool ServiceBridge::is_ready() const {
|
||||
@@ -249,5 +248,5 @@ void ServiceBridge::maybe_signal_ready(bool old_ready) {
|
||||
if (!old_ready && is_ready())
|
||||
me->on_ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -1,14 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "lib/mercury/actors/Actor.h"
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/mercury/actors/Actor.h"
|
||||
#include <memory>
|
||||
|
||||
// fwds
|
||||
namespace bts {
|
||||
namespace api {
|
||||
class ServiceContext;
|
||||
namespace admin { class AdminData;}
|
||||
namespace admin {
|
||||
class AdminData;
|
||||
}
|
||||
namespace orderman {
|
||||
class OrderRecord;
|
||||
class Fill;
|
||||
@@ -17,32 +19,36 @@ class Create;
|
||||
class Update;
|
||||
class Cancel;
|
||||
class Crack;
|
||||
}}
|
||||
} // namespace orderman
|
||||
} // namespace api
|
||||
namespace orderman {
|
||||
class StoredFillEvent;
|
||||
class StoredOrderEvent;
|
||||
class NewSecuritiesEvent;
|
||||
class OrderManagerReadyEvent;
|
||||
class NewAdminDataEvent;
|
||||
}}
|
||||
class DynamicOrderRegistry;
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
// end fwds
|
||||
|
||||
|
||||
// Provides a threading bridge between the quickbux/service world and
|
||||
// the mercury event broker.
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
class ServiceBridge : public mercury::Actor
|
||||
{
|
||||
public:
|
||||
template <class EV> using OnEv = std::function<void(EV const&)>;
|
||||
class ServiceBridge : public mercury::Actor {
|
||||
public:
|
||||
template <class EV> using OnEv = std::function<void(EV const &)>;
|
||||
|
||||
using OnReady = std::function<void()>;
|
||||
using OnOrders = std::function<void (std::vector<api::orderman::OrderRecord> const& )>;
|
||||
using OnFills = std::function<void (std::vector<api::orderman::Fill> const&)>;
|
||||
|
||||
ServiceBridge(OnReady const&, OnOrders const&, OnFills const&);
|
||||
using OnOrders =
|
||||
std::function<void(std::vector<api::orderman::OrderRecord> const &)>;
|
||||
using OnFills =
|
||||
std::function<void(std::vector<api::orderman::Fill> const &)>;
|
||||
|
||||
ServiceBridge(OnReady const &, OnOrders const &, OnFills const &,
|
||||
DynamicOrderRegistry const &);
|
||||
void init() override;
|
||||
~ServiceBridge();
|
||||
|
||||
@@ -50,23 +56,25 @@ public:
|
||||
void block_until_ready();
|
||||
|
||||
// these can be called from any thread, after block_until_ready() returns
|
||||
api::orderman::Response create_order(api::orderman::Create const&c);
|
||||
api::orderman::Response update_order(api::orderman::Update const&c);
|
||||
api::orderman::Response cancel_order(api::orderman::Cancel const&c);
|
||||
api::orderman::Response crack_order(api::orderman::Crack const&c);
|
||||
void update_admin_data(std::shared_ptr<api::admin::AdminData const> const &admin);
|
||||
|
||||
private:
|
||||
api::orderman::Response create_order(api::orderman::Create const &c);
|
||||
api::orderman::Response update_order(api::orderman::Update const &c);
|
||||
api::orderman::Response cancel_order(api::orderman::Cancel const &c);
|
||||
api::orderman::Response crack_order(api::orderman::Crack const &c);
|
||||
void
|
||||
update_admin_data(std::shared_ptr<api::admin::AdminData const> const &admin);
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
bool is_ready () const;
|
||||
bool is_ready() const;
|
||||
void maybe_signal_ready(bool old_ready);
|
||||
|
||||
void on(mercury::Update<StoredFillEvent> const&);
|
||||
void on(mercury::Update<StoredOrderEvent> const&);
|
||||
void on(mercury::Update<NewSecuritiesEvent> const&);
|
||||
void on(mercury::Update<OrderManagerReadyEvent> const&);
|
||||
void on(mercury::Update<NewAdminDataEvent> const&);
|
||||
|
||||
void on(mercury::Update<StoredFillEvent> const &);
|
||||
void on(mercury::Update<StoredOrderEvent> const &);
|
||||
void on(mercury::Update<NewSecuritiesEvent> const &);
|
||||
void on(mercury::Update<OrderManagerReadyEvent> const &);
|
||||
void on(mercury::Update<NewAdminDataEvent> const &);
|
||||
};
|
||||
|
||||
}}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -40,7 +40,8 @@ struct OrderManager::OrderInfo {
|
||||
};
|
||||
|
||||
struct OrderManager::PImpl {
|
||||
PImpl(Actor &owner) : state(State::WAIT_ADMIN), services_data(owner) {}
|
||||
PImpl(Actor &owner, DynamicOrderRegistry const &b)
|
||||
: state(State::WAIT_ADMIN), services_data(owner, b) {}
|
||||
|
||||
State state;
|
||||
std::unordered_map<OrderKey, OrderInfo> orders;
|
||||
@@ -50,7 +51,7 @@ struct OrderManager::PImpl {
|
||||
mercury::Stream<OrderManagerReadyEvent> pub_ready;
|
||||
};
|
||||
|
||||
OrderManager::OrderManager() : me(new PImpl(*this)) {}
|
||||
OrderManager::OrderManager(DynamicOrderRegistry const&b) : me(new PImpl(*this,b)) {}
|
||||
OrderManager::~OrderManager() {}
|
||||
|
||||
void OrderManager::init() {
|
||||
@@ -202,8 +203,7 @@ void OrderManager::on_activate_order(
|
||||
OrderInfo oi{*order, me->services_data};
|
||||
auto serv_ptr = oi.order_services.get();
|
||||
me->orders[k] = std::move(oi);
|
||||
order->on_activate(ev.price, ev.quantity, *serv_ptr,
|
||||
ev.trace);
|
||||
order->on_activate(ev.price, ev.quantity, *serv_ptr, ev.trace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,8 +213,7 @@ void OrderManager::on_update_order(const mercury::Update<UpdateOrderEvent> &m) {
|
||||
auto k = ev.key();
|
||||
auto it = me->orders.find(k);
|
||||
if (it != me->orders.end())
|
||||
it->second.order->on_update(ev.price, ev.quantity,
|
||||
ev.trace);
|
||||
it->second.order->on_update(ev.price, ev.quantity, ev.trace);
|
||||
else {
|
||||
LOG(OrderMan, Error,
|
||||
"Received an update request for an unknown order {}. "
|
||||
|
||||
@@ -22,6 +22,7 @@ class StoredFillEvent;
|
||||
class CreateFIXBufferReplyEvent;
|
||||
class GatewayStatusChangeEvent;
|
||||
class NewAdminDataEvent;
|
||||
class DynamicOrderRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ namespace orderman {
|
||||
|
||||
class OrderManager : public mercury::Actor {
|
||||
public:
|
||||
OrderManager();
|
||||
OrderManager(DynamicOrderRegistry const&dyn_order_builder);
|
||||
~OrderManager();
|
||||
void init() override;
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
OrderServicesData::OrderServicesData(mercury::Actor &owner)
|
||||
: owner(owner), order_router(), order_factory(sec_db, order_router),
|
||||
OrderServicesData::OrderServicesData(mercury::Actor &owner,DynamicOrderRegistry const&b)
|
||||
: owner(owner), order_router(), order_factory(sec_db, order_router,b),
|
||||
last_timer_ev(
|
||||
Timer::now(),
|
||||
to<mercury::TimeStampStr>(datetime::FIX_timestamp(datetime::now()))) {
|
||||
|
||||
@@ -67,13 +67,14 @@ struct SessionServicesData {
|
||||
|
||||
class OrderServicesData {
|
||||
public:
|
||||
OrderServicesData(mercury::Actor &owner);
|
||||
OrderServicesData(mercury::Actor &owner,DynamicOrderRegistry const&b);
|
||||
|
||||
mercury::Actor &owner;
|
||||
securities::MapSecurityDB sec_db;
|
||||
OrderRouter order_router;
|
||||
Limiter limiter;
|
||||
OrderFactory order_factory;
|
||||
|
||||
|
||||
std::unique_ptr<mercury::ContentSubscription<BookUpdateEvent>> md_subs;
|
||||
std::unique_ptr<
|
||||
mercury::ContentSubscription<OrderStateUpdateEvent, ParentKey>>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
class DynamicOrder;
|
||||
|
||||
using DynamicOrderBuilder = std::function<std::unique_ptr<DynamicOrder>()>;
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "DynamicOrderRegistry.h"
|
||||
#include "lib/orderman/orders/DynamicOrder.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
struct DynamicOrderRegistry::PImpl {
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
std::pair<DynamicOrderBuilder, api::orderman::DynamicOrderDescriptor>>
|
||||
dyn_orders;
|
||||
};
|
||||
|
||||
DynamicOrderRegistry::DynamicOrderRegistry() : me(new PImpl()) {}
|
||||
DynamicOrderRegistry::~DynamicOrderRegistry() {}
|
||||
|
||||
void DynamicOrderRegistry::register_dynamic_order(
|
||||
api::orderman::DynamicOrderDescriptor const &desc,
|
||||
DynamicOrderBuilder const &b) {
|
||||
me->dyn_orders[desc.dynamic_order_type()] = std::make_pair(b, desc);
|
||||
}
|
||||
|
||||
std::unique_ptr<DynamicOrder>
|
||||
DynamicOrderRegistry::build(std::string const &dynamic_order_type) const {
|
||||
auto it = me->dyn_orders.find(dynamic_order_type);
|
||||
if (it != me->dyn_orders.end())
|
||||
return it->second.first();
|
||||
else
|
||||
return std::unique_ptr<DynamicOrder>();
|
||||
}
|
||||
|
||||
std::vector<api::orderman::DynamicOrderDescriptor>
|
||||
DynamicOrderRegistry::get_all_dynamic_order_types() const {
|
||||
|
||||
std::vector<api::orderman::DynamicOrderDescriptor> result;
|
||||
for (auto const &ot : me->dyn_orders)
|
||||
result.push_back(ot.second.second);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/orderman/order_factory/DynamicOrderBuilder.h"
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
|
||||
class DynamicOrderRegistry {
|
||||
public:
|
||||
DynamicOrderRegistry();
|
||||
~DynamicOrderRegistry();
|
||||
|
||||
void register_dynamic_order(api::orderman::DynamicOrderDescriptor const&desc,
|
||||
DynamicOrderBuilder const&builder);
|
||||
|
||||
// can return a null if no such order type exists
|
||||
std::unique_ptr<DynamicOrder> build(std::string const&dynamic_order_type) const;
|
||||
|
||||
std::vector<api::orderman::DynamicOrderDescriptor> get_all_dynamic_order_types() const;
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr <PImpl> me;
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -1,24 +1,25 @@
|
||||
#include "OrderFactory.h"
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/orderman_utils/ExecutionReport.h"
|
||||
#include "lib/orderman/orders/PreActivationOrderServices.h"
|
||||
#include "lib/utils/Puid.h"
|
||||
#include "lib/utils/SpinLock.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/orderman/orderman_utils/ExecutionReport.h"
|
||||
#include "lib/orderman/orders/PreActivationOrderServices.h"
|
||||
|
||||
// order types
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
#include "lib/orderman/orders/DynamicOrder.h"
|
||||
#include "lib/orderman/orders/IcebergOrder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/SpreaderOrder.h"
|
||||
#include "lib/orderman/orders/NativeOrder.h"
|
||||
#include "lib/orderman/orders/TimeBoxOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TickOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/LeanOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/JoinOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TopOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/CoverOrder.h"
|
||||
#include "lib/orderman/orders/TriggerOrder.h"
|
||||
#include "lib/orderman/orders/DynamicOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/CoverOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/JoinOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/LeanOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TickOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/TopOrder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/SpreaderOrder.h"
|
||||
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
@@ -48,16 +49,20 @@ OrderKey gen_order_id() {
|
||||
}
|
||||
|
||||
struct OrderFactory::PImpl {
|
||||
PImpl(securities::ISecurityDB &db,OrderRouter const&router)
|
||||
: my_orders(), sec_db(db), router(router){}
|
||||
PImpl(securities::ISecurityDB &db, OrderRouter const &router,
|
||||
DynamicOrderRegistry const &dr)
|
||||
: my_orders(), sec_db(db), router(router), dynamic_order_registry(dr) {}
|
||||
|
||||
std::vector<std::unique_ptr<Order>> my_orders;
|
||||
securities::ISecurityDB &sec_db;
|
||||
OrderRouter const&router;
|
||||
OrderRouter const &router;
|
||||
DynamicOrderRegistry const &dynamic_order_registry;
|
||||
};
|
||||
|
||||
OrderFactory::OrderFactory(securities::ISecurityDB &db, OrderRouter const&router)
|
||||
: me(new PImpl(db, router)) {}
|
||||
OrderFactory::OrderFactory(securities::ISecurityDB &db,
|
||||
OrderRouter const &router,
|
||||
DynamicOrderRegistry const ®istry)
|
||||
: me(new PImpl(db, router, registry)) {}
|
||||
|
||||
OrderFactory::~OrderFactory() {}
|
||||
|
||||
@@ -66,8 +71,8 @@ Order &OrderFactory::create(OrderKey parent,
|
||||
auto k = gen_order_id();
|
||||
auto pk = parent;
|
||||
auto &order = allocate(k, pk, def);
|
||||
order.on_init_new(def,
|
||||
PreActivationOrderServices{me->sec_db, *this,me->router});
|
||||
order.on_init_new(def,
|
||||
PreActivationOrderServices{me->sec_db, *this, me->router});
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -76,7 +81,7 @@ Order &OrderFactory::recover(api::orderman::OrderRecord const &rec) {
|
||||
auto pk = OrderKey(rec.parent_key());
|
||||
auto &order = allocate(k, pk, rec.def());
|
||||
order.on_init_recovered(
|
||||
rec, PreActivationOrderServices{me->sec_db, *this,me->router});
|
||||
rec, PreActivationOrderServices{me->sec_db, *this, me->router});
|
||||
return order;
|
||||
}
|
||||
|
||||
@@ -90,7 +95,7 @@ Order &OrderFactory::recreate_from_exe_report(ExecutionReport const &r) {
|
||||
case NATIVE_ORDER_TYPE_STOP_LIMIT: {
|
||||
auto native_order = std::make_unique<NativeOrder>();
|
||||
native_order->on_init_from_exe_report(
|
||||
r, PreActivationOrderServices{me->sec_db, *this,me->router});
|
||||
r, PreActivationOrderServices{me->sec_db, *this, me->router});
|
||||
native_order->_key = r.order_key;
|
||||
native_order->_parent_key = null_order_key();
|
||||
me->my_orders.emplace_back();
|
||||
@@ -122,32 +127,40 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
|
||||
order_ptr.reset(new IcebergOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kSpreader:
|
||||
order_ptr.reset (new orderman::SpreaderOrder());
|
||||
order_ptr.reset(new orderman::SpreaderOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTimeBox:
|
||||
order_ptr.reset (new orderman::TimeBoxOrder());
|
||||
order_ptr.reset(new orderman::TimeBoxOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTick:
|
||||
order_ptr.reset (new orderman::TickOrder());
|
||||
order_ptr.reset(new orderman::TickOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kLean:
|
||||
order_ptr.reset (new orderman::LeanOrder());
|
||||
break;
|
||||
order_ptr.reset(new orderman::LeanOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kJoin:
|
||||
order_ptr.reset (new orderman::JoinOrder());
|
||||
order_ptr.reset(new orderman::JoinOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTop:
|
||||
order_ptr.reset (new orderman::TopOrder());
|
||||
order_ptr.reset(new orderman::TopOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kTrigger:
|
||||
order_ptr.reset (new orderman::TriggerOrder());
|
||||
order_ptr.reset(new orderman::TriggerOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kCover:
|
||||
order_ptr.reset (new orderman::CoverOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kDynamic:
|
||||
order_ptr.reset (new orderman::DynamicOrder());
|
||||
order_ptr.reset(new orderman::CoverOrder());
|
||||
break;
|
||||
case CustomOrderDefinition::kDynamic: {
|
||||
order_ptr = me->dynamic_order_registry.build(
|
||||
def.custom_def().dynamic().dynamic_order_type());
|
||||
if (!order_ptr) {
|
||||
// the default dynamic order is empty and will transition
|
||||
// immediately to an error state, so we use it when we cannot
|
||||
// resolve the requested type
|
||||
order_ptr.reset(new orderman::DynamicOrder());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomOrderDefinition::CUSTOM_NOT_SET:
|
||||
bts_assert(false);
|
||||
break;
|
||||
@@ -156,5 +169,5 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
|
||||
order_ptr->_parent_key = pk;
|
||||
return *order_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -11,7 +11,8 @@ class ISecurityDB;
|
||||
}
|
||||
namespace orderman {
|
||||
class Order;
|
||||
}
|
||||
class DynamicOrderRegistry;
|
||||
} // namespace orderman
|
||||
namespace orderman {
|
||||
class OrderRouter;
|
||||
}
|
||||
@@ -32,7 +33,8 @@ namespace orderman {
|
||||
|
||||
class OrderFactory : public IOrderFactory {
|
||||
public:
|
||||
OrderFactory(securities::ISecurityDB &db, OrderRouter const &router);
|
||||
OrderFactory(securities::ISecurityDB &db, OrderRouter const &router,
|
||||
DynamicOrderRegistry const &dynamic_order_reg);
|
||||
~OrderFactory();
|
||||
|
||||
Order &create(OrderKey parent,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
|
||||
namespace bts{
|
||||
namespace orderman{
|
||||
|
||||
using namespace bts::api::orderman;
|
||||
|
||||
inline bool order_in_error_state(OrderStatus order_status){
|
||||
return order_status == OrderStatus::ORDER_STATUS_ERROR ||
|
||||
order_status == OrderStatus::ORDER_STATUS_DISCONNECTED ||
|
||||
order_status == OrderStatus::ORDER_STATUS_REJECTED_BY_SPARK;
|
||||
}
|
||||
|
||||
inline bool order_in_working_state(OrderStatus order_status){
|
||||
return order_status == OrderStatus::ORDER_STATUS_WORKING ||
|
||||
order_status == OrderStatus::ORDER_STATUS_PENDING_WORKING;
|
||||
}
|
||||
|
||||
inline bool is_exchange_order(const OrderState& state){
|
||||
return state.has_market() ||
|
||||
state.has_limit() ||
|
||||
state.has_stop() ||
|
||||
state.has_stop_limit();
|
||||
}
|
||||
|
||||
inline bool is_parent_order(const OrderRecord& ord){
|
||||
return ord.parent_key()==0;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -15,7 +15,6 @@ struct DynamicOrder::PImpl {
|
||||
api::orderman::OrderState state;
|
||||
};
|
||||
|
||||
|
||||
DynamicOrder::DynamicOrder() : me(new PImpl()) {}
|
||||
|
||||
DynamicOrder::~DynamicOrder() {}
|
||||
@@ -27,13 +26,14 @@ api::orderman::OrderDefinition const &DynamicOrder::definition() const {
|
||||
void DynamicOrder::on_init_new(api::orderman::OrderDefinition const &def,
|
||||
const PreActivationOrderServices &) {
|
||||
me->def = def;
|
||||
me->state.mutable_trigger();
|
||||
me->state.mutable_dynamic();
|
||||
|
||||
auto const &dynamic_def = def.custom_def().dynamic();
|
||||
auto msg = fmt::format("Could not find implementation for dynamic order type {}",
|
||||
dynamic_def.dynamic_order_type());
|
||||
auto msg =
|
||||
fmt::format("Could not find implementation for dynamic order type {}",
|
||||
dynamic_def.dynamic_order_type());
|
||||
me->state.set_status(ORDER_STATUS_REJECTED_BY_SPARK);
|
||||
me->state.set_last_msg(msg);
|
||||
transition(ORDER_STATUS_REJECTED_BY_SPARK, msg);
|
||||
}
|
||||
|
||||
void DynamicOrder::on_init_recovered(api::orderman::OrderRecord const &rec,
|
||||
@@ -41,35 +41,21 @@ void DynamicOrder::on_init_recovered(api::orderman::OrderRecord const &rec,
|
||||
auto const &def = rec.def();
|
||||
me->def = def;
|
||||
me->state = rec.state();
|
||||
auto msg = fmt::format("Could not find implementation for dynamic order type {}",
|
||||
def.custom_def().dynamic().dynamic_order_type());
|
||||
transition(ORDER_STATUS_ERROR, msg);
|
||||
}
|
||||
|
||||
void DynamicOrder::on_activate(Price , Quantity , OrderServices &services,
|
||||
PerfTrace const&) {
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicOrder::on_update(Price , Quantity , PerfTrace const&) {}
|
||||
void DynamicOrder::on_crack(PerfTrace const&) {}
|
||||
void DynamicOrder::on_cancel(PerfTrace const&) {}
|
||||
|
||||
void DynamicOrder::transition(api::orderman::OrderStatus new_status,
|
||||
std::string const &msg) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
auto const &to = OrderStatus_Name(new_status);
|
||||
LOG(OrderMan, Info, "Transitioning dynamic order {} from {} to {}. Msg: {}",
|
||||
key().value(), from, to, msg);
|
||||
auto msg =
|
||||
fmt::format("Could not find implementation for dynamic order type {}",
|
||||
def.custom_def().dynamic().dynamic_order_type());
|
||||
me->state.set_status(ORDER_STATUS_REJECTED_BY_SPARK);
|
||||
me->state.set_last_msg(msg);
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
void DynamicOrder::report_state() {
|
||||
me->services->report_state(me->state);
|
||||
void DynamicOrder::on_activate(Price, Quantity, OrderServices &services,
|
||||
PerfTrace const &) {
|
||||
services.report_state(me->state);
|
||||
}
|
||||
|
||||
void DynamicOrder::on_update(Price, Quantity, PerfTrace const &) {}
|
||||
void DynamicOrder::on_crack(PerfTrace const &) {}
|
||||
void DynamicOrder::on_cancel(PerfTrace const &) {}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -25,8 +25,6 @@ public:
|
||||
void on_cancel(PerfTrace const&) override ;
|
||||
|
||||
private:
|
||||
void report_state();
|
||||
void transition(api::orderman::OrderStatus new_state,std::string const&msg);
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
};
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
.separator ","
|
||||
create table trace (md integer,spreader_on_book integer,event_type text,md_src integer,event_id integer,spreader_modify_order integer,order_update integer,fix_socket_r integer,spreader_on_child_order_update integer,md_sn integer,s2s_us integer,fix_socket_w integer,exe_gw integer);
|
||||
.import trace.csv trace
|
||||
create view tick_to_order as select
|
||||
event_id,
|
||||
(fix_socket_w - md) / 1000 total,
|
||||
(md_src-md)/1000 md_to_md_src,
|
||||
(spreader_on_book-md_src)/1000 md_src_to_spreader,
|
||||
(spreader_modify_order-spreader_on_book)/1000 spreader_on_book_to_modify_order,
|
||||
(order_update-spreader_modify_order)/1000 spreader_modify_order_to_native_order,
|
||||
(exe_gw-order_update)/1000 native_order_to_gw,
|
||||
(fix_socket_w - exe_gw)/1000 gw_to_socket
|
||||
from trace where md<>0 and total < 3000 and spreader_modify_order<>0;
|
||||
File diff suppressed because it is too large.
Load diff
Binary file not shown.
@@ -10,7 +10,8 @@ def gen_create_table(d,t):
|
||||
fields = [ "%s integer" % k if isinstance (v,int) else "%s text" % k for (k,v) in d.iteritems()]
|
||||
print ".separator \",\"\ncreate table trace (%s);" % ",".join(fields)
|
||||
print ".import %s trace" % t
|
||||
print '''create view tick_to_order as select
|
||||
print '''
|
||||
create view tick_to_order as select
|
||||
event_id,
|
||||
order_key,
|
||||
(fix_socket_w - md) / 1000 total,
|
||||
@@ -19,8 +20,21 @@ def gen_create_table(d,t):
|
||||
(spreader_modify_order-spreader_on_book)/1000 spreader_on_book_to_modify_order,
|
||||
(order_update-spreader_modify_order)/1000 spreader_modify_order_to_native_order,
|
||||
(exe_gw-order_update)/1000 native_order_to_gw,
|
||||
(fix_socket_w - exe_gw)/1000 gw_to_socket
|
||||
from trace where md<>0 and total < 3000 and spreader_modify_order<>0;'''
|
||||
(fix_socket_w - exe_gw)/1000 gw_to_socket
|
||||
from trace where md<>0 and total < 3000 and spreader_modify_order<>0;
|
||||
|
||||
create view tick_to_order_perc as select
|
||||
event_id,
|
||||
total,
|
||||
round(100.0*md_to_md_src/total) md_to_md_src ,
|
||||
round(100.0*md_src_to_spreader/total) md_src_to_spreader ,
|
||||
round(100.0*spreader_on_book_to_modify_order/total) spreader_on_book_to_modify_order ,
|
||||
round(100.0*spreader_modify_order_to_native_order/total) spreader_modify_order_to_native_order ,
|
||||
round(100.0*native_order_to_gw/total) native_order_to_gw ,
|
||||
round(100.0*gw_to_socket/total) gw_to_socket
|
||||
from tick_to_order;
|
||||
|
||||
'''
|
||||
|
||||
def gen_insert(d):
|
||||
values = [ "%s" % v if isinstance (v,int) else "'%s'" % v for v in d.values()]
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
#include "lib/orderman/actors/SecuritySrc.h"
|
||||
#include "lib/orderman/actors/ServiceBridge.h"
|
||||
#include "lib/orderman/actors/order_manager/OrderManager.h"
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
#include "lib/plugin/plugin.h"
|
||||
#include "lib/plugin/SparkServices.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -24,6 +27,7 @@ namespace orderman {
|
||||
struct OrderServiceServer::PImpl {
|
||||
PImpl(bts::api::ServiceContext &ctx,
|
||||
std::shared_ptr<api::ISyntheticSecurityService> &ss,
|
||||
DynamicOrderRegistry const &d,
|
||||
metrics::MetricsContainer &stats)
|
||||
: fast_broker(std::make_shared<mercury::AsyncEventBroker>()),
|
||||
slow_broker(std::make_shared<mercury::AsyncEventBroker>()),
|
||||
@@ -31,7 +35,7 @@ struct OrderServiceServer::PImpl {
|
||||
fast_thread(), slow_thread(), service_ready(false), known_orders(),
|
||||
known_fills(), publish_orders(), publish_fills(),
|
||||
admin_service(ctx.locate<api::admin::AdminService>()), md_consumer(ss),
|
||||
stats(stats) {}
|
||||
stats(stats), dyn_order_registry(d) {}
|
||||
|
||||
std::shared_ptr<mercury::AsyncEventBroker> fast_broker;
|
||||
std::shared_ptr<mercury::AsyncEventBroker> slow_broker;
|
||||
@@ -49,14 +53,16 @@ struct OrderServiceServer::PImpl {
|
||||
api::admin::AdminService admin_service;
|
||||
bts::md::MDConsumer md_consumer;
|
||||
metrics::MetricsContainer &stats;
|
||||
DynamicOrderRegistry const &dyn_order_registry;
|
||||
};
|
||||
|
||||
OrderServiceServer::OrderServiceServer(
|
||||
bts::api::ServiceContext &ctx,
|
||||
std::shared_ptr<api::ISyntheticSecurityService> &ss,
|
||||
DynamicOrderRegistry const&d,
|
||||
metrics::MetricsContainer &stats)
|
||||
: api::orderman::OrderServiceBase(ctx), me(new PImpl(ctx, ss, stats)) {
|
||||
|
||||
: api::orderman::OrderServiceBase(ctx), me(new PImpl(ctx, ss, d,stats)) {
|
||||
|
||||
me->publish_orders = make_orders_publisher();
|
||||
me->publish_fills = make_fills_publisher();
|
||||
|
||||
@@ -69,18 +75,20 @@ OrderServiceServer::OrderServiceServer(
|
||||
|
||||
[this, &ctx](auto const &fill) {
|
||||
ctx.post([this, fill] { this->on_fills(fill); });
|
||||
});
|
||||
},
|
||||
|
||||
me->dyn_order_registry);
|
||||
|
||||
me->fast_broker->init_neighbours({me->slow_broker});
|
||||
me->slow_broker->init_neighbours({me->fast_broker});
|
||||
|
||||
// fast actors
|
||||
me->fast_exe.spawn<MDSource>(me->md_consumer, me->stats);
|
||||
me->fast_exe.spawn<OrderManager>();
|
||||
me->fast_exe.spawn<OrderManager>(me->dyn_order_registry);
|
||||
|
||||
auto &all_connections = config::get<config::JetFIX>().connection();
|
||||
for (auto const &c : all_connections)
|
||||
me->fast_exe.spawn<ExecutionGateway>(c,stats);
|
||||
me->fast_exe.spawn<ExecutionGateway>(c, stats);
|
||||
|
||||
me->fast_thread = std::thread([this]() {
|
||||
os::set_thread_name("fast_exe");
|
||||
@@ -105,7 +113,7 @@ OrderServiceServer::OrderServiceServer(
|
||||
// slow actors
|
||||
me->slow_exe.activate(me->service_bridge);
|
||||
me->slow_exe.spawn<mercury::Timer>();
|
||||
me->slow_exe.spawn<AsyncFactory>();
|
||||
me->slow_exe.spawn<AsyncFactory>(me->dyn_order_registry);
|
||||
me->slow_exe.spawn<OrderStore>();
|
||||
me->slow_exe.spawn<FillStore>();
|
||||
me->slow_exe.spawn<SecuritySrc>(me->md_consumer);
|
||||
@@ -225,5 +233,17 @@ void OrderServiceServer::crack_order(
|
||||
response = me->service_bridge->crack_order(crack);
|
||||
r(response);
|
||||
}
|
||||
|
||||
void OrderServiceServer::get_registered_dynamic_order_types(
|
||||
const api::VoidMessage &,
|
||||
const api::Response<api::orderman::RegisteredDynamicOrderTypes> &r) {
|
||||
api::orderman::RegisteredDynamicOrderTypes response;
|
||||
|
||||
auto all_orders = me->dyn_order_registry.get_all_dynamic_order_types();
|
||||
for (auto const &desc : all_orders)
|
||||
*response.add_dynamic_order_desc() = desc;
|
||||
r(response);
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -1,39 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/api/services/OrderService.server.pb.h"
|
||||
#include "lib/mercury/mercury_utils/IPollableActor.h"
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
namespace api { class ISyntheticSecurityService; }
|
||||
namespace metrics {class MetricsContainer;}
|
||||
namespace api {
|
||||
class ISyntheticSecurityService;
|
||||
}
|
||||
namespace metrics {
|
||||
class MetricsContainer;
|
||||
}
|
||||
namespace orderman {
|
||||
class DynamicOrderRegistry;
|
||||
|
||||
|
||||
class OrderServiceServer : public api::orderman::OrderServiceBase
|
||||
{
|
||||
public:
|
||||
OrderServiceServer (bts::api::ServiceContext& context,
|
||||
std::shared_ptr<api::ISyntheticSecurityService>&,
|
||||
metrics::MetricsContainer &);
|
||||
class OrderServiceServer : public api::orderman::OrderServiceBase {
|
||||
public:
|
||||
OrderServiceServer(bts::api::ServiceContext &context,
|
||||
std::shared_ptr<api::ISyntheticSecurityService> &,
|
||||
DynamicOrderRegistry const&,
|
||||
metrics::MetricsContainer &);
|
||||
~OrderServiceServer();
|
||||
|
||||
void create_order(const api::orderman::Create&,
|
||||
const api::Response<api::orderman::Response>&) override;
|
||||
void cancel_order(const api::orderman::Cancel&,
|
||||
const api::Response<api::orderman::Response>&) override;
|
||||
void update_order(const api::orderman::Update&,
|
||||
const api::Response<api::orderman::Response>&) override;
|
||||
void crack_order(const api::orderman::Crack&,
|
||||
const api::Response<api::orderman::Response>& ) override;
|
||||
private:
|
||||
void create_order(const api::orderman::Create &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void cancel_order(const api::orderman::Cancel &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void update_order(const api::orderman::Update &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void crack_order(const api::orderman::Crack &,
|
||||
const api::Response<api::orderman::Response> &) override;
|
||||
void get_registered_dynamic_order_types(
|
||||
const api::VoidMessage &,
|
||||
const api::Response<api::orderman::RegisteredDynamicOrderTypes> &)
|
||||
override;
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
void on_orders(std::vector<api::orderman::OrderRecord> const&);
|
||||
void on_fills (std::vector<api::orderman::Fill> const&);
|
||||
void on_orders(std::vector<api::orderman::OrderRecord> const &);
|
||||
void on_fills(std::vector<api::orderman::Fill> const &);
|
||||
};
|
||||
|
||||
|
||||
|
||||
}}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "SparkServices.h"
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
|
||||
namespace bts {
|
||||
|
||||
using namespace orderman;
|
||||
|
||||
struct SparkServices::PImpl {
|
||||
PImpl(orderman::DynamicOrderRegistry &r) : dyn_order_registry(r) {}
|
||||
DynamicOrderRegistry &dyn_order_registry;
|
||||
};
|
||||
|
||||
SparkServices::SparkServices(orderman::DynamicOrderRegistry &r)
|
||||
: me(new PImpl(r)) {}
|
||||
|
||||
SparkServices::~SparkServices() {}
|
||||
|
||||
void SparkServices::register_dynamic_order(
|
||||
api::orderman::DynamicOrderDescriptor const &desc,
|
||||
std::function<std::unique_ptr<DynamicOrder>()> const &builder) {
|
||||
me->dyn_order_registry.register_dynamic_order(desc, builder);
|
||||
}
|
||||
|
||||
extern "C" void initialize_spark_plugin(SparkServices &) {}
|
||||
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace bts {
|
||||
|
||||
namespace orderman {
|
||||
class DynamicOrder;
|
||||
class DynamicOrderRegistry;
|
||||
} // namespace orderman
|
||||
|
||||
class SparkServices {
|
||||
public:
|
||||
SparkServices(orderman::DynamicOrderRegistry &);
|
||||
~SparkServices();
|
||||
|
||||
void register_dynamic_order(
|
||||
api::orderman::DynamicOrderDescriptor const &desc,
|
||||
std::function<std::unique_ptr<orderman::DynamicOrder>()> const &builder);
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
};
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/plugin/SparkServices.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/dll.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
||||
namespace bts {
|
||||
namespace plugin {
|
||||
|
||||
using namespace bts::orderman;
|
||||
|
||||
void init_plugins(SparkServices &services) {
|
||||
|
||||
static std::vector<decltype (boost::dll::import<void (SparkServices&)>(boost::filesystem::path(),""))> keep_alive;
|
||||
|
||||
auto plugin_path = os::sparkd_wd() + "/plugins/";
|
||||
if (!boost::filesystem::is_directory(plugin_path)) {
|
||||
LOG(Plugin, Info,
|
||||
"No plugin directory found at {}. Skipping plugin loading",
|
||||
plugin_path);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::filesystem::directory_iterator end;
|
||||
for (auto iter = boost::filesystem::directory_iterator(plugin_path);
|
||||
iter != end; ++iter) {
|
||||
auto &f = *iter;
|
||||
|
||||
auto pl = f.path().string();
|
||||
LOG(Plugin, Info, "Attempting to initialize plugin {}", pl);
|
||||
try {
|
||||
auto init_plugin = boost::dll::import<void(SparkServices &)>(
|
||||
f.path(), "init_spark_plugin");
|
||||
init_plugin(services);
|
||||
keep_alive.push_back(init_plugin);
|
||||
LOG(Plugin, Info, "Successfully initialized plugin {}", pl);
|
||||
} catch (boost::system::system_error const &e) {
|
||||
LOG(Plugin, Error,
|
||||
"Failed to initialize plugin {}. Error: {} (OS error code: {})",
|
||||
pl, std::string(e.what()), e.code());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace plugin
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace bts {
|
||||
class SparkServices;
|
||||
namespace plugin {
|
||||
void init_plugins(SparkServices &);
|
||||
}}
|
||||
@@ -7,8 +7,9 @@ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/sdk
|
||||
COMMENT "Building SDK"
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/make_sdk.sh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/build_example.sh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example/example.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/build_examples.sh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/md_publisher_example.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/examples/order_plugin_example.cpp
|
||||
server_layout)
|
||||
|
||||
add_custom_target(sdk_dir ALL DEPENDS ${CMAKE_BINARY_DIR}/sdk)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
g++ -isystem ../externals/include \
|
||||
-I ../include \
|
||||
-I ../include/spark \
|
||||
-o example \
|
||||
example.cpp \
|
||||
-Wl,-rpath,../lib \
|
||||
-L ../lib \
|
||||
-l spark \
|
||||
-llttng-ust \
|
||||
-ldl
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
g++ -isystem ../externals/include \
|
||||
-I ../include \
|
||||
-I ../include/spark \
|
||||
-o md_publisher_example \
|
||||
md_publisher_example.cpp \
|
||||
-Wl,-rpath,../lib \
|
||||
-L ../lib \
|
||||
-l spark \
|
||||
-llttng-ust \
|
||||
-ldl
|
||||
|
||||
g++ -isystem ../externals/include \
|
||||
-I ../include \
|
||||
-I ../include/spark \
|
||||
-fPIC \
|
||||
-g \
|
||||
-shared \
|
||||
-o order_plugin_example.so \
|
||||
order_plugin_example.cpp \
|
||||
-Wl,-rpath,.. \
|
||||
-L ../lib \
|
||||
-l spark
|
||||
@@ -4,10 +4,11 @@
|
||||
#include "spark/lib/md/MDProducer.h"
|
||||
#include "spark/lib/utils/PBUtils.h"
|
||||
#include "spark/lib/tracing/bts_trace_c.c"
|
||||
#include "spark/lib/md/cme/MDP3Utils.h"
|
||||
|
||||
using namespace bts;
|
||||
using namespace bts::md;
|
||||
|
||||
|
||||
void produce()
|
||||
{
|
||||
md::MDProducer producer(co2::PLATFORM_SIM);
|
||||
@@ -68,7 +69,7 @@ void produce()
|
||||
};
|
||||
|
||||
// Update book - this call does not use locks so should not be called concurrently
|
||||
producer_handles[0].update_book(utils::TimeStamp::now(), bids, asks);
|
||||
producer_handles[0].update_direct(utils::TimeStamp::now(), bids, asks);
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -0,0 +1,385 @@
|
||||
#include "spark/lib/logging/logging.h"
|
||||
#include "spark/lib/orderman/orders/DynamicOrder.h"
|
||||
#include "spark/lib/plugin/SparkServices.h"
|
||||
#include "spark/lib/orderman/actors/order_manager/ChildOrder.h"
|
||||
#include "spark/lib/orderman/actors/order_manager/OrderBuilder.h"
|
||||
#include "spark/lib/orderman/orders/DynamicOrder.h"
|
||||
#include "spark/lib/utils/PBUtils.h"
|
||||
|
||||
using namespace bts::api::orderman;
|
||||
using namespace bts::orderman;
|
||||
|
||||
namespace bts {
|
||||
namespace order_example {
|
||||
|
||||
class DynamicIcebergOrder : public DynamicOrder {
|
||||
public:
|
||||
DynamicIcebergOrder();
|
||||
~DynamicIcebergOrder();
|
||||
OrderDefinition const &definition() const override;
|
||||
void on_init_new(OrderDefinition const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
void on_init_recovered(OrderRecord const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
void on_activate(Price, Quantity, OrderServices &,
|
||||
PerfTrace const &) override;
|
||||
void on_update(Price, Quantity, PerfTrace const &) override;
|
||||
void on_crack(PerfTrace const &) override;
|
||||
void on_cancel(PerfTrace const &) override;
|
||||
|
||||
private:
|
||||
void report_state();
|
||||
void send_next_child_order();
|
||||
|
||||
void merge_states(OrderState const &iceberg_state,
|
||||
OrderState const &child_state, OrderState *merged);
|
||||
|
||||
void on_child_order_update(OrderStateUpdateEvent const &);
|
||||
void transition(OrderStatus new_state, std::string const &msg);
|
||||
void transition(OrderStatus new_state);
|
||||
|
||||
struct ActiveChild;
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
};
|
||||
|
||||
struct DynamicIcebergOrder::ActiveChild {
|
||||
ActiveChild() {}
|
||||
ChildOrder order;
|
||||
api::orderman::OrderState state;
|
||||
void clear() { state = api::orderman::OrderState(); }
|
||||
};
|
||||
|
||||
struct DynamicIcebergOrder::PImpl {
|
||||
PImpl() : services(nullptr), child() {}
|
||||
|
||||
OrderServices *services;
|
||||
api::orderman::OrderDefinition def;
|
||||
api::orderman::OrderState state;
|
||||
OrderBuilder child_builder;
|
||||
ActiveChild child;
|
||||
Quantity show_quantity;
|
||||
};
|
||||
|
||||
DynamicIcebergOrder::DynamicIcebergOrder() : me(new PImpl()) {}
|
||||
DynamicIcebergOrder::~DynamicIcebergOrder() {}
|
||||
api::orderman::OrderDefinition const &DynamicIcebergOrder::definition() const {
|
||||
return me->def;
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_init_new(
|
||||
api::orderman::OrderDefinition const &def,
|
||||
const PreActivationOrderServices &services) {
|
||||
me->def = def;
|
||||
me->state.mutable_dynamic();
|
||||
|
||||
auto const &iceberg_def = def.custom_def().dynamic();
|
||||
me->show_quantity =
|
||||
Quantity(iceberg_def.order_params().at("show_size").as_uint32());
|
||||
|
||||
auto child_def = def;
|
||||
*child_def.mutable_custom_def() =
|
||||
iceberg_def.order_params().at("child").as_order_def();
|
||||
if (me->show_quantity.value() != 0) {
|
||||
me->child_builder = OrderBuilder(
|
||||
key(), child_def, services,
|
||||
std::max((size_t)1, (size_t)(me->show_quantity).value() / 10));
|
||||
transition(ORDER_STATUS_INACTIVE);
|
||||
} else {
|
||||
auto msg = fmt::format("Show quantity must be greater than 0");
|
||||
me->state.set_last_msg(msg);
|
||||
transition(ORDER_STATUS_REJECTED_BY_SPARK, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_init_recovered(
|
||||
api::orderman::OrderRecord const &rec, const PreActivationOrderServices &) {
|
||||
auto const &def = rec.def();
|
||||
me->def = def;
|
||||
me->state = rec.state();
|
||||
|
||||
switch (me->state.status()) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_DISCONNECTED: {
|
||||
auto msg = "System restarted with active iceberg order";
|
||||
me->state.set_last_msg(msg);
|
||||
transition(ORDER_STATUS_ERROR, msg);
|
||||
break;
|
||||
}
|
||||
// terminal states
|
||||
case ORDER_STATUS_ERROR:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_activate(Price p, Quantity q,
|
||||
OrderServices &services,
|
||||
PerfTrace const &) {
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
me->child_builder.activate(services);
|
||||
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
me->state.set_price(p.value());
|
||||
me->state.set_quantity(q.value());
|
||||
services.child_updates.sub(
|
||||
key(), [this](auto const &os) { this->on_child_order_update(os); });
|
||||
transition(ORDER_STATUS_WORKING);
|
||||
send_next_child_order();
|
||||
break;
|
||||
|
||||
// these are not possible since the on_init_recovered code
|
||||
// would have transitioned us to error already
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_DISCONNECTED: {
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
// terminal states
|
||||
case ORDER_STATUS_ERROR:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
break;
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_update(Price p, Quantity q, PerfTrace const &) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
LOG(Plugin, Info,
|
||||
"Updating DynamicIceberg order {} to price {} quantity {}",
|
||||
key().value(), p.value(), q.value());
|
||||
me->state.set_price(p.value());
|
||||
me->state.set_quantity(q.value());
|
||||
break;
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
case ORDER_STATUS_ERROR:
|
||||
transition(me->state.status(), "Cannot update order");
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_crack(PerfTrace const &) {}
|
||||
|
||||
void DynamicIcebergOrder::on_cancel(PerfTrace const &) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
LOG(Plugin, Info, "Canceling DynamicIceberg Order {}", key().value());
|
||||
me->child.order.cancel();
|
||||
transition(ORDER_STATUS_CANCELED);
|
||||
break;
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
case ORDER_STATUS_ERROR:
|
||||
transition(me->state.status(), "Cannot cancel order");
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::report_state() {
|
||||
if (me->child.state.filled_quantity()) {
|
||||
api::orderman::OrderState merged_state;
|
||||
merge_states(me->state, me->child.state, &merged_state);
|
||||
me->services->report_state(merged_state);
|
||||
} else
|
||||
me->services->report_state(me->state);
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::merge_states(
|
||||
api::orderman::OrderState const &iceberg_state,
|
||||
api::orderman::OrderState const &child_state,
|
||||
api::orderman::OrderState *merged) {
|
||||
auto child_order_fills = child_state.filled_quantity();
|
||||
auto child_order_avg_price = child_state.avg_price();
|
||||
auto child_order_last_price = child_state.last_price();
|
||||
|
||||
auto iceberg_fills = iceberg_state.filled_quantity();
|
||||
auto iceberg_avg_price = iceberg_state.avg_price();
|
||||
|
||||
*merged = iceberg_state;
|
||||
merged->set_filled_quantity(child_order_fills + iceberg_fills);
|
||||
merged->set_last_price(child_order_last_price);
|
||||
merged->set_avg_price((child_order_fills * child_order_avg_price +
|
||||
iceberg_fills * iceberg_avg_price) /
|
||||
(child_order_fills + iceberg_fills));
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::send_next_child_order() {
|
||||
bts_assert(me->state.quantity() > me->state.filled_quantity());
|
||||
|
||||
auto remaining = me->state.quantity() - me->state.filled_quantity();
|
||||
auto to_send = std::min(remaining, me->show_quantity.value());
|
||||
me->child.order = me->child_builder.build();
|
||||
LOG(Plugin, Info,
|
||||
"DynamicIceberg order {} creating new child order {} with size "
|
||||
"{} price {}. Filled {} so far out of {}",
|
||||
key().value(), me->child.order.key().value(), to_send, me->state.price(),
|
||||
me->state.filled_quantity(), me->state.quantity());
|
||||
|
||||
me->child.order.activate(Price(me->state.price()), Quantity(to_send));
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::on_child_order_update(
|
||||
OrderStateUpdateEvent const &ev) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_WORKING:
|
||||
if (ev.key == me->child.order.key()) {
|
||||
me->child.state = ev.state;
|
||||
|
||||
switch (ev.state.status()) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
// nothing to do but report new state
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_COMPLETED: {
|
||||
api::orderman::OrderState merged_state;
|
||||
merge_states(me->state, me->child.state, &merged_state);
|
||||
me->state = merged_state;
|
||||
me->child.clear();
|
||||
if (me->state.quantity() > me->state.filled_quantity())
|
||||
send_next_child_order();
|
||||
else
|
||||
transition(ORDER_STATUS_COMPLETED);
|
||||
break;
|
||||
}
|
||||
|
||||
case ORDER_STATUS_CANCELED:
|
||||
LOG(Plugin, Info,
|
||||
"Unexpected cancel of child {} in DynamicIceberg Order {}. "
|
||||
"Canceling parent",
|
||||
ev.key.value(), key().value());
|
||||
transition(ORDER_STATUS_CANCELED);
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_ERROR:
|
||||
me->child.clear();
|
||||
transition(ORDER_STATUS_ERROR, "Unexpected child order state");
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG(Plugin, Info,
|
||||
"DynamicIceberg order {} received update for non active child "
|
||||
"order{} . update state = {} ",
|
||||
key().value(), me->child.order.key().value(),
|
||||
utils::pb::to_string(ev.state));
|
||||
}
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_CANCELED:
|
||||
case ORDER_STATUS_ERROR:
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_PENDING_WORKING:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_INACTIVE:
|
||||
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
report_state();
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::transition(api::orderman::OrderStatus new_status,
|
||||
std::string const &msg) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
auto const &to = OrderStatus_Name(new_status);
|
||||
LOG(Plugin, Info,
|
||||
"Transitioning dynamic iceberg order {} from {} to {}. Msg: {}",
|
||||
key().value(), from, to, msg);
|
||||
me->state.set_last_msg(msg);
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
void DynamicIcebergOrder::transition(api::orderman::OrderStatus new_status) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
auto const &to = OrderStatus_Name(new_status);
|
||||
LOG(OrderMan, Info, "Transitioning dynamic iceberg order {} from {} to {}",
|
||||
key().value(), from, to);
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
|
||||
} // namespace order_example
|
||||
} // namespace bts
|
||||
|
||||
DynamicOrderDescriptor get_dynamic_iceberg_order_desc()
|
||||
{
|
||||
DynamicOrderDescriptor desc;
|
||||
|
||||
// order type name
|
||||
desc.set_dynamic_order_type("DynamicIcebergOrder");
|
||||
|
||||
// show size
|
||||
auto param = desc.add_param_desc();
|
||||
param->set_param_name("show_size");
|
||||
param->mutable_param_type()->set_primitive(DYNAMIC_ORDER_PRIMITIVE_UINT);
|
||||
|
||||
// child order
|
||||
param = desc.add_param_desc();
|
||||
param->set_param_name("child");
|
||||
param->mutable_param_type()->set_primitive(DYNAMIC_ORDER_PRIMITIVE_ORDER_DEF);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
|
||||
using namespace bts;
|
||||
|
||||
serv.register_dynamic_order(get_dynamic_iceberg_order_desc(),
|
||||
[]() { return std::make_unique<bts::order_example::DynamicIcebergOrder>(); });
|
||||
LOG(Plugin,Info, "Initialized order_plugin_example.so");
|
||||
}
|
||||
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user