Compare commits

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

No files matched your search

+1
View File
@@ -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/
+2
View File
@@ -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
View File
@@ -4,7 +4,7 @@ VisualStudioVersion = 15.0.27130.2024
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
EndProject
@@ -12,11 +12,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\spar
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{9AD1A867-93A9-301D-BF77-0113E18E9E39}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
ProjectSection(ProjectDependencies) = postProject
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3} = {8530E0E8-3768-37EC-B1E1-8248C5A92FE3}
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C} = {69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
@@ -57,22 +57,22 @@ Global
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.Build.0 = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|Any CPU.ActiveCfg = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x64.ActiveCfg = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x64.Build.0 = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Debug|x86.ActiveCfg = Debug|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|Any CPU.ActiveCfg = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x64.ActiveCfg = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x64.Build.0 = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.Release|x86.ActiveCfg = Release|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{8530E0E8-3768-37EC-B1E1-8248C5A92FE3}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|Any CPU.ActiveCfg = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x64.ActiveCfg = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x64.Build.0 = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Debug|x86.ActiveCfg = Debug|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|Any CPU.ActiveCfg = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x64.ActiveCfg = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x64.Build.0 = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.Release|x86.ActiveCfg = Release|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{69D73CF1-9D7A-38CA-9817-0D0C3E3BCB3C}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|Any CPU.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
@@ -93,26 +93,30 @@ Global
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|x64
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Debug|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|Any CPU.ActiveCfg = Debug|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
@@ -133,22 +137,22 @@ Global
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.Build.0 = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|Any CPU.ActiveCfg = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x64.ActiveCfg = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x64.Build.0 = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Debug|x86.ActiveCfg = Debug|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|Any CPU.ActiveCfg = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x64.ActiveCfg = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x64.Build.0 = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.Release|x86.ActiveCfg = Release|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{9AD1A867-93A9-301D-BF77-0113E18E9E39}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|Any CPU.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x64.Build.0 = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Debug|x86.ActiveCfg = Debug|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|Any CPU.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x64.Build.0 = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.Release|x86.ActiveCfg = Release|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{33E7E6C5-04E3-36A8-A751-639BE5E72B9B}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|Any CPU.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
@@ -5,11 +5,9 @@ using mbts.collections;
using mbts.spark.utilities;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.settings;
using mbts.ui.spark;
using mbts.ui.utility;
using mbts.utils;
using bts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -18,7 +16,6 @@ using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
namespace mbts.spark {
partial class MarketViewVM {
public class Row : SecurityMDRow, IDisposable, IEquatable<Row>, DIYGrid.IRowVM, DIYGrid.IActionableRowVM {
@@ -78,16 +75,29 @@ namespace mbts.spark {
ask_price_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.Ask));
ask_size_click = new DelegateCommand(() => _show_order_ticket(MarketViewView.Columns.AskSize));
working_asks_click = new DelegateCommand(() => _show_order_book(MarketViewView.Columns.WorkingAsks));
_position.value_set += position_value_set;
_inside_bids.value_set += inside_bids_value_set;
_inside_asks.value_set += inside_asks_value_set;
_day_change.Changed += day_change_Changed;
_animation.AnimationsChanged += on_animations_changed;
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
_dispose = Disposable.Create(
_orders_model.on_security_root_orders(security.Id).OnDispatcher().Subscribe(_on_orders),
_position.OnDispatcher().Subscribe(v => _animation.animate_position(v.newval > v.oldval)),
_inside_bids.OnDispatcher().Subscribe(v => _animation.animate_working_bids_inside(v.newval)),
_inside_asks.OnDispatcher().Subscribe(v => _animation.animate_working_asks_inside(v.newval)),
_day_change.OnDispatcher().Subscribe(v => _animation.animate_day_change(v.newval > v.oldval)),
Disposable.Create(() => _animation.AnimationsChanged -= on_animations_changed)
Disposable.Create(() => {
_position.value_set -= position_value_set;
_inside_bids.value_set -= inside_bids_value_set;
_inside_asks.value_set -= inside_asks_value_set;
_day_change.Changed -= day_change_Changed;
_animation.AnimationsChanged -= on_animations_changed;
})
);
void position_value_set((int oldval, int newval) v) => _animation.animate_position(v.newval > v.oldval);
void inside_bids_value_set((bool oldval, bool newval) v) => _animation.animate_working_bids_inside(v.newval);
void inside_asks_value_set((bool oldval, bool newval) v) => _animation.animate_working_asks_inside(v.newval);
void day_change_Changed(double oldval, double newval) => _animation.animate_day_change(newval > oldval);
void on_animations_changed() => RaisePropertyChanged(nameof(animations));
}
public event Action invalidated;
@@ -129,27 +139,52 @@ namespace mbts.spark {
public void raise_invalidated() => invalidated?.Invoke();
public void refresh() {
/// <summary>
/// Returns a list of IDisposable 'update jobs.' Each item represents a job that will be executed when disposed; all jobs should be executed on the dispatcher thread.
/// </summary>
// Note: not guarenteed to be on the dispatcher thread, so all view-notifying actions should be wrapped in a IDisposable.
// Having said that, perform as much work as possible locally.
public List<IDisposable> refresh() {
var update_jobs = new List<IDisposable>();
bool dirty = false;
if (md.md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
_bid_price.set(b.price);
_bid_size.set(b.size);
_ask_price.set(a.price);
_ask_size.set(a.size);
_inside_bids.on_next_distinct(_bid_price.Value >= _working_best_bid.value, ref dirty);
_inside_asks.on_next_distinct(_ask_price.Value <= _working_best_ask.value, ref dirty);
prop_job(_bid_price, b.price);
prop_job(_bid_size, b.size);
prop_job(_ask_price, a.price);
prop_job(_ask_size, a.size);
cell_prop_job(_inside_bids, b.price >= _working_best_bid.value);
cell_prop_job(_inside_asks, a.price >= _working_best_ask.value);
}
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
_last_price.set(ps.price);
_last_size.on_next_distinct(ps.size, ref dirty);
_volume.on_next_distinct(v, ref dirty);
double new_last_price = last_price;
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
new_last_price = ps.price;
prop_job(_last_price, new_last_price);
cell_prop_job(_last_size, ps.size);
cell_prop_job(_volume, v);
}
double new_settlement = md.md.settlement_price;
prop_job(_settlement, new_settlement);
prop_job(_session_low, md.md.session_low);
prop_job(_session_high, md.md.session_high);
prop_job(_day_change, new_last_price - new_settlement);
if (dirty) {
update_jobs.Add(Disposable.Create(() => {
invalidated?.Invoke();
}));
}
return update_jobs;
void prop_job<T>(Property<T> p, T newval) {
var uj = p.set_as_job(newval);
if (uj != null)
update_jobs.Add(uj);
}
void cell_prop_job<T>(CellProperty<T> p, T newval) {
var uj = p.on_next_distinct_as_job(newval, ref dirty);
if (uj != null)
update_jobs.Add(uj);
}
_settlement.set(md.md.settlement_price);
_session_low.set(md.md.session_low);
_session_high.set(md.md.session_high);
_day_change.set(last_price - settlement);
if (dirty)
invalidated?.Invoke();
}
public bool Equals(Row other) =>
@@ -3,10 +3,13 @@ using mbts.spark.filters;
using mbts.ui;
using mbts.ui.utility;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media;
using static bts.shell.MarketViewWindowFactory;
@@ -14,7 +17,7 @@ using static mbts.ui.controls.DIYGrid;
using static mbts.ui.spark.MarketViewView;
namespace mbts.spark {
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD> {
partial class MarketViewVM : SecurityMDGrid<MarketViewVM.Row, SecurityMD>, IPrepareUpdateForDispatcher {
readonly IBus _bus;
readonly OrdersModel _orders_model;
@@ -112,8 +115,7 @@ namespace mbts.spark {
}), DataGridFilterHelper.hook_filters(rows_view,
security_filter, bid_price_filter, bid_size_filter, ask_price_filter, ask_size_filter, last_price_filter, last_size_filter, day_change_filter, settlement_filter,
session_low_filter, session_high_filter, position_filter, working_bid_volume_filter, working_ask_volume_filter, volume_filter, security_key_filter),
securities_connectable.Connect(),
WorkLoop.Start("MarketView", _refresh)
securities_connectable.Connect()
);
}
@@ -159,6 +161,25 @@ namespace mbts.spark {
}
#endregion
public IDisposable prepare_update() {
ConcurrentBag<List<IDisposable>> to_update = new ConcurrentBag<List<IDisposable>>();
try {
Parallel.For(0, _row_vms.Count, i => {
var r = _row_vms[i];
var update_jobs = r.refresh();
if (update_jobs.Count > 0)
to_update.Add(update_jobs);
});
} catch (IndexOutOfRangeException) {
// since rows (securities) will only be added/removed through rare user intervention,
// it is worth catching the occassional exception in exchange for lock-free code.
// if a row misses an update, or gets updated more than once, that's okay too;
// in 100ms it will tick again, so the data should never be more than a few 100 ms old, and rarely older than 100.
}
// return null, rather than an empty IDisposable; this signals to the UpdateMaster that it may skip the call to Dispatcher.InvokeAsync() as there is nothing to dispose.
return to_update.Count == 0 ? null : Disposable.Create(() => to_update.SelectMany(_ => _).DisposeAll());
}
protected override Row row_factory(SecurityMD smd) => new Row(_bus, smd, _orders_model);
protected override void on_row_removed(Row row) => row.Dispose();
protected override IEnumerable<SortingCriteria> get_default_sorting() { yield return new SortingCriteria(nameof(Row.security), true); }
@@ -167,4 +188,4 @@ namespace mbts.spark {
foreach (var r in _row_vms) r.refresh();
}
}
}
}
@@ -14,16 +14,18 @@ using System.Windows;
namespace mbts.spark {
class MarketViewWindow : SparkWindow<MarketViewWindowFactory.StartupData>, ISharedWindow {
const string _window_type = "MarketView", _thread_id = "MarketView", _window_type_display_name = "Market View";
readonly DispatcherUpdateMaster _dispatcher_update_master;
readonly OrdersModel _orders_model;
readonly AllowOnce _init_guard = new AllowOnce("MarketView");
MarketViewVM _vm;
MarketViewView _view;
MarketViewWindowFactory.StartupData _state;
IReadOnlyList<SparkCommand> _commands;
IDisposable _subscriptions;
IDisposable _resources;
public MarketViewWindow(MarketViewWindowFactory factory, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
public MarketViewWindow(MarketViewWindowFactory factory, DispatcherUpdateMaster dispatcher_update_master, IBus bus, OrdersModel orders_model, MarketViewWindowFactory.StartupData state)
: base("Market View", bus, factory, SparkCommands.ShowMarketView.icon) {
_dispatcher_update_master = dispatcher_update_master;
_orders_model = orders_model;
_state = state;
Icon.Freeze();
@@ -57,12 +59,14 @@ namespace mbts.spark {
SparkCommands.ShowSyntheticCreate.complete(_vm.selected_securities_observable(), secs => secs.Count > 0 && secs.Count <= 24, secs => new SecurityCriteria(secs)),
SparkCommands.change_securities_command(() => (update_securities_cmd, _state.security_criteria))
};
_subscriptions = _bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(c =>
_state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states())));
_resources = Disposable.Create(
_bus.subscribe(update_securities_cmd.tag).OnDispatcher().Subscribe(
c => _state_changed?.Invoke(_state = new MarketViewWindowFactory.StartupData(c, _vm.rows_view.GetSortingCriteria(), _vm.get_filter_states()))),
_dispatcher_update_master.attach(_vm));
}
public override void Dispose() {
Disposable.dispose(ref _subscriptions);
Disposable.dispose(ref _resources);
_vm.Dispose();
Commands.OfType<IDisposable>().DisposeAll();
}
@@ -12,6 +12,7 @@ namespace bts.shell {
class MarketViewWindowFactory : ShellWindowFactory<MarketViewWindowFactory.StartupData> {
readonly IBus _bus;
readonly OrdersModel _orders_model;
readonly DispatcherUpdateMaster _dispatcher_update_master = new DispatcherUpdateMaster("MarketView DispatcherUpdateMaster");
public MarketViewWindowFactory(MarketShellModule module, IBus bus, OrdersModel orders_model) : base(module, "MarketView") {
_bus = bus;
@@ -25,7 +26,7 @@ namespace bts.shell {
void _show(SecurityCriteria criteria) =>
_bus.post(SparkTags.ShowWindow, _create(new StartupData(criteria, new List<SortingCriteria> { new SortingCriteria(nameof(MarketViewVM.Row.security), true) }, null)));
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _bus, _orders_model, state);
IShellWindow _create(StartupData state) => new MarketViewWindow(this, _dispatcher_update_master, _bus, _orders_model, state);
[ProtoContract]
public class StartupData {
@@ -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); }
}
}
+85 -57
View File
@@ -156,15 +156,13 @@ namespace mbts.ui.shell
public string name => _propname;
public void set(T value) {
if (!Equals(value, _value)) {
Changing?.Invoke(_value, value);
var old = _value;
_value = value;
Changed?.Invoke(old, value);
_owner.RaisePropertyChanged(_propname);
}
if (!Equals(value, _value))
_apply_new_value(value);
}
public IDisposable set_as_job(T value) =>
Equals(value, _value) ? null : Disposable.Create(() => _apply_new_value(value));
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
Changed += pch;
return Disposable.Create(() => Changed -= pch);
@@ -182,6 +180,14 @@ namespace mbts.ui.shell
get { return _value; }
set { set(value); }
}
void _apply_new_value(T new_value) {
Changing?.Invoke(_value, new_value);
var old = _value;
_value = new_value;
Changed?.Invoke(old, new_value);
_owner.RaisePropertyChanged(_propname);
}
}
protected class DelegateProperty<T> : Property<T> {
@@ -529,7 +535,7 @@ namespace mbts.ui.shell
/// <para/>If the user has not selected an item, but the current items do not contain the desired item, it will re-evaluate whether or not to select the item when new items arrive.
/// </summary>
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IReadOnlyList<PropertyValidation<T>> validation_steps) =>
backing(name, items, desired_item, select_default, null, validation_steps);
backing(name, items, desired_item, select_default, EqualityComparer<T>.Default, validation_steps);
/// <summary>
/// Returns a SelectorProperty&lt;T&gt; that observes an items source, and a desired item. When either observable ticks, it determines whether or not to assign the selected_item property.
@@ -541,8 +547,8 @@ namespace mbts.ui.shell
/// <param name="desired_item">The observable sequence of a desired item.</param>
/// <param name="select_default">The fallback function to select an item by default.</param>
/// <param name="items_match">The item-matching function used to preserve a selected item when new items arrive.</param>
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, Func<T, T, bool> items_match) =>
backing(name, items, desired_item, select_default, items_match, new List<PropertyValidation<T>>(0));
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IEqualityComparer<T> comparer) =>
backing(name, items, desired_item, select_default, comparer, new List<PropertyValidation<T>>(0));
/// <summary>
/// Returns a SelectorProperty&lt;T&gt; that observes an items source, and a desired item. When either observable ticks, it determines whether or not to assign the selected_item property.
@@ -555,14 +561,24 @@ namespace mbts.ui.shell
/// <param name="select_default">The fallback function to select an item by default.</param>
/// <param name="items_match">The item-matching function used to preserve a selected item when new items arrive.</param>
/// <param name="validation_steps">The validation steps to take when selected_item changes.</param>
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, Func<T, T, bool> items_match, IReadOnlyList<PropertyValidation<T>> validation_steps) {
if (_observable_properties == null) _observable_properties = new List<IDisposable>();
var prop = new SelectorProperty<T>(this, name, select_default, items_match, validation_steps);
_observable_properties.Add(items.OnDispatcher().Subscribe(prop));
_observable_properties.Add(desired_item.OnDispatcher().Subscribe(prop));
protected SelectorProperty<T> backing<T>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T> select_default, IEqualityComparer<T> comparer, IReadOnlyList<PropertyValidation<T>> validation_steps) {
var prop = new SelectorProperty<T>(this, name, select_default, comparer, validation_steps);
attach(prop, items, desired_item);
return prop;
}
protected SelectorProperty<T, V> backing<T, V>(string name, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item, Func<T, V> item_to_value, Func<V> select_default, IEqualityComparer<V> comparer, IReadOnlyList<PropertyValidation<V>> validation_steps) {
var prop = new SelectorProperty<T, V>(this, name, item_to_value, select_default, comparer, validation_steps);
attach(prop, items, desired_item);
return prop;
}
protected void attach<T, V>(SelectorProperty<T, V> selector_property, IObservable<IEnumerable<T>> items, IObservable<InlineUserProperty<T>> desired_item) {
if (_observable_properties == null) _observable_properties = new List<IDisposable>();
_observable_properties.Add(items.OnDispatcher().Subscribe(selector_property));
_observable_properties.Add(desired_item.OnDispatcher().Subscribe(selector_property));
}
protected void set_dispose(IDisposable disposable) {
if (_dispose != null) throw new InvalidOperationException("Cannot set disposable twice");
_dispose = disposable;
@@ -579,37 +595,44 @@ namespace mbts.ui.shell
OnDisposed?.Invoke(true);
}
protected class SelectorProperty<T> : SelectorProperty<T, T> {
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<T> select_default, IEqualityComparer<T> comparer, IReadOnlyList<PropertyValidation<T>> validation_steps)
: base(owner, prop_name, i => i, select_default, comparer, validation_steps) { }
}
/// <summary>
/// Designed to observe an items source, and a [settings-driven] desired item. When a new desired item is observed, it will evaluate it's current state and determine if it should be assigned to the selected_item.
/// <para/>Notes: If the user has selected an item (ie the selected_item has been assigned through the public setter), the desired item will be ignored unless force_override is true.
/// <para/>If the user has not selected an item, but the current items do not contain the desired item, it will re-evaluate whether or not to select the item when new items arrive.
/// </summary>
protected class SelectorProperty<T> : IObserver<InlineUserProperty<T>>, IObserver<IEnumerable<T>>, IObservable<(T oldval, T newval)> {
protected class SelectorProperty<TItem, TValue> : IObserver<InlineUserProperty<TItem>>, IObserver<IEnumerable<TItem>>, IObservable<(TValue oldval, TValue newval)> {
readonly DisposableViewModelBase _owner;
readonly string _prop_name;
readonly IReadOnlyList<PropertyValidation<T>> _validation_steps;
readonly ObservableCollection<T> _items = new ObservableCollection<T>();
readonly Func<T> _select_default;
readonly Func<T, T, bool> _items_match; // used to maintain selected_item through an items-change
T _selected_item;
InlineUserProperty<T> _desired_item;
readonly IReadOnlyList<PropertyValidation<TValue>> _validation_steps;
readonly ObservableCollection<TItem> _items = new ObservableCollection<TItem>();
readonly Func<TValue> _select_default;
readonly IEqualityComparer<TValue> _value_comparer;
readonly Func<TItem, TValue> _item_to_value;
TValue _selected_item;
InlineUserProperty<TItem> _desired_item = new InlineUserProperty<TItem>();
bool _is_user_selected_item;
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<T> select_default, Func<T, T, bool> items_match, IReadOnlyList<PropertyValidation<T>> validation_steps) {
public SelectorProperty(DisposableViewModelBase owner, string prop_name, Func<TItem, TValue> item_to_value, Func<TValue> select_default, IEqualityComparer<TValue> value_comparer, IReadOnlyList<PropertyValidation<TValue>> validation_steps) {
_owner = owner;
_prop_name = prop_name;
_item_to_value = item_to_value;
_select_default = select_default;
_items_match = items_match;
_value_comparer = value_comparer ?? EqualityComparer<TValue>.Default;
_validation_steps = validation_steps;
items = new ReadOnlyObservableCollection<T>(_items);
items = new ReadOnlyObservableCollection<TItem>(_items);
}
public event PropertyChange<T> Changing;
public event PropertyChange<T> Changed;
public event PropertyChange<TValue> Changing;
public event PropertyChange<TValue> Changed;
public ReadOnlyObservableCollection<T> items { get; }
public ReadOnlyObservableCollection<TItem> items { get; }
public T selected_item {
public TValue selected_item {
get => _selected_item;
set {
_is_user_selected_item = true;
@@ -617,31 +640,31 @@ namespace mbts.ui.shell
}
}
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) {
public IDisposable Subscribe(IObserver<(TValue oldval, TValue newval)> observer) {
Changed += pch;
return Disposable.Create(() => Changed -= pch);
void pch(T o, T n) => observer.OnNext((o, n));
void pch(TValue o, TValue n) => observer.OnNext((o, n));
}
public IObservable<T> observe_current(bool start_now = false) {
public IObservable<TValue> observe_current(bool start_now = false) {
var source = this.Select(vals => vals.newval);
if (start_now)
source = source.StartWith(_selected_item);
source = source.StartWith(selected_item);
return source;
}
void IObserver<InlineUserProperty<T>>.OnNext(InlineUserProperty<T> iup) {
void IObserver<InlineUserProperty<TItem>>.OnNext(InlineUserProperty<TItem> iup) {
_desired_item = iup;
_try_auto_select();
}
void IObserver<InlineUserProperty<T>>.OnError(Exception error) { }
void IObserver<InlineUserProperty<T>>.OnCompleted() { }
void IObserver<InlineUserProperty<TItem>>.OnError(Exception error) { }
void IObserver<InlineUserProperty<TItem>>.OnCompleted() { }
void IObserver<IEnumerable<T>>.OnNext(IEnumerable<T> value) {
if (_items_match != null && _is_user_selected_item) {
void IObserver<IEnumerable<TItem>>.OnNext(IEnumerable<TItem> value) {
if (_is_user_selected_item) {
var curr_selected_item = selected_item;
_items.sync_with(value);
if (_try_match_item(curr_selected_item, out T match))
if (_try_match_item(curr_selected_item, out TValue match))
selected_item = match;
else {
_is_user_selected_item = false;
@@ -649,18 +672,13 @@ namespace mbts.ui.shell
}
} else {
_items.sync_with(value);
if (_is_user_selected_item) {
_is_user_selected_item = _items.Contains(_selected_item);
}
if (!_is_user_selected_item) {
_try_auto_select();
}
_try_auto_select();
}
}
void IObserver<IEnumerable<T>>.OnError(Exception error) { }
void IObserver<IEnumerable<T>>.OnCompleted() { }
void IObserver<IEnumerable<TItem>>.OnError(Exception error) { }
void IObserver<IEnumerable<TItem>>.OnCompleted() { }
void _run_validation(T val) {
void _run_validation(TValue val) {
var invalid_steps = _validation_steps.Select(v => v.validate(val)).Where(r => !r.valid);
if (invalid_steps.Count() > 0) {
var error_msg = string.Join("\n", invalid_steps.Where(r => !string.IsNullOrEmpty(r.msg)).Select(r => r.msg));
@@ -670,15 +688,15 @@ namespace mbts.ui.shell
void _try_auto_select() {
if (_is_user_selected_item) {
if (desired_item_valid() && _desired_item.force_override && _try_match_item(_desired_item.value, out T match)) {
if (desired_item_valid() && _desired_item.force_override && _try_match_item(_desired_item.value, out TValue match)) {
_set_selected_item(match);
return;
}
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out T match)) {
} else if (desired_item_valid() && _try_match_item(_desired_item.value, out TValue match)) {
_set_selected_item(match);
return;
}
if (_try_match_item(_select_default(), out T default_match))
if (_try_match_item(_select_default(), out TValue default_match))
_set_selected_item(default_match);
else {
// the _set_selected_item has never been entered, so validation has never ran, force it here
@@ -688,8 +706,8 @@ namespace mbts.ui.shell
bool desired_item_valid() => (_desired_item?.has_value).GetValueOrDefault();
}
void _set_selected_item(T value) {
if (!Equals(value, _selected_item)) {
void _set_selected_item(TValue value) {
if (!_value_comparer.Equals(value, _selected_item)) {
Changing?.Invoke(_selected_item, value);
var old = _selected_item;
_selected_item = value;
@@ -699,10 +717,20 @@ namespace mbts.ui.shell
}
}
bool _try_match_item(T item, out T match) =>
_items_match != null ?
_items.TryGetFirst(i => _items_match(i, item), out match) :
_items.TryGetFirst(i => i.Equals(item), out match);
bool _try_match_item(TValue value, out TValue match) {
foreach (TItem item in _items) {
TValue v = _item_to_value(item);
if (_value_comparer.Equals(v, value)) {
match = v;
return true;
}
}
match = default;
return false;
}
bool _try_match_item(TItem item, out TValue match) =>
_try_match_item(_item_to_value(item), out match);
}
public event Action<bool> OnDisposed;
@@ -15,7 +15,7 @@ namespace mbts.spark {
value = initial_value;
}
event Action<(T oldval, T newval)> _value_set;
public event Action<(T oldval, T newval)> value_set;
public T value { get; private set; }
public string text => _text ?? (_text = _format(value));
@@ -27,14 +27,22 @@ namespace mbts.spark {
}
}
public IDisposable on_next_distinct_as_job(T value, ref bool dirty) {
if (!value.Equals(this.value)) {
dirty = true;
return Disposable.Create(() => OnNext(value));
}
return null;
}
public void OnCompleted() { }
public void OnError(Exception error) { }
public void OnNext(T value) {
if (_value_set != null) {
if (value_set != null) {
T prev = this.value;
this.value = value;
_text = null;
_value_set.Invoke((prev, value));
value_set.Invoke((prev, value));
} else {
this.value = value;
_text = null;
@@ -42,7 +50,7 @@ namespace mbts.spark {
}
public IDisposable Subscribe(IObserver<(T oldval, T newval)> observer) =>
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => _value_set += cb, cb => _value_set -= cb)
Observable.FromEvent<Action<(T oldval, T newval)>, (T oldval, T newval)>(cb => value_set += cb, cb => value_set -= cb)
.Subscribe(observer);
}
}
@@ -47,7 +47,7 @@
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<usp:OrderTypeItem OrderType="{Binding order_type}" Metadata="{Binding meta}"/>
<usp:OrderTypeItem OrderType="{Binding order_type}" DisplayName="{Binding display_name}" Metadata="{Binding meta}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
@@ -33,7 +33,7 @@
Width="15"
Height="10"
/>
<TextBlock
<TextBlock x:Name="text"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="20,0,0,0"
@@ -3,23 +3,49 @@ using bts.spark;
using System.Windows;
using System.Windows.Controls;
namespace mbts.ui.spark
{
namespace mbts.ui.spark {
/// <summary>
/// Interaction logic for OrderTypeItem.xaml
/// </summary>
public partial class OrderTypeItem : Control
{
static OrderTypeItem() {
partial class OrderTypeItem : Control {
static OrderTypeItem() =>
DefaultStyleKeyProperty.OverrideMetadata(typeof(OrderTypeItem), new FrameworkPropertyMetadata(typeof(OrderTypeItem)));
}
public static readonly DependencyProperty OrderTypeProperty = DependencyProperty.Register(nameof(OrderType), typeof(CustomOrderDefinition.CustomOneofCase), typeof(OrderTypeItem),
new PropertyMetadata(CustomOrderDefinition.CustomOneofCase.None));
public CustomOrderDefinition.CustomOneofCase OrderType { get => (CustomOrderDefinition.CustomOneofCase)GetValue(OrderTypeProperty); set => SetValue(OrderTypeProperty, value); }
public static readonly DependencyProperty DisplayNameProperty =
WPFHelper.create_dp<string, OrderTypeItem>(nameof(DisplayName), (o, v) => {
o._display_name = v;
o._update_text();
});
public string DisplayName {
get => GetValue(DisplayNameProperty) as string;
set => SetValue(DisplayNameProperty, value);
}
public static readonly DependencyProperty MetadataProperty = DependencyProperty.Register(nameof(Metadata), typeof(OrderMetadata), typeof(OrderTypeItem),
new PropertyMetadata(new OrderMetadata { Color = 0, KeyBinding = string.Empty }));
public OrderMetadata Metadata { get => GetValue(MetadataProperty) as OrderMetadata; set => SetValue(MetadataProperty, value); }
string _display_name;
TextBlock _text;
public override void OnApplyTemplate() {
this.try_get_template_child("text", out _text);
_update_text();
}
void _update_text() {
if (_text != null) {
if (string.IsNullOrEmpty(_display_name)) {
_text.ClearValue(TextBlock.TextProperty);
} else {
_text.SetCurrentValue(TextBlock.TextProperty, _display_name);
}
}
}
}
}
}
@@ -1,18 +0,0 @@
using bts.api;
using mbts.ui.utility;
using System;
using System.Windows.Data;
namespace mbts.ui.converters
{
public class SecurityTypeStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return SecurityDisplay.format_security_type((SecurityType)value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
}
@@ -1,32 +0,0 @@
using bts.api;
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace mbts.ui.converters
{
[ValueConversion(typeof(SecurityType), typeof(Brush))]
public class SecurityTypeForegroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (value is SecurityType) return _convert((SecurityType)value);
//else if (value is SecurityTuple) return _convert(((SecurityTuple)value).security_type);
//else if (value is SecurityExpiration) return _convert(((SecurityExpiration)value).security_type);
else return SystemColors.ControlTextBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
private Brush _convert(SecurityType type) {
switch (type) {
case SecurityType.Option: return (Brush)BTSColors.header_text;
case SecurityType.Future: return new SolidColorBrush(Colors.Gold);
case SecurityType.Spread: return new SolidColorBrush(Colors.SlateBlue);
default: return new SolidColorBrush(Colors.PaleGreen);
}
}
}
}
@@ -26,8 +26,6 @@
<cv:CellPathConverter x:Key="CellPathConverter" />
<cv:CellKeyConverter x:Key="CellKeyConverter" />
<cv:SecurityDisplayTextConverter x:Key="SecurityTextConverter"/>
<cv:SecurityTypeForegroundConverter x:Key="SecurityTypeForegroundConverter" />
<cv:SecurityTypeStringConverter x:Key="SecurityTypeStringConverter" />
<cv:NumericSignBrushConverter x:Key="NumericSignBrushConverter" />
<cv:TickDisplayTextConverter x:Key="TickTextConverter" />
<cv:DoubleTextConverter x:Key="DoubleTextConverter" />
@@ -386,7 +386,7 @@ namespace mbts.spark {
void _tick() {
if (_settings != null) {
ulong unused = 0;
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out DateTime _, out ulong __);
bool last_trade_changed = _vm.md.get_last_trade(ref unused, out _last_trade, out ulong __);
bool depth_changed = _vm.md.get_depth(ref _prices_updated, ref _bids, ref _asks);
_mkt_break_lines.refresh();
bool prices_changed =
@@ -78,7 +78,7 @@ namespace mbts.spark {
_dispose = Disposable.Create(
settings_command,
order_properties_vm,
order_properties_vm.observe_account(true).Select(a => a.name).Subscribe(account_positions),
order_properties_vm.observe_account(true).Select(a => a?.name ?? string.Empty).Subscribe(account_positions),
account_positions,
size_calculator = new CalculatorLogic(0, _settings_manager.subscribe_current().Select(s => s.calculator_buttons)),
bus.subscribe(SparkTags.LogActivity).OnDispatcher().Subscribe(status_update),
@@ -275,7 +275,7 @@ namespace mbts.spark {
_open.set(md.open_price);
_settlement.set(md.settlement_price);
ulong unused = 0;
md.get_last_trade(ref unused, out NativePriceSize last, out DateTime time, out ulong volume);
md.get_last_trade(ref unused, out NativePriceSize last, out ulong volume);
if (!double.IsNaN(last.price)) {
_change.set(last.price - md.settlement_price);
} else {
@@ -113,7 +113,7 @@ namespace mbts.spark {
if (!sec_md.md.get_bbo(ref bbo_time, out NativePriceSize bid, out NativePriceSize ask)) return false;
// last is only used in waterfall and last calculations, so if neither of those types are selected
// we should not exit early if last is somehow not avaialble
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out DateTime unused1, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
if (!sec_md.md.get_last_trade(ref last_trade_time, out NativePriceSize last, out ulong unused2) && pnl_request.HasFlag(pnl_calc_type.waterfall | pnl_calc_type.last)) return false;
if (pnl_request.HasFlag(pnl_calc_type.waterfall)) {
// last price is available and withing range of available bid and ask
@@ -12,7 +12,7 @@ namespace mbts.spark.utilities
internal interface ISecurityMDPump
{
IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo { get; }
IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade { get; }
IObservable<(double last, uint last_size, ulong volume)> last_trade { get; }
IObservable<double> bid_price { get; }
IObservable<uint> bid_size { get; }
IObservable<double> ask_price { get; }
@@ -61,7 +61,6 @@ namespace mbts.spark.utilities
private double _bid_price, _ask_price, _last_price;
private uint _bid_size, _ask_size, _last_size;
private ulong _volume;
private DateTime _last_time;
private bool _refresh_bbo(MDConsumerHandle md) {
if (md.get_bbo(ref _bbo_ref, out NativePriceSize b, out NativePriceSize a)) {
@@ -75,10 +74,9 @@ namespace mbts.spark.utilities
}
private bool _refresh_last(MDConsumerHandle md) {
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
if (md.get_last_trade(ref _last_ref, out NativePriceSize ps, out ulong v)) {
_last_price = ps.price;
_last_size = ps.size;
_last_time = ts;
_volume = v;
return true;
}
@@ -86,17 +84,16 @@ namespace mbts.spark.utilities
}
private (double, uint, double, uint) _select_bbo() { return (_bid_price, _bid_size, _ask_price, _ask_size); }
private (double, uint, DateTime, ulong) _select_last() { return (_last_price, _last_size, _last_time, _volume); }
private (double, uint, ulong) _select_last() { return (_last_price, _last_size, _volume); }
public IObservable<(double bid, uint bid_size, double ask, uint ask_size)> bbo => _bbo_pump.Select(_ => _select_bbo()).StartWith(_select_bbo());
public IObservable<(double last, uint last_size, DateTime time_stamp, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
public IObservable<(double last, uint last_size, ulong volume)> last_trade => _last_pump.Select(_ => _select_last()).StartWith(_select_last());
public IObservable<double> bid_price => _bbo_pump.Select(_ => _bid_price).DistinctUntilChanged().StartWith(_bid_price);
public IObservable<uint> bid_size => _bbo_pump.Select(_ => _bid_size).DistinctUntilChanged().StartWith(_bid_size);
public IObservable<double> ask_price => _bbo_pump.Select(_ => _ask_price).DistinctUntilChanged().StartWith(_ask_price);
public IObservable<uint> ask_size => _bbo_pump.Select(_ => _ask_size).DistinctUntilChanged().StartWith(_ask_size);
public IObservable<double> last_price => _bbo_pump.Select(_ => _last_price).DistinctUntilChanged().StartWith(_last_price);
public IObservable<uint> last_size => _bbo_pump.Select(_ => _last_size).DistinctUntilChanged().StartWith(_last_size);
public IObservable<DateTime> last_time => _last_pump.Select(_ => _last_time).DistinctUntilChanged().StartWith(_last_time);
public IObservable<ulong> volume => _last_pump.Select(_ => _volume).DistinctUntilChanged().StartWith(_volume);
public IObservable<double> session_low => _root_pump.Select(md => md.session_low).DistinctUntilChanged();
public IObservable<double> session_high => _root_pump.Select(md => md.session_high).DistinctUntilChanged();
@@ -110,6 +110,29 @@ namespace mbts.spark.utilities {
return defs;
}
public Dictionary<OrderTemplateHeader, CustomOrderDefinitionImmutable> default_order_type_templates(SecurityImmutable security, bool is_child = false) {
const int name_ref_seed = 1;
// standard types
var defs = default_order_types(security, is_child)
.Except(new[] { CustomOrderDefinition.CustomOneofCase.Dynamic })
.ToDictionary(ot => new OrderTemplateHeader(new OrderTemplateKey(ot), OrderUtils.order_type_display_name(ot)), ot => new CustomOrderDefinitionImmutable(custom_order(ot)));
// TODO: replace with better naming scheme (right now, the order type ref count 'n' is appended to the order-type name)
var order_type_ref_count = defs.ToDictionary(kv => kv.Key, kv => name_ref_seed);
var dynamic_defs = new List<CustomOrderDefinitionImmutable>();
DynamicOrderHelper.add_dynamic_order_defs(dynamic_defs, ot => custom_order(ot));
foreach (var ddef in dynamic_defs) {
var header = new OrderTemplateHeader(new OrderTemplateKey(ddef.CustomCase, ddef.Dynamic.DynamicOrderType), ddef.Dynamic.DynamicOrderType );
// if (order_type_ref_count.TryGetValue(header, out int count)) {
// order_type_ref_count[header]++;
// header = new OrderTemplateHeader(new OrderTemplateKey(header.key.type, $"{header.key.name}{count}"), $"{header.display_name}{count}");
// } else {
// order_type_ref_count[header] = name_ref_seed;
// }
defs.Add(header, ddef);
}
return defs;
}
public IEnumerable<CustomOrderDefinition.CustomOneofCase> default_order_types(SecurityImmutable? security, bool is_child=false) =>
security.HasValue ? default_order_types(security.Value, is_child) : default_order_types();
@@ -212,7 +235,7 @@ namespace mbts.spark.utilities {
public DynamicOrderDefinition dynamic_order() => new DynamicOrderDefinition
{
Child = custom_order(),
//Child = custom_order(),
};
@@ -7,8 +7,8 @@ using System.Windows.Threading;
namespace mbts.spark {
static class WorkLoop {
public const double default_excessive_cycle_ratio = 1.2;
static readonly DispatcherPriority default_priority;
static readonly TimeSpan default_interval;
public static readonly TimeSpan default_interval;
public static readonly DispatcherPriority default_priority;
static WorkLoop() {
var timer_params = config.Configuration.get<bts.config.LadderKnobs>();
@@ -1,90 +0,0 @@
using bts.api;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace mbts.ui.utility
{
public enum DateFormat { Standard, DayMonthAbvDiff2000, DayMonthCodeDiff2000 }
static class SecurityDisplay
{
/// <summary>
/// Returns a shorthand string representation of a security type appropriate for UIs.
/// </summary>
public static string format_security_type(SecurityType type) {
switch (type) {
case SecurityType.Option: return "Opt";
case SecurityType.Future: return "Fut";
case SecurityType.Stock: return "Stk";
case SecurityType.Spread: return "Spd";
default: return type.ToString();
}
}
/// <summary>
/// Returns a concise string representation of a security expiration appropriate for UIs (e.g. es March 22, 2019: es 22 Mar 19).
/// </summary>
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date) { return format_expiration(sec_type, symbol, exp_date, false, true, true, DateFormat.DayMonthAbvDiff2000); }
/// <summary>
/// Returns a concise string representation of a security expiration (using symbol-mapped expiration dates, and single-letter month codes) appropriate for UIs (e.g. es March 22, 2019: [Opt] [es] 22 Mar 19).
/// </summary>
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date, bool show_type, bool show_symbol, bool use_mapped_exp) { return format_expiration(sec_type, symbol, exp_date, show_type, show_symbol, use_mapped_exp, DateFormat.Standard); }
/// <summary>
/// Returns a concise string representation of a security expiration (using symbol-mapped expiration dates, and single-letter month codes) appropriate for UIs (e.g. es March 22, 2019: [Opt] [es] 22 Mar 19, or [Opt] [es] 22 H19).
/// </summary>
public static string format_expiration(SecurityType sec_type, string symbol, DateTime exp_date, bool show_type, bool show_symbol, bool use_mapped_exp, DateFormat date_format) {
if (use_mapped_exp) exp_date = ExpirationFormatter.convert_real_to_mapped(sec_type, symbol, exp_date);
string result = format_date(exp_date);
if (show_symbol) result = (symbol + " " + result);
if (show_type) result = (format_security_type(sec_type) + " " + result);
return result;
}
/// <summary>
/// Returns a concise string representation of a future trade appropriate for UIs.
/// </summary>
public static string format_future_trade(string symbol, DateTime exp_date, int size, double marginal_price) { return "{0} {1} lots @ {2:C}".fmt(format_expiration(SecurityType.Future, symbol, exp_date, false, true, true), size, marginal_price); }
/// <summary>
/// Returns a concise string representation of an option trade appropriate for UIs.
/// </summary>
public static string format_option_trade(string symbol, DateTime exp_date, double strike, bool is_call, int size, double marginal_price) {
return "{0} {1} {2} {3} lots @ {4:C}".fmt(format_expiration(SecurityType.Option, symbol, exp_date, false, true, true), strike, is_call ? "C" : "P", size, marginal_price);
}
/// <summary>
/// Returns a concise string representation of a date (using standard month abbreviations) appropriate for UIs (e.g. March 22, 2019: 22 Mar 19).
/// </summary>
public static string format_date(DateTime date) { return format_date(date.Year, date.Month, date.Day, DateFormat.DayMonthAbvDiff2000); }
/// <summary>
/// Returns a concise string representation of a date (using single-letter month codes) appropriate for UIs (e.g. March 22, 2019: 22 Mar 19, or 22 H19).
/// </summary>
public static string format_date(int year, int month, int day, DateFormat format) {
switch(format) {
case DateFormat.DayMonthAbvDiff2000: return "{0} {1} {2}".fmt(day, get_month_abv(month), year - 2000);
case DateFormat.DayMonthCodeDiff2000: return "{0} {1}{2}".fmt(day, get_month_code(month), year - 2000);
case DateFormat.Standard: goto default;
default: return "{0}/{1}/{2}".fmt(day, month, year);
}
}
/// <summary>
/// Returns the option industry standard month code.
/// </summary>
public static string get_month_code(int month) { _check_month(month); return _month_codes[month - 1]; }
/// <summary>
/// Returns the standard month abbreviation (Jan, Feb, Mar, etc.).
/// </summary>
public static string get_month_abv(int month) { _check_month(month); return _month_abvs[month - 1]; }
#region Private Members
private static void _check_month(int month) { if (month < 1 || month > 12) throw new ArgumentException("There are only twelve months in a year", "month"); }
private static string[] _month_codes = new string[] { "F", "G", "H", "J", "K", "M", "N", "Q", "U", "V", "X", "Z" };
private static string[] _month_abvs = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
#endregion
}
}
+2 -1
View File
@@ -31,7 +31,8 @@ namespace bts {
Mercury,
Testing,
Latency,
DataFlow
DataFlow,
Plugin
// Please keep this list in sync with logging.h/logging.cpp
}
readonly struct Logger {
+10 -5
View File
@@ -72,7 +72,12 @@ namespace mbts.co2
return false;
}
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out DateTime timestamp, out ulong total_volume) {
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out ulong total_volume) {
total_volume = _cold->total_volume;
return (_cold->last_trade.load_if_new(ref time, out ps));
}
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out utils.LLDateTime timestamp, out ulong total_volume) {
timestamp = _cold->last_trade_time;
total_volume = _cold->total_volume;
return (_cold->last_trade.load_if_new(ref time, out ps));
@@ -88,15 +93,15 @@ namespace mbts.co2
public ulong total_volume { get { return _cold->total_volume; } }
public double settlement_price { get { return _cold->settlement_price;} }
public DateTime settlement_date { get { return _cold->settlement_date;} }
public utils.LLDate settlement_date { get { return _cold->settlement_date;} }
public double previous_settlement_price { get { return _cold->previous_settlement_price;} }
public DateTime previous_settlement_date { get { return _cold->previous_settlement_date;} }
public utils.LLDate previous_settlement_date { get { return _cold->previous_settlement_date;} }
public double open_price { get { return _cold->open_price;} }
public DateTime open_date { get { return _cold->open_date; } }
public utils.LLDate open_date { get { return _cold->open_date; } }
public double close_price { get { return _cold->close_price;} }
public DateTime close_date { get { return _cold->close_date; } }
public utils.LLDate close_date { get { return _cold->close_date; } }
public double session_high { get { return _cold->session_high;} }
public double session_low { get { return _cold->session_low; } }
public double open_interest { get { return _cold->open_interest; } }
@@ -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));
+12 -7
View File
@@ -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);
-3
View File
@@ -13,8 +13,5 @@ namespace sparkcmd {
ConsoleCommandDispatcher.DispatchCommand(commands, args, Console.Out);
return;
}
}
}
+2 -1
View File
@@ -8,7 +8,8 @@
<Authors>Blue Trading Systems</Authors>
<Company>Blue Trading Systems</Company>
<Product>Spark</Product>
<Platforms>x64</Platforms>
<Platform>x64</Platform>
<PlatformTarget>x64</PlatformTarget>
<Version>1.0.0</Version>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
+1 -1
View File
@@ -1 +1 @@
set(sources 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 ///////////////////////////
////////////////////////////////////////////
+199 -145
View File
@@ -4,12 +4,13 @@
#include "lib/api/services/AdminService.server.pb.h"
#include "lib/api/services/OrderService.server.pb.h"
#include "lib/domain_model/Security.h"
#include "lib/config/protos/jetfix.pb.h"
#include "lib/config/config.h"
namespace bts{
namespace admin{
using namespace bts::api::admin;
using namespace bts::api::orderman;
class AdminServiceUtils{
public:
////////////////////////////////////////////
@@ -17,233 +18,286 @@ public:
////////////////////////////////////////////
// finds the max id out of all the existing connections
// (todo: deleted connections)
static uint32_t find_max_connection_id (const bts::api::admin::AdminData& data);
static uint32_t find_max_connection_id (const AdminData& data);
// finds a connection by name and returns a mutable pointer to it
static const bts::api::admin::ExchangeConnection* find_connection(const bts::api::admin::AdminData& data,
const std::string& connection_name);
static const ExchangeConnection* find_connection(const AdminData& data,
const std::string& connection_name);
// finds the presence of an exchange in a connection
static bool has_exchange(const bts::api::admin::ExchangeConnection& conn,
static bool has_exchange(const ExchangeConnection& conn,
bts::api::Venue exchange);
// finds the default connections for an exchange
// in a given account
static const bts::api::admin::ExchangeConnection* find_default_account_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
bts::api::Venue exchange);
static const bts::api::admin::ExchangeConnection* resolve_cme_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
const bts::api::Security& sec);
static const bts::api::admin::ExchangeConnection* resolve_sim_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
const bts::api::Security& sec);
static const bts::api::admin::ExchangeConnection* resolve_connection(const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
const bts::api::Security& sec);
static const ExchangeConnection* find_default_account_connection(
const AdminData& data,
const BTSAccount& account,
bts::api::Venue exchange);
static const ExchangeConnection* resolve_cme_connection(
const AdminData& data,
const BTSAccount& account,
const api::Security& sec);
static const ExchangeConnection* resolve_sim_connection(
const AdminData& data,
const BTSAccount& account,
const api::Security& sec);
static const ExchangeConnection* resolve_connection(
const AdminData& data,
const BTSAccount& account,
const bts::api::Security& sec);
////////////////////////////////////////////
// connection mutators /////////////////////
////////////////////////////////////////////
// adds a new connection (does not check for name uniqueness)
static bts::api::admin::ExchangeConnection* add_connection(bts::api::admin::AdminData& data,
const bts::api::admin::ExchangeConnection& new_connection);
static ExchangeConnection* add_connection(AdminData& data,
const ExchangeConnection& new_connection);
// reads the connections from config and fills in the
// admin data (with names only)
static void fill_connections_from_config(bts::api::admin::AdminData& admin_data);
static void fill_connections_from_config(AdminData& admin_data);
////////////////////////////////////////////
// account accessors ///////////////////////
////////////////////////////////////////////
// finds the account from the name and returns
// a mutable pointer to the account
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, const std::string& acct_name, bool include_deleted=false);
static BTSAccount* find_account (AdminData& data,
const std::string& acct_name,
bool include_deleted=false);
// same as above for const pointer
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::AdminData& data, const std::string& acct_name, bool include_deleted=false);
static const BTSAccount* find_account (const AdminData& data,
const std::string& acct_name,
bool include_deleted=false);
// finds the account from the id and returns
// a mutable pointer to the account
static bts::api::admin::BTSAccount* find_account (bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static BTSAccount* find_account (AdminData& data,
uint32_t id,
bool include_deleted=false);
// like above but returns a const pointer
static const bts::api::admin::BTSAccount* find_account (const bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static const BTSAccount* find_account (const AdminData& data,
uint32_t id,
bool include_deleted=false);
// this function is an indirection layer for account access
// so deletions are dealt in a more deliberate manner
static std::vector<const bts::api::admin::BTSAccount*> accounts (const bts::api::admin::AdminData& data, bool include_deleted);
static std::vector<bts::api::admin::BTSAccount*> accounts_mutable (bts::api::admin::AdminData& data, bool include_deleted);
static std::vector<const BTSAccount*> accounts (const AdminData& data,
bool include_deleted);
static std::vector<BTSAccount*> accounts_mutable (AdminData& data,
bool include_deleted);
// finds the max id amongts all the existing accounts
static uint32_t find_max_acct_id (const bts::api::admin::AdminData& data);
static uint32_t find_max_acct_id (const AdminData& data);
// gets the account data for cme (and goes up the hierarchy
// if needed)
static const bts::api::admin::CMEAccountData* get_account_cme_data(const bts::api::admin::BTSAccount& account,
const bts::api::admin::AdminData& data);
static const bts::api::admin::SIMAccountData* get_account_sim_data(const bts::api::admin::BTSAccount& account,
const bts::api::admin::AdminData& data);
static const CMEAccountData* get_account_cme_data(const BTSAccount& account,
const AdminData& data);
static const SIMAccountData* get_account_sim_data(const BTSAccount& account,
const AdminData& data);
// returns true if an account has a connection
bool static account_has_connection(const bts::api::admin::BTSAccount& account, const std::string& connection_name);
bool static account_has_connection(const BTSAccount& account,
const std::string& connection_name);
// finds the external/clearing account associated
// with an account
static std::string find_account_exchange_account (const bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& account,
api::Venue exchange,
bts::api::admin::AdminServiceOperationResult& out_result);
static std::string find_account_exchange_account (const AdminData& data,
const BTSAccount& account,
api::Venue exchange,
AdminServiceOperationResult& out_result);
// returns a map of the accounts vs their 'is_active'
static std::map<uint32_t,bool> accounts_map(const bts::api::admin::AdminData& admin_data);
static std::map<uint32_t,bool> accounts_map(const AdminData& admin_data);
// validates that the update to the account is valid
static void validate_account_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSAccount& updated_account,
bts::api::admin::AdminServiceOperationResult& result);
static void validate_account_update (const AdminData& admin_data,
const BTSAccount& updated_account,
AdminServiceOperationResult& result);
// validates that the account exchange changes are valid
// (ex > 12 characters for accounts at CME)
static void validate_account_exchange_data (const bts::api::admin::BTSAccount& account,
bts::api::admin::AdminServiceOperationResult& out_result);
static bts::api::orderman::RoutingRecord get_routing_record(const bts::api::admin::AdminData& data,
const std::string& account_name,
const std::string& user_name,
const bts::api::Security& sec,
bts::api::admin::AdminServiceOperationResult& out_result);
static bts::api::orderman::RoutingRecord get_routing_record(const bts::api::admin::AdminData& data,
uint32_t account_id,
uint32_t user_id,
const bts::api::Security& sec,
bts::api::admin::AdminServiceOperationResult& out_result);
static void validate_account_exchange_data (const BTSAccount& account,
AdminServiceOperationResult& out_result);
static RoutingRecord get_routing_record(
const AdminData& data,
const std::string& account_name,
const std::string& user_name,
const bts::api::Security& sec,
AdminServiceOperationResult& out_result);
static RoutingRecord get_routing_record(const AdminData& data,
uint32_t account_id,
uint32_t user_id,
const bts::api::Security& sec,
AdminServiceOperationResult& out_result);
////////////////////////////////////////////
// account mutators ////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSAccount* create_account(bts::api::admin::AdminData& data,
uint32_t parent_account_id,
const std::string& account_name,
const std::string& description,
bool is_active,
bts::api::admin::AdminServiceCreateAccountResult& result);
static BTSAccount* create_account(AdminData& data,
uint32_t parent_account_id,
const std::string& account_name,
const std::string& description,
bool is_active,
AdminServiceCreateAccountResult& result);
// writes over the account data completely
static void update_account(bts::api::admin::AdminData& data,
const bts::api::admin::BTSAccount& updated_account,
bts::api::admin::AdminServiceOperationResult& result);
static void delete_account (bts::api::admin::AdminData& admin_data,
const bts::api::admin::IDAPIArgument& id,
bts::api::admin::AdminServiceOperationResult& result);
static void set_account_exchange_data(bts::api::admin::BTSAccount* account,
const bts::api::admin::ExchangeAccountData& exchange_data);
static void update_account(AdminData& data,
const BTSAccount& updated_account,
AdminServiceOperationResult& result);
static void delete_account (AdminData& admin_data,
const IDAPIArgument& id,
AdminServiceOperationResult& result);
static void set_account_exchange_data(BTSAccount* account,
const ExchangeAccountData& exchange_data);
// this is not a generally useful function but since
// connection are in config, this cleans up the account's
// connections and syncs it with the list in AdminData
static void sync_account_connections(const bts::api::admin::AdminData& data,
bts::api::admin::BTSAccount& account);
static void sync_account_connections(const AdminData& data,
BTSAccount& account);
////////////////////////////////////////////
// group accessors /////////////////////////
////////////////////////////////////////////
// given an id, finds the mutable pointer to a group
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, uint32_t id);
static BTSUserGroup* find_group (AdminData& data, uint32_t id);
// given an id, finds the const pointer to a group
static const bts::api::admin::BTSUserGroup* const find_group (const bts::api::admin::AdminData& data, uint32_t id);
static const BTSUserGroup* const find_group (const AdminData& data,
uint32_t id);
// given a name, finds the mutable pointer to a group
static bts::api::admin::BTSUserGroup* find_group (bts::api::admin::AdminData& data, const std::string& group_name);
static BTSUserGroup* find_group (AdminData& data,
const std::string& group_name);
// finds the max id out of all the groups
static uint32_t find_max_group_id (const bts::api::admin::AdminData& data);
static uint32_t find_max_group_id (const AdminData& data);
// travels up the group tree until it finds a populated cme data
static const bts::api::admin::CMEUserData* get_group_cme_data(const bts::api::admin::BTSUserGroup& group,
const bts::api::admin::AdminData& data);
static const bts::api::admin::SIMUserData* get_group_sim_data(const bts::api::admin::BTSUserGroup& group,
const bts::api::admin::AdminData& data);
static const bts::api::admin::UserAccountPermissions* const get_group_user_permissions (const bts::api::admin::AdminData& admin_data,
uint32_t group_id);
static const CMEUserData* get_group_cme_data(const BTSUserGroup& group,
const AdminData& data);
static const SIMUserData* get_group_sim_data(const BTSUserGroup& group,
const AdminData& data);
static const UserAccountPermissions* const get_group_user_permissions (
const bts::api::admin::AdminData& admin_data,
uint32_t group_id);
////////////////////////////////////////////
// group mutators/ /////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSUserGroup* create_group(bts::api::admin::AdminData& data,
uint32_t parent_group_id,
const std::string& group_name,
bts::api::admin::AdminServiceOperationResult& result);
static BTSUserGroup* create_group(AdminData& data,
uint32_t parent_group_id,
const std::string& group_name,
AdminServiceOperationResult& result);
////////////////////////////////////////////
// user accessors //////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSUser* find_user (bts::api::admin::AdminData& data, const std::string& user_name, bool include_deleted=false);
static const bts::api::admin::BTSUser* find_user (const bts::api::admin::AdminData& data, const std::string& user_name, bool include_deleted=false);
static bts::api::admin::BTSUser* find_user (bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static const bts::api::admin::BTSUser* const find_user (const bts::api::admin::AdminData& data, uint32_t id, bool include_deleted=false);
static std::vector<const bts::api::admin::BTSUser*> users (const bts::api::admin::AdminData& data, bool include_deleted);
static std::vector<bts::api::admin::BTSUser*> users_mutable (bts::api::admin::AdminData& data, bool include_deleted);
static uint32_t find_max_user_id (const bts::api::admin::AdminData& data);
static const bts::api::admin::CMEUserData* get_user_cme_data(const bts::api::admin::BTSUser& user,
const bts::api::admin::AdminData& data);
static const bts::api::admin::SIMUserData* get_user_sim_data(const bts::api::admin::BTSUser& user,
const bts::api::admin::AdminData& data);
static BTSUser* find_user (AdminData& data,
const std::string& user_name,
bool include_deleted=false);
static const BTSUser* find_user (const AdminData& data,
const std::string& user_name,
bool include_deleted=false);
static BTSUser* find_user (AdminData& data,
uint32_t id,
bool include_deleted=false);
static const BTSUser* const find_user (const AdminData& data,
uint32_t id,
bool include_deleted=false);
static std::vector<const BTSUser*> users (const AdminData& data,
bool include_deleted);
static std::vector<BTSUser*> users_mutable (AdminData& data,
bool include_deleted);
static uint32_t find_max_user_id (const AdminData& data);
static const CMEUserData* get_user_cme_data(const BTSUser& user,
const AdminData& data);
static const SIMUserData* get_user_sim_data(const BTSUser& user,
const AdminData& data);
// finds the "exchange user" (ex: "operator_id" at CME or "authorized_trader"
// at ICE) for a user
static std::string find_user_exchange_id (const bts::api::admin::AdminData& data,
const bts::api::admin::BTSUser& user,
api::Venue exchange,
bts::api::admin::AdminServiceOperationResult& out_result);
static std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>
find_user_account_matches (const bts::api::admin::AdminData& admin_data,
const std::string& connection, const std::string& exchange_account,
static std::string find_user_exchange_id (
const AdminData& data,
const BTSUser& user,
api::Venue exchange,
AdminServiceOperationResult& out_result);
static std::pair<const BTSAccount*, const BTSUser*>
find_user_account_matches (const AdminData& admin_data,
const std::string& connection,
const std::string& exchange_account,
const std::string& exchange_user,
api::Venue exchange);
// for a given user finds the account permissions (if permissions are
// derived from the group, it traverses the group hierarcy to find the
// correct permissions.
static const bts::api::admin::UserAccountPermissions* get_user_permissions (const bts::api::admin::AdminData& admin_data, uint32_t user_id);
static const UserAccountPermissions* get_user_permissions (
const AdminData& admin_data,
uint32_t user_id);
// for a given user, fills in the associated_accounts ref arg
// with the accounts the user has permission to trade in
static void find_user_trading_accounts (const bts::api::admin::AdminData& admin_data,
uint32_t user_id,
std::vector<const api::admin::BTSAccount*>& associated_accounts);
static void find_user_trading_accounts (
const AdminData& admin_data,
uint32_t user_id,
std::vector<const BTSAccount*>& associated_accounts);
// validates that changes in user data satisfy all the
// constraints
static void validate_user_update (const bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& result);
static void validate_user_update (const AdminData& admin_data,
const BTSUser& updated_user,
AdminServiceOperationResult& result);
// vaidates the exchange part of user data updates
static void validate_user_exchange_data (const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& out_result);
static void validate_user_exchange_data (
const BTSUser& updated_user,
AdminServiceOperationResult& out_result);
static void get_md_entitlement_report(const AdminData& admin_data,
std::vector<MDEntitlementReportUnit>& entitlements);
// Gets a reporting unit out of CMEMicData
static MDEntitlementReportUnit get_cme_md_entitlement_unit(
const std::string& user,
const CMEMicData& cme_mic_data);
static void get_user_symbol_permissions(
const AdminData& data,
const BTSUser& user,
std::vector<UserSymbolMDPermissionUnit>& res);
////////////////////////////////////////////
// user mutators ///////////////////////////
////////////////////////////////////////////
static bts::api::admin::BTSUser* create_user (bts::api::admin::AdminData& data,
uint32_t parent_group_id,
const std::string& name,
const std::string& password,
bool is_active,
const bts::api::admin::LicenseData& license_data,
const bts::api::admin::LicenseEntitlements& license_entitlements,
bts::api::admin::AdminServiceCreateEntityResult& result);
static bts::api::admin::BTSUser* update_user(bts::api::admin::AdminData& admin_data,
const bts::api::admin::BTSUser& updated_user,
bts::api::admin::AdminServiceOperationResult& result);
static void delete_user (bts::api::admin::AdminData& admin_data,
const bts::api::admin::IDAPIArgument& id,
bts::api::admin::AdminServiceOperationResult& result);
static void set_user_exchange_data(bts::api::admin::BTSUser* user,
const bts::api::admin::ExchangeUserData& exchange_user_data);
static void set_user_md_entitlement_data(bts::api::admin::BTSUser* user,
const bts::api::admin::ExchangeUserMarketDataEntitlementData& exchange_user_md_entitelemnt_data);
static void clear_user_accounts (bts::api::admin::BTSUser* user);
static void set_user_accounts (bts::api::admin::BTSUser* user,
const bts::api::admin::UserAccountPermissions& user_account_permissions);
static BTSUser* create_user (AdminData& data,
uint32_t parent_group_id,
const std::string& name,
const std::string& password,
bool is_active,
const LicenseData& license_data,
const LicenseEntitlements& license_entitlements,
AdminServiceCreateEntityResult& result);
static BTSUser* update_user(AdminData& admin_data,
const BTSUser& updated_user,
AdminServiceOperationResult& result);
static void delete_user (AdminData& admin_data,
const IDAPIArgument& id,
AdminServiceOperationResult& result);
static void set_user_exchange_data(
BTSUser* user,
const ExchangeUserData& exchange_user_data);
static void set_user_md_entitlement_data(BTSUser* user,
const ExchangeUserMarketDataEntitlementData&);
static void clear_user_accounts (BTSUser* user);
static void set_user_accounts (BTSUser* user,
const UserAccountPermissions& user_account_permissions);
////////////////////////////////////////////
//risk limits //////////////////////////////
////////////////////////////////////////////
// sorting function used by sort_limits to
// sort SecurityScope's
static bool _sort_security_scopes (const bts::api::admin::SecurityScope& a, const bts::api::admin::SecurityScope& b);
static bool _sort_security_scopes (const SecurityScope& a,
const SecurityScope& b);
// sorting function used by sort_limits to
// sort ProductScope's
static bool _sort_product_scopes (const bts::api::admin::ProductScope& a, const bts::api::admin::ProductScope&);
static bool _sort_product_scopes (const ProductScope& a,
const ProductScope&);
// this sorts the rules such that the most
// specific ones are at the top. this makes it
// easier to match rules with securities/products
static void sort_limits (bts::api::admin::BTSAccount& account);
static void sort_limits (BTSAccount& account);
// creates a copy of AdminData with sorted rules
static bts::api::admin::AdminData sort_limits (const bts::api::admin::AdminData& admin_data);
static AdminData sort_limits (const AdminData& admin_data);
// find the clip size for a security, account
static const uint32_t find_account_security_clip_size(const bts::api::admin::BTSAccount& account,
const api::Security& security);
static const uint32_t find_account_security_clip_size(
const BTSAccount& account,
const api::Security& security);
// find the position limit for an account, security
static const bts::api::admin::AccountSecurityPositionLimitUnit* find_account_security_position_limit(const bts::api::admin::BTSAccount& account,
static const AccountSecurityPositionLimitUnit*
find_account_security_position_limit(const BTSAccount& account,
const api::Security& security);
// find the position limit for an account, product
static const bts::api::admin::AccountProductPositionLimitUnit* find_account_product_position_limit(const bts::api::admin::BTSAccount& account,
static const AccountProductPositionLimitUnit*
find_account_product_position_limit(const BTSAccount& account,
const api::Product& product);
static bool match_security_scope (const bts::api::admin::SecurityScope& scope,
const bts::api::Security& security);
static bool match_product_scope (const bts::api::admin::ProductScope& scope,
const bts::api::Product& product);
static bool match_product(const api::Security& security, const api::Product& product);
static bool _match_limit_rule_symbol (const std::string& symbol, const std::string& limit_symbol);
static bool match_security_scope (const SecurityScope& scope,
const api::Security& security);
static bool match_product_scope (const ProductScope& scope,
const api::Product& product);
static bool match_product(const api::Security& security,
const api::Product& product);
static bool _match_limit_rule_symbol (const std::string& symbol,
const std::string& limit_symbol);
static api::SecurityType security_type(const api::Security& security);
////////////////////////////////////////////
// misc//////// ////////////////////////////
+62
View File
@@ -182,6 +182,17 @@ message AccountExchangeConnections{
/***************************Exchange Data********************************/
/************************************************************************/
message CMEMicData{
api.CMEMics mic=10;
bool enabled=20;
// there are other things here
}
message ICEMicData{
api.CMEMics mic=10;
bool enabled=20;
}
message ExchangeUserMarketDataEntitlementData{
CMEUserMarketDataEntitlementData cme_data = 10;
ICEUserMarketDataEntitlementData ice_data = 20;
@@ -276,6 +287,8 @@ message CMEUserData{
string smp_instruction = 70;
string max_order_rate_per_connection = 80;
string location = 90;
// add suff here
repeated CMEMicData md_permissions = 1000;
}
message SIMUserData {
@@ -331,6 +344,48 @@ message ICEUserData{
message ICEUserMarketDataEntitlementData{
}
///////////////////////////////////////////////////////////
// Order Auxiliary Service ////////////////////////////////
message OrdersSummaryUnit{
string account = 10;
string user = 20;
uint32 total_orders = 30;
uint32 total_contracts = 40;
}
message OrdersSummary{
repeated OrdersSummaryUnit units = 10;
}
message OrderSummaryRequest{
}
// top level orders that have account
// and user that are present here, will
// be cancelled. wild cards are not
// supported.
message OrderCancelRequest{
repeated string accounts = 10;
repeated string users = 20;
}
///////////////////////////////////////////////////////////
// Reporting //////////////////////////////////////////////
message MDEntitlementReportUnit{
string record_id = 1 [(bts.api.key)=true];
string user = 10;
string exchange = 20;
string mic = 30;
bool enabled = 40;
}
////////////////////////////////////////////////////////////
// Misc ///////////////////////////////////////////////////
message UserSymbolMDPermissionUnit{
string record_id = 1 [(bts.api.key)=true];
string user=10;
api.Venue exchange=20;
string symbol=30;
bool enabled=40;
}
/************************************************************************/
/************************************************************************/
/************************************************************************/
@@ -385,4 +440,11 @@ service AdminService {
// subscription
rpc admin_data(bts.api.VoidMessage) returns (stream AdminData);
rpc get_admin_data(bts.api.VoidMessage) returns (AdminData);
// orders
rpc get_order_summary(bts.api.VoidMessage) returns (OrdersSummary);
rpc cancel_orders(OrderCancelRequest) returns (bts.api.VoidMessage);
// reports
rpc md_entitlement_data(bts.api.VoidMessage) returns (stream MDEntitlementReportUnit);
// misc
rpc md_permissions_data(bts.api.VoidMessage) returns (stream UserSymbolMDPermissionUnit);
}
@@ -0,0 +1,17 @@
syntax="proto3";
package bts.api.md.auxiliary;
option csharp_namespace="bts.api.md.auxiliary";
import "lib/api/apioptions.proto";
import "lib/api/apicore.proto";
message VolumeAtPriceLevel{
int32 record_id = 1 [(bts.api.key)=true];
uint32 security_id = 20;
double price = 30;
uint32 volume = 40;
}
service MarketDataAuxiliaryService{
option (bts.api.service_description)="Provides non-core supplementary market data";
rpc volume_at_price(bts.api.VoidMessage) returns (stream VolumeAtPriceLevel);
}
+79 -3
View File
@@ -6,6 +6,7 @@ import "lib/api/apioptions.proto";
import "lib/domain_model/Security.proto";
import "google/protobuf/timestamp.proto";
import "lib/sparkproto/SparkProtos.proto";
import "lib/api/apicore.proto";
service OrderService {
option (bts.api.service_description)="Implements order management";
@@ -15,9 +16,12 @@ service OrderService {
rpc cancel_order(Cancel) returns (Response);
rpc update_order(Update) returns (Response);
rpc crack_order(Crack) returns (Response);
rpc get_registered_dynamic_order_types(bts.api.VoidMessage) returns (RegisteredDynamicOrderTypes);
// streams
rpc orders (OrdersSub) returns (stream OrderRecord);
rpc fills (FillsSub) returns (stream Fill);
}
@@ -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
+12 -12
View File
@@ -2,17 +2,17 @@
DynamicOrderList {
value {
# dynamic_orders
# {
# type_name: 'DynamicOrder1'
# parameter_keys: 'param1'
# parameter_keys: 'param2'
# }
# dynamic_orders
# {
# type_name: 'DynamicOrder2'
# parameter_keys: 'param3'
# parameter_keys: 'param4'
# }
dynamic_orders
{
type_name: 'DynamicOrder1'
parameter_keys: 'param1'
parameter_keys: 'param2'
}
dynamic_orders
{
type_name: 'DynamicOrder2'
parameter_keys: 'param3'
parameter_keys: 'param4'
}
}
}
@@ -1,194 +0,0 @@
ExpirationDisplayOffset
{
value
{
entries
{
security_type: "OPTION"
security_name: "lo"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "CL"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ob"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "RB"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "oh"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "HO"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "wbs"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "WBS"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "so"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "SI"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "og"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "GC"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "hxe"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "HG"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozs"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozw"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "osd"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZS"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozm"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZM"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozl"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZL"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozc"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZC"
addition_count: 0
addition_type: MonthMoveToStart
}
entries
{
security_type: "OPTION"
security_name: "ozn"
addition_count: 1
addition_type: MonthMoveToStart
}
entries
{
security_type: "FUTURE"
security_name: "ZN"
addition_count: 0
addition_type: MonthMoveToStart
}
}
}
@@ -0,0 +1,11 @@
syntax='proto2';
package bts.config;
import "lib/domain_model/Security.proto";
message CppConfig {
map<string, double> cpp_entry = 1;
}
message CmeSymbolMics {
map<string, bts.api.CMEMics> cme_mic = 1;
}
-6
View File
@@ -1,6 +0,0 @@
syntax='proto2';
package bts.config;
message CppConfig {
map<string, double> cpp_entry = 1;
}
@@ -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;
}
+4
View File
@@ -26,4 +26,8 @@ message OrdersSoftCleanup{
message ToastNotifications {
optional bool enabled = 1 [default = false];
}
message VolumeAtPrice{
optional bool enabled = 1 [default = true];
}
+16
View File
@@ -40,6 +40,22 @@ enum Currency {
CURRENCY_RMB = 14;
}
enum CMEMics {
UNSET = 0;
CME = 1;
NYMEX = 2;
CBT = 3;
COMEX = 4;
MGE = 5;
DME = 6;
NYMSW = 7;
FXS = 8;
}
enum ICEMics{
ICE_FUTURES_CANADA=0;
}
enum Side {
SIDE_UNDEFINED = 0;
SIDE_BUY = 49;
+1
View File
@@ -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"] =
+1
View File
@@ -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;
+6 -1
View File
@@ -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
+3 -3
View File
@@ -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());
+2 -2
View File
@@ -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 {
+1 -1
View File
@@ -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) {
+3 -3
View File
@@ -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()
+2 -1
View File
@@ -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;
+21 -22
View File
@@ -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
+37 -29
View File
@@ -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;
};
}}
+45 -32
View File
@@ -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 &registry)
: 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;
}
}}
+16 -30
View File
@@ -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
-2
View File
@@ -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
@@ -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()]
+27 -7
View File
@@ -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
+32 -24
View File
@@ -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
+26
View File
@@ -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
+28
View File
@@ -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
+50
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
#pragma once
namespace bts {
class SparkServices;
namespace plugin {
void init_plugins(SparkServices &);
}}
+3 -2
View File
@@ -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)
-13
View File
@@ -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
+24
View File
@@ -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()
+385
View File
@@ -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